From c903fdcac0d41cef8d24b275ae336f28f6f35c29 Mon Sep 17 00:00:00 2001 From: Matthieu Moquet Date: Tue, 19 Nov 2024 00:47:41 +0100 Subject: [PATCH] feat: add command menu --- src/components/command/command-menu.tsx | 70 +++++++++++++++++++++++++ src/components/layout/app-layout.tsx | 2 + src/components/ui/command.tsx | 3 +- src/components/ui/dialog.tsx | 2 +- 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 src/components/command/command-menu.tsx diff --git a/src/components/command/command-menu.tsx b/src/components/command/command-menu.tsx new file mode 100644 index 0000000..e6f2c74 --- /dev/null +++ b/src/components/command/command-menu.tsx @@ -0,0 +1,70 @@ +'use client' + +import { useEffect, useState } from "react" +import { CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command" +import { useRouter } from "next/navigation" +import { Bell, ChevronRight, Settings2, SquareDot } from "lucide-react" +import { useConfig } from "@/contexts/config" + +const navigation = [ + { + title: "Alerts", + url: "/alerts", + icon: Bell, + }, + // { + // title: "Silences", + // url: "/silences", + // icon: CircleSlash2, + // }, + { + title: "Settings", + url: "/settings", + icon: Settings2, + }, +] + +export function CommandMenu() { + const [open, setOpen] = useState(false) + const router = useRouter() + const { config } = useConfig() + const { views, viewCategories } = config + + useEffect(() => { + const down = (e: KeyboardEvent) => { + if (e.key === "k" && (e.metaKey || e.ctrlKey)) { + e.preventDefault() + setOpen((open) => !open) + } + } + document.addEventListener("keydown", down) + return () => document.removeEventListener("keydown", down) + }, []) + + return ( + + + + No results found. + + {navigation.map((item) => ( + { router.push(item.url); setOpen(false) }}> + + {item.title} + + ))} + {Object.entries(views) + .filter(([handle]) => handle !== "default") + .map(([handle, view]) => ( + { router.push(`/alerts/${handle}`); setOpen(false) }}> + + {viewCategories[view.category]?.name ? `${viewCategories[view.category].name}` : view.category} + {view.category ? ยป : ''} + {view.name || handle} + + ))} + + + + ) +} diff --git a/src/components/layout/app-layout.tsx b/src/components/layout/app-layout.tsx index 2d8cb8f..76a2f7b 100644 --- a/src/components/layout/app-layout.tsx +++ b/src/components/layout/app-layout.tsx @@ -1,4 +1,5 @@ import { SidebarProvider } from "@/components/ui/sidebar"; +import { CommandMenu } from "@/components/command/command-menu"; import { AppSidebar } from "./app-sidebar"; import { AppThemeColor } from "./app-theme-color"; @@ -7,6 +8,7 @@ export function AppLayout({ children }: { children: React.ReactNode }) { +
{children} diff --git a/src/components/ui/command.tsx b/src/components/ui/command.tsx index 59a2645..9b6faca 100644 --- a/src/components/ui/command.tsx +++ b/src/components/ui/command.tsx @@ -1,7 +1,7 @@ "use client" import * as React from "react" -import { type DialogProps } from "@radix-ui/react-dialog" +import { DialogTitle, type DialogProps } from "@radix-ui/react-dialog" import { Command as CommandPrimitive } from "cmdk" import { Search } from "lucide-react" @@ -26,6 +26,7 @@ Command.displayName = CommandPrimitive.displayName const CommandDialog = ({ children, ...props }: DialogProps) => { return ( + Command Menu {children} diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx index 01ff19c..8c47d6a 100644 --- a/src/components/ui/dialog.tsx +++ b/src/components/ui/dialog.tsx @@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef<