{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "shortcuts-dialog",
  "title": "Shortcuts Dialog",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/shortcuts-dialog/ShortcutsDialog.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport { Keyboard } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n  DialogTrigger,\n} from '@/components/ui/dialog'\nimport { Kbd } from '@/components/ui/kbd'\n\ninterface Shortcut {\n  keys: string[]\n  description: string\n}\n\ninterface ShortcutGroup {\n  label: string\n  shortcuts: Shortcut[]\n}\n\nconst props = withDefaults(\n  defineProps<{\n    groups?: ShortcutGroup[]\n    /** Render the built-in trigger button. */\n    trigger?: boolean\n    /** Show the 'Press Esc to close' footer hint. */\n    footer?: boolean\n    open?: boolean\n    class?: HTMLAttributes['class']\n  }>(),\n  {\n    groups: () => [\n      {\n        label: 'Navigation',\n        shortcuts: [\n          { keys: ['G', 'I'], description: 'Go to inbox' },\n          { keys: ['G', 'D'], description: 'Go to drafts' },\n          { keys: ['⌘', 'K'], description: 'Open command menu' },\n          { keys: ['⌥', '↑', '↓'], description: 'Move between items' },\n        ],\n      },\n      {\n        label: 'Actions',\n        shortcuts: [\n          { keys: ['C'], description: 'Compose new' },\n          { keys: ['/'], description: 'Focus search' },\n          { keys: ['⌘', 'S'], description: 'Save changes' },\n          { keys: ['E'], description: 'Archive selection' },\n        ],\n      },\n      {\n        label: 'General',\n        shortcuts: [\n          { keys: ['?'], description: 'Show this dialog' },\n          { keys: ['⇧', '?'], description: 'Show cheat sheet' },\n          { keys: ['Esc'], description: 'Close dialogs' },\n        ],\n      },\n    ],\n    trigger: true,\n    footer: true,\n    open: undefined,\n  },\n)\n\nconst emit = defineEmits<{ 'update:open': [boolean] }>()\n\n// Local state drives the uncontrolled case; the `open` prop takes precedence.\nconst internalOpen = ref(false)\nconst isOpen = computed({\n  get: () => (props.open !== undefined ? props.open : internalOpen.value),\n  set: (value) => {\n    internalOpen.value = value\n    emit('update:open', value)\n  },\n})\n</script>\n\n<template>\n  <Dialog data-slot=\"shortcuts-dialog\" v-model:open=\"isOpen\">\n    <DialogTrigger v-if=\"trigger\" as-child>\n      <Button variant=\"outline\" size=\"sm\">\n        <Keyboard aria-hidden=\"true\" />\n        Shortcuts\n        <Kbd>?</Kbd>\n      </Button>\n    </DialogTrigger>\n    <slot v-else />\n    <DialogContent :class=\"cn('max-w-lg', props.class)\">\n      <DialogHeader>\n        <DialogTitle>Keyboard shortcuts</DialogTitle>\n        <DialogDescription>Move faster without leaving the keyboard.</DialogDescription>\n      </DialogHeader>\n      <div class=\"grid max-h-[60vh] gap-x-8 gap-y-6 overflow-y-auto pr-1 sm:grid-cols-2\">\n        <div v-for=\"group in groups\" :key=\"group.label\" class=\"space-y-2\">\n          <p class=\"text-muted-foreground text-xs font-medium tracking-widest uppercase\">{{ group.label }}</p>\n          <ul class=\"divide-y\">\n            <li\n              v-for=\"shortcut in group.shortcuts\"\n              :key=\"shortcut.description\"\n              class=\"flex items-center justify-between gap-4 py-1.5\"\n            >\n              <span class=\"text-sm\">{{ shortcut.description }}</span>\n              <span class=\"flex shrink-0 items-center gap-1\">\n                <Kbd v-for=\"key in shortcut.keys\" :key=\"key\">{{ key }}</Kbd>\n              </span>\n            </li>\n          </ul>\n        </div>\n      </div>\n      <DialogFooter v-if=\"footer\" class=\"justify-start\">\n        <p class=\"text-muted-foreground flex items-center gap-1.5 text-xs\">Press <Kbd>Esc</Kbd> to close</p>\n      </DialogFooter>\n    </DialogContent>\n  </Dialog>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/ShortcutsDialog.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/dialog.json",
    "https://uipkge.dev/r/vue/kbd.json"
  ],
  "description": "Linear-style keyboard reference sheet: a '?' dialog listing shortcut groups (label, description, Kbd combo) in a responsive two-column grid. Ships a built-in trigger button, controlled/uncontrolled open, custom groups via prop, and an Esc footer hint. Display only — wire real handlers in your app.",
  "categories": [
    "layout",
    "dashboard",
    "navigation"
  ]
}