Omarchy Command Palette

block

An Omarchy-menu-style command palette bound to Super+Space.

bunx --bun shadcn@latest add yamz8/omarchy-shadcn-registry/omarchy-command-palette

Preview

Command Palette

Search for a command to run...

Dependencies

npm
lucide-react
registry
button, command, yamz8/omarchy-shadcn-registry/omarchy-keycap

Source

registry/blocks/omarchy-command-palette.tsx
"use client"

import * as React from "react"
import {
  CameraIcon,
  ImageIcon,
  LockIcon,
  MonitorIcon,
  PaletteIcon,
  PowerIcon,
  SmileIcon,
  TerminalIcon,
} from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  Command,
  CommandDialog,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandShortcut,
} from "@/components/ui/command"
import { OmarchyShortcut } from "@/components/ui/omarchy-keycap"

type PaletteCommand = {
  id: string
  name: string
  icon: React.ReactNode
  keys: readonly string[]
}

const groups: readonly {
  heading: string
  commands: readonly PaletteCommand[]
}[] = [
  {
    heading: "Menus",
    commands: [
      {
        id: "menu",
        name: "Omarchy menu",
        icon: <TerminalIcon />,
        keys: ["Super", "Space"],
      },
      {
        id: "capture",
        name: "Capture menu",
        icon: <CameraIcon />,
        keys: ["Super", "Ctrl", "C"],
      },
      {
        id: "hardware",
        name: "Hardware menu",
        icon: <MonitorIcon />,
        keys: ["Super", "Ctrl", "H"],
      },
      {
        id: "emojis",
        name: "Emojis",
        icon: <SmileIcon />,
        keys: ["Super", "Ctrl", "E"],
      },
    ],
  },
  {
    heading: "Appearance",
    commands: [
      {
        id: "theme",
        name: "Theme menu",
        icon: <PaletteIcon />,
        keys: ["Super", "Shift", "Ctrl", "Space"],
      },
      {
        id: "background",
        name: "Background switcher",
        icon: <ImageIcon />,
        keys: ["Super", "Ctrl", "Space"],
      },
    ],
  },
  {
    heading: "System",
    commands: [
      {
        id: "lock",
        name: "Lock screen",
        icon: <LockIcon />,
        keys: ["Super", "Escape"],
      },
      {
        id: "power",
        name: "System menu",
        icon: <PowerIcon />,
        keys: ["Super", "Escape"],
      },
    ],
  },
]

/**
 * An Omarchy-menu-style command palette. Opens on Super+Space (Meta+Space in
 * the browser) and reports the chosen command through `onRun`.
 */
export function OmarchyCommandPalette({
  onRun,
}: {
  onRun?: (id: string) => void
}) {
  const [open, setOpen] = React.useState(false)

  React.useEffect(() => {
    function onKeyDown(event: KeyboardEvent) {
      if (event.key === " " && event.metaKey) {
        event.preventDefault()
        setOpen((previous) => !previous)
      }
    }

    document.addEventListener("keydown", onKeyDown)

    return () => document.removeEventListener("keydown", onKeyDown)
  }, [])

  return (
    <>
      <Button
        variant="outline"
        onClick={() => setOpen(true)}
        className="justify-between gap-8 font-normal text-muted-foreground"
      >
        Run a command
        <OmarchyShortcut keys={["Super", "Space"]} />
      </Button>
      <CommandDialog open={open} onOpenChange={setOpen}>
        <Command>
          <CommandInput placeholder="Type a command…" />
          <CommandList>
            <CommandEmpty>No matching command.</CommandEmpty>
            {groups.map((group) => (
              <CommandGroup key={group.heading} heading={group.heading}>
                {group.commands.map((command) => (
                  <CommandItem
                    key={command.id}
                    value={command.name}
                    onSelect={() => {
                      setOpen(false)
                      onRun?.(command.id)
                    }}
                  >
                    {command.icon}
                    {command.name}
                    <CommandShortcut>{command.keys.join(" ")}</CommandShortcut>
                  </CommandItem>
                ))}
              </CommandGroup>
            ))}
          </CommandList>
        </Command>
      </CommandDialog>
    </>
  )
}