{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "invoices-list",
  "title": "Invoices List",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/invoices-list/InvoicesList.vue",
      "content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Check, Download, Eye, MoreHorizontal, Plus } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback } from '@/components/ui/avatar'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent } from '@/components/ui/card'\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\n\ntype InvoiceStatus = 'paid' | 'pending' | 'overdue' | 'draft'\n\ninterface Invoice {\n  id: string\n  number: string\n  client: string\n  issued: string\n  due: string\n  amount: string\n  status: InvoiceStatus\n}\n\nconst props = defineProps<{\n  class?: HTMLAttributes['class']\n}>()\n\nconst summary = [\n  { label: 'Total outstanding', value: '$12,480.00', note: '5 unpaid invoices', tone: '' },\n  { label: 'Paid this month', value: '$28,930.00', note: '+12% vs last month', tone: '' },\n  {\n    label: 'Overdue',\n    value: '$3,120.00',\n    note: '2 invoices past due',\n    tone: 'text-destructive',\n  },\n]\n\nconst statusClass: Record<InvoiceStatus, string> = {\n  paid: 'bg-success/10 text-success',\n  pending: 'bg-warning/10 text-warning',\n  overdue: 'bg-destructive/10 text-destructive',\n  draft: '',\n}\n\nconst invoices: Invoice[] = [\n  {\n    id: 'i1',\n    number: 'INV-2026-0142',\n    client: 'Acme Corp',\n    issued: 'Aug 18, 2026',\n    due: 'Sep 1, 2026',\n    amount: '$4,800.00',\n    status: 'pending',\n  },\n  {\n    id: 'i2',\n    number: 'INV-2026-0141',\n    client: 'Northwind Traders',\n    issued: 'Aug 15, 2026',\n    due: 'Aug 30, 2026',\n    amount: '$2,350.00',\n    status: 'overdue',\n  },\n  {\n    id: 'i3',\n    number: 'INV-2026-0140',\n    client: 'Globex Industries',\n    issued: 'Aug 12, 2026',\n    due: 'Sep 10, 2026',\n    amount: '$1,200.00',\n    status: 'draft',\n  },\n  {\n    id: 'i4',\n    number: 'INV-2026-0139',\n    client: 'Helios Labs',\n    issued: 'Aug 8, 2026',\n    due: 'Aug 22, 2026',\n    amount: '$6,750.00',\n    status: 'paid',\n  },\n  {\n    id: 'i5',\n    number: 'INV-2026-0138',\n    client: 'Acme Corp',\n    issued: 'Aug 5, 2026',\n    due: 'Aug 19, 2026',\n    amount: '$770.00',\n    status: 'paid',\n  },\n  {\n    id: 'i6',\n    number: 'INV-2026-0137',\n    client: 'Vertex Media',\n    issued: 'Jul 30, 2026',\n    due: 'Aug 13, 2026',\n    amount: '$3,120.00',\n    status: 'overdue',\n  },\n  {\n    id: 'i7',\n    number: 'INV-2026-0136',\n    client: 'Initech Systems',\n    issued: 'Jul 24, 2026',\n    due: 'Aug 7, 2026',\n    amount: '$5,400.00',\n    status: 'paid',\n  },\n]\n\nfunction initials(name: string) {\n  return name\n    .split(' ')\n    .map((part) => part[0])\n    .slice(0, 2)\n    .join('')\n    .toUpperCase()\n}\n</script>\n\n<template>\n  <div data-slot=\"invoices-list\" :class=\"cn('w-full space-y-6', props.class)\">\n    <div class=\"flex flex-wrap items-center justify-between gap-4\">\n      <div>\n        <h2 class=\"text-2xl font-bold tracking-tight\">Invoices</h2>\n        <p class=\"text-muted-foreground mt-1 text-sm\">Manage billing for all of your clients.</p>\n      </div>\n      <Button>\n        <Plus aria-hidden=\"true\" />\n        New invoice\n      </Button>\n    </div>\n\n    <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n      <Card v-for=\"item in summary\" :key=\"item.label\" class=\"shadow-xs\">\n        <CardContent class=\"space-y-1\">\n          <p class=\"text-muted-foreground text-sm\">{{ item.label }}</p>\n          <p class=\"text-2xl font-bold tracking-tight tabular-nums\" :class=\"item.tone\">{{ item.value }}</p>\n          <p class=\"text-muted-foreground text-xs\">{{ item.note }}</p>\n        </CardContent>\n      </Card>\n    </div>\n\n    <div class=\"bg-card overflow-x-auto rounded-lg border shadow-xs\">\n      <Table>\n        <TableHeader>\n          <TableRow>\n            <TableHead>Invoice</TableHead>\n            <TableHead>Client</TableHead>\n            <TableHead>Issued</TableHead>\n            <TableHead>Due</TableHead>\n            <TableHead class=\"text-right\">Amount</TableHead>\n            <TableHead>Status</TableHead>\n            <TableHead class=\"w-12\"><span class=\"sr-only\">Actions</span></TableHead>\n          </TableRow>\n        </TableHeader>\n        <TableBody>\n          <TableRow v-for=\"invoice in invoices\" :key=\"invoice.id\">\n            <TableCell class=\"font-mono text-xs font-medium\">{{ invoice.number }}</TableCell>\n            <TableCell>\n              <div class=\"flex items-center gap-2\">\n                <Avatar class=\"size-7\">\n                  <AvatarFallback class=\"text-xs\">{{ initials(invoice.client) }}</AvatarFallback>\n                </Avatar>\n                <span class=\"truncate text-sm font-medium\">{{ invoice.client }}</span>\n              </div>\n            </TableCell>\n            <TableCell class=\"text-muted-foreground text-sm\">{{ invoice.issued }}</TableCell>\n            <TableCell class=\"text-muted-foreground text-sm\">{{ invoice.due }}</TableCell>\n            <TableCell class=\"text-right font-medium tabular-nums\">{{ invoice.amount }}</TableCell>\n            <TableCell>\n              <Badge\n                :variant=\"invoice.status === 'draft' ? 'secondary' : undefined\"\n                :class=\"cn('capitalize', statusClass[invoice.status])\"\n              >\n                {{ invoice.status }}\n              </Badge>\n            </TableCell>\n            <TableCell>\n              <DropdownMenu>\n                <DropdownMenuTrigger as-child>\n                  <Button variant=\"ghost\" size=\"icon-sm\" class=\"text-muted-foreground\">\n                    <MoreHorizontal aria-hidden=\"true\" />\n                    <span class=\"sr-only\">Open actions for {{ invoice.number }}</span>\n                  </Button>\n                </DropdownMenuTrigger>\n                <DropdownMenuContent align=\"end\">\n                  <DropdownMenuItem>\n                    <Eye aria-hidden=\"true\" />\n                    View\n                  </DropdownMenuItem>\n                  <DropdownMenuItem>\n                    <Download aria-hidden=\"true\" />\n                    Download\n                  </DropdownMenuItem>\n                  <DropdownMenuSeparator />\n                  <DropdownMenuItem :disabled=\"invoice.status === 'paid' || invoice.status === 'draft'\">\n                    <Check aria-hidden=\"true\" />\n                    Mark as paid\n                  </DropdownMenuItem>\n                </DropdownMenuContent>\n              </DropdownMenu>\n            </TableCell>\n          </TableRow>\n        </TableBody>\n      </Table>\n    </div>\n\n    <div class=\"flex items-center justify-between\">\n      <p class=\"text-muted-foreground text-sm\">Showing {{ invoices.length }} of 42 invoices</p>\n      <div class=\"flex items-center gap-2\">\n        <Button variant=\"outline\" size=\"sm\" disabled>Previous</Button>\n        <Button variant=\"outline\" size=\"sm\">Next</Button>\n      </div>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/InvoicesList.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/avatar.json",
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/dropdown-menu.json",
    "https://uipkge.dev/r/vue/table.json"
  ],
  "description": "Invoice history page: header with a New invoice action, a three-card summary strip (total outstanding, paid this month, overdue), and an invoice table pairing monospace invoice numbers with avatar clients, issue/due dates, tabular-nums amounts, color-coded status badges, and a per-row View/Download/Mark-as-paid dropdown, closed by a pagination hint. Data is stubbed inline; swap for your source.",
  "categories": [
    "finance",
    "app",
    "billing"
  ]
}