{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"note","type":"registry:ui","title":"Note","description":"An aside in the flow of a page: a tip or a caveat on a calm card, with a breath of its color in the corner.","dependencies":["lucide-react"],"registryDependencies":["https://dashral.com/r/utils.json"],"files":[{"path":"registry/dashral/note.tsx","type":"registry:file","target":"components/dashral/note.tsx","content":"import * as React from \"react\"\nimport { CircleAlert, CircleCheck, Info, Lightbulb, Sparkles, TriangleAlert } from \"lucide-react\"\n\nimport { cn } from \"./lib/utils\"\n\ntype NoteColor = \"neutral\" | \"primary\" | \"info\" | \"success\" | \"warning\" | \"destructive\" | \"highlight\"\n\n// The color is a breath of light in the top corner and the icon; the frame and the words stay neutral. Every class is\n// written out in full so Tailwind finds it.\nconst tones: Record<NoteColor, string> = {\n  neutral: \"[--note:var(--foreground)] [--note-glow:6%] dark:[--note-glow:9%] **:data-[slot=note-icon]:text-muted-foreground\",\n  primary: \"[--note:var(--primary)] [--note-glow:16%] dark:[--note-glow:22%] **:data-[slot=note-icon]:text-primary-text\",\n  info: \"[--note:var(--info)] [--note-glow:16%] dark:[--note-glow:22%] **:data-[slot=note-icon]:text-info-text\",\n  success: \"[--note:var(--success)] [--note-glow:16%] dark:[--note-glow:22%] **:data-[slot=note-icon]:text-success-text\",\n  warning: \"[--note:var(--warning)] [--note-glow:18%] dark:[--note-glow:22%] **:data-[slot=note-icon]:text-warning-text\",\n  destructive: \"[--note:var(--destructive)] [--note-glow:14%] dark:[--note-glow:22%] **:data-[slot=note-icon]:text-destructive-text\",\n  highlight: \"[--note:var(--highlight)] [--note-glow:14%] dark:[--note-glow:22%] **:data-[slot=note-icon]:text-highlight-text\",\n}\n\nconst defaultIcons: Record<NoteColor, React.ReactNode> = {\n  neutral: <Lightbulb />,\n  primary: <Lightbulb />,\n  info: <Info />,\n  success: <CircleCheck />,\n  warning: <TriangleAlert />,\n  destructive: <CircleAlert />,\n  highlight: <Sparkles />,\n}\n\ntype NoteProps = Omit<React.ComponentProps<\"div\">, \"title\" | \"color\"> & {\n  /** The heading beside the icon, e.g. \"Good to know\". */\n  title?: React.ReactNode\n  /** Its tint: neutral by default; each color brings a fitting icon. */\n  color?: NoteColor\n  /** Replaces the color's icon; false shows none. */\n  icon?: React.ReactNode | false\n  classNames?: { icon?: string; title?: string; body?: string }\n}\n\n/**\n * An aside in the flow of a page, in one tag: a tip, a caveat, a \"good to know\" beside the steps. A card with a faint\n * grid and a breath of its color in the top corner; words and lists inside read as they would in the text around it.\n * Not a status message: for \"saved\" or \"failed\" use Alert, which is announced.\n */\nfunction Note({ title, color = \"neutral\", icon, className, classNames, children, ...props }: NoteProps) {\n  const shownIcon = icon === false ? null : (icon ?? defaultIcons[color])\n  const iconNode = shownIcon && (\n    <span data-slot=\"note-icon\" aria-hidden className={cn(\"flex shrink-0 [&_svg]:size-4\", classNames?.icon)}>\n      {shownIcon}\n    </span>\n  )\n  return (\n    <div\n      role=\"note\"\n      data-slot=\"note\"\n      data-color={color}\n      className={cn(\n        \"relative isolate overflow-hidden rounded-xl border border-foreground/10 bg-card p-5 text-sm text-card-foreground\",\n        // A wash (the website hero's): light pooling from three sides on the card's own color, the top corner's in the\n        // note's color, the other two a faint grey.\n        \"bg-[radial-gradient(ellipse_50%_60%_at_88%_-5%,color-mix(in_oklch,var(--note)_var(--note-glow),transparent),transparent),radial-gradient(ellipse_38%_48%_at_-2%_100%,color-mix(in_oklch,var(--foreground)_3%,transparent),transparent),radial-gradient(ellipse_42%_40%_at_58%_112%,color-mix(in_oklch,var(--foreground)_3%,transparent),transparent)]\",\n        // And its faint grid: hairlines every 48px, strongest in the middle and gone at the edges.\n        \"before:pointer-events-none before:absolute before:inset-0 before:-z-10 before:content-['']\",\n        \"before:bg-[linear-gradient(to_right,color-mix(in_oklch,var(--foreground)_5.5%,transparent)_1px,transparent_1px),linear-gradient(to_bottom,color-mix(in_oklch,var(--foreground)_5.5%,transparent)_1px,transparent_1px)] before:bg-size-[48px_48px] before:bg-center\",\n        \"before:[mask-image:radial-gradient(ellipse_60%_55%_at_50%_45%,#000_20%,transparent_75%)]\",\n        tones[color],\n        className\n      )}\n      {...props}\n    >\n      {title ? (\n        <div data-slot=\"note-title\" className={cn(\"flex items-center gap-2 font-medium\", classNames?.title)}>\n          {iconNode}\n          {title}\n        </div>\n      ) : null}\n      {children ? (\n        <div\n          data-slot=\"note-body\"\n          className={cn(\n            \"flex gap-2.5 leading-relaxed text-muted-foreground\",\n            title && \"mt-2.5\",\n            // Links, code and lists read the way they do in the text around it.\n            \"[&_a]:font-medium [&_a]:text-foreground [&_a]:underline [&_a]:decoration-foreground/30 [&_a]:underline-offset-4 hover:[&_a]:decoration-foreground\",\n            \"[&_code]:rounded [&_code]:bg-foreground/[0.06] [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.92em] [&_code]:text-foreground\",\n            \"[&_strong]:font-semibold [&_strong]:text-foreground [&_ul]:list-disc [&_ul]:space-y-1.5 [&_ul]:ps-5 [&_ol]:list-decimal [&_ol]:space-y-1.5 [&_ol]:ps-5\",\n            classNames?.body\n          )}\n        >\n          {/* No title: the icon leads the text instead. */}\n          {!title && iconNode && <span className=\"mt-0.5\">{iconNode}</span>}\n          <div className=\"min-w-0 flex-1 space-y-2\">{children}</div>\n        </div>\n      ) : null}\n    </div>\n  )\n}\n\nexport { Note, type NoteProps, type NoteColor }\n"}],"cssVars":{"theme":{"color-primary-text":"var(--primary-text, var(--primary))","color-destructive-foreground":"var(--destructive-foreground)","color-destructive-text":"var(--destructive-text)","color-info":"var(--info)","color-info-foreground":"var(--info-foreground)","color-info-text":"var(--info-text)","color-success":"var(--success)","color-success-foreground":"var(--success-foreground)","color-success-text":"var(--success-text)","color-warning":"var(--warning)","color-warning-foreground":"var(--warning-foreground)","color-warning-text":"var(--warning-text)","color-highlight":"var(--highlight)","color-highlight-foreground":"var(--highlight-foreground)","color-highlight-text":"var(--highlight-text)"},"light":{"destructive-foreground":"oklch(0.985 0 0)","destructive-text":"#bd2800","info":"oklch(0.5 0.134 242.749)","info-foreground":"oklch(0.985 0 0)","info-text":"oklch(0.443 0.11 240.79)","success":"oklch(0.508 0.118 165.612)","success-foreground":"oklch(0.985 0 0)","success-text":"oklch(0.432 0.095 166.913)","warning":"#f59200","warning-foreground":"oklch(0.3 0.07 60)","warning-text":"#964e00","highlight":"#b8008c","highlight-foreground":"oklch(0.985 0 0)","highlight-text":"#a3007b"},"dark":{"destructive-foreground":"oklch(0.2 0 0)","destructive-text":"#ff8a5c","info":"oklch(0.685 0.169 237.323)","info-foreground":"oklch(0.2 0 0)","info-text":"oklch(0.746 0.16 232.661)","success":"oklch(0.696 0.17 162.48)","success-foreground":"oklch(0.2 0.04 160)","success-text":"oklch(0.765 0.177 163.223)","warning":"#f59200","warning-foreground":"oklch(0.25 0.06 60)","warning-text":"#ffba42","highlight":"#ff2ecf","highlight-foreground":"oklch(0.2 0 0)","highlight-text":"#ff75df"}}}