-
Notifications
You must be signed in to change notification settings - Fork 522
Feat: Implement Smart Search Bar with Voice Search for Quick Navigation #657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Added error handling and voice search functionality to the Navbar component.
Added voice command functionality and improved error handling.
Refactor ErrorDialog and Navbar components for improved styling and functionality. Adjust voice search handling and cleanup code structure.
WalkthroughThis pull request adds voice-to-text functionality through a new Changes
Sequence DiagramssequenceDiagram
actor User
participant Navbar
participant VoiceCommand
participant SpeechRecognition
participant RouteMap
User->>Navbar: Click microphone icon
Navbar->>VoiceCommand: Mount VoiceCommand component
VoiceCommand->>SpeechRecognition: Initialize & start listening
Note over VoiceCommand: Display "Listening…" state
User->>SpeechRecognition: Speak command (e.g., "favourites")
SpeechRecognition->>VoiceCommand: Return transcript
VoiceCommand->>VoiceCommand: Lowercase & trim transcript
VoiceCommand->>Navbar: Invoke onCommand callback
Navbar->>RouteMap: Match transcript to route
alt Route found
Navbar->>Navbar: Navigate via window.location.href
Note over Navbar: Clear search, update UI
else Route not found
Navbar->>Navbar: Show ErrorDialog to user
end
sequenceDiagram
actor User
participant Navbar
User->>Navbar: Type in search input
Navbar->>Navbar: Update query state
Navbar->>Navbar: Filter suggestions based on query
Navbar->>Navbar: Display dropdown results
alt Keyboard navigation
User->>Navbar: Press ArrowDown
Navbar->>Navbar: Highlight next suggestion
User->>Navbar: Press Enter
Navbar->>Navbar: Navigate to selected page
else Voice input
User->>Navbar: Click microphone
Note over Navbar: VoiceCommand flow initiated
else Direct selection
User->>Navbar: Click suggestion
Navbar->>Navbar: Navigate to page
end
Navbar->>Navbar: Clear search state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (7)
frontend/src/components/Dialog/VoiceCommand.tsx (2)
11-40: Avoid blockingalertfor speech errors; surface via props or app‑level UI
alertcalls for unsupported browsers and recognition errors break the app’s visual/UX flow and are harder to style or internationalize. Since you already have in‑app dialogs elsewhere, it would be cleaner to surface these via a callback or parent UI instead of hard‑coding alerts here.Consider extending the props and delegating error display to the caller:
-interface Props { - onCommand: (cmd: string) => void; -} +interface Props { + onCommand: (cmd: string) => void; + onError?: (message: string) => void; +} ... - if (!SpeechRecognition) { - alert("Speech recognition not supported in this browser."); - return; - } + if (!SpeechRecognition) { + onError?.("Speech recognition is not supported in this browser."); + return; + } ... - recognition.onerror = () => { - setListening(false); - alert("Try again..."); - }; + recognition.onerror = () => { + setListening(false); + onError?.("There was an error with speech recognition. Please try again."); + };This keeps the component reusable and lets Navbar (or others) decide how to present errors.
43-55: Unify voice handling with Navbar to avoid duplicated Web Speech logicNavbar currently imports
VoiceCommandbut reimplements its own SpeechRecognition wiring and mic button. That gives you two separate code paths to maintain for essentially the same concern.Either:
- Replace the inline mic button in
Navbarwith<VoiceCommand onCommand={...} />wired to yourgoToPagelogic (and optionalonErroras above), or- If Navbar’s overlay‑style UX is preferred and
VoiceCommandwon’t be reused, drop the import/this component to avoid dead/duplicate behavior.Reusing
VoiceCommandin Navbar keeps speech configuration, language, and error behavior in one place.frontend/src/components/Navigation/Navbar/Navbar.tsx (5)
14-21: Reuse shared dialog components instead of a bespokeErrorDialogoverlayYou define a custom
ErrorDialoghere while other flows (e.g.,FaceSearchDialog) already rely on sharedDialog/showInfoDialogpatterns. For consistency in styling, accessibility, and focus management, consider reusing those existing primitives instead of maintaining a separate modal implementation just for navbar errors.
28-35: Avoid subscribing tostate.searchif navbar doesn’t use it
searchState,isSearchActive, andqueryImageare derived but not used later, which means Navbar will still re‑render on every search state change without benefiting from the data.If this subscription is no longer needed, you can remove the selector and derived locals to reduce unnecessary renders:
- const searchState = useSelector((state: any) => state.search); - const dispatch = useDispatch(); - - const isSearchActive = searchState.active; - const queryImage = searchState.queryImage; + const dispatch = useDispatch();You still call
dispatch(clearSearch())ingoToPage, so the slice remains in use without coupling Navbar’s render cycle to it.
63-72: Prefer router navigation (useNavigate/Link) overwindow.locationand raw anchors
goToPageuseswindow.location.href, and the logo/settings use<a href>links. In a React SPA (and givenFaceSearchDialogusesuseNavigate), this forces full page reloads and bypasses client‑side routing.Consider switching to router navigation, for example:
-import React, { useState, useEffect, useRef } from "react"; +import React, { useState, useEffect, useRef } from "react"; +import { useNavigate, Link } from "react-router-dom"; ... export function Navbar() { + const navigate = useNavigate(); ... const goToPage = (label: string) => { dispatch(clearSearch()); const key = label.trim().toLowerCase().replace(/\s+/g, "-"); - if (routeMap[key]) { - window.location.href = routeMap[key]; - } else { + if (routeMap[key]) { + navigate(routeMap[key]); + } else { setError(`The page "${label}" does not exist.`); } }; ... - <a href="/" className="flex items-center gap-2"> + <Link to="/" className="flex items-center gap-2"> ... - <a href="/settings"> + <Link to="/settings"> ... - </a> + </Link>This keeps navigation within the SPA and plays nicely with history, guards, and Tauri’s routing integration.
Also applies to: 144-147, 196-201
74-87: Improve Enter‑key behavior when no suggestion is highlighted
handleKeyDownonly reacts to Enter whenactiveIndex >= 0, so typing a query and pressing Enter without using the arrow keys is a no‑op even whenfilteredhas matches.Consider treating Enter with no active item as “go to the first suggestion” (or directly attempt
goToPage(query)):- } else if (e.key === "Enter" && activeIndex >= 0) { - goToPage(filtered[activeIndex]); - setActiveIndex(-1); - } + } else if (e.key === "Enter") { + if (activeIndex >= 0) { + goToPage(filtered[activeIndex]); + } else if (filtered.length > 0) { + goToPage(filtered[0]); + } + setActiveIndex(-1); + }This aligns with typical search‑box UX where Enter triggers navigation based on the current query.
91-140: StopSpeechRecognitionwhen closing the voice dialog and reuse the existing refThe voice flow starts a
SpeechRecognitioninstance and stores it inrecognitionRef, but closing the voice overlay (✕ button) only togglesvoiceOpenand never callsstop(). That can leave recognition running briefly in the background after the UI disappears, and the ref is otherwise unused.You can centralize cleanup and make use of
recognitionRef:const recognitionRef = useRef<any>(null); ... - const startListening = () => { + const stopListening = () => { + if (recognitionRef.current) { + recognitionRef.current.stop(); + recognitionRef.current = null; + } + setVoiceOpen(false); + }; + + const startListening = () => { setVoiceOpen(true); ... - const recog = new SR(); - recognitionRef.current = recog; + const recog = new SR(); + recognitionRef.current = recog; ... - recog.onerror = () => { - setVoiceText("Try again"); - setTimeout(() => setVoiceOpen(false), 800); - }; + recog.onerror = () => { + setVoiceText("Try again"); + setTimeout(() => stopListening(), 800); + }; ... - recog.start(); + recog.start(); }; ... - {voiceOpen && ( + {voiceOpen && ( <div className="fixed top-28 left-0 right-0 flex justify-center z-[2000]"> <div className="relative max-w-sm w-full rounded-3xl p-6 bg-white border shadow-xl dark:bg-neutral-900"> - <button className="absolute top-3 right-4 text-xl font-bold" onClick={() => setVoiceOpen(false)}> + <button + className="absolute top-3 right-4 text-xl font-bold" + onClick={stopListening} + > ✕ </button>Also, since you already have a dedicated
VoiceCommandcomponent encapsulating Web Speech behavior, consider delegating recognition there and using its callback to route, to avoid diverging behavior/config between two separate implementations.Also applies to: 206-215
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
frontend/src/components/Dialog/VoiceCommand.tsx(1 hunks)frontend/src/components/Navigation/Navbar/Navbar.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/components/Navigation/Navbar/Navbar.tsx (4)
frontend/src/features/onboardingSelectors.ts (2)
selectName(15-15)selectAvatar(13-13)frontend/src/features/searchSlice.ts (1)
clearSearch(21-24)frontend/src/components/Dialog/FaceSearchDialog.tsx (1)
FaceSearchDialog(25-153)frontend/src/components/ThemeToggle.tsx (1)
ThemeSelector(12-52)
|
Hi Sir @rahulharpal1603 , I kindly request you to please review this PR and share your valuable feedback whenever you get time. |
|
Is this issue assigned? |
|
Yes @Vaibhavi-14shetty , |
Overview
This PR implements a Smart Search Bar with a Voice Search button for PictoPy.
Previously, users had to manually browse the sidebar to access features like AI Tagging, Videos, or Albums.
With this enhancement, users can quickly search for pages, images, or tags using text or voice input.
Features Added
Smart Search Bar
AI Tagging,Videos,Albums, etc.Benefits
Implementation Notes
SearchBarcomponent.Micicon for voice search.Screenshots
LIGHT MODE
DARK MODE
###Video
22.11.2025_11.38.11_REC_PICTOPY.mp4
Issue
Closes #627
Summary by CodeRabbit
Release Notes
✏️ Tip: You can customize this high-level summary in your review settings.