Command Menu
atroui/command-menuFreeBlock
⌘K command palette for nav, posts, connect, and theme.
Install it
npx shadcn@latest add https://atroui.com/r/command-menu.jsonSource
1"use client"23import * as React from "react"4import { Command } from "cmdk"5import { useRouter } from "next/navigation"6import { useTheme } from "next-themes"7import {8 ArrowRight,9 ArrowUpRight,10 Github,11 Home,12 Mail,13 Moon,14 Sun,15} from "lucide-react"1617/** Edit email, nav, and connect links after install. */18const CONTENT = {19 email: "hello@example.com",20 nav: [21 { label: "Home", href: "/" },22 { label: "Projects", href: "/projects" },23 { label: "Writing", href: "/writing" },24 { label: "Log", href: "/log" },25 { label: "Resume", href: "/resume" },26 { label: "Contact", href: "/contact" },27 ] as Array<{ label: string; href: string; external?: boolean }>,28 connect: [29 {30 label: "GitHub",31 href: "https://github.com",32 external: true,33 },34 {35 label: "X / Twitter",36 href: "https://x.com",37 external: true,38 },39 ] as Array<{ label: string; href: string; external?: boolean }>,40}4142export type CommandMenuPost = { slug: string; title: string; href?: string }43export type CommandMenuPage = {44 label: string45 href: string46 external?: boolean47}4849export function CommandMenu({50 email = CONTENT.email,51 nav = CONTENT.nav,52 connect = CONTENT.connect,53 posts,54 pages,55}: {56 email?: string57 nav?: CommandMenuPage[]58 connect?: CommandMenuPage[]59 posts?: CommandMenuPost[]60 pages?: CommandMenuPage[]61} = {}) {62 const router = useRouter()63 const { resolvedTheme, setTheme } = useTheme()64 const [open, setOpen] = React.useState(false)65 const [copied, setCopied] = React.useState(false)6667 React.useEffect(() => {68 const onKeyDown = (e: KeyboardEvent) => {69 const isToggle =70 (e.key === "k" || e.key === "K") && (e.metaKey || e.ctrlKey)71 if (isToggle) {72 e.preventDefault()73 setOpen((v) => !v)74 }75 }76 window.addEventListener("keydown", onKeyDown)77 return () => window.removeEventListener("keydown", onKeyDown)78 }, [])7980 React.useEffect(() => {81 if (!open) return82 const y = window.scrollY83 const { style } = document.body84 const prev = {85 overflow: style.overflow,86 position: style.position,87 top: style.top,88 width: style.width,89 left: style.left,90 right: style.right,91 }92 style.overflow = "hidden"93 style.position = "fixed"94 style.top = `-${y}px`95 style.left = "0"96 style.right = "0"97 style.width = "100%"98 return () => {99 style.overflow = prev.overflow100 style.position = prev.position101// … truncated
What it pulls in
npm packages
Files it writes
More from atroui
All 81 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Analytics Provideranalytics-provider | atroui | Blocks | Free | 1 dep | |
| AR Portfolioar-portfolio | atroui | Blocks | Free | 1 dep | |
| Before / Afterbefore-after-slider | atroui | Blocks | Free | no deps | |
| Calendly Embedcalendly-embed | atroui | Blocks | Free | 1 dep | |
| Changelogchangelog | atroui | Blocks | Free | no deps | |
| Contact Formcontact-form | atroui | Blocks | Free | 2 deps | |
| Contextual CTAcontextual-cta | atroui | Blocks | Free | 2 deps | |
| Count Upcount-up | atroui | Blocks | Free | no deps |
