{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "store-dashboard",
  "title": "Store dashboard",
  "description": "Shop admin with a sidebar, KPI cards, a revenue chart with a period switch, top products and recent orders.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/manniche/store-dashboard/store-dashboard.tsx",
      "content": "// An admin dashboard for a small online shop. The period switch, the chart tooltips and the mobile menu are plain HTML\n// and CSS (radio buttons with :has(), :hover, :focus-within and details), so the markup also works as a static page.\nimport {\n  ArrowDownRight,\n  ArrowUpRight,\n  BarChart3,\n  Bell,\n  Box,\n  ChevronDown,\n  Home,\n  Menu,\n  Package,\n  Search,\n  Settings,\n  ShoppingCart,\n  Tag,\n  Users,\n  X,\n} from 'lucide-react'\nimport { cn } from '@/lib/utils'\n\nconst navItems = [\n  { icon: Home, label: 'Overview', current: true },\n  { icon: ShoppingCart, label: 'Orders', count: 12 },\n  { icon: Package, label: 'Products' },\n  { icon: Users, label: 'Customers' },\n  { icon: Tag, label: 'Discounts' },\n  { icon: BarChart3, label: 'Reports' },\n]\n\nconst kpis = [\n  { label: 'Revenue', value: '€48,290', change: 12.4, points: [8, 10, 9, 12, 11, 14, 13, 16, 15, 18, 17, 21] },\n  { label: 'Orders', value: '1,284', change: 8.1, points: [10, 11, 10, 12, 14, 13, 15, 14, 16, 15, 17, 18] },\n  { label: 'Average order', value: '€37.60', change: 3.9, points: [12, 12, 13, 12, 13, 14, 13, 14, 14, 15, 14, 15] },\n  { label: 'Returns', value: '2.1%', change: -0.6, points: [16, 15, 15, 14, 15, 13, 13, 12, 12, 11, 12, 10], lowerIsBetter: true },\n]\n\nconst periods = [\n  {\n    id: 'week',\n    label: '7 days',\n    total: '€11,940',\n    bars: [\n      ['Mon', 1420],\n      ['Tue', 1610],\n      ['Wed', 1380],\n      ['Thu', 1890],\n      ['Fri', 2140],\n      ['Sat', 2010],\n      ['Sun', 1490],\n    ],\n  },\n  {\n    id: 'month',\n    label: '30 days',\n    total: '€48,290',\n    bars: [\n      ['Wk 1', 10200],\n      ['Wk 2', 11800],\n      ['Wk 3', 12650],\n      ['Wk 4', 13640],\n    ],\n  },\n  {\n    id: 'year',\n    label: '12 months',\n    total: '€512,400',\n    bars: [\n      ['Jan', 31000],\n      ['Feb', 29500],\n      ['Mar', 36200],\n      ['Apr', 38900],\n      ['May', 41000],\n      ['Jun', 39800],\n      ['Jul', 37400],\n      ['Aug', 40100],\n      ['Sep', 44600],\n      ['Oct', 47300],\n      ['Nov', 58200],\n      ['Dec', 68400],\n    ],\n  },\n] as const\n\nconst topProducts = [\n  { name: 'Morning mug', sold: 342, revenue: '€8,208', share: 0.92 },\n  { name: 'Linen napkins, set of 4', sold: 251, revenue: '€7,028', share: 0.74 },\n  { name: 'Serving bowl', sold: 168, revenue: '€7,056', share: 0.61 },\n  { name: 'Water carafe', sold: 133, revenue: '€4,788', share: 0.42 },\n  { name: 'Tall vase', sold: 71, revenue: '€4,118', share: 0.28 },\n]\n\ntype Status = 'Paid' | 'Shipped' | 'Pending' | 'Refunded'\nconst orders: { id: string; customer: string; date: string; items: number; total: string; status: Status }[] = [\n  { id: '#3021', customer: 'Ana Ruiz', date: 'Today, 09:41', items: 3, total: '€96.00', status: 'Paid' },\n  { id: '#3020', customer: 'Jonas Petersen', date: 'Today, 08:12', items: 1, total: '€42.00', status: 'Pending' },\n  { id: '#3019', customer: 'Mei Lin', date: 'Yesterday', items: 6, total: '€214.50', status: 'Shipped' },\n  { id: '#3018', customer: 'Tomás Novak', date: 'Yesterday', items: 2, total: '€60.00', status: 'Shipped' },\n  { id: '#3017', customer: 'Sara Holm', date: '2 Oct', items: 1, total: '€24.00', status: 'Refunded' },\n]\n\nconst statusStyle: Record<Status, string> = {\n  Paid: 'bg-primary/12 text-primary',\n  Shipped: 'bg-success/12 text-success',\n  Pending: 'bg-muted text-muted-foreground',\n  Refunded: 'bg-destructive/12 text-destructive',\n}\n\nfunction Sparkline({ points, good }: { points: readonly number[]; good: boolean }) {\n  const max = Math.max(...points)\n  const min = Math.min(...points)\n  const xy = points.map((p, i) => `${(i / (points.length - 1)) * 100},${28 - ((p - min) / (max - min || 1)) * 24}`)\n  return (\n    <svg viewBox=\"0 0 100 30\" preserveAspectRatio=\"none\" className=\"h-10 w-full overflow-visible\" aria-hidden>\n      <path d={`M0,30 L${xy.join(' L')} L100,30 Z`} className={good ? 'fill-primary/10' : 'fill-destructive/10'} />\n      <path\n        d={`M${xy.join(' L')}`}\n        fill=\"none\"\n        strokeWidth=\"2\"\n        vectorEffect=\"non-scaling-stroke\"\n        strokeLinejoin=\"round\"\n        className={good ? 'stroke-primary' : 'stroke-destructive'}\n      />\n    </svg>\n  )\n}\n\nfunction Brand() {\n  return (\n    <a href=\"#top\" className=\"flex items-center gap-2 font-semibold tracking-tight\">\n      <span className=\"grid size-8 place-items-center rounded-lg bg-primary text-primary-foreground\">\n        <Box className=\"size-4\" aria-hidden />\n      </span>\n      Linden Admin\n    </a>\n  )\n}\n\nfunction Nav() {\n  return (\n    <ul className=\"space-y-1\">\n      {navItems.map(({ icon: Icon, label, current, count }) => (\n        <li key={label}>\n          <a\n            href={`#${label.toLowerCase()}`}\n            aria-current={current ? 'page' : undefined}\n            className=\"flex items-center gap-3 rounded-lg px-3 py-2 text-sm text-muted-foreground transition-colors duration-150 hover:bg-muted hover:text-foreground aria-[current=page]:bg-accent aria-[current=page]:font-medium aria-[current=page]:text-accent-foreground\"\n          >\n            <Icon className=\"size-4\" aria-hidden />\n            {label}\n            {count && <span className=\"ml-auto rounded-full bg-primary px-1.5 text-xs font-medium text-primary-foreground tabular-nums\">{count}</span>}\n          </a>\n        </li>\n      ))}\n    </ul>\n  )\n}\n\n/** Shop admin dashboard: sidebar, KPI cards with sparklines, a revenue chart with a period switch, top products and recent orders. */\nexport function StoreDashboard() {\n  return (\n    <div id=\"top\" className=\"group/dash min-h-dvh bg-muted/40 font-sans text-foreground antialiased lg:grid lg:grid-cols-[15rem_1fr]\">\n      <aside className=\"hidden border-r bg-card lg:sticky lg:top-0 lg:flex lg:h-dvh lg:flex-col\">\n        <div className=\"flex h-16 items-center px-5\">\n          <Brand />\n        </div>\n        <nav aria-label=\"Main\" className=\"flex-1 px-3 py-4\">\n          <Nav />\n        </nav>\n        <div className=\"m-3 rounded-xl border bg-accent/50 p-4\">\n          <p className=\"text-sm font-medium\">Black Friday in 52 days</p>\n          <p className=\"mt-1 text-xs text-muted-foreground\">Set up discounts early so you can test them.</p>\n          <a href=\"#discounts\" className=\"mt-3 inline-block text-xs font-medium text-primary underline-offset-4 hover:underline\">\n            Plan a discount\n          </a>\n        </div>\n        <a href=\"#settings\" className=\"flex items-center gap-3 border-t px-6 py-4 text-sm text-muted-foreground transition-colors hover:text-foreground\">\n          <Settings className=\"size-4\" aria-hidden />\n          Settings\n        </a>\n      </aside>\n\n      <div className=\"min-w-0\">\n        <header className=\"sticky top-0 z-20 flex h-16 items-center gap-3 border-b bg-background/85 px-4 backdrop-blur sm:px-6\">\n          <details className=\"group/menu relative lg:hidden\">\n            <summary className=\"grid size-9 cursor-pointer list-none place-items-center rounded-lg border [&::-webkit-details-marker]:hidden\">\n              <Menu className=\"size-4 group-open/menu:hidden\" aria-hidden />\n              <X className=\"hidden size-4 group-open/menu:block\" aria-hidden />\n              <span className=\"sr-only\">Menu</span>\n            </summary>\n            <nav aria-label=\"Main\" className=\"absolute top-12 left-0 w-60 rounded-xl border bg-card p-2 shadow-lg\">\n              <Nav />\n            </nav>\n          </details>\n          <div className=\"lg:hidden\">\n            <Brand />\n          </div>\n          <label className=\"ml-auto hidden h-9 w-72 items-center gap-2 rounded-lg border bg-card px-3 text-sm text-muted-foreground focus-within:ring-2 focus-within:ring-ring sm:flex lg:ml-0\">\n            <Search className=\"size-4\" aria-hidden />\n            <input\n              type=\"search\"\n              placeholder=\"Search orders, products…\"\n              className=\"w-full bg-transparent text-foreground outline-none placeholder:text-muted-foreground\"\n            />\n          </label>\n          <div className=\"ml-auto flex items-center gap-2 sm:ml-0 lg:ml-auto\">\n            <button type=\"button\" className=\"relative grid size-9 place-items-center rounded-lg border bg-card\" aria-label=\"Notifications, 3 new\">\n              <Bell className=\"size-4\" aria-hidden />\n              <span className=\"absolute top-1.5 right-1.5 size-2 rounded-full bg-primary ring-2 ring-card\" />\n            </button>\n            <button type=\"button\" className=\"flex items-center gap-2 rounded-lg py-1 pr-2 pl-1 transition-colors hover:bg-muted\">\n              <span className=\"grid size-7 place-items-center rounded-full bg-accent text-xs font-semibold text-accent-foreground\">MK</span>\n              <span className=\"hidden text-sm font-medium sm:block\">Maja K.</span>\n              <ChevronDown className=\"size-4 text-muted-foreground\" aria-hidden />\n            </button>\n          </div>\n        </header>\n\n        <main className=\"mx-auto max-w-7xl space-y-6 p-4 sm:p-6\">\n          <div className=\"flex flex-wrap items-end justify-between gap-4\">\n            <div>\n              <p className=\"text-sm text-muted-foreground\">Good morning, Maja</p>\n              <h1 className=\"text-2xl font-semibold tracking-tight\">Overview</h1>\n            </div>\n            <fieldset className=\"flex rounded-lg border bg-card p-1 text-sm\">\n              <legend className=\"sr-only\">Period</legend>\n              {periods.map((p) => (\n                <label\n                  key={p.id}\n                  className=\"cursor-pointer rounded-md px-3 py-1.5 text-muted-foreground transition-colors duration-150 has-checked:bg-foreground has-checked:text-background has-focus-visible:ring-2 has-focus-visible:ring-ring\"\n                >\n                  <input type=\"radio\" name=\"period\" value={p.id} defaultChecked={p.id === 'month'} className=\"sr-only\" />\n                  {p.label}\n                </label>\n              ))}\n            </fieldset>\n          </div>\n\n          <ul className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n            {kpis.map((k) => {\n              const good = k.lowerIsBetter ? k.change < 0 : k.change > 0\n              const Arrow = k.change > 0 ? ArrowUpRight : ArrowDownRight\n              return (\n                <li key={k.label} className=\"rounded-2xl border bg-card p-5 transition-shadow duration-200 hover:shadow-md\">\n                  <div className=\"flex items-center justify-between\">\n                    <p className=\"text-sm text-muted-foreground\">{k.label}</p>\n                    <span\n                      className={cn(\n                        'inline-flex items-center gap-0.5 rounded-full px-1.5 py-0.5 text-xs font-medium tabular-nums',\n                        good ? 'bg-success/12 text-success' : 'bg-destructive/12 text-destructive',\n                      )}\n                    >\n                      <Arrow className=\"size-3\" aria-hidden />\n                      {Math.abs(k.change)}%\n                    </span>\n                  </div>\n                  <p className=\"mt-2 text-2xl font-semibold tracking-tight tabular-nums\">{k.value}</p>\n                  <div className=\"mt-3\">\n                    <Sparkline points={k.points} good={good} />\n                  </div>\n                  <p className=\"mt-1 text-xs text-muted-foreground\">vs. the 30 days before</p>\n                </li>\n              )\n            })}\n          </ul>\n\n          <div className=\"grid gap-6 xl:grid-cols-[1.6fr_1fr]\">\n            <section aria-labelledby=\"revenue\" className=\"min-w-0 rounded-2xl border bg-card p-5 sm:p-6\">\n              {periods.map((p) => {\n                const max = Math.max(...p.bars.map(([, v]) => v))\n                return (\n                  <div\n                    key={p.id}\n                    className={cn(\n                      'hidden',\n                      p.id === 'week' && 'group-has-[[value=week]:checked]/dash:block',\n                      p.id === 'month' && 'group-has-[[value=month]:checked]/dash:block',\n                      p.id === 'year' && 'group-has-[[value=year]:checked]/dash:block',\n                    )}\n                  >\n                    <div className=\"flex items-baseline justify-between gap-4\">\n                      <div>\n                        <h2 id={p.id === 'month' ? 'revenue' : undefined} className=\"text-sm text-muted-foreground\">\n                          Revenue, {p.label}\n                        </h2>\n                        <p className=\"mt-1 text-3xl font-semibold tracking-tight tabular-nums\">{p.total}</p>\n                      </div>\n                      <p className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n                        <span className=\"size-2.5 rounded-sm bg-primary\" aria-hidden />\n                        Sales incl. VAT\n                      </p>\n                    </div>\n                    <ol className=\"mt-8 flex h-56 items-end gap-2 border-b sm:gap-3\" aria-label={`Revenue by period, ${p.label}`}>\n                      {p.bars.map(([label, value], i) => (\n                        <li key={label} className=\"group/bar relative flex h-full flex-1 flex-col justify-end\" tabIndex={0}>\n                          <span\n                            className={cn(\n                              'pointer-events-none absolute z-10 scale-95 rounded-md bg-foreground px-2 py-1 text-xs whitespace-nowrap text-background opacity-0 shadow-lg transition-[opacity,scale] duration-150 group-hover/bar:scale-100 group-hover/bar:opacity-100 group-focus/bar:scale-100 group-focus/bar:opacity-100',\n                              i === 0 ? 'left-0' : i === p.bars.length - 1 ? 'right-0' : 'left-1/2 -translate-x-1/2',\n                            )}\n                            style={{ bottom: `calc(${(value / max) * 100}% + 6px)` }}\n                          >\n                            {label}: €{value.toLocaleString('en-GB')}\n                          </span>\n                          <span\n                            className=\"block origin-bottom rounded-t-md bg-primary/75 transition-[background-color,scale] duration-500 ease-out-quint group-hover/bar:bg-primary group-focus/bar:bg-primary starting:scale-y-0\"\n                            style={{ height: `${(value / max) * 100}%`, transitionDelay: `${i * 30}ms` }}\n                          />\n                        </li>\n                      ))}\n                    </ol>\n                    <ol className=\"mt-2 flex gap-2 text-center text-xs text-muted-foreground sm:gap-3\" aria-hidden>\n                      {p.bars.map(([label]) => (\n                        <li key={label} className=\"flex-1 truncate\">\n                          {label}\n                        </li>\n                      ))}\n                    </ol>\n                  </div>\n                )\n              })}\n            </section>\n\n            <section aria-labelledby=\"top-products\" className=\"min-w-0 rounded-2xl border bg-card p-5 sm:p-6\">\n              <div className=\"flex items-center justify-between\">\n                <h2 id=\"top-products\" className=\"font-semibold\">\n                  Top products\n                </h2>\n                <a href=\"#products\" className=\"text-sm text-muted-foreground transition-colors hover:text-foreground\">\n                  See all\n                </a>\n              </div>\n              <ol className=\"mt-5 space-y-4\">\n                {topProducts.map((p, i) => (\n                  <li key={p.name}>\n                    <div className=\"flex items-center gap-3 text-sm\">\n                      <span className=\"grid size-7 shrink-0 place-items-center rounded-md bg-muted text-xs font-medium text-muted-foreground tabular-nums\">\n                        {i + 1}\n                      </span>\n                      <span className=\"min-w-0 flex-1 truncate font-medium\">{p.name}</span>\n                      <span className=\"text-muted-foreground tabular-nums\">{p.sold} sold</span>\n                      <span className=\"w-16 text-right font-medium tabular-nums\">{p.revenue}</span>\n                    </div>\n                    <div className=\"mt-2 ml-10 h-1.5 overflow-hidden rounded-full bg-muted\">\n                      <div\n                        className=\"h-full origin-left rounded-full bg-primary transition-[scale] duration-700 ease-out-quint starting:scale-x-0\"\n                        style={{ width: `${p.share * 100}%` }}\n                      />\n                    </div>\n                  </li>\n                ))}\n              </ol>\n            </section>\n          </div>\n\n          <section aria-labelledby=\"orders\" className=\"overflow-hidden rounded-2xl border bg-card\">\n            <div className=\"flex items-center justify-between p-5 sm:px-6\">\n              <h2 id=\"orders\" className=\"font-semibold\">\n                Recent orders\n              </h2>\n              <a href=\"#orders\" className=\"rounded-lg border px-3 py-1.5 text-sm transition-colors hover:bg-muted\">\n                View all\n              </a>\n            </div>\n            <div className=\"overflow-x-auto\">\n              <table className=\"w-full min-w-160 text-left text-sm whitespace-nowrap\">\n                <thead className=\"border-y bg-muted/50 text-xs text-muted-foreground\">\n                  <tr>\n                    {['Order', 'Customer', 'Date', 'Items', 'Status', 'Total'].map((h) => (\n                      <th key={h} scope=\"col\" className={cn('px-6 py-3 font-medium', h === 'Total' && 'text-right')}>\n                        {h}\n                      </th>\n                    ))}\n                  </tr>\n                </thead>\n                <tbody className=\"divide-y\">\n                  {orders.map((o) => (\n                    <tr key={o.id} className=\"transition-colors duration-150 hover:bg-muted/40\">\n                      <td className=\"px-6 py-4 font-medium tabular-nums\">{o.id}</td>\n                      <td className=\"px-6 py-4\">\n                        <span className=\"flex items-center gap-3\">\n                          <span className=\"grid size-7 place-items-center rounded-full bg-accent text-xs font-semibold text-accent-foreground\">\n                            {o.customer\n                              .split(' ')\n                              .map((w) => w[0])\n                              .join('')}\n                          </span>\n                          {o.customer}\n                        </span>\n                      </td>\n                      <td className=\"px-6 py-4 text-muted-foreground\">{o.date}</td>\n                      <td className=\"px-6 py-4 tabular-nums\">{o.items}</td>\n                      <td className=\"px-6 py-4\">\n                        <span className={cn('inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium', statusStyle[o.status])}>\n                          <span className=\"size-1.5 rounded-full bg-current\" aria-hidden />\n                          {o.status}\n                        </span>\n                      </td>\n                      <td className=\"px-6 py-4 text-right font-medium tabular-nums\">{o.total}</td>\n                    </tr>\n                  ))}\n                </tbody>\n              </table>\n            </div>\n          </section>\n\n          <p className=\"pb-2 text-center text-xs text-muted-foreground\">Linden Admin is a template from Manniche UI. All figures are made up.</p>\n        </main>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "cssVars": {
    "theme": {
      "color-success": "var(--success)",
      "ease-out-quint": "cubic-bezier(0.23, 1, 0.32, 1)"
    },
    "light": {
      "success": "oklch(0.55 0.13 155)"
    },
    "dark": {
      "success": "oklch(0.72 0.13 155)"
    }
  },
  "categories": [
    "templates"
  ],
  "type": "registry:block"
}