{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "notifications-5",
  "title": "Dismissible Alert Stack",
  "description": "Stack of dismissible inline notification alerts in success, info, warning, and error variants, resolving to an all caught up empty state.",
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/blocks/notifications/5/notifications-block.tsx",
      "content": "\"use client\"\n\nimport { useState } from \"react\"\nimport { cn } from \"@/lib/utils\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\n\n/** Props a call site may pass through to an icon. */\ntype IconProps = { className?: string; size?: number | string }\n\n/** An icon held in data and rendered later, e.g. `<item.icon className=\"size-4\" />`. */\ntype IconRenderer = (props: IconProps) => React.ReactNode\n\ntype Variant = \"success\" | \"info\" | \"warning\" | \"error\"\n\nconst config: Record<Variant, { icon: IconRenderer; accent: string }> = {\n  success: {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"CircleCheck\"\n        tabler=\"IconCircleCheck\"\n        hugeicons=\"CheckmarkCircle02Icon\"\n        phosphor=\"CheckCircle\"\n        remixicon=\"RiCheckboxCircleFill\"\n        {...p}\n      />\n    ),\n    accent: \"text-success\",\n  },\n  info: {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"Info\"\n        tabler=\"IconInfoCircle\"\n        hugeicons=\"InformationCircleIcon\"\n        phosphor=\"Info\"\n        remixicon=\"RiInformationFill\"\n        {...p}\n      />\n    ),\n    accent: \"text-foreground\",\n  },\n  warning: {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"TriangleAlert\"\n        tabler=\"IconAlertTriangle\"\n        hugeicons=\"Alert01Icon\"\n        phosphor=\"Warning\"\n        remixicon=\"RiAlertFill\"\n        {...p}\n      />\n    ),\n    accent: \"text-warning\",\n  },\n  error: {\n    icon: (p: IconProps) => (\n      <IconPlaceholder\n        lucide=\"CircleAlert\"\n        tabler=\"IconAlertCircle\"\n        hugeicons=\"AlertCircleIcon\"\n        phosphor=\"WarningCircle\"\n        remixicon=\"RiErrorWarningFill\"\n        {...p}\n      />\n    ),\n    accent: \"text-destructive\",\n  },\n}\n\nconst initial: { id: number; variant: Variant; title: string; body: string }[] =\n  [\n    {\n      id: 1,\n      variant: \"success\",\n      title: \"Changes saved\",\n      body: \"Your project settings were updated successfully.\",\n    },\n    {\n      id: 2,\n      variant: \"info\",\n      title: \"New version available\",\n      body: \"Refresh to get the latest features and fixes.\",\n    },\n    {\n      id: 3,\n      variant: \"warning\",\n      title: \"Usage nearing limit\",\n      body: \"You've used 85% of your monthly quota.\",\n    },\n    {\n      id: 4,\n      variant: \"error\",\n      title: \"Payment failed\",\n      body: \"We couldn't process your card. Update it to continue.\",\n    },\n  ]\n\nexport default function NotificationsBlock() {\n  const [toasts, setToasts] = useState(initial)\n\n  return (\n    <section className=\"flex min-h-svh w-full items-center justify-center bg-muted/30 px-6 py-16 text-foreground\">\n      <div className=\"flex w-full max-w-sm flex-col gap-3\">\n        {toasts.map((toast) => {\n          const { icon: Icon, accent } = config[toast.variant]\n          return (\n            <div\n              key={toast.id}\n              role=\"status\"\n              className=\"flex items-start gap-3 rounded-lg border border-border bg-background p-4 shadow-sm\"\n            >\n              <Icon\n                className={cn(\"mt-0.5 size-5 shrink-0\", accent)}\n                aria-hidden=\"true\"\n              />\n              <div className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n                <span className=\"text-sm font-semibold\">{toast.title}</span>\n                <span className=\"text-xs text-muted-foreground\">\n                  {toast.body}\n                </span>\n              </div>\n              <button\n                type=\"button\"\n                onClick={() =>\n                  setToasts((prev) => prev.filter((t) => t.id !== toast.id))\n                }\n                aria-label=\"Dismiss\"\n                className=\"shrink-0 text-muted-foreground transition-colors hover:text-foreground\"\n              >\n                <IconPlaceholder\n                  lucide=\"X\"\n                  tabler=\"IconX\"\n                  hugeicons=\"Cancel01Icon\"\n                  phosphor=\"X\"\n                  remixicon=\"RiCloseLine\"\n                  className=\"size-4\"\n                  aria-hidden=\"true\"\n                />\n              </button>\n            </div>\n          )\n        })}\n        {toasts.length === 0 && (\n          <p className=\"rounded-lg border border-dashed border-border py-10 text-center text-sm text-muted-foreground\">\n            You&apos;re all caught up.\n          </p>\n        )}\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/blocks/notifications-5.tsx"
    }
  ],
  "cssVars": {
    "light": {
      "success": "oklch(0.432 0.095 166.913)",
      "warning": "oklch(0.473 0.137 46.201)"
    },
    "dark": {
      "success": "oklch(0.765 0.177 163.223)",
      "warning": "oklch(0.828 0.189 84.429)"
    }
  },
  "meta": {
    "height": "476px",
    "tier": "free"
  },
  "categories": [
    "notifications"
  ],
  "type": "registry:block"
}