From 3bc26bf56a0d3f3d4d5516391d869386f7f98ff5 Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Thu, 12 Jun 2025 01:47:45 -0400 Subject: [PATCH 1/7] ran on my computer - m3, and search bar fix wip --- apps/desktop/.cargo/config.toml | 18 ++ apps/desktop/build.rs | 23 ++ apps/desktop/build_with_patch.sh | 18 ++ apps/desktop/fix_cmake.sh | 38 +++ .../right-panel/views/transcript-view.tsx | 255 +++++++++++++++--- crates/llama/Cargo.toml | 2 +- crates/whisper/Cargo.toml | 2 +- packages/tiptap/src/styles/transcript.css | 6 + 8 files changed, 330 insertions(+), 32 deletions(-) create mode 100644 apps/desktop/.cargo/config.toml create mode 100644 apps/desktop/build.rs create mode 100644 apps/desktop/build_with_patch.sh create mode 100644 apps/desktop/fix_cmake.sh diff --git a/apps/desktop/.cargo/config.toml b/apps/desktop/.cargo/config.toml new file mode 100644 index 0000000000..7939e6b6ca --- /dev/null +++ b/apps/desktop/.cargo/config.toml @@ -0,0 +1,18 @@ +[env] +GGML_NATIVE = "OFF" +GGML_CPU_NATIVE = "0" +CMAKE_C_FLAGS = "-mcpu=apple-m1" +CMAKE_CXX_FLAGS = "-mcpu=apple-m1" +CC = "clang" +CXX = "clang++" +CFLAGS = "-mcpu=apple-m1" +CXXFLAGS = "-mcpu=apple-m1" +CMAKE_OSX_ARCHITECTURES = "arm64" +CMAKE_SYSTEM_PROCESSOR = "aarch64" +CMAKE_HOST_SYSTEM_PROCESSOR = "aarch64" + +[target.aarch64-apple-darwin] +rustflags = ["-C", "target-cpu=apple-m1"] + +[build] +target = "aarch64-apple-darwin" \ No newline at end of file diff --git a/apps/desktop/build.rs b/apps/desktop/build.rs new file mode 100644 index 0000000000..bd99d7abd8 --- /dev/null +++ b/apps/desktop/build.rs @@ -0,0 +1,23 @@ +fn main() { + // Set environment variables to prevent Apple Silicon mcpu issues + if cfg!(target_arch = "aarch64") && cfg!(target_os = "macos") { + println!("cargo:rustc-env=GGML_NATIVE=OFF"); + println!("cargo:rustc-env=CMAKE_C_FLAGS=-mcpu=apple-m1"); + println!("cargo:rustc-env=CMAKE_CXX_FLAGS=-mcpu=apple-m1"); + println!("cargo:rustc-env=CC=clang"); + println!("cargo:rustc-env=CXX=clang++"); + println!("cargo:rustc-env=CFLAGS=-mcpu=apple-m1"); + println!("cargo:rustc-env=CXXFLAGS=-mcpu=apple-m1"); + + // Also set them as actual environment variables + std::env::set_var("GGML_NATIVE", "OFF"); + std::env::set_var("CMAKE_C_FLAGS", "-mcpu=apple-m1"); + std::env::set_var("CMAKE_CXX_FLAGS", "-mcpu=apple-m1"); + std::env::set_var("CC", "clang"); + std::env::set_var("CXX", "clang++"); + std::env::set_var("CFLAGS", "-mcpu=apple-m1"); + std::env::set_var("CXXFLAGS", "-mcpu=apple-m1"); + + println!("cargo:warning=Setting Apple Silicon build flags"); + } +} \ No newline at end of file diff --git a/apps/desktop/build_with_patch.sh b/apps/desktop/build_with_patch.sh new file mode 100644 index 0000000000..7cdb5cdb6a --- /dev/null +++ b/apps/desktop/build_with_patch.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Start the patch monitor in background +./fix_cmake.sh & +PATCH_PID=$! + +# Function to cleanup +cleanup() { + echo "Cleaning up..." + kill $PATCH_PID 2>/dev/null + exit +} + +# Set trap to cleanup on exit +trap cleanup EXIT INT TERM + +# Run the build +GGML_NATIVE=OFF CMAKE_C_FLAGS="-mcpu=apple-m1" CMAKE_CXX_FLAGS="-mcpu=apple-m1" CC=clang CXX=clang++ CFLAGS="-mcpu=apple-m1" CXXFLAGS="-mcpu=apple-m1" CARGO_BUILD_TARGET=aarch64-apple-darwin pnpm exec turbo -F @hypr/desktop tauri:dev \ No newline at end of file diff --git a/apps/desktop/fix_cmake.sh b/apps/desktop/fix_cmake.sh new file mode 100644 index 0000000000..c7e335cf52 --- /dev/null +++ b/apps/desktop/fix_cmake.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Function to patch CMakeLists.txt files +patch_cmake_file() { + local file="$1" + if [[ -f "$file" ]]; then + echo "Patching $file for Apple Silicon..." + + # Replace the problematic ARM feature detection logic + sed -i '' 's/if (GGML_NATIVE)/if (GGML_NATIVE AND NOT APPLE)/' "$file" + + # Add Apple Silicon specific handling + sed -i '' '/if (CMAKE_OSX_ARCHITECTURES.*STREQUAL "arm64"/a\ + # Apple Silicon fix - skip native optimization\ + if (APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)$")\ + message(STATUS "Apple Silicon detected - using safe flags")\ + list(APPEND ARCH_FLAGS -mcpu=apple-m1)\ + elif (GGML_NATIVE) +' "$file" + + echo "Patched $file successfully" + fi +} + +# Monitor for CMakeLists.txt files and patch them +while true; do + # Find all CMakeLists.txt files in whisper-rs build directories + find src-tauri/target -name "whisper-rs-sys-*" -type d 2>/dev/null | while read -r dir; do + if [[ -d "$dir" ]]; then + find "$dir" -name "CMakeLists.txt" -path "*/ggml-cpu/*" | while read -r cmake_file; do + if [[ -f "$cmake_file" ]] && ! grep -q "Apple Silicon fix" "$cmake_file"; then + patch_cmake_file "$cmake_file" + fi + done + fi + done + sleep 1 +done \ No newline at end of file diff --git a/apps/desktop/src/components/right-panel/views/transcript-view.tsx b/apps/desktop/src/components/right-panel/views/transcript-view.tsx index fa10b8bedb..762903de0f 100644 --- a/apps/desktop/src/components/right-panel/views/transcript-view.tsx +++ b/apps/desktop/src/components/right-panel/views/transcript-view.tsx @@ -2,7 +2,7 @@ import { commands as tauriCommands } from "@/types/tauri.gen"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useMatch } from "@tanstack/react-router"; import useDebouncedCallback from "beautiful-react-hooks/useDebouncedCallback"; -import { AudioLinesIcon, CheckIcon, ClipboardIcon, CopyIcon, TextSearchIcon, UploadIcon } from "lucide-react"; +import { AudioLinesIcon, CheckIcon, ClipboardIcon, CopyIcon, TextSearchIcon, UploadIcon, XIcon, ChevronUpIcon, ChevronDownIcon } from "lucide-react"; import { memo, useCallback, useEffect, useRef, useState } from "react"; import { ParticipantsChipInner } from "@/components/editor-area/note-header/chips/participants-chip"; @@ -329,9 +329,11 @@ function SpeakerRangeSelector({ value, onChange }: SpeakerRangeSelectorProps) { } function SearchAndReplace({ editorRef }: { editorRef: React.RefObject }) { - const [expanded, setExpanded] = useState(false); + const [isActive, setIsActive] = useState(false); const [searchTerm, setSearchTerm] = useState(""); const [replaceTerm, setReplaceTerm] = useState(""); + const [resultCount, setResultCount] = useState(0); + const [currentIndex, setCurrentIndex] = useState(0); const debouncedSetSearchTerm = useDebouncedCallback( (value: string) => { @@ -341,6 +343,23 @@ function SearchAndReplace({ editorRef }: { editorRef: React.RefObject }) { if (value.substring(0, value.length - 1) === replaceTerm) { setReplaceTerm(value); } + + // Get search results count from the extension's storage + setTimeout(() => { + if (editorRef.current?.editor?.storage?.searchAndReplace) { + const storage = editorRef.current.editor.storage.searchAndReplace; + + // Debug: Log the storage structure to understand what's available + console.log('SearchAndReplace storage:', storage); + + // Try different possible result storage formats + const results = storage.results || storage.searchResults || []; + const count = results.length || storage.resultCount || 0; + + setResultCount(count); + setCurrentIndex(count > 0 ? 1 : 0); + } + }, 100); } }, [editorRef, replaceTerm], @@ -357,55 +376,231 @@ function SearchAndReplace({ editorRef }: { editorRef: React.RefObject }) { } }, [replaceTerm]); + // Keyboard shortcut handler - only when transcript editor is focused + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + // Check for Ctrl+F (Windows/Linux) or Cmd+F (Mac) + if ((e.ctrlKey || e.metaKey) && e.key === 'f') { + // Only activate if the transcript editor is focused + const isTranscriptFocused = editorRef.current?.editor?.isFocused; + + if (isTranscriptFocused) { + e.preventDefault(); // Prevent browser's default find + setIsActive(true); + } + } + }; + + document.addEventListener('keydown', handleKeyDown); + return () => { + document.removeEventListener('keydown', handleKeyDown); + }; + }, [editorRef]); + + // Improved navigation using DOM-based approach since extension storage might not have positions + const navigateToResult = (direction: 'next' | 'previous') => { + if (!editorRef.current?.editor || resultCount === 0) return; + + const editor = editorRef.current.editor; + const editorElement = editor.view.dom; + + // Find all highlighted search results in the DOM + const searchResults = editorElement.querySelectorAll('.search-result') as NodeListOf; + + if (searchResults.length === 0) return; + + let targetIndex: number; + + if (direction === 'next') { + targetIndex = currentIndex >= searchResults.length ? 0 : currentIndex; + } else { + targetIndex = currentIndex <= 1 ? searchResults.length - 1 : currentIndex - 2; + } + + const targetElement = searchResults[targetIndex]; + if (targetElement) { + // Remove previous active highlighting + searchResults.forEach((el: HTMLElement) => el.classList.remove('search-result-active')); + + console.log("hitting the target element", targetElement); + console.log("target index", targetIndex); + console.log("target element class list", targetElement.classList); + // Add active highlighting to current result + targetElement.classList.remove('search-result'); + targetElement.classList.add('search-result-active'); + + // Scroll the element into view + targetElement.scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'nearest' + }); + + // Update the current index (1-based for display) + setCurrentIndex(targetIndex + 1); + } + }; + + const handleNext = () => { + navigateToResult('next'); + }; + + const handlePrevious = () => { + navigateToResult('previous'); + }; + const handleReplaceAll = () => { if (editorRef.current && searchTerm) { - editorRef.current.editor.commands.replaceAll(replaceTerm); - setExpanded(false); + editorRef.current.editor.commands.replaceAll(); + // Update count after replacement + setTimeout(() => { + if (editorRef.current?.editor?.storage?.searchAndReplace) { + const storage = editorRef.current.editor.storage.searchAndReplace; + const results = storage.results || storage.searchResults || []; + const count = results.length || storage.resultCount || 0; + setResultCount(count); + setCurrentIndex(count > 0 ? 1 : 0); + } + }, 100); } }; - useEffect(() => { - if (!expanded) { + const handleToggle = () => { + setIsActive(!isActive); + if (isActive) { + // Clear search when closing setSearchTerm(""); setReplaceTerm(""); + setResultCount(0); + setCurrentIndex(0); + // Clear search highlighting + if (editorRef.current) { + editorRef.current.editor.commands.setSearchTerm(""); + + // Remove any active highlighting + const editorElement = editorRef.current.editor.view.dom; + const searchResults = editorElement.querySelectorAll('.search-result-active') as NodeListOf; + searchResults.forEach((el: HTMLElement) => el.classList.remove('search-result-active')); + } } - }, [expanded]); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Escape') { + handleToggle(); + } else if (e.key === 'Enter') { + if (e.shiftKey) { + // Shift+Enter for previous result + e.preventDefault(); + handlePrevious(); + } else { + // Enter for next result (or replace all if no results to navigate) + e.preventDefault(); + if (resultCount > 0) { + handleNext(); + } else { + handleReplaceAll(); + } + } + } else if (e.key === 'F3') { + // F3 for next, Shift+F3 for previous (common browser behavior) + e.preventDefault(); + if (e.shiftKey) { + handlePrevious(); + } else { + handleNext(); + } + } + }; return ( - - +
+ {!isActive ? ( - - -
- setSearchTerm(e.target.value)} - placeholder="Search" - /> - setReplaceTerm(e.target.value)} - placeholder="Replace" - /> + ) : ( +
+
+ setSearchTerm(e.target.value)} + onKeyDown={handleKeyDown} + placeholder="Search..." + autoFocus + /> +
+ setReplaceTerm(e.target.value)} + onKeyDown={handleKeyDown} + placeholder="Replace..." + /> +
+ + {/* Result count and navigation */} + {searchTerm && ( +
+ + {resultCount > 0 ? `${currentIndex}/${resultCount}` : "0/0"} + + + {/* Navigation buttons */} +
+ + +
+
+ )} + + {/* Replace button */} + + {/* Close button */} +
- - + )} +
); } diff --git a/crates/llama/Cargo.toml b/crates/llama/Cargo.toml index 8750a84ddb..7a54e904e1 100644 --- a/crates/llama/Cargo.toml +++ b/crates/llama/Cargo.toml @@ -21,7 +21,7 @@ thiserror = { workspace = true } llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", default-features = false, features = ["openmp", "native"], branch = "update-llama-cpp-2025-05-28" } [target.'cfg(all(target_os = "macos", target_arch = "aarch64"))'.dependencies] -llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", features = ["openmp", "native", "metal"], branch = "update-llama-cpp-2025-05-28" } +llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", features = ["openmp", "metal"], branch = "update-llama-cpp-2025-05-28" } [target.'cfg(all(target_os = "macos", target_arch = "x86_64"))'.dependencies] llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", features = ["native"], branch = "update-llama-cpp-2025-05-28" } diff --git a/crates/whisper/Cargo.toml b/crates/whisper/Cargo.toml index d52103606c..74c71ecf24 100644 --- a/crates/whisper/Cargo.toml +++ b/crates/whisper/Cargo.toml @@ -39,7 +39,7 @@ regex = { workspace = true, optional = true } whisper-rs = { git = "https://github.com/tazz4843/whisper-rs", rev = "e3d67d5", features = ["raw-api", "tracing_backend"], optional = true } [target.'cfg(all(target_os = "macos", target_arch = "aarch64"))'.dependencies] -whisper-rs = { git = "https://github.com/tazz4843/whisper-rs", rev = "e3d67d5", features = ["raw-api", "metal", "tracing_backend"], optional = true } +whisper-rs = { git = "https://github.com/tazz4843/whisper-rs", rev = "e3d67d5", features = ["raw-api", "tracing_backend"], optional = true } [target.'cfg(all(target_os = "macos", target_arch = "x86_64"))'.dependencies] whisper-rs = { git = "https://github.com/tazz4843/whisper-rs", rev = "e3d67d5", features = ["raw-api", "tracing_backend"], optional = true } diff --git a/packages/tiptap/src/styles/transcript.css b/packages/tiptap/src/styles/transcript.css index 557cc0799c..42e0a78812 100644 --- a/packages/tiptap/src/styles/transcript.css +++ b/packages/tiptap/src/styles/transcript.css @@ -4,6 +4,12 @@ padding: 1px 0; } +.search-result-active { + background-color: #8c00ff !important; + border-radius: 2px; + padding: 1px 0; +} + .transcript-speaker { margin-bottom: 14px; line-height: 1.6; From 5de510a8543bdeedac6ced3762ea98868c9c4a9a Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Fri, 13 Jun 2025 20:59:29 -0400 Subject: [PATCH 2/7] finished transcription search - 1 --- apps/desktop/build.rs | 4 +- apps/desktop/build_with_patch.sh | 18 -- apps/desktop/fix_cmake.sh | 38 ---- apps/desktop/src-tauri/.cargo/config.toml | 2 +- .../right-panel/views/transcript-view.tsx | 203 ++++++++---------- packages/tiptap/src/styles/transcript.css | 4 +- 6 files changed, 90 insertions(+), 179 deletions(-) delete mode 100644 apps/desktop/build_with_patch.sh delete mode 100644 apps/desktop/fix_cmake.sh diff --git a/apps/desktop/build.rs b/apps/desktop/build.rs index bd99d7abd8..86aeca5ff7 100644 --- a/apps/desktop/build.rs +++ b/apps/desktop/build.rs @@ -8,7 +8,7 @@ fn main() { println!("cargo:rustc-env=CXX=clang++"); println!("cargo:rustc-env=CFLAGS=-mcpu=apple-m1"); println!("cargo:rustc-env=CXXFLAGS=-mcpu=apple-m1"); - + // Also set them as actual environment variables std::env::set_var("GGML_NATIVE", "OFF"); std::env::set_var("CMAKE_C_FLAGS", "-mcpu=apple-m1"); @@ -17,7 +17,7 @@ fn main() { std::env::set_var("CXX", "clang++"); std::env::set_var("CFLAGS", "-mcpu=apple-m1"); std::env::set_var("CXXFLAGS", "-mcpu=apple-m1"); - + println!("cargo:warning=Setting Apple Silicon build flags"); } } \ No newline at end of file diff --git a/apps/desktop/build_with_patch.sh b/apps/desktop/build_with_patch.sh deleted file mode 100644 index 7cdb5cdb6a..0000000000 --- a/apps/desktop/build_with_patch.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# Start the patch monitor in background -./fix_cmake.sh & -PATCH_PID=$! - -# Function to cleanup -cleanup() { - echo "Cleaning up..." - kill $PATCH_PID 2>/dev/null - exit -} - -# Set trap to cleanup on exit -trap cleanup EXIT INT TERM - -# Run the build -GGML_NATIVE=OFF CMAKE_C_FLAGS="-mcpu=apple-m1" CMAKE_CXX_FLAGS="-mcpu=apple-m1" CC=clang CXX=clang++ CFLAGS="-mcpu=apple-m1" CXXFLAGS="-mcpu=apple-m1" CARGO_BUILD_TARGET=aarch64-apple-darwin pnpm exec turbo -F @hypr/desktop tauri:dev \ No newline at end of file diff --git a/apps/desktop/fix_cmake.sh b/apps/desktop/fix_cmake.sh deleted file mode 100644 index c7e335cf52..0000000000 --- a/apps/desktop/fix_cmake.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -# Function to patch CMakeLists.txt files -patch_cmake_file() { - local file="$1" - if [[ -f "$file" ]]; then - echo "Patching $file for Apple Silicon..." - - # Replace the problematic ARM feature detection logic - sed -i '' 's/if (GGML_NATIVE)/if (GGML_NATIVE AND NOT APPLE)/' "$file" - - # Add Apple Silicon specific handling - sed -i '' '/if (CMAKE_OSX_ARCHITECTURES.*STREQUAL "arm64"/a\ - # Apple Silicon fix - skip native optimization\ - if (APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)$")\ - message(STATUS "Apple Silicon detected - using safe flags")\ - list(APPEND ARCH_FLAGS -mcpu=apple-m1)\ - elif (GGML_NATIVE) -' "$file" - - echo "Patched $file successfully" - fi -} - -# Monitor for CMakeLists.txt files and patch them -while true; do - # Find all CMakeLists.txt files in whisper-rs build directories - find src-tauri/target -name "whisper-rs-sys-*" -type d 2>/dev/null | while read -r dir; do - if [[ -d "$dir" ]]; then - find "$dir" -name "CMakeLists.txt" -path "*/ggml-cpu/*" | while read -r cmake_file; do - if [[ -f "$cmake_file" ]] && ! grep -q "Apple Silicon fix" "$cmake_file"; then - patch_cmake_file "$cmake_file" - fi - done - fi - done - sleep 1 -done \ No newline at end of file diff --git a/apps/desktop/src-tauri/.cargo/config.toml b/apps/desktop/src-tauri/.cargo/config.toml index a6b014e959..9823a4d535 100644 --- a/apps/desktop/src-tauri/.cargo/config.toml +++ b/apps/desktop/src-tauri/.cargo/config.toml @@ -1,2 +1,2 @@ [build] -target-dir = "target" +target-dir = "target" \ No newline at end of file diff --git a/apps/desktop/src/components/right-panel/views/transcript-view.tsx b/apps/desktop/src/components/right-panel/views/transcript-view.tsx index 762903de0f..dc8fb10bc9 100644 --- a/apps/desktop/src/components/right-panel/views/transcript-view.tsx +++ b/apps/desktop/src/components/right-panel/views/transcript-view.tsx @@ -2,7 +2,7 @@ import { commands as tauriCommands } from "@/types/tauri.gen"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useMatch } from "@tanstack/react-router"; import useDebouncedCallback from "beautiful-react-hooks/useDebouncedCallback"; -import { AudioLinesIcon, CheckIcon, ClipboardIcon, CopyIcon, TextSearchIcon, UploadIcon, XIcon, ChevronUpIcon, ChevronDownIcon } from "lucide-react"; +import { AudioLinesIcon, CheckIcon, ClipboardIcon, CopyIcon, TextSearchIcon, UploadIcon, XIcon, ChevronUpIcon, ChevronDownIcon, ReplaceIcon, ArrowRightLeftIcon, RefreshCwIcon } from "lucide-react"; import { memo, useCallback, useEffect, useRef, useState } from "react"; import { ParticipantsChipInner } from "@/components/editor-area/note-header/chips/participants-chip"; @@ -101,6 +101,7 @@ export function TranscriptView() {
)}
+ {showActions && } {(audioExist.data && showActions) && ( )} - {showActions && } {showActions && }
@@ -328,41 +328,31 @@ function SpeakerRangeSelector({ value, onChange }: SpeakerRangeSelectorProps) { ); } -function SearchAndReplace({ editorRef }: { editorRef: React.RefObject }) { +export function SearchAndReplace({ editorRef }: { editorRef: React.RefObject }) { const [isActive, setIsActive] = useState(false); const [searchTerm, setSearchTerm] = useState(""); const [replaceTerm, setReplaceTerm] = useState(""); const [resultCount, setResultCount] = useState(0); const [currentIndex, setCurrentIndex] = useState(0); + + // Add ref for the search container + const searchContainerRef = useRef(null); + // Debounced search term update const debouncedSetSearchTerm = useDebouncedCallback( (value: string) => { if (editorRef.current) { editorRef.current.editor.commands.setSearchTerm(value); - - if (value.substring(0, value.length - 1) === replaceTerm) { - setReplaceTerm(value); - } - - // Get search results count from the extension's storage + editorRef.current.editor.commands.resetIndex(); setTimeout(() => { - if (editorRef.current?.editor?.storage?.searchAndReplace) { - const storage = editorRef.current.editor.storage.searchAndReplace; - - // Debug: Log the storage structure to understand what's available - console.log('SearchAndReplace storage:', storage); - - // Try different possible result storage formats - const results = storage.results || storage.searchResults || []; - const count = results.length || storage.resultCount || 0; - - setResultCount(count); - setCurrentIndex(count > 0 ? 1 : 0); - } + const storage = editorRef.current.editor.storage.searchAndReplace; + const results = storage.results || []; + setResultCount(results.length); + setCurrentIndex((storage.resultIndex ?? 0) + 1); }, 100); } }, - [editorRef, replaceTerm], + [editorRef], 300, ); @@ -376,112 +366,103 @@ function SearchAndReplace({ editorRef }: { editorRef: React.RefObject }) { } }, [replaceTerm]); + // Click outside handler + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (searchContainerRef.current && !searchContainerRef.current.contains(event.target as Node)) { + if (isActive) { + setIsActive(false); + setSearchTerm(""); + setReplaceTerm(""); + setResultCount(0); + setCurrentIndex(0); + if (editorRef.current) { + editorRef.current.editor.commands.setSearchTerm(""); + } + } + } + }; + + if (isActive) { + document.addEventListener('mousedown', handleClickOutside); + } + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [isActive, editorRef]); + // Keyboard shortcut handler - only when transcript editor is focused useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { - // Check for Ctrl+F (Windows/Linux) or Cmd+F (Mac) if ((e.ctrlKey || e.metaKey) && e.key === 'f') { - // Only activate if the transcript editor is focused const isTranscriptFocused = editorRef.current?.editor?.isFocused; - if (isTranscriptFocused) { - e.preventDefault(); // Prevent browser's default find + e.preventDefault(); setIsActive(true); } } }; - document.addEventListener('keydown', handleKeyDown); - return () => { - document.removeEventListener('keydown', handleKeyDown); - }; + return () => document.removeEventListener('keydown', handleKeyDown); }, [editorRef]); - // Improved navigation using DOM-based approach since extension storage might not have positions - const navigateToResult = (direction: 'next' | 'previous') => { - if (!editorRef.current?.editor || resultCount === 0) return; - - const editor = editorRef.current.editor; - const editorElement = editor.view.dom; - - // Find all highlighted search results in the DOM - const searchResults = editorElement.querySelectorAll('.search-result') as NodeListOf; - - if (searchResults.length === 0) return; - - let targetIndex: number; - - if (direction === 'next') { - targetIndex = currentIndex >= searchResults.length ? 0 : currentIndex; - } else { - targetIndex = currentIndex <= 1 ? searchResults.length - 1 : currentIndex - 2; - } - - const targetElement = searchResults[targetIndex]; - if (targetElement) { - // Remove previous active highlighting - searchResults.forEach((el: HTMLElement) => el.classList.remove('search-result-active')); - - console.log("hitting the target element", targetElement); - console.log("target index", targetIndex); - console.log("target element class list", targetElement.classList); - // Add active highlighting to current result - targetElement.classList.remove('search-result'); - targetElement.classList.add('search-result-active'); - - // Scroll the element into view - targetElement.scrollIntoView({ - behavior: 'smooth', - block: 'center', - inline: 'nearest' - }); - - // Update the current index (1-based for display) - setCurrentIndex(targetIndex + 1); - } - }; - + // Use extension's navigation commands const handleNext = () => { - navigateToResult('next'); + if (editorRef.current?.editor) { + editorRef.current.editor.commands.nextSearchResult(); + setTimeout(() => { + const storage = editorRef.current.editor.storage.searchAndReplace; + setCurrentIndex((storage.resultIndex ?? 0) + 1); + scrollCurrentResultIntoView(editorRef); + }, 100); + } }; const handlePrevious = () => { - navigateToResult('previous'); + if (editorRef.current?.editor) { + editorRef.current.editor.commands.previousSearchResult(); + setTimeout(() => { + const storage = editorRef.current.editor.storage.searchAndReplace; + setCurrentIndex((storage.resultIndex ?? 0) + 1); + scrollCurrentResultIntoView(editorRef); + }, 100); + } }; + function scrollCurrentResultIntoView(editorRef: React.RefObject) { + if (!editorRef.current) return; + const editorElement = editorRef.current.editor.view.dom; + const current = editorElement.querySelector('.search-result-current') as HTMLElement | null; + if (current) { + current.scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'nearest', + }); + } + } + const handleReplaceAll = () => { if (editorRef.current && searchTerm) { editorRef.current.editor.commands.replaceAll(); - // Update count after replacement setTimeout(() => { - if (editorRef.current?.editor?.storage?.searchAndReplace) { - const storage = editorRef.current.editor.storage.searchAndReplace; - const results = storage.results || storage.searchResults || []; - const count = results.length || storage.resultCount || 0; - setResultCount(count); - setCurrentIndex(count > 0 ? 1 : 0); - } + const storage = editorRef.current.editor.storage.searchAndReplace; + const results = storage.results || []; + setResultCount(results.length); + setCurrentIndex(results.length > 0 ? 1 : 0); }, 100); } }; const handleToggle = () => { setIsActive(!isActive); - if (isActive) { - // Clear search when closing + if (isActive && editorRef.current) { setSearchTerm(""); setReplaceTerm(""); setResultCount(0); setCurrentIndex(0); - // Clear search highlighting - if (editorRef.current) { - editorRef.current.editor.commands.setSearchTerm(""); - - // Remove any active highlighting - const editorElement = editorRef.current.editor.view.dom; - const searchResults = editorElement.querySelectorAll('.search-result-active') as NodeListOf; - searchResults.forEach((el: HTMLElement) => el.classList.remove('search-result-active')); - } + editorRef.current.editor.commands.setSearchTerm(""); } }; @@ -489,21 +470,13 @@ function SearchAndReplace({ editorRef }: { editorRef: React.RefObject }) { if (e.key === 'Escape') { handleToggle(); } else if (e.key === 'Enter') { + e.preventDefault(); if (e.shiftKey) { - // Shift+Enter for previous result - e.preventDefault(); handlePrevious(); } else { - // Enter for next result (or replace all if no results to navigate) - e.preventDefault(); - if (resultCount > 0) { - handleNext(); - } else { - handleReplaceAll(); - } + handleNext(); } } else if (e.key === 'F3') { - // F3 for next, Shift+F3 for previous (common browser behavior) e.preventDefault(); if (e.shiftKey) { handlePrevious(); @@ -514,7 +487,7 @@ function SearchAndReplace({ editorRef }: { editorRef: React.RefObject }) { }; return ( -
+
{!isActive ? (
- - {/* Result count and navigation */} {searchTerm && (
{resultCount > 0 ? `${currentIndex}/${resultCount}` : "0/0"} - - {/* Navigation buttons */}
)} - - {/* Replace button */} - - {/* Close button */} - ) : ( -
-
- setSearchTerm(e.target.value)} - onKeyDown={handleKeyDown} - placeholder="Search..." - autoFocus - /> -
- setReplaceTerm(e.target.value)} - onKeyDown={handleKeyDown} - placeholder="Replace..." - /> -
- {searchTerm && ( -
- - {resultCount > 0 ? `${currentIndex}/${resultCount}` : "0/0"} - -
- - -
-
- )} - + {!isActive + ? ( -
- )} + ) + : ( +
+
+ setSearchTerm(e.target.value)} + onKeyDown={handleKeyDown} + placeholder="Search..." + autoFocus + /> +
+ setReplaceTerm(e.target.value)} + onKeyDown={handleKeyDown} + placeholder="Replace..." + /> +
+ {searchTerm && ( +
+ + {resultCount > 0 ? `${currentIndex}/${resultCount}` : "0/0"} + +
+ + +
+
+ )} + + +
+ )}
); } From 4cae3183dece896882ac99278ab62ec13eaade30 Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Sat, 14 Jun 2025 23:03:44 -0400 Subject: [PATCH 4/7] updated right panel responsiveness --- .../right-panel/views/transcript-view.tsx | 124 ++++++++++++++---- 1 file changed, 102 insertions(+), 22 deletions(-) diff --git a/apps/desktop/src/components/right-panel/views/transcript-view.tsx b/apps/desktop/src/components/right-panel/views/transcript-view.tsx index 250ce050ea..295905d102 100644 --- a/apps/desktop/src/components/right-panel/views/transcript-view.tsx +++ b/apps/desktop/src/components/right-panel/views/transcript-view.tsx @@ -34,8 +34,37 @@ import { ListeningIndicator } from "../components/listening-indicator"; import { useTranscript } from "../hooks/useTranscript"; import { useTranscriptWidget } from "../hooks/useTranscriptWidget"; +function useContainerWidth(ref: React.RefObject) { + const [width, setWidth] = useState(0); + + useEffect(() => { + const element = ref.current; + if (!element) return; + + const resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + setWidth(entry.contentRect.width); + } + }); + + resizeObserver.observe(element); + // Set initial width + setWidth(element.getBoundingClientRect().width); + + return () => { + resizeObserver.disconnect(); + }; + }, [ref]); + + return width; +} + export function TranscriptView() { const queryClient = useQueryClient(); + + // Add container ref to track the panel width + const containerRef = useRef(null); + const panelWidth = useContainerWidth(containerRef); const noteMatch = useMatch({ from: "/app/note/$id", shouldThrow: true }); const sessionId = noteMatch.params.id; @@ -98,7 +127,7 @@ export function TranscriptView() { const showActions = hasTranscript && sessionId && ongoingSession.isInactive; return ( -
+
{!showEmptyMessage && (
@@ -112,7 +141,7 @@ export function TranscriptView() {
)}
- {showActions && } + {showActions && panelWidth >= 530 && } {(audioExist.data && showActions) && ( - to see live transcript + {showFullText && ( + to see live transcript + )}
-
+
or
- - + {isUltraCompact ? ( + <> + + + + ) : ( + <> + + + + )}
@@ -339,7 +417,10 @@ function SpeakerRangeSelector({ value, onChange }: SpeakerRangeSelectorProps) { ); } -export function SearchAndReplace({ editorRef }: { editorRef: React.RefObject }) { +export function SearchAndReplace({ editorRef, panelWidth }: { + editorRef: React.RefObject; + panelWidth: number; +}) { const [isActive, setIsActive] = useState(false); const [searchTerm, setSearchTerm] = useState(""); const [replaceTerm, setReplaceTerm] = useState(""); @@ -500,7 +581,7 @@ export function SearchAndReplace({ editorRef }: { editorRef: React.RefObject +
{!isActive ? ( From 401892ad3a8b43f53425464d0ef67409dd59dc9e Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Sat, 14 Jun 2025 23:07:12 -0400 Subject: [PATCH 5/7] added comment --- .../right-panel/views/transcript-view.tsx | 108 +++++++++--------- 1 file changed, 57 insertions(+), 51 deletions(-) diff --git a/apps/desktop/src/components/right-panel/views/transcript-view.tsx b/apps/desktop/src/components/right-panel/views/transcript-view.tsx index 295905d102..a38a809a88 100644 --- a/apps/desktop/src/components/right-panel/views/transcript-view.tsx +++ b/apps/desktop/src/components/right-panel/views/transcript-view.tsx @@ -39,7 +39,9 @@ function useContainerWidth(ref: React.RefObject) { useEffect(() => { const element = ref.current; - if (!element) return; + if (!element) { + return; + } const resizeObserver = new ResizeObserver((entries) => { for (const entry of entries) { @@ -61,7 +63,7 @@ function useContainerWidth(ref: React.RefObject) { export function TranscriptView() { const queryClient = useQueryClient(); - + // Add container ref to track the panel width const containerRef = useRef(null); const panelWidth = useContainerWidth(containerRef); @@ -192,21 +194,25 @@ function RenderEmpty({ sessionId }: { sessionId: string }) { } }; - // Determine layout based on actual panel width + // Determine layout based on actual panel width (empty screen) const isUltraCompact = panelWidth < 150; // Just icons - const isVeryNarrow = panelWidth < 200; // Short text - const isNarrow = panelWidth < 400; // No helper text - const showFullText = panelWidth >= 400; // Full text + const isVeryNarrow = panelWidth < 200; // Short text + const isNarrow = panelWidth < 400; // No helper text + const showFullText = panelWidth >= 400; // Full text return (
-
- - {showFullText && ( - to see live transcript - )} + {showFullText && to see live transcript}
-
+
or
- {isUltraCompact ? ( - <> - - - - ) : ( - <> - - - - )} + {isUltraCompact + ? ( + <> + + + + ) + : ( + <> + + + + )}
@@ -417,7 +423,7 @@ function SpeakerRangeSelector({ value, onChange }: SpeakerRangeSelectorProps) { ); } -export function SearchAndReplace({ editorRef, panelWidth }: { +export function SearchAndReplace({ editorRef, panelWidth }: { editorRef: React.RefObject; panelWidth: number; }) { From 92a27efd083f51fd0e9ab3902cac4e59776d40cf Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Sat, 14 Jun 2025 23:25:46 -0400 Subject: [PATCH 6/7] fixed compiled with llama --- crates/llama/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/llama/Cargo.toml b/crates/llama/Cargo.toml index c8c0bd2777..b8a4eabfc8 100644 --- a/crates/llama/Cargo.toml +++ b/crates/llama/Cargo.toml @@ -21,8 +21,7 @@ thiserror = { workspace = true } llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", default-features = false, features = ["openmp"], branch = "update-llama-cpp-2025-06-04" } [target.'cfg(all(target_os = "macos", target_arch = "aarch64"))'.dependencies] - -llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", features = ["openmp", "metal"], branch = "update-llama-cpp-2025-05-28" } +llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", features = ["openmp", "metal"], branch = "update-llama-cpp-2025-06-04" } [target.'cfg(all(target_os = "macos", target_arch = "x86_64"))'.dependencies] llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", features = ["native"], branch = "update-llama-cpp-2025-06-04" } From 1f37616c00ad7dc8a782712dbfc79cdad4fb5299 Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Sat, 14 Jun 2025 23:45:48 -0400 Subject: [PATCH 7/7] fixed responsiveness --- Cargo.lock | 4 ++-- crates/llama/Cargo.toml | 6 +++--- crates/whisper/Cargo.toml | 2 -- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4563a94421..afee6d9ee4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7840,7 +7840,7 @@ dependencies = [ [[package]] name = "llama-cpp-2" version = "0.1.108" -source = "git+https://github.com/utilityai/llama-cpp-rs?branch=update-llama-cpp-2025-06-04#73707a44ce892578ad94d630b356c0ec417c7476" +source = "git+https://github.com/utilityai/llama-cpp-rs?branch=update-llama-cpp-2025-05-28#c007d3654a093a37ee1580cf66f54ce75e8efaef" dependencies = [ "enumflags2", "llama-cpp-sys-2", @@ -7852,7 +7852,7 @@ dependencies = [ [[package]] name = "llama-cpp-sys-2" version = "0.1.108" -source = "git+https://github.com/utilityai/llama-cpp-rs?branch=update-llama-cpp-2025-06-04#73707a44ce892578ad94d630b356c0ec417c7476" +source = "git+https://github.com/utilityai/llama-cpp-rs?branch=update-llama-cpp-2025-05-28#c007d3654a093a37ee1580cf66f54ce75e8efaef" dependencies = [ "bindgen 0.69.5", "cc", diff --git a/crates/llama/Cargo.toml b/crates/llama/Cargo.toml index b8a4eabfc8..f0772b65de 100644 --- a/crates/llama/Cargo.toml +++ b/crates/llama/Cargo.toml @@ -18,13 +18,13 @@ serde = { workspace = true } thiserror = { workspace = true } [target.'cfg(not(target_os = "macos"))'.dependencies] -llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", default-features = false, features = ["openmp"], branch = "update-llama-cpp-2025-06-04" } +llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", default-features = false, features = ["openmp"], branch = "update-llama-cpp-2025-05-28" } [target.'cfg(all(target_os = "macos", target_arch = "aarch64"))'.dependencies] -llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", features = ["openmp", "metal"], branch = "update-llama-cpp-2025-06-04" } +llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", features = ["openmp", "metal"], branch = "update-llama-cpp-2025-05-28" } [target.'cfg(all(target_os = "macos", target_arch = "x86_64"))'.dependencies] -llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", features = ["native"], branch = "update-llama-cpp-2025-06-04" } +llama-cpp-2 = { git = "https://github.com/utilityai/llama-cpp-rs", features = ["native"], branch = "update-llama-cpp-2025-05-28" } [dev-dependencies] hypr-buffer = { workspace = true } diff --git a/crates/whisper/Cargo.toml b/crates/whisper/Cargo.toml index c3f683dfc7..74c71ecf24 100644 --- a/crates/whisper/Cargo.toml +++ b/crates/whisper/Cargo.toml @@ -41,7 +41,5 @@ whisper-rs = { git = "https://github.com/tazz4843/whisper-rs", rev = "e3d67d5", [target.'cfg(all(target_os = "macos", target_arch = "aarch64"))'.dependencies] whisper-rs = { git = "https://github.com/tazz4843/whisper-rs", rev = "e3d67d5", features = ["raw-api", "tracing_backend"], optional = true } -whisper-rs = { git = "https://github.com/tazz4843/whisper-rs", rev = "e3d67d5", features = ["raw-api", "tracing_backend"], optional = true } - [target.'cfg(all(target_os = "macos", target_arch = "x86_64"))'.dependencies] whisper-rs = { git = "https://github.com/tazz4843/whisper-rs", rev = "e3d67d5", features = ["raw-api", "tracing_backend"], optional = true }