make syntax reference guide keyboard shortcut hint clickable (#229)

This commit is contained in:
Brendan Kellam 2025-03-13 13:02:49 -07:00 committed by GitHub
parent bf76cb9358
commit 998a4dd07b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 75 additions and 19 deletions

View file

@ -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<HTMLDivElement>) => {
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"
/>
<div className="flex flex-row items-center justify-between mt-1">
<div className="flex flex-row gap-1.5 items-center">
<div
className="flex flex-row gap-1.5 items-center cursor-pointer"
onClick={() => onOpenChanged(true)}
>
<p className="text-muted-foreground text-sm">
Syntax help:
</p>

View file

@ -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<HTMLElement | null>(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) {

View file

@ -0,0 +1,17 @@
'use client';
import { useSyntaxGuide } from "../syntaxGuideProvider";
import { KeyboardShortcutHint } from "./keyboardShortcutHint";
export const SyntaxReferenceGuideHint = () => {
const { isOpen, onOpenChanged } = useSyntaxGuide();
return (
<div
className="text-sm cursor-pointer"
onClick={() => onOpenChanged(!isOpen)}
>
<span className="dark:text-gray-300">Reference guide: </span><KeyboardShortcutHint shortcut="⌘" /> <KeyboardShortcutHint shortcut="/" />
</div>
)
}

View file

@ -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({
>
<QueryClientProvider>
<TooltipProvider>
{/*
@todo : ideally we don't wrap everything in a suspense boundary.
@see : https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout
*/}
<Suspense>
{children}
</Suspense>
<SyntaxReferenceGuide />
<SyntaxGuideProvider>
{/*
@todo : ideally we don't wrap everything in a suspense boundary.
@see : https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout
*/}
<Suspense>
{children}
</Suspense>
<SyntaxReferenceGuide />
</SyntaxGuideProvider>
</TooltipProvider>
</QueryClientProvider>
</ThemeProvider>

View file

@ -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() {
</QueryExample>
</HowToSection>
</div>
<div className="text-sm">
<span className="dark:text-gray-300">Reference guide: </span><KeyboardShortcutHint shortcut="⌘" /> <KeyboardShortcutHint shortcut="/" />
</div>
<SyntaxReferenceGuideHint />
</div>
</div>

View file

@ -0,0 +1,32 @@
'use client';
import { createContext, useContext, useCallback, useState } from 'react';
interface SyntaxGuideContextType {
isOpen: boolean;
onOpenChanged: (isOpen: boolean) => void;
}
const SyntaxGuideContext = createContext<SyntaxGuideContextType | null>(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 (
<SyntaxGuideContext.Provider value={{ isOpen, onOpenChanged }}>
{children}
</SyntaxGuideContext.Provider>
);
};