Files
Frontend/src/app/components/command-menu.tsx
Liam 49daf6f1a4
All checks were successful
Deploy App / docker (ubuntu-latest) (push) Successful in 3m26s
impl command menu and change theme colors
2024-04-22 01:21:04 +01:00

114 lines
3.0 KiB
TypeScript

"use client";
import React, { ReactElement, useState } from "react";
import { DocsContentMetadata } from "@/app/common/documentation";
import {
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/app/components/ui/command";
import { Button, ButtonProps } from "@/app/components/ui/button";
import { useRouter } from "next/navigation";
import { cn } from "@/app/common/utils";
export function CommandMenu({ ...props }: ButtonProps): ReactElement {
const router = useRouter();
/**
* Whether to show the search
*/
const [open, setOpen] = useState<boolean>(false);
/**
* The pages that were found
*/
const [pages, setPages] = useState<DocsContentMetadata[] | undefined>(undefined);
// Handle keyboard shortcuts
React.useEffect(() => {
const down = (e: KeyboardEvent) => {
if ((e.key === "k" && (e.metaKey || e.ctrlKey)) || e.key === "/") {
if (
(e.target instanceof HTMLElement && e.target.isContentEditable) ||
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLTextAreaElement ||
e.target instanceof HTMLSelectElement
) {
return;
}
e.preventDefault();
setOpen(open => !open);
}
};
return () => document.removeEventListener("keydown", down);
}, []);
/**
* Search the documentation
* for the given query.
*
* @param query the query to search for
*/
async function searchDocs(query: string): Promise<void> {
// Don't bother searching if the query is less than 3 characters
if (query.length < 3) {
setPages(undefined);
return;
}
// Attempt to search for the query
const response = await fetch(`/api/docs/search?query=${query}`);
const pages: DocsContentMetadata[] = await response.json();
setPages(pages);
}
return (
<>
<Button
variant="outline"
className={cn(
"relative h-8 w-full justify-start rounded-[0.5rem] bg-background text-sm font-normal text-muted-foreground shadow-none sm:pr-12 md:w-40 lg:w-64",
props.className,
)}
onClick={() => setOpen(true)}
>
Search
</Button>
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput
placeholder="Query..."
onValueChange={async search => {
await searchDocs(search);
}}
/>
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
{pages && (
<CommandGroup heading="Suggestions">
{pages.map(page => {
return (
<CommandItem
key={page.slug}
onSelect={() => {
router.push(`/docs/${page.slug}`);
setOpen(false);
}}
>
{page.title}
</CommandItem>
);
})}
</CommandGroup>
)}
</CommandList>
</CommandDialog>
</>
);
}