mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-11 20:05:25 +00:00
make syntax reference guide keyboard shortcut hint clickable (#229)
This commit is contained in:
parent
bf76cb9358
commit
998a4dd07b
6 changed files with 75 additions and 19 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
17
packages/web/src/app/components/syntaxReferenceGuideHint.tsx
Normal file
17
packages/web/src/app/components/syntaxReferenceGuideHint.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
32
packages/web/src/app/syntaxGuideProvider.tsx
Normal file
32
packages/web/src/app/syntaxGuideProvider.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
Loading…
Reference in a new issue