From 998a4dd07bb198e872b95462478e52d75a688237 Mon Sep 17 00:00:00 2001 From: Brendan Kellam Date: Thu, 13 Mar 2025 13:02:49 -0700 Subject: [PATCH] make syntax reference guide keyboard shortcut hint clickable (#229) --- .../searchBar/searchSuggestionsBox.tsx | 7 +++- .../app/components/syntaxReferenceGuide.tsx | 13 ++++---- .../components/syntaxReferenceGuideHint.tsx | 17 ++++++++++ packages/web/src/app/layout.tsx | 19 ++++++----- packages/web/src/app/page.tsx | 6 ++-- packages/web/src/app/syntaxGuideProvider.tsx | 32 +++++++++++++++++++ 6 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 packages/web/src/app/components/syntaxReferenceGuideHint.tsx create mode 100644 packages/web/src/app/syntaxGuideProvider.tsx diff --git a/packages/web/src/app/components/searchBar/searchSuggestionsBox.tsx b/packages/web/src/app/components/searchBar/searchSuggestionsBox.tsx index 1b31c1cf..a8bb5bd9 100644 --- a/packages/web/src/app/components/searchBar/searchSuggestionsBox.tsx +++ b/packages/web/src/app/components/searchBar/searchSuggestionsBox.tsx @@ -17,6 +17,7 @@ import { VscFile, VscFilter, VscRepo, VscSymbolMisc } from "react-icons/vsc"; import { Skeleton } from "@/components/ui/skeleton"; import { Separator } from "@/components/ui/separator"; import { KeyboardShortcutHint } from "../keyboardShortcutHint"; +import { useSyntaxGuide } from "@/app/syntaxGuideProvider"; export type Suggestion = { value: string; @@ -79,6 +80,7 @@ const SearchSuggestionsBox = forwardRef(({ searchHistorySuggestions, }: SearchSuggestionsBoxProps, ref: Ref) => { const [highlightedSuggestionIndex, setHighlightedSuggestionIndex] = useState(0); + const { onOpenChanged } = useSyntaxGuide(); const { suggestions, isHighlightEnabled, descriptionPlacement, DefaultIcon, onSuggestionClicked } = useMemo(() => { if (!isEnabled) { @@ -391,7 +393,10 @@ const SearchSuggestionsBox = forwardRef(({ className="my-2" />
-
+
onOpenChanged(true)} + >

Syntax help:

