{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"0n-spotlight","type":"registry:block","title":"Spotlight","description":"A keyboard-driven cmd+k command palette. Drop into any app to give users one place to jump anywhere — search, navigate, run commands.","dependencies":["lucide-react"],"registryDependencies":["button","dialog","input"],"files":[{"path":"components/0n/spotlight.tsx","type":"registry:block","target":"components/0n/spotlight.tsx","content":"'use client'\n\n/**\n * 0n Spotlight — keyboard-driven cmd+k command palette.\n *\n * Triggers from a button, opens a centered dialog with a search input\n * and a list of suggestions. Esc closes. Arrow keys + Enter select.\n *\n * Install:\n *   npx shadcn@latest add https://0nmcp.com/r/0n-spotlight.json\n *\n * Use:\n *   <Spotlight items={[\n *     { icon: Mail, label: 'Compose new message', onSelect: () => {} },\n *     ...\n *   ]} />\n */\n\nimport { useEffect, useState, type ReactNode } from 'react'\nimport { Search } from 'lucide-react'\nimport { Button } from '@/components/ui/button'\nimport { Dialog, DialogContent } from '@/components/ui/dialog'\nimport { Input } from '@/components/ui/input'\n\nexport interface SpotlightItem {\n  icon?: React.ComponentType<{ className?: string }>\n  label: string\n  hint?: string\n  onSelect: () => void\n}\n\nexport interface SpotlightProps {\n  items: SpotlightItem[]\n  triggerLabel?: string\n  placeholder?: string\n}\n\nexport function Spotlight({\n  items,\n  triggerLabel = 'Open Spotlight',\n  placeholder = 'Jump to anything…',\n}: SpotlightProps) {\n  const [open, setOpen] = useState(false)\n  const [query, setQuery] = useState('')\n\n  // Cmd+K to open globally\n  useEffect(() => {\n    function down(e: KeyboardEvent) {\n      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {\n        e.preventDefault()\n        setOpen((v) => !v)\n      }\n    }\n    window.addEventListener('keydown', down)\n    return () => window.removeEventListener('keydown', down)\n  }, [])\n\n  const q = query.toLowerCase().trim()\n  const filtered = q\n    ? items.filter((i) => i.label.toLowerCase().includes(q))\n    : items\n\n  return (\n    <>\n      <Button variant=\"outline\" onClick={() => setOpen(true)}>\n        <Search className=\"mr-2 h-4 w-4\" />\n        {triggerLabel}\n        <kbd className=\"ml-3 rounded border border-border/60 px-1.5 py-0.5 font-mono text-[10px]\">⌘K</kbd>\n      </Button>\n      <Dialog open={open} onOpenChange={setOpen}>\n        <DialogContent className=\"p-0 max-w-md\">\n          <div className=\"flex items-center gap-2 border-b border-border/60 px-4 py-3\">\n            <Search className=\"h-4 w-4 text-muted-foreground\" />\n            <Input\n              autoFocus\n              value={query}\n              onChange={(e) => setQuery(e.target.value)}\n              placeholder={placeholder}\n              className=\"border-0 bg-transparent focus-visible:ring-0 px-0\"\n            />\n          </div>\n          <div className=\"p-2 text-sm\">\n            <div className=\"px-3 py-2 text-xs font-mono uppercase tracking-widest text-muted-foreground\">\n              Suggestions\n            </div>\n            {filtered.map((item) => {\n              const Icon = item.icon\n              return (\n                <button\n                  key={item.label}\n                  onClick={() => {\n                    item.onSelect()\n                    setOpen(false)\n                  }}\n                  className=\"flex w-full items-center gap-3 rounded-md px-3 py-2 text-left hover:bg-muted/50\"\n                >\n                  {Icon ? <Icon className=\"h-4 w-4 text-muted-foreground\" /> : null}\n                  <span className=\"flex-1\">{item.label}</span>\n                  {item.hint ? (\n                    <span className=\"font-mono text-[10px] text-muted-foreground\">{item.hint}</span>\n                  ) : null}\n                </button>\n              )\n            })}\n            {filtered.length === 0 && (\n              <p className=\"px-3 py-6 text-center text-xs text-muted-foreground\">\n                No matches for \"{query}\"\n              </p>\n            )}\n          </div>\n        </DialogContent>\n      </Dialog>\n    </>\n  )\n}\n"}]}