Add Pagefind docs search to left sidebar#2074
Add Pagefind docs search to left sidebar#2074ComputelessComputer wants to merge 5 commits intomainfrom
Conversation
Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
✅ Deploy Preview for hyprnote-storybook ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
❌ Deploy Preview for hyprnote failed.
|
📝 WalkthroughWalkthroughAdds client-side docs search: new React Changes
Sequence Diagram(s)mermaid User->>UI: Ctrl/Cmd+K or click -> open search Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
apps/web/src/components/docs-search.tsx (1)
6-23: Consider inlining interfaces (optional).Per coding guidelines, interfaces that aren't shared could be inlined. However, since these types document the Pagefind API structure, keeping them separate may aid clarity.
If you prefer to follow the guideline strictly, you could inline them:
const [pagefind, setPagefind] = useState<{ search: (query: string) => Promise<{ results: Array<{ id: string; data: () => Promise<{ url: string; meta: { title: string }; excerpt: string; }>; }>; } | null>; } | null>(null);However, the current approach is more readable.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (3)
apps/web/package.json(2 hunks)apps/web/src/components/docs-search.tsx(1 hunks)apps/web/src/routes/_view/docs/route.tsx(2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, usecn(import from@hypr/utils). It is similar toclsx. Always pass an array and split by logical grouping.
Usemotion/reactinstead offramer-motion.
Files:
apps/web/src/components/docs-search.tsxapps/web/src/routes/_view/docs/route.tsx
🧠 Learnings (1)
📚 Learning: 2025-11-24T16:32:24.348Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: apps/desktop-e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:24.348Z
Learning: Applies to apps/desktop-e2e/**/*.{test,spec}.{js,ts,tsx} : Refer to `scripts/setup-desktop-e2e.sh` for end-to-end test environment setup if setup is missing
Applied to files:
apps/web/package.json
🧬 Code graph analysis (2)
apps/web/src/components/docs-search.tsx (1)
packages/utils/src/cn.ts (1)
cn(20-22)
apps/web/src/routes/_view/docs/route.tsx (1)
apps/web/src/components/docs-search.tsx (1)
DocsSearch(25-158)
🪛 ast-grep (0.40.0)
apps/web/src/components/docs-search.tsx
[warning] 142-142: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
apps/web/src/components/docs-search.tsx
[error] 143-143: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🪛 GitHub Actions: web_ci
apps/web/src/components/docs-search.tsx
[error] 1-1: vite: Rollup failed to resolve import '/pagefind/pagefind.js' from docs-search.tsx. This may break runtime; consider externalizing the module or ensuring the path exists.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Devin
🔇 Additional comments (4)
apps/web/package.json (2)
7-7: LGTM! Build script correctly chains Pagefind indexing.The updated build script properly sequences the Vite build before running Pagefind indexing, ensuring the HTML files exist before indexing. The glob pattern appropriately targets only docs HTML files.
80-80: Version 1.4.0 is the latest stable release (as of September 2025). The dependency is correctly placed in devDependencies with an appropriate caret range for patch-level updates.apps/web/src/routes/_view/docs/route.tsx (2)
10-10: LGTM! Clean import statement.The import follows the project's path alias conventions and uses a named export appropriately.
83-83: LGTM! Appropriate component placement.The DocsSearch component is correctly positioned in the sidebar before the navigation menu, providing a logical search-then-navigate flow.
Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (3)
apps/web/src/components/docs-search.tsx (3)
117-184: Add keyboard navigation for accessibility.The search dropdown still lacks keyboard navigation (arrow keys to navigate results, Enter to select, Escape to close), which prevents keyboard-only users from using the search feature and violates WCAG accessibility standards.
Implement keyboard support with state for selected index:
export function DocsSearch() { const [query, setQuery] = useState(""); const [results, setResults] = useState<PagefindResult[]>([]); const [isOpen, setIsOpen] = useState(false); const [isLoading, setIsLoading] = useState(false); const [pagefind, setPagefind] = useState<PagefindInstance | null>(null); + const [selectedIndex, setSelectedIndex] = useState(-1); const inputRef = useRef<HTMLInputElement>(null); const containerRef = useRef<HTMLDivElement>(null); + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (!isOpen || results.length === 0) return; + + switch (e.key) { + case 'ArrowDown': + e.preventDefault(); + setSelectedIndex(prev => prev < results.length - 1 ? prev + 1 : 0); + break; + case 'ArrowUp': + e.preventDefault(); + setSelectedIndex(prev => prev > 0 ? prev - 1 : results.length - 1); + break; + case 'Enter': + e.preventDefault(); + if (selectedIndex >= 0 && results[selectedIndex]) { + window.location.href = results[selectedIndex].url; + setIsOpen(false); + } + break; + case 'Escape': + e.preventDefault(); + setIsOpen(false); + break; + } + };Apply to the input:
<input ref={inputRef} type="text" value={query} onChange={(e) => handleSearch(e.target.value)} onFocus={() => query && setIsOpen(true)} + onKeyDown={handleKeyDown} placeholder="Search docs..."And highlight the selected result:
<a href={result.url} onClick={() => setIsOpen(false)} className={cn([ "block px-4 py-3 hover:bg-neutral-50 transition-colors", "border-b border-neutral-100 last:border-b-0", + selectedIndex === index && "bg-neutral-100", ])} >
170-170: Sanitize HTML before rendering with dangerouslySetInnerHTML.The excerpt HTML from Pagefind is rendered without sanitization, creating an XSS vulnerability. Even though Pagefind should sanitize during indexing, defense-in-depth requires sanitization before rendering.
Install DOMPurify:
npm install dompurify npm install --save-dev @types/dompurifyThen sanitize the excerpt:
+import DOMPurify from 'dompurify'; + // ... in the component: <div className="text-xs text-neutral-500 mt-1 line-clamp-2" - dangerouslySetInnerHTML={{ __html: result.excerpt }} + dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(result.excerpt) }} />
156-156: Use unique identifier for result keys instead of array index.Using array index as
keycan cause React reconciliation issues when search results change. Useresult.urlwhich should be unique per result.-{results.map((result, index) => ( - <li key={index}> +{results.map((result) => ( + <li key={result.url}>
🧹 Nitpick comments (1)
apps/web/src/components/docs-search.tsx (1)
88-115: Consider logging search errors for debugging.The search handler silently catches and ignores errors (line 108-109). While the PR description mentions "fails silently with console.warn", no warning is actually logged. Adding a console.warn or console.error would improve debugging when Pagefind fails to load or search errors occur.
Apply this diff to add error logging:
- } catch { + } catch (error) { + console.warn('Pagefind search failed:', error); setResults([]); } finally {
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/src/components/docs-search.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, usecn(import from@hypr/utils). It is similar toclsx. Always pass an array and split by logical grouping.
Usemotion/reactinstead offramer-motion.
Files:
apps/web/src/components/docs-search.tsx
🧬 Code graph analysis (1)
apps/web/src/components/docs-search.tsx (1)
packages/utils/src/cn.ts (1)
cn(20-22)
🪛 ast-grep (0.40.0)
apps/web/src/components/docs-search.tsx
[warning] 169-169: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
apps/web/src/components/docs-search.tsx
[error] 170-170: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: fmt
- GitHub Check: Redirect rules - hyprnote
- GitHub Check: Header rules - hyprnote
- GitHub Check: Pages changed - hyprnote
- GitHub Check: ci
- GitHub Check: Devin
🔇 Additional comments (2)
apps/web/src/components/docs-search.tsx (2)
1-29: LGTM!The imports and interface definitions are appropriate. The interfaces correctly type the external Pagefind API, and the use of
cnfrom@hypr/utilsfollows the coding guidelines.
40-86: LGTM!The Pagefind initialization logic correctly handles SSR, checks for existing instances, and uses proper cleanup. The click-outside handler follows standard React patterns with appropriate event listener cleanup.
- Use vite-plugin-pagefind for better dev/build integration - Use @hypr/ui Command components for command palette UI - Add Cmd+K keyboard shortcut to open search (only on docs pages) - Import Pagefind types from vite-plugin-pagefind/types Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
apps/web/src/components/docs-search.tsx (3)
68-91: Consider debouncing search input for better performance.The search executes on every keystroke, which could cause unnecessary API calls for fast typists. Adding a small debounce (e.g., 150-300ms) would improve performance without impacting UX.
You could use a debounce utility or adjust the implementation:
const handleSearch = useCallback(async (value: string) => { setQuery(value); if (!value.trim() || !pagefindRef.current) { setResults([]); return; } setIsLoading(true); try { // Add debounce delay here if desired const res = await pagefindRef.current.search(value); // ... rest of logic } catch { setResults([]); } finally { setIsLoading(false); } }, []);However, since Pagefind is a static client-side search, the performance impact is likely minimal.
147-150: Consider sanitizing HTML excerpts for defense-in-depth security.While Pagefind generates excerpts from trusted docs at build time (lowering the risk), sanitizing HTML before rendering adds an extra security layer and follows React best practices.
Install DOMPurify:
npm install dompurify npm install --save-dev @types/dompurifyThen update the component:
+import DOMPurify from 'dompurify'; + // ... in the render: <div className="text-xs text-muted-foreground line-clamp-2" - dangerouslySetInnerHTML={{ __html: result.excerpt }} + dangerouslySetInnerHTML={{ + __html: DOMPurify.sanitize(result.excerpt, { ALLOWED_TAGS: ['mark', 'b', 'strong', 'em'] }) + }} />Note: Ensure DOMPurify is instantiated client-side only (the component already has SSR guards, so this should be safe).
117-119: Keyboard shortcut hint shows Mac-only symbol.The ⌘ (Command) symbol is Mac-specific. Consider showing platform-appropriate hints (Ctrl for Windows/Linux).
const isMac = typeof navigator !== 'undefined' && navigator.userAgent.toLowerCase().includes('mac'); // In render: <span className="text-[11px] rounded border border-neutral-300 px-1.5 py-0.5 text-neutral-400"> {isMac ? <span className="font-sans">⌘</span> : 'Ctrl+'}K </span>
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (3)
apps/web/package.json(3 hunks)apps/web/src/components/docs-search.tsx(1 hunks)apps/web/vite.config.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.ts: Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework
Agent communication should use defined message protocols and interfaces
Files:
apps/web/vite.config.ts
**/*.config.{ts,json}
📄 CodeRabbit inference engine (CLAUDE.md)
Agent configuration should be centralized and externalized from implementation logic
Files:
apps/web/vite.config.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, usecn(import from@hypr/utils). It is similar toclsx. Always pass an array and split by logical grouping.
Usemotion/reactinstead offramer-motion.
Files:
apps/web/vite.config.tsapps/web/src/components/docs-search.tsx
🧠 Learnings (1)
📚 Learning: 2025-11-24T16:32:24.348Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: apps/desktop-e2e/AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:24.348Z
Learning: Applies to apps/desktop-e2e/**/*.{test,spec}.{js,ts,tsx} : Refer to `scripts/setup-desktop-e2e.sh` for end-to-end test environment setup if setup is missing
Applied to files:
apps/web/package.json
🧬 Code graph analysis (1)
apps/web/src/components/docs-search.tsx (2)
packages/utils/src/cn.ts (1)
cn(20-22)extensions/shared/types/hypr-extension.d.ts (6)
CommandDialog(202-202)CommandInput(205-205)CommandList(207-207)CommandEmpty(203-203)CommandGroup(204-204)CommandItem(206-206)
🪛 ast-grep (0.40.0)
apps/web/src/components/docs-search.tsx
[warning] 148-148: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
apps/web/src/components/docs-search.tsx
[error] 149-149: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Redirect rules - hyprnote
- GitHub Check: Header rules - hyprnote
- GitHub Check: Pages changed - hyprnote
- GitHub Check: ci
- GitHub Check: fmt
- GitHub Check: Devin
🔇 Additional comments (9)
apps/web/package.json (2)
7-7: Build script correctly chains Pagefind indexing after Vite build.The command sequence ensures Pagefind only indexes if the build succeeds. Verify that the glob pattern
docs/**/*.htmlcaptures all prerendered docs pages mentioned in the prerender filter (lines 23-33 in vite.config.ts show docs pages are prerendered).
41-41: The package versions specified are current and secure. cmdk@1.1.1 is the latest stable release with no known vulnerabilities. pagefind@^1.4.0 resolves to version 1.4.0 (the latest stable), which is well above the version threshold (1.1.1+) that fixed CVE-2024-45389. vite-plugin-pagefind@^1.0.7 has no known direct vulnerabilities and its dependency on pagefind is safe with the specified range. No updates required.apps/web/src/components/docs-search.tsx (5)
1-16: LGTM: Imports are well-organized.All dependencies are correctly imported, including proper TypeScript types for Pagefind.
18-23: LGTM: State initialization follows React best practices.The component appropriately uses
useStatefor UI state anduseReffor the Pagefind instance reference.
25-43: LGTM: Pagefind loading handles edge cases correctly.The effect properly handles SSR, prevents race conditions with a cancellation flag, and gracefully degrades when Pagefind is unavailable in development mode.
45-66: LGTM: Keyboard shortcut implementation is robust.The Cmd/Ctrl+K handler properly checks for conflicting input contexts and prevents default browser behavior. The internal result navigation is handled by the
cmdklibrary components (CommandDialog, CommandItem).
93-98: LGTM: Result selection handler works correctly.Using
window.location.assignfor navigation is appropriate here, as it ensures proper page state and hydration for the doc pages.apps/web/vite.config.ts (2)
8-8: LGTM: Plugin import is correct.The import aligns with the
vite-plugin-pagefinddevDependency added in package.json.
40-44: Pagefind plugin configuration is correct.The configuration options are all valid and properly documented:
outputDirectory: "dist/client"correctly points to TanStack Start's prerender output,buildScript: "build"matches the npm build script, anddevelopStrategy: "lazy"is the appropriate indexing strategy for development mode.
Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/web/src/components/docs-search.tsx (2)
69-92: Consider usingpagefind.debouncedSearchto avoid stale/overlapping queriesEvery keystroke triggers
await pagefindRef.current.search(value)(lines 78–85). If the user types quickly, earlier slower searches can resolve after later ones and overwrite newer results, causing unnecessary work on large indexes.Pagefind exposes a debounced helper that cancels earlier calls:
const search = await pagefind.debouncedSearch(trimmed); // search === null means a newer query superseded this one if (!search) return; // then slice + data() as you're doing nowThis reduces redundant work and ensures result ordering stays consistent under rapid typing.
148-152: Resolve the linter complaint arounddangerouslySetInnerHTMLYou're already sanitizing
result.excerptwith DOMPurify before injecting it (Lines 148–152), which is the right mitigation. Pagefind'sexcerptfield is HTML-escaped and safe for innerHTML with only<mark>tags for highlighting, whilecontentandmetafields are raw and require sanitization. DOMPurify's defaultsanitize()preserves<mark>tags, so your current approach is both secure and functional.Add a focused ignore with justification:
+ {/* Pagefind's excerpt is pre-escaped and then sanitized again via DOMPurify. */} + {/* biome-ignore lint/security/noDangerouslySetInnerHtml: Controlled HTML from Pagefind, sanitized client-side. */} <div className="text-xs text-muted-foreground line-clamp-2" dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(result.excerpt), }} />
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (3)
.gitignore(1 hunks)apps/web/package.json(3 hunks)apps/web/src/components/docs-search.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/package.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, usecn(import from@hypr/utils). It is similar toclsx. Always pass an array and split by logical grouping.
Usemotion/reactinstead offramer-motion.
Files:
apps/web/src/components/docs-search.tsx
🧬 Code graph analysis (1)
apps/web/src/components/docs-search.tsx (2)
apps/desktop/src/components/main/body/search.tsx (1)
Search(12-59)extensions/shared/types/hypr-extension.d.ts (6)
CommandDialog(202-202)CommandInput(205-205)CommandList(207-207)CommandEmpty(203-203)CommandGroup(204-204)CommandItem(206-206)
🪛 ast-grep (0.40.0)
apps/web/src/components/docs-search.tsx
[warning] 149-149: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
apps/web/src/components/docs-search.tsx
[error] 150-150: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Redirect rules - hyprnote
- GitHub Check: Header rules - hyprnote
- GitHub Check: Pages changed - hyprnote
- GitHub Check: ci
- GitHub Check: fmt
- GitHub Check: Devin
🔇 Additional comments (2)
.gitignore (1)
24-25: LGTM!The addition correctly ignores Pagefind-generated index directories using the
**/pagefind/glob pattern, which will match thedist/client/pagefind/directory and any nested instances. The comment is clear and the placement is appropriate.apps/web/src/components/docs-search.tsx (1)
19-161: Overall implementation looks solidThe Pagefind lazy-load, Cmd/Ctrl+K hotkey behavior, and
CommandDialog-based UI all look clean and align well with the project’s patterns (use ofcn, Hypr UI command components, DOMPurify for excerpts, etc.). Aside from the small search-handler tweaks noted above, this component is in good shape.
Add Pagefind docs search to left sidebar
Summary
Adds static search functionality to the docs using Pagefind. The search is accessible via a button in the left sidebar that opens a command palette (using cmdk), or by pressing Cmd+K / Ctrl+K.
Changes:
pagefind,vite-plugin-pagefind,cmdk, anddompurifyas dependenciesDocsSearchcomponent with command palette UI and keyboard shortcut support**/pagefind/to .gitignoreUpdates since last revision
Review & Testing Checklist for Human
Recommended test plan: Open the preview deployment at https://deploy-preview-2074--hyprnote.netlify.app/docs, test both the button click and Cmd+K hotkey to open search, search for terms like "analytics" or "extension", click a result and confirm navigation works.
Notes
dangerouslySetInnerHTMLfor excerpts because Pagefind returns HTML with highlighted search terms - now sanitized with DOMPurify/pagefind/pagefind.jswhich only exists after build completesLink to Devin run: https://app.devin.ai/sessions/c35a8e838c334d5995fd562322863989
Requested by: john@hyprnote.com (@ComputelessComputer)