diff --git a/packages/web/src/app/components/syntaxReferenceGuide.tsx b/packages/web/src/app/components/syntaxReferenceGuide.tsx index d2225799..f92edcd3 100644 --- a/packages/web/src/app/components/syntaxReferenceGuide.tsx +++ b/packages/web/src/app/components/syntaxReferenceGuide.tsx @@ -12,30 +12,31 @@ import { } from "@/components/ui/table"; import clsx from "clsx"; import Link from "next/link"; -import { useCallback, useRef, useState } from "react"; +import { useCallback, useRef } from "react"; import { useHotkeys } from "react-hotkeys-hook"; +import { useSyntaxGuide } from "../syntaxGuideProvider"; const LINGUIST_LINK = "https://github.com/github-linguist/linguist/blob/main/lib/linguist/languages.yml"; const CTAGS_LINK = "https://ctags.io/"; export const SyntaxReferenceGuide = () => { - const [isOpen, setIsOpen] = useState(false); + const { isOpen, onOpenChanged } = useSyntaxGuide(); const previousFocusedElement = useRef(null); const openDialog = useCallback(() => { previousFocusedElement.current = document.activeElement as HTMLElement; - setIsOpen(true); - }, []); + onOpenChanged(true); + }, [onOpenChanged]); const closeDialog = useCallback(() => { - setIsOpen(false); + onOpenChanged(false); // @note: Without requestAnimationFrame, focus was not being returned // to codemirror elements for some reason. requestAnimationFrame(() => { previousFocusedElement.current?.focus(); }); - }, []); + }, [onOpenChanged]); const handleOpenChange = useCallback((isOpen: boolean) => { if (isOpen) { diff --git a/packages/web/src/app/components/syntaxReferenceGuideHint.tsx b/packages/web/src/app/components/syntaxReferenceGuideHint.tsx new file mode 100644 index 00000000..35dfa473 --- /dev/null +++ b/packages/web/src/app/components/syntaxReferenceGuideHint.tsx @@ -0,0 +1,17 @@ +'use client'; + +import { useSyntaxGuide } from "../syntaxGuideProvider"; +import { KeyboardShortcutHint } from "./keyboardShortcutHint"; + +export const SyntaxReferenceGuideHint = () => { + const { isOpen, onOpenChanged } = useSyntaxGuide(); + + return ( +
onOpenChanged(!isOpen)} + > + Reference guide: +
+ ) +} \ No newline at end of file diff --git a/packages/web/src/app/layout.tsx b/packages/web/src/app/layout.tsx index 0f370369..9043f590 100644 --- a/packages/web/src/app/layout.tsx +++ b/packages/web/src/app/layout.tsx @@ -7,6 +7,7 @@ import { PHProvider } from "./posthogProvider"; import { Toaster } from "@/components/ui/toaster"; import { TooltipProvider } from "@/components/ui/tooltip"; import { SyntaxReferenceGuide } from "./components/syntaxReferenceGuide"; +import { SyntaxGuideProvider } from "./syntaxGuideProvider"; export const metadata: Metadata = { title: "Sourcebot", @@ -35,14 +36,16 @@ export default function RootLayout({ > - {/* - @todo : ideally we don't wrap everything in a suspense boundary. - @see : https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout - */} - - {children} - - + + {/* + @todo : ideally we don't wrap everything in a suspense boundary. + @see : https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout + */} + + {children} + + + diff --git a/packages/web/src/app/page.tsx b/packages/web/src/app/page.tsx index 4a4a1465..986d5572 100644 --- a/packages/web/src/app/page.tsx +++ b/packages/web/src/app/page.tsx @@ -11,9 +11,9 @@ import { Separator } from "@/components/ui/separator"; import { SymbolIcon } from "@radix-ui/react-icons"; import { UpgradeToast } from "./components/upgradeToast"; import Link from "next/link"; -import { KeyboardShortcutHint } from "./components/keyboardShortcutHint"; import RegistrationCard from "./components/registrationCard"; import { PUBLIC_SEARCH_DEMO } from "@/lib/environment"; +import { SyntaxReferenceGuideHint } from "./components/syntaxReferenceGuideHint"; export default async function Home() { return ( @@ -103,9 +103,7 @@ export default async function Home() {
-
- Reference guide: -
+
diff --git a/packages/web/src/app/syntaxGuideProvider.tsx b/packages/web/src/app/syntaxGuideProvider.tsx new file mode 100644 index 00000000..cd0c2c8b --- /dev/null +++ b/packages/web/src/app/syntaxGuideProvider.tsx @@ -0,0 +1,32 @@ +'use client'; + +import { createContext, useContext, useCallback, useState } from 'react'; + +interface SyntaxGuideContextType { + isOpen: boolean; + onOpenChanged: (isOpen: boolean) => void; +} + +const SyntaxGuideContext = createContext(null); + +export const useSyntaxGuide = () => { + const context = useContext(SyntaxGuideContext); + if (!context) { + throw new Error('useSyntaxGuide must be used within a SyntaxGuideProvider'); + } + return context; +}; + +export const SyntaxGuideProvider = ({ children }: { children: React.ReactNode }) => { + const [isOpen, setIsOpen] = useState(false); + + const onOpenChanged = useCallback((isOpen: boolean) => { + setIsOpen(isOpen); + }, []); + + return ( + + {children} + + ); +}; \ No newline at end of file