{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "inbox",
  "title": "Inbox",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/inbox/Inbox.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\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-react'\nimport { Avatar, AvatarFallback } from '@/components/ui/avatar'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { cn } from '@/lib/utils'\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: React.ComponentType<{ className?: string }>\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 defaultMails: 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\nexport interface InboxProps {\n  messages?: Mail[]\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\nexport function Inbox({ messages = defaultMails }: InboxProps) {\n  const [mails, setMails] = React.useState<Mail[]>(messages)\n  const [activeFolder, setActiveFolder] = React.useState<FolderId>('inbox')\n  const [activeLabel, setActiveLabel] = React.useState<string | null>(null)\n  const [activeId, setActiveId] = React.useState<string>('e1')\n  const [search, setSearch] = React.useState('')\n  const [replyMode, setReplyMode] = React.useState<ReplyMode>('reply')\n  const [replyDraft, setReplyDraft] = React.useState('')\n  const [justSent, setJustSent] = React.useState(false)\n\n  function unreadCount(id: FolderId): number {\n    if (id === 'starred') return mails.filter((m) => m.starred && !m.read && m.folder !== 'trash').length\n    return mails.filter((m) => m.folder === id && !m.read).length\n  }\n\n  const labelCounts = React.useMemo(\n    () =>\n      labels.reduce<Record<string, number>>((acc, l) => {\n        acc[l.id] = mails.filter((m) => m.labels.includes(l.id)).length\n        return acc\n      }, {}),\n    [mails],\n  )\n\n  const visibleMails = React.useMemo(() => {\n    const q = search.trim().toLowerCase()\n    let list = mails.filter((m) => {\n      if (activeLabel) return m.labels.includes(activeLabel)\n      if (activeFolder === 'starred') return m.starred && m.folder !== 'trash'\n      return m.folder === activeFolder\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  }, [mails, search, activeLabel, activeFolder])\n\n  const activeMail = React.useMemo(() => mails.find((m) => m.id === activeId) ?? null, [mails, activeId])\n\n  function selectMail(id: string) {\n    setActiveId(id)\n    setMails((prev) => prev.map((m) => (m.id === id ? { ...m, read: true } : m)))\n  }\n\n  function selectFolder(id: FolderId) {\n    setActiveFolder(id)\n    setActiveLabel(null)\n    const list = [...mails]\n      .filter((m) => (id === 'starred' ? m.starred && m.folder !== 'trash' : m.folder === id))\n      .sort((a, b) => b.receivedAt.getTime() - a.receivedAt.getTime())\n    const first = list[0]\n    if (first) setActiveId(first.id)\n  }\n\n  function selectLabel(id: string) {\n    setActiveLabel(id)\n    const list = [...mails]\n      .filter((m) => m.labels.includes(id))\n      .sort((a, b) => b.receivedAt.getTime() - a.receivedAt.getTime())\n    const first = list[0]\n    if (first) setActiveId(first.id)\n  }\n\n  function toggleStar(id: string, e?: React.MouseEvent) {\n    e?.stopPropagation()\n    setMails((prev) => prev.map((m) => (m.id === id ? { ...m, starred: !m.starred } : m)))\n  }\n\n  function archive(id: string) {\n    setMails((prev) => {\n      const next = prev.filter((m) => m.id !== id)\n      const visible = [...next]\n        .filter((m) => {\n          if (activeLabel) return m.labels.includes(activeLabel)\n          if (activeFolder === 'starred') return m.starred && m.folder !== 'trash'\n          return m.folder === activeFolder\n        })\n        .sort((a, b) => b.receivedAt.getTime() - a.receivedAt.getTime())\n      const nextActive = visible[0]\n      if (nextActive) setActiveId(nextActive.id)\n      return next\n    })\n  }\n\n  const replyRecipient = React.useMemo(() => {\n    const m = activeMail\n    if (!m) return ''\n    if (replyMode === 'forward') return ''\n    return m.from.name + ' <' + m.from.email + '>'\n  }, [activeMail, replyMode])\n\n  const replyPlaceholder = replyMode === 'forward' ? 'Add a note before forwarding' : 'Write a reply'\n\n  const sendDisabled = !replyDraft.trim() || (replyMode === 'forward' && false)\n\n  function changeReplyMode(mode: ReplyMode) {\n    setReplyMode(mode)\n    setJustSent(false)\n  }\n\n  function sendReply() {\n    const body = replyDraft.trim()\n    if (!body) return\n    setReplyDraft('')\n    setJustSent(true)\n    window.setTimeout(() => {\n      setJustSent(false)\n    }, 1800)\n  }\n\n  function onReplyKey(e: React.KeyboardEvent) {\n    if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n      e.preventDefault()\n      sendReply()\n    }\n  }\n\n  React.useEffect(() => {\n    setReplyDraft('')\n    setReplyMode('reply')\n    setJustSent(false)\n  }, [activeId])\n\n  return (\n    <div className=\"bg-card text-card-foreground grid h-[680px] w-full grid-cols-[220px_340px_1fr] overflow-hidden rounded-xl border shadow-sm\">\n      <aside className=\"bg-muted/30 flex min-w-0 flex-col border-r\">\n        <div className=\"flex h-14 shrink-0 items-center border-b px-3\">\n          <Button className=\"h-9 w-full justify-start gap-2 rounded-lg\" size=\"sm\">\n            <Pencil className=\"size-4\" />\n            Compose\n          </Button>\n        </div>\n        <nav className=\"flex-1 space-y-1 overflow-y-auto px-3 pt-3 pb-3\">\n          <p className=\"text-muted-foreground px-2 pb-1 text-[10px] font-semibold tracking-widest uppercase\">Folders</p>\n          {folders.map((f) => (\n            <button\n              key={f.id}\n              className={cn(\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              onClick={() => selectFolder(f.id)}\n            >\n              <span className=\"flex min-w-0 items-center gap-2\">\n                <f.icon className=\"size-4 shrink-0\" />\n                <span className=\"truncate\">{f.label}</span>\n              </span>\n              {unreadCount(f.id) > 0 && (\n                <span className=\"text-muted-foreground shrink-0 text-[10px] tabular-nums\">{unreadCount(f.id)}</span>\n              )}\n            </button>\n          ))}\n\n          <p className=\"text-muted-foreground mt-4 px-2 pb-1 text-[10px] font-semibold tracking-widest uppercase\">\n            Labels\n          </p>\n          {labels.map((l) => (\n            <button\n              key={l.id}\n              className={cn(\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              onClick={() => selectLabel(l.id)}\n            >\n              <span className=\"flex min-w-0 items-center gap-2\">\n                <span className={cn('size-2.5 shrink-0 rounded-full', l.color)} />\n                <span className=\"truncate\">{l.label}</span>\n              </span>\n              <span className=\"text-muted-foreground shrink-0 text-[10px] tabular-nums\">{labelCounts[l.id] ?? 0}</span>\n            </button>\n          ))}\n        </nav>\n      </aside>\n\n      <section className=\"bg-background flex min-w-0 flex-col border-r\">\n        <div className=\"flex h-14 shrink-0 items-center gap-2 border-b px-3\">\n          <div className=\"relative flex-1\">\n            <Search className=\"text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\" />\n            <Input\n              value={search}\n              onChange={(e) => setSearch(e.target.value)}\n              placeholder=\"Search mail\"\n              className=\"h-8 rounded-lg pl-8 text-xs\"\n            />\n          </div>\n          <Button variant=\"ghost\" size=\"icon\" className=\"size-8\" aria-label=\"Filter\">\n            <Tag className=\"size-4\" />\n          </Button>\n        </div>\n        <div className=\"flex items-center justify-between px-4 pt-3 pb-2\">\n          <h2 className=\"text-sm font-semibold tracking-tight capitalize\">\n            {activeLabel ? labelMeta(activeLabel)?.label : activeFolder}\n          </h2>\n          <span className=\"text-muted-foreground text-[10px] tabular-nums\">\n            {visibleMails.length} message{visibleMails.length === 1 ? '' : 's'}\n          </span>\n        </div>\n        <div className=\"list-scroll flex-1 overflow-y-auto pb-3\">\n          {visibleMails.map((m) => (\n            <button\n              key={m.id}\n              className={cn(\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              onClick={() => selectMail(m.id)}\n            >\n              {m.id === activeId && (\n                <span className=\"bg-primary absolute top-2 bottom-2 left-0 w-[3px] rounded-r-full\" />\n              )}\n              <div className=\"flex items-start gap-3\">\n                <Avatar className=\"mt-0.5 size-8 shrink-0\">\n                  <AvatarFallback className=\"text-[11px]\">{m.from.initials}</AvatarFallback>\n                </Avatar>\n                <div className=\"min-w-0 flex-1\">\n                  <div className=\"flex items-center justify-between gap-2\">\n                    <p className={cn('truncate text-[13px]', m.read ? 'font-medium' : 'font-semibold')}>\n                      {m.from.name}\n                    </p>\n                    <span className=\"text-muted-foreground shrink-0 text-[10px] tabular-nums\">\n                      {formatMailTime(m.receivedAt)}\n                    </span>\n                  </div>\n                  <p className={cn('mt-0.5 truncate text-xs', m.read ? 'text-foreground/80' : 'font-semibold')}>\n                    {m.subject}\n                  </p>\n                  <p className=\"text-muted-foreground mt-0.5 line-clamp-2 text-xs leading-relaxed\">{m.preview}</p>\n                  <div className=\"mt-1.5 flex items-center gap-1.5\">\n                    {m.labels.map((lid) => (\n                      <span\n                        key={lid}\n                        className=\"text-muted-foreground bg-muted inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-[10px]\"\n                      >\n                        <span className={cn('size-1.5 rounded-full', labelMeta(lid)?.color)} />\n                        {labelMeta(lid)?.label}\n                      </span>\n                    ))}\n                    {m.hasAttachment && <Paperclip className=\"text-muted-foreground size-3\" />}\n                    {!m.read && <span className=\"bg-primary ml-auto size-1.5 shrink-0 rounded-full\" />}\n                  </div>\n                </div>\n                <button\n                  className=\"text-muted-foreground hover:text-warning shrink-0 transition-colors\"\n                  title={m.starred ? 'Unstar' : 'Star'}\n                  onClick={(e) => toggleStar(m.id, e)}\n                >\n                  <Star className={cn('size-3.5', m.starred ? 'fill-warning text-warning' : '')} />\n                </button>\n              </div>\n            </button>\n          ))}\n\n          {visibleMails.length === 0 && (\n            <div className=\"flex flex-col items-center justify-center px-6 py-16 text-center\">\n              <div className=\"bg-muted mb-3 rounded-full p-3\">\n                <InboxIcon className=\"text-muted-foreground size-5\" />\n              </div>\n              <p className=\"text-sm font-medium\">Nothing here</p>\n              <p className=\"text-muted-foreground mt-0.5 text-xs\">No messages match the current filter.</p>\n            </div>\n          )}\n        </div>\n      </section>\n\n      <section className=\"bg-background flex min-w-0 flex-col\">\n        {activeMail ? (\n          <>\n            <div className=\"flex h-14 shrink-0 items-center justify-between gap-2 border-b px-4\">\n              <div className=\"flex items-center gap-1\">\n                <Button variant=\"ghost\" size=\"icon\" className=\"size-8\" aria-label=\"Back\">\n                  <ArrowLeft className=\"size-4\" />\n                </Button>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"size-8\"\n                  aria-label=\"Archive\"\n                  onClick={() => archive(activeMail.id)}\n                >\n                  <Archive className=\"size-4\" />\n                </Button>\n                <Button variant=\"ghost\" size=\"icon\" className=\"size-8\" aria-label=\"Delete\">\n                  <Trash2 className=\"size-4\" />\n                </Button>\n                <Button variant=\"ghost\" size=\"icon\" className=\"size-8\" aria-label=\"Save\">\n                  <Bookmark className=\"size-4\" />\n                </Button>\n              </div>\n              <div className=\"flex items-center gap-1\">\n                <Button variant=\"ghost\" size=\"icon\" className=\"size-8\" aria-label=\"Reply\">\n                  <Reply className=\"size-4\" />\n                </Button>\n                <Button variant=\"ghost\" size=\"icon\" className=\"size-8\" aria-label=\"Reply all\">\n                  <ReplyAll className=\"size-4\" />\n                </Button>\n                <Button variant=\"ghost\" size=\"icon\" className=\"size-8\" aria-label=\"Forward\">\n                  <Forward className=\"size-4\" />\n                </Button>\n                <Button variant=\"ghost\" size=\"icon\" className=\"size-8\" aria-label=\"More options\">\n                  <MoreVertical className=\"size-4\" />\n                </Button>\n              </div>\n            </div>\n\n            <div className=\"reader-scroll flex-1 overflow-y-auto\">\n              <div className=\"px-6 pt-5 pb-3\">\n                <h1 className=\"text-foreground text-xl leading-tight font-semibold tracking-tight\">\n                  {activeMail.subject}\n                </h1>\n                <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n                  {activeMail.labels.map((lid) => (\n                    <span\n                      key={lid}\n                      className=\"text-foreground/70 bg-muted inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px]\"\n                    >\n                      <span className={cn('size-1.5 rounded-full', labelMeta(lid)?.color)} />\n                      {labelMeta(lid)?.label}\n                    </span>\n                  ))}\n                </div>\n              </div>\n\n              <div className=\"flex items-start gap-3 px-6 pb-4\">\n                <Avatar className=\"size-10\">\n                  <AvatarFallback>{activeMail.from.initials}</AvatarFallback>\n                </Avatar>\n                <div className=\"min-w-0 flex-1\">\n                  <div className=\"flex flex-wrap items-baseline gap-x-2\">\n                    <p className=\"text-sm font-semibold\">{activeMail.from.name}</p>\n                    <p className=\"text-muted-foreground text-xs\">&lt;{activeMail.from.email}&gt;</p>\n                  </div>\n                  <p className=\"text-muted-foreground text-xs\">to {activeMail.to}</p>\n                </div>\n                <div className=\"text-muted-foreground flex shrink-0 items-center gap-2 text-xs\">\n                  <span>{formatFullTime(activeMail.receivedAt)}</span>\n                  <button\n                    className=\"hover:text-warning transition-colors\"\n                    title={activeMail.starred ? 'Unstar' : 'Star'}\n                    onClick={() => toggleStar(activeMail.id)}\n                  >\n                    <Star className={cn('size-4', activeMail.starred ? 'fill-warning text-warning' : '')} />\n                  </button>\n                </div>\n              </div>\n\n              <article className=\"text-foreground/90 px-6 pb-6 text-sm leading-relaxed whitespace-pre-wrap\">\n                {activeMail.body}\n              </article>\n\n              {activeMail.hasAttachment && (\n                <div className=\"px-6 pb-6\">\n                  <div className=\"bg-muted/40 flex items-center gap-3 rounded-lg border px-3 py-2.5\">\n                    <div className=\"bg-info/10 text-info flex size-8 items-center justify-center rounded-md\">\n                      <FileText className=\"size-4\" />\n                    </div>\n                    <div className=\"min-w-0 flex-1\">\n                      <p className=\"truncate text-xs font-medium\">attachment.pdf</p>\n                      <p className=\"text-muted-foreground text-[10px]\">142 KB · PDF</p>\n                    </div>\n                    <Button variant=\"ghost\" size=\"sm\" className=\"h-7 text-xs\">\n                      Download\n                    </Button>\n                  </div>\n                </div>\n              )}\n            </div>\n\n            <div className=\"bg-muted/20 border-t px-4 pt-3 pb-3\">\n              <div className=\"mb-2 flex items-center gap-1\">\n                <button\n                  className={cn(\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                  onClick={() => changeReplyMode('reply')}\n                >\n                  <Reply className=\"size-3.5\" />\n                  Reply\n                </button>\n                <button\n                  className={cn(\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                  onClick={() => changeReplyMode('reply-all')}\n                >\n                  <ReplyAll className=\"size-3.5\" />\n                  Reply all\n                </button>\n                <button\n                  className={cn(\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                  onClick={() => changeReplyMode('forward')}\n                >\n                  <Forward className=\"size-3.5\" />\n                  Forward\n                </button>\n              </div>\n              <div className=\"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                {replyRecipient && (\n                  <p className=\"border-input/40 text-muted-foreground border-b px-4 pt-2.5 pb-2 text-[11px]\">\n                    <span className=\"text-foreground/70 font-medium\">To:</span> {replyRecipient}\n                  </p>\n                )}\n                <textarea\n                  value={replyDraft}\n                  onChange={(e) => setReplyDraft(e.target.value)}\n                  placeholder={replyPlaceholder}\n                  rows={1}\n                  className=\"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 outline-none focus-visible:ring-0\"\n                  onKeyDown={onReplyKey}\n                />\n                <div className=\"flex items-center justify-between gap-2 px-2 pb-2\">\n                  <div className=\"flex items-center gap-0.5\">\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon\"\n                      className=\"text-muted-foreground hover:text-foreground size-8\"\n                      aria-label=\"Attach file\"\n                    >\n                      <Paperclip className=\"size-4\" />\n                    </Button>\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon\"\n                      className=\"text-muted-foreground hover:text-foreground size-8\"\n                      aria-label=\"Emoji\"\n                    >\n                      <Smile className=\"size-4\" />\n                    </Button>\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon\"\n                      className=\"text-muted-foreground hover:text-foreground size-8\"\n                      aria-label=\"Mention\"\n                    >\n                      <AtSign className=\"size-4\" />\n                    </Button>\n                  </div>\n                  <div className=\"flex items-center gap-2\">\n                    <kbd className=\"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                      <span>⌘</span>\n                      <span>↵</span>\n                    </kbd>\n                    <Button\n                      className=\"h-8 gap-1.5 rounded-lg px-3 text-xs font-medium\"\n                      disabled={sendDisabled}\n                      aria-label=\"Send\"\n                      onClick={sendReply}\n                    >\n                      Send\n                      <ArrowRight className=\"size-3.5\" />\n                    </Button>\n                  </div>\n                </div>\n              </div>\n              {justSent && <p className=\"text-success mt-2 text-center text-[11px] font-medium\">Reply sent</p>}\n            </div>\n          </>\n        ) : (\n          <div className=\"flex flex-1 items-center justify-center\">\n            <div className=\"text-center\">\n              <div className=\"bg-muted mx-auto mb-3 size-12 rounded-full p-3\">\n                <InboxIcon className=\"text-muted-foreground size-6\" />\n              </div>\n              <p className=\"text-sm font-medium\">No message selected</p>\n              <p className=\"text-muted-foreground mt-1 text-xs\">Pick a message from the list to read it here.</p>\n            </div>\n          </div>\n        )}\n      </section>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/Inbox.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/avatar.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/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"
  ]
}