{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "inbox",
  "title": "Inbox",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/inbox/Inbox.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, nextTick, ref, watch } from 'vue'\nimport {\n  Archive,\n  ArrowLeft,\n  ArrowRight,\n  AtSign,\n  Forward,\n  Inbox as InboxIcon,\n  MoreVertical,\n  Paperclip,\n  Pencil,\n  Reply,\n  ReplyAll,\n  Search,\n  Send,\n  Smile,\n  Star,\n  Tag,\n  Trash2,\n  AlertOctagon,\n  FileText,\n  Bookmark,\n} from 'lucide-vue-next'\nimport { Avatar, AvatarFallback } from '@/components/ui/avatar'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Textarea } from '@/components/ui/textarea'\n\ntype ReplyMode = 'reply' | 'reply-all' | 'forward'\n\ntype FolderId = 'inbox' | 'starred' | 'sent' | 'drafts' | 'spam' | 'trash'\n\ninterface Folder {\n  id: FolderId\n  label: string\n  icon: any\n}\n\ninterface LabelTag {\n  id: string\n  label: string\n  color: string\n}\n\ninterface Mail {\n  id: string\n  folder: FolderId\n  from: { name: string; email: string; initials: string }\n  to: string\n  subject: string\n  preview: string\n  body: string\n  receivedAt: Date\n  read: boolean\n  starred: boolean\n  hasAttachment: boolean\n  labels: string[]\n}\n\nconst folders: Folder[] = [\n  { id: 'inbox', label: 'Inbox', icon: InboxIcon },\n  { id: 'starred', label: 'Starred', icon: Star },\n  { id: 'sent', label: 'Sent', icon: Send },\n  { id: 'drafts', label: 'Drafts', icon: FileText },\n  { id: 'spam', label: 'Spam', icon: AlertOctagon },\n  { id: 'trash', label: 'Trash', icon: Trash2 },\n]\n\nconst labels: LabelTag[] = [\n  { id: 'work', label: 'Work', color: 'bg-primary' },\n  { id: 'personal', label: 'Personal', color: 'bg-success' },\n  { id: 'finance', label: 'Finance', color: 'bg-info' },\n  { id: 'travel', label: 'Travel', color: 'bg-warning' },\n]\n\nconst now = new Date()\nconst todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate())\nconst yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000)\n\nconst mails = ref<Mail[]>([\n  {\n    id: 'e1',\n    folder: 'inbox',\n    from: { name: 'Sarah Connor', email: 'sarah@acme.com', initials: 'SC' },\n    to: 'you@acme.com',\n    subject: 'Q2 OKR draft — your sign-off needed',\n    preview:\n      'Pulled together the Q2 OKR draft from the leadership offsite. I have flagged the two areas where we need…',\n    body: `Hi,\\n\\nPulled together the Q2 OKR draft from the leadership offsite. I have flagged the two areas where we need your call before we lock it:\\n\\n• Hiring plan: 4 vs 6 ENG roles (page 3)\\n• EU rollout timing: April vs June (page 7)\\n\\nGoing to share with the rest of the leadership team Wednesday EOD, so anything from you by Tuesday is great.\\n\\nThanks,\\nSarah`,\n    receivedAt: new Date(now.getTime() - 18 * 60 * 1000),\n    read: false,\n    starred: true,\n    hasAttachment: true,\n    labels: ['work'],\n  },\n  {\n    id: 'e2',\n    folder: 'inbox',\n    from: { name: 'Marcus Rivera', email: 'marcus@acme.com', initials: 'MR' },\n    to: 'you@acme.com',\n    subject: 'Re: Dashboard review tomorrow',\n    preview:\n      'Yes! Pushing to 10:30 so we can join from the standup. I will own the slides and pull the latest kanban metrics.',\n    body: `Yes! Pushing to 10:30 so we can join from the standup. I will own the slides and pull the latest kanban metrics.\\n\\nFew things I want to cover:\\n  - Throughput delta vs last sprint\\n  - The two stories we de-scoped\\n  - Q2 capacity ask\\n\\nSee you tomorrow,\\nMarcus`,\n    receivedAt: new Date(now.getTime() - 95 * 60 * 1000),\n    read: false,\n    starred: false,\n    hasAttachment: false,\n    labels: ['work'],\n  },\n  {\n    id: 'e3',\n    folder: 'inbox',\n    from: { name: 'Stripe', email: 'receipts@stripe.com', initials: 'St' },\n    to: 'you@acme.com',\n    subject: 'Your invoice from Acme Inc. — $1,290.00',\n    preview: 'Thanks for using Stripe. Your invoice for the period Mar 1 – Mar 31 is attached. Total due: $1,290.00…',\n    body: 'Thanks for using Stripe. Your invoice for the period Mar 1 – Mar 31 is attached. Total due: $1,290.00.',\n    receivedAt: new Date(now.getTime() - 4 * 60 * 60 * 1000),\n    read: true,\n    starred: false,\n    hasAttachment: true,\n    labels: ['finance'],\n  },\n  {\n    id: 'e4',\n    folder: 'inbox',\n    from: { name: 'Linear', email: 'no-reply@linear.app', initials: 'Li' },\n    to: 'you@acme.com',\n    subject: 'Weekly summary: 14 issues closed, 22 opened',\n    preview:\n      'Good news — the team closed 14 issues this week, up 3 from last week. Top contributors: Marcus, Priya, Devon.',\n    body: 'Good news — the team closed 14 issues this week, up 3 from last week. Top contributors: Marcus, Priya, Devon.',\n    receivedAt: new Date(now.getTime() - 9 * 60 * 60 * 1000),\n    read: true,\n    starred: false,\n    hasAttachment: false,\n    labels: ['work'],\n  },\n  {\n    id: 'e5',\n    folder: 'inbox',\n    from: { name: 'Priya Shah', email: 'priya@acme.com', initials: 'PS' },\n    to: 'you@acme.com',\n    subject: 'Color tokens are live in staging',\n    preview:\n      'Pushed the new OKLCH token set to staging. All chart colors, success/warning/info, sidebar variants. Take a look…',\n    body: 'Pushed the new OKLCH token set to staging. All chart colors, success/warning/info, sidebar variants. Take a look when you have a sec.',\n    receivedAt: yesterday,\n    read: true,\n    starred: true,\n    hasAttachment: false,\n    labels: ['work'],\n  },\n  {\n    id: 'e6',\n    folder: 'inbox',\n    from: { name: 'United Airlines', email: 'reservations@united.com', initials: 'UA' },\n    to: 'you@acme.com',\n    subject: 'Your itinerary: SFO → LHR, departing Apr 12',\n    preview: 'Your reservation is confirmed. Check-in opens 24h before departure. Booking reference: 7HQ4P2.',\n    body: 'Your reservation is confirmed. Check-in opens 24h before departure. Booking reference: 7HQ4P2.',\n    receivedAt: new Date(now.getTime() - 38 * 60 * 60 * 1000),\n    read: true,\n    starred: false,\n    hasAttachment: true,\n    labels: ['travel'],\n  },\n  {\n    id: 'e7',\n    folder: 'inbox',\n    from: { name: 'Mom', email: 'mom@family.net', initials: 'M' },\n    to: 'you@acme.com',\n    subject: 'Sunday lunch?',\n    preview: 'Are you free for lunch this Sunday? Dad is making his lasagne. Let me know!',\n    body: 'Are you free for lunch this Sunday? Dad is making his lasagne. Let me know!',\n    receivedAt: new Date(now.getTime() - 55 * 60 * 60 * 1000),\n    read: true,\n    starred: false,\n    hasAttachment: false,\n    labels: ['personal'],\n  },\n])\n\nconst activeFolder = ref<FolderId>('inbox')\nconst activeLabel = ref<string | null>(null)\nconst activeId = ref<string>('e1')\nconst search = ref('')\nconst replyMode = ref<ReplyMode>('reply')\nconst replyDraft = ref('')\nconst justSent = ref(false)\n\nfunction folderCount(id: FolderId): number {\n  if (id === 'starred') return mails.value.filter((m) => m.starred && m.folder !== 'trash').length\n  return mails.value.filter((m) => m.folder === id).length\n}\n\nfunction unreadCount(id: FolderId): number {\n  if (id === 'starred') return mails.value.filter((m) => m.starred && !m.read && m.folder !== 'trash').length\n  return mails.value.filter((m) => m.folder === id && !m.read).length\n}\n\nconst labelCounts = computed(() =>\n  labels.reduce<Record<string, number>>((acc, l) => {\n    acc[l.id] = mails.value.filter((m) => m.labels.includes(l.id)).length\n    return acc\n  }, {}),\n)\n\nconst visibleMails = computed(() => {\n  const q = search.value.trim().toLowerCase()\n  let list = mails.value.filter((m) => {\n    if (activeLabel.value) return m.labels.includes(activeLabel.value)\n    if (activeFolder.value === 'starred') return m.starred && m.folder !== 'trash'\n    return m.folder === activeFolder.value\n  })\n  if (q) {\n    list = list.filter(\n      (m) =>\n        m.subject.toLowerCase().includes(q) ||\n        m.from.name.toLowerCase().includes(q) ||\n        m.preview.toLowerCase().includes(q),\n    )\n  }\n  return [...list].sort((a, b) => b.receivedAt.getTime() - a.receivedAt.getTime())\n})\n\nconst activeMail = computed(() => mails.value.find((m) => m.id === activeId.value) ?? null)\n\nfunction selectMail(id: string) {\n  activeId.value = id\n  const m = mails.value.find((m) => m.id === id)\n  if (m) m.read = true\n}\n\nfunction selectFolder(id: FolderId) {\n  activeFolder.value = id\n  activeLabel.value = null\n  const first = visibleMails.value[0]\n  if (first) activeId.value = first.id\n}\n\nfunction selectLabel(id: string) {\n  activeLabel.value = id\n  const first = visibleMails.value[0]\n  if (first) activeId.value = first.id\n}\n\nfunction toggleStar(id: string, e?: Event) {\n  e?.stopPropagation()\n  const m = mails.value.find((m) => m.id === id)\n  if (m) m.starred = !m.starred\n}\n\nfunction archive(id: string) {\n  mails.value = mails.value.filter((m) => m.id !== id)\n  const next = visibleMails.value[0]\n  if (next) activeId.value = next.id\n}\n\nfunction formatMailTime(d: Date): string {\n  if (d >= todayStart) return d.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })\n  if (d.toDateString() === yesterday.toDateString()) return 'Yesterday'\n  const diffDays = Math.floor((now.getTime() - d.getTime()) / (24 * 60 * 60 * 1000))\n  if (diffDays < 7) return d.toLocaleDateString(undefined, { weekday: 'short' })\n  return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })\n}\n\nfunction formatFullTime(d: Date): string {\n  return d.toLocaleString(undefined, {\n    weekday: 'short',\n    month: 'short',\n    day: 'numeric',\n    hour: 'numeric',\n    minute: '2-digit',\n  })\n}\n\nfunction labelMeta(id: string): LabelTag | undefined {\n  return labels.find((l) => l.id === id)\n}\n\nconst replyRecipient = computed(() => {\n  const m = activeMail.value\n  if (!m) return ''\n  if (replyMode.value === 'forward') return ''\n  return m.from.name + ' <' + m.from.email + '>'\n})\n\nconst replyPlaceholder = computed(() =>\n  replyMode.value === 'forward' ? 'Add a note before forwarding' : 'Write a reply',\n)\n\nconst sendDisabled = computed(() => !replyDraft.value.trim() || (replyMode.value === 'forward' && false))\n\nfunction setReplyMode(mode: ReplyMode) {\n  replyMode.value = mode\n  justSent.value = false\n}\n\nfunction sendReply() {\n  const body = replyDraft.value.trim()\n  if (!body) return\n  replyDraft.value = ''\n  justSent.value = true\n  window.setTimeout(() => {\n    justSent.value = false\n  }, 1800)\n}\n\nfunction onReplyKey(e: KeyboardEvent) {\n  if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n    e.preventDefault()\n    sendReply()\n  }\n}\n\nwatch(activeId, () => {\n  replyDraft.value = ''\n  replyMode.value = 'reply'\n  justSent.value = false\n  nextTick()\n})\n</script>\n\n<template>\n  <div\n    class=\"bg-card text-card-foreground grid h-[680px] w-full grid-cols-[220px_340px_1fr] overflow-hidden rounded-xl border shadow-sm\"\n  >\n    <aside class=\"bg-muted/30 flex min-w-0 flex-col border-r\">\n      <div class=\"flex h-14 shrink-0 items-center border-b px-3\">\n        <Button class=\"h-9 w-full justify-start gap-2 rounded-lg\" size=\"sm\">\n          <Pencil class=\"size-4\" />\n          Compose\n        </Button>\n      </div>\n      <nav class=\"flex-1 space-y-1 overflow-y-auto px-3 pt-3 pb-3\">\n        <p class=\"text-muted-foreground px-2 pb-1 text-[10px] font-semibold tracking-widest uppercase\">Folders</p>\n        <button\n          v-for=\"f in folders\"\n          :key=\"f.id\"\n          :class=\"[\n            'flex w-full items-center justify-between gap-2 rounded-md px-2 py-1.5 text-left text-[13px] transition-colors',\n            activeFolder === f.id && !activeLabel\n              ? 'bg-primary/10 text-primary font-medium'\n              : 'hover:bg-muted/60 text-foreground/80',\n          ]\"\n          @click=\"selectFolder(f.id)\"\n        >\n          <span class=\"flex min-w-0 items-center gap-2\">\n            <component :is=\"f.icon\" class=\"size-4 shrink-0\" />\n            <span class=\"truncate\">{{ f.label }}</span>\n          </span>\n          <span v-if=\"unreadCount(f.id) > 0\" class=\"text-muted-foreground shrink-0 text-[10px] tabular-nums\">\n            {{ unreadCount(f.id) }}\n          </span>\n        </button>\n\n        <p class=\"text-muted-foreground mt-4 px-2 pb-1 text-[10px] font-semibold tracking-widest uppercase\">Labels</p>\n        <button\n          v-for=\"l in labels\"\n          :key=\"l.id\"\n          :class=\"[\n            'flex w-full items-center justify-between gap-2 rounded-md px-2 py-1.5 text-left text-[13px] transition-colors',\n            activeLabel === l.id ? 'bg-primary/10 text-primary font-medium' : 'hover:bg-muted/60 text-foreground/80',\n          ]\"\n          @click=\"selectLabel(l.id)\"\n        >\n          <span class=\"flex min-w-0 items-center gap-2\">\n            <span :class=\"['size-2.5 shrink-0 rounded-full', l.color]\" />\n            <span class=\"truncate\">{{ l.label }}</span>\n          </span>\n          <span class=\"text-muted-foreground shrink-0 text-[10px] tabular-nums\">\n            {{ labelCounts[l.id] ?? 0 }}\n          </span>\n        </button>\n      </nav>\n    </aside>\n\n    <section class=\"bg-background flex min-w-0 flex-col border-r\">\n      <div class=\"flex h-14 shrink-0 items-center gap-2 border-b px-3\">\n        <div class=\"relative flex-1\">\n          <Search class=\"text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\" />\n          <Input v-model=\"search\" placeholder=\"Search mail\" class=\"h-8 rounded-lg pl-8 text-xs\" />\n        </div>\n        <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Filter\">\n          <Tag class=\"size-4\" />\n        </Button>\n      </div>\n      <div class=\"flex items-center justify-between px-4 pt-3 pb-2\">\n        <h2 class=\"text-sm font-semibold tracking-tight capitalize\">\n          {{ activeLabel ? labelMeta(activeLabel)?.label : activeFolder }}\n        </h2>\n        <span class=\"text-muted-foreground text-[10px] tabular-nums\">\n          {{ visibleMails.length }} message{{ visibleMails.length === 1 ? '' : 's' }}\n        </span>\n      </div>\n      <div class=\"list-scroll flex-1 overflow-y-auto pb-3\">\n        <button\n          v-for=\"m in visibleMails\"\n          :key=\"m.id\"\n          :class=\"[\n            'group relative w-full px-4 py-3 text-left transition-colors',\n            m.id === activeId ? 'bg-primary/5' : 'hover:bg-muted/60',\n          ]\"\n          @click=\"selectMail(m.id)\"\n        >\n          <span v-if=\"m.id === activeId\" class=\"bg-primary absolute top-2 bottom-2 left-0 w-[3px] rounded-r-full\" />\n          <div class=\"flex items-start gap-3\">\n            <Avatar class=\"mt-0.5 size-8 shrink-0\">\n              <AvatarFallback class=\"text-[11px]\">{{ m.from.initials }}</AvatarFallback>\n            </Avatar>\n            <div class=\"min-w-0 flex-1\">\n              <div class=\"flex items-center justify-between gap-2\">\n                <p :class=\"['truncate text-[13px]', m.read ? 'font-medium' : 'font-semibold']\">\n                  {{ m.from.name }}\n                </p>\n                <span class=\"text-muted-foreground shrink-0 text-[10px] tabular-nums\">\n                  {{ formatMailTime(m.receivedAt) }}\n                </span>\n              </div>\n              <p :class=\"['mt-0.5 truncate text-xs', m.read ? 'text-foreground/80' : 'font-semibold']\">\n                {{ m.subject }}\n              </p>\n              <p class=\"text-muted-foreground mt-0.5 line-clamp-2 text-xs leading-relaxed\">\n                {{ m.preview }}\n              </p>\n              <div class=\"mt-1.5 flex items-center gap-1.5\">\n                <span\n                  v-for=\"lid in m.labels\"\n                  :key=\"lid\"\n                  class=\"text-muted-foreground bg-muted inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-[10px]\"\n                >\n                  <span :class=\"['size-1.5 rounded-full', labelMeta(lid)?.color]\" />\n                  {{ labelMeta(lid)?.label }}\n                </span>\n                <Paperclip v-if=\"m.hasAttachment\" class=\"text-muted-foreground size-3\" />\n                <span v-if=\"!m.read\" class=\"bg-primary ml-auto size-1.5 shrink-0 rounded-full\" />\n              </div>\n            </div>\n            <button\n              class=\"text-muted-foreground hover:text-warning shrink-0 transition-colors\"\n              :title=\"m.starred ? 'Unstar' : 'Star'\"\n              @click=\"toggleStar(m.id, $event)\"\n            >\n              <Star :class=\"['size-3.5', m.starred ? 'fill-warning text-warning' : '']\" />\n            </button>\n          </div>\n        </button>\n\n        <div v-if=\"visibleMails.length === 0\" class=\"flex flex-col items-center justify-center px-6 py-16 text-center\">\n          <div class=\"bg-muted mb-3 rounded-full p-3\">\n            <InboxIcon class=\"text-muted-foreground size-5\" />\n          </div>\n          <p class=\"text-sm font-medium\">Nothing here</p>\n          <p class=\"text-muted-foreground mt-0.5 text-xs\">No messages match the current filter.</p>\n        </div>\n      </div>\n    </section>\n\n    <section class=\"bg-background flex min-w-0 flex-col\">\n      <template v-if=\"activeMail\">\n        <div class=\"flex h-14 shrink-0 items-center justify-between gap-2 border-b px-4\">\n          <div class=\"flex items-center gap-1\">\n            <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Back\">\n              <ArrowLeft class=\"size-4\" />\n            </Button>\n            <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Archive\" @click=\"archive(activeMail.id)\">\n              <Archive class=\"size-4\" />\n            </Button>\n            <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Delete\">\n              <Trash2 class=\"size-4\" />\n            </Button>\n            <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Save\">\n              <Bookmark class=\"size-4\" />\n            </Button>\n          </div>\n          <div class=\"flex items-center gap-1\">\n            <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Reply\">\n              <Reply class=\"size-4\" />\n            </Button>\n            <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Reply all\">\n              <ReplyAll class=\"size-4\" />\n            </Button>\n            <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Forward\">\n              <Forward class=\"size-4\" />\n            </Button>\n            <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"More options\">\n              <MoreVertical class=\"size-4\" />\n            </Button>\n          </div>\n        </div>\n\n        <div class=\"reader-scroll flex-1 overflow-y-auto\">\n          <div class=\"px-6 pt-5 pb-3\">\n            <h1 class=\"text-foreground text-xl leading-tight font-semibold tracking-tight\">\n              {{ activeMail.subject }}\n            </h1>\n            <div class=\"mt-2 flex flex-wrap items-center gap-2\">\n              <span\n                v-for=\"lid in activeMail.labels\"\n                :key=\"lid\"\n                class=\"text-foreground/70 bg-muted inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px]\"\n              >\n                <span :class=\"['size-1.5 rounded-full', labelMeta(lid)?.color]\" />\n                {{ labelMeta(lid)?.label }}\n              </span>\n            </div>\n          </div>\n\n          <div class=\"flex items-start gap-3 px-6 pb-4\">\n            <Avatar class=\"size-10\">\n              <AvatarFallback>{{ activeMail.from.initials }}</AvatarFallback>\n            </Avatar>\n            <div class=\"min-w-0 flex-1\">\n              <div class=\"flex flex-wrap items-baseline gap-x-2\">\n                <p class=\"text-sm font-semibold\">{{ activeMail.from.name }}</p>\n                <p class=\"text-muted-foreground text-xs\">&lt;{{ activeMail.from.email }}&gt;</p>\n              </div>\n              <p class=\"text-muted-foreground text-xs\">to {{ activeMail.to }}</p>\n            </div>\n            <div class=\"text-muted-foreground flex shrink-0 items-center gap-2 text-xs\">\n              <span>{{ formatFullTime(activeMail.receivedAt) }}</span>\n              <button\n                class=\"hover:text-warning transition-colors\"\n                :title=\"activeMail.starred ? 'Unstar' : 'Star'\"\n                @click=\"toggleStar(activeMail.id)\"\n              >\n                <Star :class=\"['size-4', activeMail.starred ? 'fill-warning text-warning' : '']\" />\n              </button>\n            </div>\n          </div>\n\n          <article class=\"text-foreground/90 px-6 pb-6 text-sm leading-relaxed whitespace-pre-wrap\">\n            {{ activeMail.body }}\n          </article>\n\n          <div v-if=\"activeMail.hasAttachment\" class=\"px-6 pb-6\">\n            <div class=\"bg-muted/40 flex items-center gap-3 rounded-lg border px-3 py-2.5\">\n              <div class=\"bg-info/10 text-info flex size-8 items-center justify-center rounded-md\">\n                <FileText class=\"size-4\" />\n              </div>\n              <div class=\"min-w-0 flex-1\">\n                <p class=\"truncate text-xs font-medium\">attachment.pdf</p>\n                <p class=\"text-muted-foreground text-[10px]\">142 KB · PDF</p>\n              </div>\n              <Button variant=\"ghost\" size=\"sm\" class=\"h-7 text-xs\">Download</Button>\n            </div>\n          </div>\n        </div>\n\n        <div class=\"bg-muted/20 border-t px-4 pt-3 pb-3\">\n          <div class=\"mb-2 flex items-center gap-1\">\n            <button\n              :class=\"[\n                'inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-[11px] font-medium transition-colors',\n                replyMode === 'reply'\n                  ? 'bg-background text-foreground border-input/60 border shadow-sm'\n                  : 'text-muted-foreground hover:bg-background/60 hover:text-foreground',\n              ]\"\n              @click=\"setReplyMode('reply')\"\n            >\n              <Reply class=\"size-3.5\" />\n              Reply\n            </button>\n            <button\n              :class=\"[\n                'inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-[11px] font-medium transition-colors',\n                replyMode === 'reply-all'\n                  ? 'bg-background text-foreground border-input/60 border shadow-sm'\n                  : 'text-muted-foreground hover:bg-background/60 hover:text-foreground',\n              ]\"\n              @click=\"setReplyMode('reply-all')\"\n            >\n              <ReplyAll class=\"size-3.5\" />\n              Reply all\n            </button>\n            <button\n              :class=\"[\n                'inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-[11px] font-medium transition-colors',\n                replyMode === 'forward'\n                  ? 'bg-background text-foreground border-input/60 border shadow-sm'\n                  : 'text-muted-foreground hover:bg-background/60 hover:text-foreground',\n              ]\"\n              @click=\"setReplyMode('forward')\"\n            >\n              <Forward class=\"size-3.5\" />\n              Forward\n            </button>\n          </div>\n          <div\n            class=\"bg-background border-input/60 focus-within:border-primary/40 focus-within:ring-primary/10 group flex flex-col overflow-hidden rounded-2xl border shadow-sm transition-all duration-150 focus-within:shadow-md focus-within:ring-4\"\n          >\n            <p\n              v-if=\"replyRecipient\"\n              class=\"border-input/40 text-muted-foreground border-b px-4 pt-2.5 pb-2 text-[11px]\"\n            >\n              <span class=\"text-foreground/70 font-medium\">To:</span> {{ replyRecipient }}\n            </p>\n            <Textarea\n              v-model=\"replyDraft\"\n              :placeholder=\"replyPlaceholder\"\n              rows=\"1\"\n              class=\"placeholder:text-muted-foreground/70 max-h-40 min-h-[44px] resize-none border-0 bg-transparent px-4 pt-3 pb-1 text-sm leading-relaxed shadow-none focus-visible:ring-0\"\n              @keydown=\"onReplyKey\"\n            />\n            <div class=\"flex items-center justify-between gap-2 px-2 pb-2\">\n              <div class=\"flex items-center gap-0.5\">\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  class=\"text-muted-foreground hover:text-foreground size-8\"\n                  aria-label=\"Attach file\"\n                >\n                  <Paperclip class=\"size-4\" />\n                </Button>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  class=\"text-muted-foreground hover:text-foreground size-8\"\n                  aria-label=\"Emoji\"\n                >\n                  <Smile class=\"size-4\" />\n                </Button>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  class=\"text-muted-foreground hover:text-foreground size-8\"\n                  aria-label=\"Mention\"\n                >\n                  <AtSign class=\"size-4\" />\n                </Button>\n              </div>\n              <div class=\"flex items-center gap-2\">\n                <kbd\n                  class=\"bg-muted text-muted-foreground hidden h-5 items-center gap-0.5 rounded border px-1.5 font-mono text-[10px] sm:inline-flex\"\n                >\n                  <span>⌘</span><span>↵</span>\n                </kbd>\n                <Button\n                  class=\"h-8 gap-1.5 rounded-lg px-3 text-xs font-medium\"\n                  :disabled=\"sendDisabled\"\n                  aria-label=\"Send\"\n                  @click=\"sendReply\"\n                >\n                  Send\n                  <ArrowRight class=\"size-3.5\" />\n                </Button>\n              </div>\n            </div>\n          </div>\n          <p v-if=\"justSent\" class=\"text-success mt-2 text-center text-[11px] font-medium\">Reply sent</p>\n        </div>\n      </template>\n\n      <div v-else class=\"flex flex-1 items-center justify-center\">\n        <div class=\"text-center\">\n          <div class=\"bg-muted mx-auto mb-3 size-12 rounded-full p-3\">\n            <InboxIcon class=\"text-muted-foreground size-6\" />\n          </div>\n          <p class=\"text-sm font-medium\">No message selected</p>\n          <p class=\"text-muted-foreground mt-1 text-xs\">Pick a message from the list to read it here.</p>\n        </div>\n      </div>\n    </section>\n  </div>\n</template>\n\n<style scoped>\n.list-scroll::-webkit-scrollbar,\n.reader-scroll::-webkit-scrollbar {\n  width: 6px;\n}\n.list-scroll::-webkit-scrollbar-thumb,\n.reader-scroll::-webkit-scrollbar-thumb {\n  background: var(--border);\n  border-radius: 3px;\n}\n</style>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/Inbox.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/avatar.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/input.json"
  ],
  "description": "Three-pane mail surface. Left rail: Compose button, folders (Inbox/Starred/Sent/Drafts/Spam/Trash) with unread counts, colour-coded labels with totals. Middle: searchable message list with sender, subject, preview, labels, attachment glyphs, star toggle, smart timestamps. Right: reader pane with subject, from/to, body, attachment chip, reply/forward/archive actions. Stateful demo — swap `mails` for your data source.",
  "categories": [
    "communication",
    "layout"
  ]
}