{ "$schema": "https://ui.shadcn.com/schema/registry.json", "name": "quill", "homepage": "https://www.quilldesignsystem.com", "items": [ { "name": "quill", "type": "registry:base", "title": "Quill Design System", "description": "Warm neutral grounds, moss accents, Fraunces display type, and ink-toned type. A low-contrast editorial theme for digital products.", "author": "Craftwell (https://www.quilldesignsystem.com)", "files": [ { "path": "registry/themes/quill.css", "type": "registry:base", "target": "app/quill-theme.css" } ], "cssVars": { "theme": { "font-sans": "\"Raleway\", -apple-system, BlinkMacSystemFont, sans-serif", "font-display": "\"Fraunces\", Georgia, serif", "font-heading": "\"Fraunces\", Georgia, serif", "font-mono": "ui-monospace, \"SF Mono\", Menlo, monospace", "font-ui": "\"Inter\", -apple-system, BlinkMacSystemFont, sans-serif", "font-data": "\"JetBrains Mono\", \"SF Mono\", ui-monospace, monospace", "color-background": "var(--background)", "color-foreground": "var(--foreground)", "color-card": "var(--card)", "color-card-foreground": "var(--card-foreground)", "color-popover": "var(--popover)", "color-popover-foreground": "var(--popover-foreground)", "color-primary": "var(--primary)", "color-primary-foreground": "var(--primary-foreground)", "color-secondary": "var(--secondary)", "color-secondary-foreground": "var(--secondary-foreground)", "color-muted": "var(--muted)", "color-muted-foreground": "var(--muted-foreground)", "color-accent": "var(--accent)", "color-accent-foreground": "var(--accent-foreground)", "color-destructive": "var(--destructive)", "color-border": "var(--border)", "color-input": "var(--input)", "color-ring": "var(--ring)", "color-chart-1": "var(--chart-1)", "color-chart-2": "var(--chart-2)", "color-chart-3": "var(--chart-3)", "color-chart-4": "var(--chart-4)", "color-chart-5": "var(--chart-5)", "color-sidebar": "var(--sidebar)", "color-sidebar-foreground": "var(--sidebar-foreground)", "color-sidebar-primary": "var(--sidebar-primary)", "color-sidebar-primary-foreground": "var(--sidebar-primary-foreground)", "color-sidebar-accent": "var(--sidebar-accent)", "color-sidebar-accent-foreground": "var(--sidebar-accent-foreground)", "color-sidebar-border": "var(--sidebar-border)", "color-sidebar-ring": "var(--sidebar-ring)", "color-paper": "var(--paper)", "color-paper-warm": "var(--paper-warm)", "color-paper-deep": "var(--paper-deep)", "color-ink": "var(--ink)", "color-ink-soft": "var(--ink-soft)", "color-ink-muted": "var(--ink-muted)", "color-terracotta": "var(--terracotta)", "color-terracotta-deep": "var(--terracotta-deep)", "color-moss": "var(--moss)", "color-moss-deep": "var(--moss-deep)", "color-indigo-brand": "var(--indigo)", "color-indigo-brand-deep": "var(--indigo-deep)", "color-gold": "var(--gold)", "color-gold-deep": "var(--gold-deep)", "color-gold-text": "var(--gold-text)", "color-teal": "var(--teal)", "color-teal-deep": "var(--teal-deep)", "radius-xs": "0.125rem", "radius-sm": "0.25rem", "radius-md": "0.375rem", "radius-lg": "0.5rem", "radius-xl": "1rem", "radius-2xl": "1.5rem", "radius-3xl": "2rem", "radius-4xl": "2.5rem", "text-2xs": "0.7rem", "text-xs": "0.75rem", "text-sm": "0.85rem", "text-base": "0.95rem", "text-lg": "1.15rem", "text-xl": "1.5rem", "text-2xl": "2rem", "text-3xl": "3rem", "text-4xl": "4rem", "text-5xl": "5.5rem", "shadow-2xs": "var(--shadow-xs)", "shadow-xs": "var(--shadow-xs)", "shadow-sm": "var(--shadow-sm)", "shadow-md": "var(--shadow)", "shadow-lg": "var(--shadow-lg)", "shadow-xl": "var(--shadow-pop)", "shadow-2xl": "var(--shadow-pop)" }, "light": { "paper": "#F5EDDD", "paper-warm": "#EFE4CE", "paper-deep": "#E8DCC0", "ink": "#2A2622", "ink-soft": "#5C524A", "ink-muted": "#675F58", "terracotta": "#C4684B", "terracotta-deep": "#8A4530", "moss": "#7A8C5C", "moss-deep": "#4C5936", "indigo": "#5B6B8A", "indigo-deep": "#44516D", "gold": "#B89968", "gold-deep": "#9A7D4E", "gold-text": "#68522D", "teal": "#4E938B", "teal-deep": "#2F6B64", "chart-series-1": "#732510", "chart-series-2": "#345799", "chart-series-3": "#9D7614", "chart-series-4": "#79376C", "chart-series-5": "#4F6D1A", "chart-seq-1": "#C7D8B5", "chart-seq-2": "#A1B787", "chart-seq-3": "#7C975A", "chart-seq-4": "#567428", "chart-seq-5": "#375101", "chart-div-1": "#903F2B", "chart-div-2": "#BB8273", "chart-div-3": "#CFC9C5", "chart-div-4": "#7993C1", "chart-div-5": "#36589B", "line-faint": "rgba(42, 38, 34, 0.08)", "line-soft": "rgba(42, 38, 34, 0.12)", "line": "rgba(42, 38, 34, 0.15)", "line-strong": "rgba(42, 38, 34, 0.20)", "line-control": "#8A7F6E", "shadow-xs": "0 1px 2px -1px rgba(42, 38, 34, 0.12), 0 0 0 1px rgba(42, 38, 34, 0.05)", "shadow-sm": "0 2px 4px -1px rgba(42, 38, 34, 0.14), 0 1px 2px -1px rgba(42, 38, 34, 0.08)", "shadow": "0 4px 8px -2px rgba(42, 38, 34, 0.16), 0 2px 4px -2px rgba(42, 38, 34, 0.10)", "shadow-lg": "0 12px 20px -4px rgba(42, 38, 34, 0.18), 0 4px 8px -4px rgba(42, 38, 34, 0.10)", "shadow-pop": "0 20px 32px -6px rgba(42, 38, 34, 0.22), 0 8px 12px -6px rgba(42, 38, 34, 0.12)", "ease-out": "cubic-bezier(0.4, 0, 0.2, 1)", "ease-soft": "cubic-bezier(0.22, 1, 0.36, 1)", "dur-fast": "0.2s", "dur": "0.3s", "dur-slow": "0.5s", "lift": "translateY(-4px)", "lift-sm": "translateY(-2px)", "fraunces-display": "\"opsz\" 144, \"SOFT\" 50, \"WONK\" 0", "fraunces-accent": "\"opsz\" 144, \"SOFT\" 100, \"WONK\" 1", "fraunces-text": "\"opsz\" 24, \"SOFT\" 50", "fraunces-caption": "\"opsz\" 14, \"SOFT\" 100", "accent-pigment": "var(--moss)", "accent-pigment-text": "var(--moss-deep)", "surface-page": "var(--paper)", "surface-card": "var(--paper-warm)", "surface-well": "var(--paper-deep)", "text-strong": "var(--ink)", "text-body": "var(--ink-soft)", "text-muted-color": "var(--ink-muted)", "text-on-ink": "var(--paper)", "text-accent-color": "var(--accent-pigment-text)", "link": "var(--accent-pigment-text)", "border-card": "var(--line-soft)", "border-field": "var(--line-control)", "border-divider": "var(--line-faint)", "success": "var(--moss-deep)", "warning": "var(--gold-text)", "danger": "var(--terracotta-deep)", "info": "var(--indigo-deep)", "working": "var(--teal-deep)", "queued": "var(--ink-muted)", "radius": "0.5rem", "space-1": "0.25rem", "space-2": "0.5rem", "space-3": "0.75rem", "space-4": "1rem", "space-5": "1.25rem", "space-6": "1.5rem", "space-7": "1.75rem", "space-8": "2rem", "space-9": "2.25rem", "space-10": "2.5rem", "space-12": "3rem", "space-16": "4rem", "space-20": "5rem", "space-24": "6rem", "border-width-0": "0px", "border-width-1": "1px", "border-width-2": "2px", "border-width-3": "3px", "border-width-4": "4px", "background": "var(--paper)", "foreground": "var(--ink)", "card": "var(--paper-warm)", "card-foreground": "var(--ink)", "popover": "var(--paper-warm)", "popover-foreground": "var(--ink)", "primary": "var(--ink)", "primary-foreground": "var(--paper)", "secondary": "var(--paper-deep)", "secondary-foreground": "var(--ink)", "muted": "var(--paper-deep)", "muted-foreground": "var(--ink-muted)", "accent": "var(--paper-deep)", "accent-foreground": "var(--ink)", "destructive": "var(--terracotta-deep)", "border": "var(--line-soft)", "input": "var(--line-control)", "ring": "var(--accent-pigment-text)", "chart-1": "var(--chart-series-1)", "chart-2": "var(--chart-series-2)", "chart-3": "var(--chart-series-3)", "chart-4": "var(--chart-series-4)", "chart-5": "var(--chart-series-5)", "sidebar": "var(--paper-warm)", "sidebar-foreground": "var(--ink)", "sidebar-primary": "var(--ink)", "sidebar-primary-foreground": "var(--paper)", "sidebar-accent": "var(--paper-deep)", "sidebar-accent-foreground": "var(--ink)", "sidebar-border": "var(--line-faint)", "sidebar-ring": "var(--accent-pigment-text)", "dk-paper": "#20180E", "cl-paper": "#FFFFFF", "cd-paper": "#000000", "int-paper": "#0E100D", "dk-paper-warm": "#2A2014", "cl-paper-warm": "#F7F7F7", "cd-paper-warm": "#111111", "int-paper-warm": "#171A14", "dk-paper-deep": "#352A1A", "cl-paper-deep": "#EFEFEF", "cd-paper-deep": "#1C1C1C", "int-paper-deep": "#1D2117", "dk-ink": "#F1E7D3", "cl-ink": "#171717", "cd-ink": "#F5F5F5", "int-ink": "#E9E5D6", "dk-ink-soft": "#C8B9A0", "cl-ink-soft": "#454545", "cd-ink-soft": "#C9C9C9", "int-ink-soft": "#A9A791", "dk-ink-muted": "#A89880", "cl-ink-muted": "#5E5E5E", "cd-ink-muted": "#A0A0A0", "int-ink-muted": "#93927C", "dk-terracotta": "#DB8568", "cl-terracotta": "#DE501B", "cd-terracotta": "#F57345", "int-terracotta": "#C96F4C", "dk-terracotta-deep": "#E89A80", "cl-terracotta-deep": "#9D3209", "cd-terracotta-deep": "#FE8D67", "int-terracotta-deep": "#E08A66", "dk-moss": "#A2B57E", "cl-moss": "#758F43", "cd-moss": "#9DB962", "int-moss": "#7FAE5A", "dk-moss-deep": "#B6C896", "cl-moss-deep": "#516526", "cd-moss-deep": "#B1CC7E", "int-moss-deep": "#9BC47D", "dk-indigo": "#92A2C2", "cl-indigo": "#536A99", "cd-indigo": "#8AA2D2", "int-indigo": "#8B8FD8", "dk-indigo-deep": "#AAB8D4", "cl-indigo-deep": "#3D507A", "cd-indigo-deep": "#A3B8E2", "int-indigo-deep": "#A6AAE3", "dk-gold": "#D6BA86", "cl-gold": "#C49544", "cd-gold": "#E2B764", "int-gold": "#E0A340", "dk-gold-deep": "#E2CA9E", "cl-gold-deep": "#A57928", "cd-gold-deep": "#ECC883", "int-gold-deep": "#E8BC72", "dk-gold-text": "#E2CA9E", "cl-gold-text": "#7C5814", "cd-gold-text": "#ECC883", "int-gold-text": "#E8BC72", "dk-teal": "#4AA9A0", "cl-teal": "#178F84", "cd-teal": "#3DBDB1", "int-teal": "#4AA9A0", "dk-teal-deep": "#63BCB2", "cl-teal-deep": "#0E6B61", "cd-teal-deep": "#5FD3C7", "int-teal-deep": "#63BCB2", "dk-chart-series-1": "#CA725C", "cl-chart-series-1": "#7C1C01", "cd-chart-series-1": "#C75E45", "int-chart-series-1": "#C66F59", "dk-chart-series-2": "#5175BA", "cl-chart-series-2": "#194AAC", "cd-chart-series-2": "#3966B9", "int-chart-series-2": "#466AAE", "dk-chart-series-3": "#A17A1B", "cl-chart-series-3": "#AD8214", "cd-chart-series-3": "#BA8B01", "int-chart-series-3": "#BF973F", "dk-chart-series-4": "#CC83BB", "cl-chart-series-4": "#8D297E", "cd-chart-series-4": "#F086DA", "int-chart-series-4": "#EEA3DD", "dk-chart-series-5": "#9ABE6D", "cl-chart-series-5": "#577A16", "cd-chart-series-5": "#8CB258", "int-chart-series-5": "#A0C473", "dk-chart-seq-1": "#303D20", "cl-chart-seq-1": "#CCE0B6", "cd-chart-seq-1": "#2A3815", "int-chart-seq-1": "#303D20", "dk-chart-seq-2": "#475A2E", "cl-chart-seq-2": "#A0BC7E", "cd-chart-seq-2": "#41591D", "int-chart-seq-2": "#475A2E", "dk-chart-seq-3": "#5F793D", "cl-chart-seq-3": "#779A45", "cd-chart-seq-3": "#5A7B25", "int-chart-seq-3": "#5F793D", "dk-chart-seq-4": "#79994D", "cl-chart-seq-4": "#527602", "cd-chart-seq-4": "#749F2B", "int-chart-seq-4": "#79994D", "dk-chart-seq-5": "#97B86B", "cl-chart-seq-5": "#375101", "cd-chart-seq-5": "#95C352", "int-chart-seq-5": "#97B86B", "dk-chart-div-1": "#DC836D", "cl-chart-div-1": "#A22801", "cd-chart-div-1": "#FA7959", "int-chart-div-1": "#DC836D", "dk-chart-div-2": "#986153", "cl-chart-div-2": "#C77B68", "cd-chart-div-2": "#A75D4B", "int-chart-div-2": "#986153", "dk-chart-div-3": "#403C39", "cl-chart-div-3": "#D4D0CD", "cd-chart-div-3": "#3A3735", "int-chart-div-3": "#403C39", "dk-chart-div-4": "#59729E", "cl-chart-div-4": "#7092D0", "cd-chart-div-4": "#5474AF", "int-chart-div-4": "#59729E", "dk-chart-div-5": "#779EE6", "cl-chart-div-5": "#2253B5", "cd-chart-div-5": "#71A3FF", "int-chart-div-5": "#779EE6", "dk-line-faint": "rgba(241, 231, 211, 0.07)", "cl-line-faint": "rgba(0, 0, 0, 0.07)", "cd-line-faint": "rgba(255, 255, 255, 0.08)", "int-line-faint": "rgba(233, 229, 214, 0.07)", "dk-line-soft": "rgba(241, 231, 211, 0.11)", "cl-line-soft": "rgba(0, 0, 0, 0.11)", "cd-line-soft": "rgba(255, 255, 255, 0.12)", "int-line-soft": "rgba(233, 229, 214, 0.11)", "dk-line": "rgba(241, 231, 211, 0.15)", "cl-line": "rgba(0, 0, 0, 0.14)", "cd-line": "rgba(255, 255, 255, 0.16)", "int-line": "rgba(233, 229, 214, 0.15)", "dk-line-strong": "rgba(241, 231, 211, 0.22)", "cl-line-strong": "rgba(0, 0, 0, 0.20)", "cd-line-strong": "rgba(255, 255, 255, 0.24)", "int-line-strong": "rgba(233, 229, 214, 0.22)", "dk-line-control": "#746B5D", "cl-line-control": "#858585", "cd-line-control": "#757575", "int-line-control": "#767663", "dk-shadow-xs": "0 1px 2px -1px rgba(8, 5, 3, 0.40), 0 0 0 1px rgba(8, 5, 3, 0.18)", "cl-shadow-xs": "0 1px 2px -1px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.05)", "cd-shadow-xs": "0 1px 2px -1px rgba(0, 0, 0, 0.50), 0 0 0 1px rgba(255, 255, 255, 0.06)", "int-shadow-xs": "0 1px 2px -1px rgba(8, 5, 3, 0.40), 0 0 0 1px rgba(8, 5, 3, 0.18)", "dk-shadow-sm": "0 2px 4px -1px rgba(8, 5, 3, 0.48), 0 1px 2px -1px rgba(8, 5, 3, 0.30)", "cl-shadow-sm": "0 2px 4px -1px rgba(0, 0, 0, 0.14), 0 1px 2px -1px rgba(0, 0, 0, 0.08)", "cd-shadow-sm": "0 2px 4px -1px rgba(0, 0, 0, 0.55), 0 1px 2px -1px rgba(0, 0, 0, 0.35)", "int-shadow-sm": "0 2px 4px -1px rgba(8, 5, 3, 0.48), 0 1px 2px -1px rgba(8, 5, 3, 0.30)", "dk-shadow": "0 4px 8px -2px rgba(8, 5, 3, 0.54), 0 2px 4px -2px rgba(8, 5, 3, 0.36)", "cl-shadow": "0 4px 8px -2px rgba(0, 0, 0, 0.16), 0 2px 4px -2px rgba(0, 0, 0, 0.10)", "cd-shadow": "0 4px 8px -2px rgba(0, 0, 0, 0.60), 0 2px 4px -2px rgba(0, 0, 0, 0.40)", "int-shadow": "0 4px 8px -2px rgba(8, 5, 3, 0.54), 0 2px 4px -2px rgba(8, 5, 3, 0.36)", "dk-shadow-lg": "0 12px 20px -4px rgba(8, 5, 3, 0.62), 0 4px 8px -4px rgba(8, 5, 3, 0.40)", "cl-shadow-lg": "0 12px 20px -4px rgba(0, 0, 0, 0.18), 0 4px 8px -4px rgba(0, 0, 0, 0.10)", "cd-shadow-lg": "0 12px 20px -4px rgba(0, 0, 0, 0.68), 0 4px 8px -4px rgba(0, 0, 0, 0.44)", "int-shadow-lg": "0 12px 20px -4px rgba(8, 5, 3, 0.62), 0 4px 8px -4px rgba(8, 5, 3, 0.40)", "dk-shadow-pop": "0 20px 32px -6px rgba(8, 5, 3, 0.72), 0 8px 12px -6px rgba(8, 5, 3, 0.48)", "cl-shadow-pop": "0 20px 32px -6px rgba(0, 0, 0, 0.22), 0 8px 12px -6px rgba(0, 0, 0, 0.12)", "cd-shadow-pop": "0 20px 32px -6px rgba(0, 0, 0, 0.78), 0 8px 12px -6px rgba(0, 0, 0, 0.52)", "int-shadow-pop": "0 20px 32px -6px rgba(8, 5, 3, 0.72), 0 8px 12px -6px rgba(8, 5, 3, 0.48)" } }, "css": { "[data-theme=\"dark\"]": { "--paper": "var(--dk-paper)", "--paper-warm": "var(--dk-paper-warm)", "--paper-deep": "var(--dk-paper-deep)", "--ink": "var(--dk-ink)", "--ink-soft": "var(--dk-ink-soft)", "--ink-muted": "var(--dk-ink-muted)", "--terracotta": "var(--dk-terracotta)", "--terracotta-deep": "var(--dk-terracotta-deep)", "--moss": "var(--dk-moss)", "--moss-deep": "var(--dk-moss-deep)", "--indigo": "var(--dk-indigo)", "--indigo-deep": "var(--dk-indigo-deep)", "--gold": "var(--dk-gold)", "--gold-deep": "var(--dk-gold-deep)", "--gold-text": "var(--dk-gold-text)", "--teal": "var(--dk-teal)", "--teal-deep": "var(--dk-teal-deep)", "--chart-series-1": "var(--dk-chart-series-1)", "--chart-series-2": "var(--dk-chart-series-2)", "--chart-series-3": "var(--dk-chart-series-3)", "--chart-series-4": "var(--dk-chart-series-4)", "--chart-series-5": "var(--dk-chart-series-5)", "--chart-seq-1": "var(--dk-chart-seq-1)", "--chart-seq-2": "var(--dk-chart-seq-2)", "--chart-seq-3": "var(--dk-chart-seq-3)", "--chart-seq-4": "var(--dk-chart-seq-4)", "--chart-seq-5": "var(--dk-chart-seq-5)", "--chart-div-1": "var(--dk-chart-div-1)", "--chart-div-2": "var(--dk-chart-div-2)", "--chart-div-3": "var(--dk-chart-div-3)", "--chart-div-4": "var(--dk-chart-div-4)", "--chart-div-5": "var(--dk-chart-div-5)", "--line-faint": "var(--dk-line-faint)", "--line-soft": "var(--dk-line-soft)", "--line": "var(--dk-line)", "--line-strong": "var(--dk-line-strong)", "--line-control": "var(--dk-line-control)", "--shadow-xs": "var(--dk-shadow-xs)", "--shadow-sm": "var(--dk-shadow-sm)", "--shadow": "var(--dk-shadow)", "--shadow-lg": "var(--dk-shadow-lg)", "--shadow-pop": "var(--dk-shadow-pop)", "--accent-pigment": "var(--moss)", "--accent-pigment-text": "var(--moss-deep)", "--surface-page": "var(--paper)", "--surface-card": "var(--paper-warm)", "--surface-well": "var(--paper-deep)", "--text-strong": "var(--ink)", "--text-body": "var(--ink-soft)", "--text-muted-color": "var(--ink-muted)", "--text-on-ink": "var(--paper)", "--text-accent-color": "var(--accent-pigment-text)", "--link": "var(--accent-pigment-text)", "--border-card": "var(--line-soft)", "--border-field": "var(--line-control)", "--border-divider": "var(--line-faint)", "--success": "var(--moss-deep)", "--warning": "var(--gold-text)", "--danger": "var(--terracotta-deep)", "--info": "var(--indigo-deep)", "--working": "var(--teal-deep)", "--queued": "var(--ink-muted)", "--background": "var(--paper)", "--foreground": "var(--ink)", "--card": "var(--paper-warm)", "--card-foreground": "var(--ink)", "--popover": "var(--paper-warm)", "--popover-foreground": "var(--ink)", "--primary": "var(--ink)", "--primary-foreground": "var(--paper)", "--secondary": "var(--paper-deep)", "--secondary-foreground": "var(--ink)", "--muted": "var(--paper-deep)", "--muted-foreground": "var(--ink-muted)", "--accent": "var(--paper-deep)", "--accent-foreground": "var(--ink)", "--destructive": "var(--terracotta-deep)", "--border": "var(--line-soft)", "--input": "var(--line-control)", "--ring": "var(--accent-pigment-text)", "--chart-1": "var(--chart-series-1)", "--chart-2": "var(--chart-series-2)", "--chart-3": "var(--chart-series-3)", "--chart-4": "var(--chart-series-4)", "--chart-5": "var(--chart-series-5)", "--sidebar": "var(--paper-warm)", "--sidebar-foreground": "var(--ink)", "--sidebar-primary": "var(--ink)", "--sidebar-primary-foreground": "var(--paper)", "--sidebar-accent": "var(--paper-deep)", "--sidebar-accent-foreground": "var(--ink)", "--sidebar-border": "var(--line-faint)", "--sidebar-ring": "var(--accent-pigment-text)" }, "[data-theme=\"classic-light\"]": { "--paper": "var(--cl-paper)", "--paper-warm": "var(--cl-paper-warm)", "--paper-deep": "var(--cl-paper-deep)", "--ink": "var(--cl-ink)", "--ink-soft": "var(--cl-ink-soft)", "--ink-muted": "var(--cl-ink-muted)", "--terracotta": "var(--cl-terracotta)", "--terracotta-deep": "var(--cl-terracotta-deep)", "--moss": "var(--cl-moss)", "--moss-deep": "var(--cl-moss-deep)", "--indigo": "var(--cl-indigo)", "--indigo-deep": "var(--cl-indigo-deep)", "--gold": "var(--cl-gold)", "--gold-deep": "var(--cl-gold-deep)", "--gold-text": "var(--cl-gold-text)", "--teal": "var(--cl-teal)", "--teal-deep": "var(--cl-teal-deep)", "--chart-series-1": "var(--cl-chart-series-1)", "--chart-series-2": "var(--cl-chart-series-2)", "--chart-series-3": "var(--cl-chart-series-3)", "--chart-series-4": "var(--cl-chart-series-4)", "--chart-series-5": "var(--cl-chart-series-5)", "--chart-seq-1": "var(--cl-chart-seq-1)", "--chart-seq-2": "var(--cl-chart-seq-2)", "--chart-seq-3": "var(--cl-chart-seq-3)", "--chart-seq-4": "var(--cl-chart-seq-4)", "--chart-seq-5": "var(--cl-chart-seq-5)", "--chart-div-1": "var(--cl-chart-div-1)", "--chart-div-2": "var(--cl-chart-div-2)", "--chart-div-3": "var(--cl-chart-div-3)", "--chart-div-4": "var(--cl-chart-div-4)", "--chart-div-5": "var(--cl-chart-div-5)", "--line-faint": "var(--cl-line-faint)", "--line-soft": "var(--cl-line-soft)", "--line": "var(--cl-line)", "--line-strong": "var(--cl-line-strong)", "--line-control": "var(--cl-line-control)", "--shadow-xs": "var(--cl-shadow-xs)", "--shadow-sm": "var(--cl-shadow-sm)", "--shadow": "var(--cl-shadow)", "--shadow-lg": "var(--cl-shadow-lg)", "--shadow-pop": "var(--cl-shadow-pop)", "--accent-pigment": "var(--moss)", "--accent-pigment-text": "var(--moss-deep)", "--surface-page": "var(--paper)", "--surface-card": "var(--paper-warm)", "--surface-well": "var(--paper-deep)", "--text-strong": "var(--ink)", "--text-body": "var(--ink-soft)", "--text-muted-color": "var(--ink-muted)", "--text-on-ink": "var(--paper)", "--text-accent-color": "var(--accent-pigment-text)", "--link": "var(--accent-pigment-text)", "--border-card": "var(--line-soft)", "--border-field": "var(--line-control)", "--border-divider": "var(--line-faint)", "--success": "var(--moss-deep)", "--warning": "var(--gold-text)", "--danger": "var(--terracotta-deep)", "--info": "var(--indigo-deep)", "--working": "var(--teal-deep)", "--queued": "var(--ink-muted)", "--background": "var(--paper)", "--foreground": "var(--ink)", "--card": "var(--paper-warm)", "--card-foreground": "var(--ink)", "--popover": "var(--paper-warm)", "--popover-foreground": "var(--ink)", "--primary": "var(--ink)", "--primary-foreground": "var(--paper)", "--secondary": "var(--paper-deep)", "--secondary-foreground": "var(--ink)", "--muted": "var(--paper-deep)", "--muted-foreground": "var(--ink-muted)", "--accent": "var(--paper-deep)", "--accent-foreground": "var(--ink)", "--destructive": "var(--terracotta-deep)", "--border": "var(--line-soft)", "--input": "var(--line-control)", "--ring": "var(--accent-pigment-text)", "--chart-1": "var(--chart-series-1)", "--chart-2": "var(--chart-series-2)", "--chart-3": "var(--chart-series-3)", "--chart-4": "var(--chart-series-4)", "--chart-5": "var(--chart-series-5)", "--sidebar": "var(--paper-warm)", "--sidebar-foreground": "var(--ink)", "--sidebar-primary": "var(--ink)", "--sidebar-primary-foreground": "var(--paper)", "--sidebar-accent": "var(--paper-deep)", "--sidebar-accent-foreground": "var(--ink)", "--sidebar-border": "var(--line-faint)", "--sidebar-ring": "var(--accent-pigment-text)" }, "[data-theme=\"classic-dark\"]": { "--paper": "var(--cd-paper)", "--paper-warm": "var(--cd-paper-warm)", "--paper-deep": "var(--cd-paper-deep)", "--ink": "var(--cd-ink)", "--ink-soft": "var(--cd-ink-soft)", "--ink-muted": "var(--cd-ink-muted)", "--terracotta": "var(--cd-terracotta)", "--terracotta-deep": "var(--cd-terracotta-deep)", "--moss": "var(--cd-moss)", "--moss-deep": "var(--cd-moss-deep)", "--indigo": "var(--cd-indigo)", "--indigo-deep": "var(--cd-indigo-deep)", "--gold": "var(--cd-gold)", "--gold-deep": "var(--cd-gold-deep)", "--gold-text": "var(--cd-gold-text)", "--teal": "var(--cd-teal)", "--teal-deep": "var(--cd-teal-deep)", "--chart-series-1": "var(--cd-chart-series-1)", "--chart-series-2": "var(--cd-chart-series-2)", "--chart-series-3": "var(--cd-chart-series-3)", "--chart-series-4": "var(--cd-chart-series-4)", "--chart-series-5": "var(--cd-chart-series-5)", "--chart-seq-1": "var(--cd-chart-seq-1)", "--chart-seq-2": "var(--cd-chart-seq-2)", "--chart-seq-3": "var(--cd-chart-seq-3)", "--chart-seq-4": "var(--cd-chart-seq-4)", "--chart-seq-5": "var(--cd-chart-seq-5)", "--chart-div-1": "var(--cd-chart-div-1)", "--chart-div-2": "var(--cd-chart-div-2)", "--chart-div-3": "var(--cd-chart-div-3)", "--chart-div-4": "var(--cd-chart-div-4)", "--chart-div-5": "var(--cd-chart-div-5)", "--line-faint": "var(--cd-line-faint)", "--line-soft": "var(--cd-line-soft)", "--line": "var(--cd-line)", "--line-strong": "var(--cd-line-strong)", "--line-control": "var(--cd-line-control)", "--shadow-xs": "var(--cd-shadow-xs)", "--shadow-sm": "var(--cd-shadow-sm)", "--shadow": "var(--cd-shadow)", "--shadow-lg": "var(--cd-shadow-lg)", "--shadow-pop": "var(--cd-shadow-pop)", "--accent-pigment": "var(--moss)", "--accent-pigment-text": "var(--moss-deep)", "--surface-page": "var(--paper)", "--surface-card": "var(--paper-warm)", "--surface-well": "var(--paper-deep)", "--text-strong": "var(--ink)", "--text-body": "var(--ink-soft)", "--text-muted-color": "var(--ink-muted)", "--text-on-ink": "var(--paper)", "--text-accent-color": "var(--accent-pigment-text)", "--link": "var(--accent-pigment-text)", "--border-card": "var(--line-soft)", "--border-field": "var(--line-control)", "--border-divider": "var(--line-faint)", "--success": "var(--moss-deep)", "--warning": "var(--gold-text)", "--danger": "var(--terracotta-deep)", "--info": "var(--indigo-deep)", "--working": "var(--teal-deep)", "--queued": "var(--ink-muted)", "--background": "var(--paper)", "--foreground": "var(--ink)", "--card": "var(--paper-warm)", "--card-foreground": "var(--ink)", "--popover": "var(--paper-warm)", "--popover-foreground": "var(--ink)", "--primary": "var(--ink)", "--primary-foreground": "var(--paper)", "--secondary": "var(--paper-deep)", "--secondary-foreground": "var(--ink)", "--muted": "var(--paper-deep)", "--muted-foreground": "var(--ink-muted)", "--accent": "var(--paper-deep)", "--accent-foreground": "var(--ink)", "--destructive": "var(--terracotta-deep)", "--border": "var(--line-soft)", "--input": "var(--line-control)", "--ring": "var(--accent-pigment-text)", "--chart-1": "var(--chart-series-1)", "--chart-2": "var(--chart-series-2)", "--chart-3": "var(--chart-series-3)", "--chart-4": "var(--chart-series-4)", "--chart-5": "var(--chart-series-5)", "--sidebar": "var(--paper-warm)", "--sidebar-foreground": "var(--ink)", "--sidebar-primary": "var(--ink)", "--sidebar-primary-foreground": "var(--paper)", "--sidebar-accent": "var(--paper-deep)", "--sidebar-accent-foreground": "var(--ink)", "--sidebar-border": "var(--line-faint)", "--sidebar-ring": "var(--accent-pigment-text)" }, "[data-theme=\"intelligent\"]": { "--paper": "var(--int-paper)", "--paper-warm": "var(--int-paper-warm)", "--paper-deep": "var(--int-paper-deep)", "--ink": "var(--int-ink)", "--ink-soft": "var(--int-ink-soft)", "--ink-muted": "var(--int-ink-muted)", "--terracotta": "var(--int-terracotta)", "--terracotta-deep": "var(--int-terracotta-deep)", "--moss": "var(--int-moss)", "--moss-deep": "var(--int-moss-deep)", "--indigo": "var(--int-indigo)", "--indigo-deep": "var(--int-indigo-deep)", "--gold": "var(--int-gold)", "--gold-deep": "var(--int-gold-deep)", "--gold-text": "var(--int-gold-text)", "--teal": "var(--int-teal)", "--teal-deep": "var(--int-teal-deep)", "--chart-series-1": "var(--int-chart-series-1)", "--chart-series-2": "var(--int-chart-series-2)", "--chart-series-3": "var(--int-chart-series-3)", "--chart-series-4": "var(--int-chart-series-4)", "--chart-series-5": "var(--int-chart-series-5)", "--chart-seq-1": "var(--int-chart-seq-1)", "--chart-seq-2": "var(--int-chart-seq-2)", "--chart-seq-3": "var(--int-chart-seq-3)", "--chart-seq-4": "var(--int-chart-seq-4)", "--chart-seq-5": "var(--int-chart-seq-5)", "--chart-div-1": "var(--int-chart-div-1)", "--chart-div-2": "var(--int-chart-div-2)", "--chart-div-3": "var(--int-chart-div-3)", "--chart-div-4": "var(--int-chart-div-4)", "--chart-div-5": "var(--int-chart-div-5)", "--line-faint": "var(--int-line-faint)", "--line-soft": "var(--int-line-soft)", "--line": "var(--int-line)", "--line-strong": "var(--int-line-strong)", "--line-control": "var(--int-line-control)", "--shadow-xs": "var(--int-shadow-xs)", "--shadow-sm": "var(--int-shadow-sm)", "--shadow": "var(--int-shadow)", "--shadow-lg": "var(--int-shadow-lg)", "--shadow-pop": "var(--int-shadow-pop)", "--accent-pigment": "var(--moss)", "--accent-pigment-text": "var(--moss-deep)", "--surface-page": "var(--paper)", "--surface-card": "var(--paper-warm)", "--surface-well": "var(--paper-deep)", "--text-strong": "var(--ink)", "--text-body": "var(--ink-soft)", "--text-muted-color": "var(--ink-muted)", "--text-on-ink": "var(--paper)", "--text-accent-color": "var(--accent-pigment-text)", "--link": "var(--accent-pigment-text)", "--border-card": "var(--line-soft)", "--border-field": "var(--line-control)", "--border-divider": "var(--line-faint)", "--success": "var(--moss-deep)", "--warning": "var(--gold-text)", "--danger": "var(--terracotta-deep)", "--info": "var(--indigo-deep)", "--working": "var(--teal-deep)", "--queued": "var(--ink-muted)", "--background": "var(--paper)", "--foreground": "var(--ink)", "--card": "var(--paper-warm)", "--card-foreground": "var(--ink)", "--popover": "var(--paper-warm)", "--popover-foreground": "var(--ink)", "--primary": "var(--ink)", "--primary-foreground": "var(--paper)", "--secondary": "var(--paper-deep)", "--secondary-foreground": "var(--ink)", "--muted": "var(--paper-deep)", "--muted-foreground": "var(--ink-muted)", "--accent": "var(--paper-deep)", "--accent-foreground": "var(--ink)", "--destructive": "var(--terracotta-deep)", "--border": "var(--line-soft)", "--input": "var(--line-control)", "--ring": "var(--accent-pigment-text)", "--chart-1": "var(--chart-series-1)", "--chart-2": "var(--chart-series-2)", "--chart-3": "var(--chart-series-3)", "--chart-4": "var(--chart-series-4)", "--chart-5": "var(--chart-series-5)", "--sidebar": "var(--paper-warm)", "--sidebar-foreground": "var(--ink)", "--sidebar-primary": "var(--ink)", "--sidebar-primary-foreground": "var(--paper)", "--sidebar-accent": "var(--paper-deep)", "--sidebar-accent-foreground": "var(--ink)", "--sidebar-border": "var(--line-faint)", "--sidebar-ring": "var(--accent-pigment-text)" }, "[data-accent=\"terracotta\"]": { "--accent-pigment": "var(--terracotta)", "--accent-pigment-text": "var(--terracotta-deep)" }, "[data-accent=\"moss\"]": { "--accent-pigment": "var(--moss)", "--accent-pigment-text": "var(--moss-deep)" }, "[data-accent=\"indigo\"]": { "--accent-pigment": "var(--indigo)", "--accent-pigment-text": "var(--indigo-deep)" }, "[data-accent=\"gold\"]": { "--accent-pigment": "var(--gold-deep)", "--accent-pigment-text": "var(--gold-text)" } }, "docs": "Themes — set data-theme on : unset (or data-theme=\"light\") → Dawn (default) · data-theme=\"dark\" → Dusk · data-theme=\"classic-light\" → Classic Light · data-theme=\"classic-dark\" → Classic Dark · data-theme=\"intelligent\" → Intelligent. 5 themes in total. Accents — set data-accent on , independently of the theme: terracotta · moss (default) · indigo · gold. The accent drives links, eyebrows, focus rings and accent italics. The two attributes are separate axes; a dark ground and an accent choice do not constrain each other. Runtime contract — the theme-selector block owns both attributes. After hydration it reads localStorage (\"quill-theme\" and \"quill-accent\") and stamps . Prerendered markup is always Dawn + moss, so server output and first paint agree. Charts — use the chart tokens (--chart-series-1..5, the sequential and diverging ramps), never raw pigments. Assign series colours in that fixed order and never reorder or cycle survivors when a filter drops one: the order is what keeps the palette distinguishable under all three dichromacies. Fonts — Raleway for body, Fraunces for display. The theme file already @imports both from Google Fonts, so no next/font setup is needed; loading them again under a different family name is what makes the theme's literal font-family names fail to match. Updating — re-run with --overwrite, not --yes. On a file you have changed, --yes does not overwrite: it prompts in a terminal and silently skips when non-interactive. Full machine-readable reference for agents: https://www.quilldesignsystem.com/llms.txt. Per-component usage guides at /usage/.md." }, { "name": "icon", "type": "registry:ui", "title": "Icon (Material Symbols)", "description": "The Quill icon component — Material Symbols Outlined at weight 400, shipped as a self-contained core set of 91 names covering every icon the Quill blocks use.", "files": [ { "path": "registry/lib/icon.tsx", "type": "registry:ui", "target": "components/ui/icon.tsx" }, { "path": "src/components/ui/icons.core.mjs", "type": "registry:ui", "target": "components/ui/icons.core.mjs" }, { "path": "registry/lib/icons.core.d.mts", "type": "registry:ui", "target": "components/ui/icons.core.d.mts" } ], "docs": "The Quill icon component — Material Symbols Outlined at weight 400, shipped as a self-contained core set of 91 names covering every icon the Quill blocks use. Do: Pick a name from the core set the `icon` item ships (91 names): account_balance, add, add_circle, archive, arrow_back, arrow_downward, arrow_forward, arrow_upward, attach_file, attach_money, calendar_today, cancel, chat_bubble, check, check_box, check_box_outline_blank, check_circle, chevron_left, chevron_right, close, cloud_upload, content_copy, credit_card, dangerous, dark_mode, dashboard, delete, description, dock_to_left, download, draft, edit, error, favorite, filter_list, folder_open, format_align_center, format_align_left, format_align_right, format_bold, format_italic, format_underlined, forward, group, help, home, info, ink_pen, keyboard_arrow_down, keyboard_arrow_left, keyboard_arrow_right, keyboard_arrow_up, keyboard_command_key, language, light_mode, link, lock, login, logout, mail, menu, menu_book, more_horiz, more_vert, notifications, open_in_new, palette, person, person_add, photo_library, progress_activity, radio_button_checked, radio_button_unchecked, refresh, remove, reply, save, schedule, search, send, settings, share, sort, space_dashboard, star, star_shine, upload, visibility, visibility_off, wallet, warning. Don't: Use any other Material Symbol name in an app. The consumer `` bundles only the core set, so an unknown name renders as an empty, size-reserved box (plus a console warning in development); the design-system site lazy-loads the whole library, so a name can look fine on quilldesignsystem.com and be blank in your app. Do: Size through the `size` prop — a pixel number, or leave the `1em` default so the glyph follows the surrounding text. Don't: Scale an icon with a `transform` or a width/height class — the reserved box stops matching the glyph and the layout shifts. Do: Leave an icon decorative (the default renders `aria-hidden`) when the text next to it already carries the meaning. Don't: Add an `aria-label` to an icon that sits beside its own label — screen readers then announce the meaning twice. Use button when the glyph is the whole control — use Button with an icon size (`icon`, `icon-sm`) and an `aria-label`; Icon on its own is never interactive. Use spinner when the glyph means \"loading\" — Spinner carries the motion and the status semantics an icon does not." }, { "name": "tone-badge", "type": "registry:ui", "title": "Tone badge", "description": "Quill's uppercase tag pill for status, tiers, and labels — wraps Badge with the pigment vocabulary (moss/gold/terracotta/indigo/neutral/muted) baked in so tone never drifts per call site.", "registryDependencies": [ "badge" ], "files": [ { "path": "registry/lib/tone-badge.tsx", "target": "components/ui/tone-badge.tsx", "type": "registry:ui" } ], "docs": "Quill's uppercase tag pill for status, tiers, and labels — wraps Badge with the pigment vocabulary (moss/gold/terracotta/indigo/neutral/muted) baked in so tone never drifts per call site. Do: Leave `solid` false (the tinted default) for regular status/tier labels — it is the visually quieter option and still hits AA contrast per tone. Don't: Set `solid` on every ToneBadge in a view — solid is reserved for the one strong cue (a \"current\" marker, a live state) and loses its signal once everything is solid. Do: Render every uppercase tag pill through ToneBadge, even one-off labels. Don't: Hand-roll a `rounded-full … uppercase` span with ad hoc tone colors — it drifts from the AA-checked tint/solid pairs and the two-size scale. Do: Use ToneBadge's own size scale — `md` (20px) or `sm` (16px, the count-pill scale). Don't: Shrink a pill by hand-tightening its tracking or padding instead of passing `size=\"sm\"` — type stays `--text-2xs` at 0.1em tracking in both sizes. Use badge when the label is a generic chip outside Quill's tag-pill vocabulary — use Badge directly instead of forcing it through a tone." }, { "name": "example-app-page", "type": "registry:component", "title": "Example: app page", "description": "An example showing how to compose an app page: the sidebar-nav shell wrapping a page-header, then stat-cards, then a data-table — the page leads with what it is about, and the numbers sit inside it.", "files": [ { "path": "registry/examples/example-app-page.tsx", "type": "registry:component", "target": "components/examples/example-app-page.tsx" } ], "registryDependencies": [ "https://www.quilldesignsystem.com/r/sidebar-nav.json", "https://www.quilldesignsystem.com/r/page-header.json", "https://www.quilldesignsystem.com/r/stat-cards.json", "https://www.quilldesignsystem.com/r/data-table.json" ], "docs": "Composition, top to bottom: sidebar-nav → page-header → stat-cards → data-table. Install it, then replace the blocks' sample content with your own; keep the order and the spacing.\n\nA **4px base step** (`--space-1` = 0.25rem). Editorial rhythm — sections breathe.\n\n`--space-1` 4px · `--space-2` 8px · `--space-3` 12px · `--space-4` 16px · `--space-5` 20px · `--space-6` 24px · `--space-7` 28px · `--space-8` 32px · `--space-9` 36px · `--space-10` 40px · `--space-12` 48px · `--space-16` 64px · `--space-20` 80px · `--space-24` 96px\n\nComponents sit on `--space-4` / `--space-6`; sections breathe with `--space-24`.\n\n### Layout\nNo layout tokens ship; use the values the site uses. Marketing max-width **1400px** (`max-w-[1400px]`), reading column **800px**, side padding **48px** on desktop (`px-12`) and **24px** on mobile (`px-6`), vertical section rhythm **96px** (`py-24`; `py-14` on mobile).\n\n### Composition\n- Recurring section header: eyebrow → headline (one accent word) → right-aligned italic caption.\n- One idea per section: a heading plus one composition (a grid of cards, a table, a form), never a stack of unrelated widgets.\n- No hero-metric row above an identical card grid — that is the generic dashboard Quill exists to avoid. Lead with the thing the page is about; let numbers sit inside it." }, { "name": "example-marketing-page", "type": "registry:component", "title": "Example: marketing page", "description": "An example showing how to compose a marketing page: navbar, hero, feature-section, pricing, testimonial and footer — one idea per section, breathing at the 96px rhythm.", "files": [ { "path": "registry/examples/example-marketing-page.tsx", "type": "registry:component", "target": "components/examples/example-marketing-page.tsx" } ], "registryDependencies": [ "https://www.quilldesignsystem.com/r/navbar.json", "https://www.quilldesignsystem.com/r/hero.json", "https://www.quilldesignsystem.com/r/feature-section.json", "https://www.quilldesignsystem.com/r/pricing.json", "https://www.quilldesignsystem.com/r/testimonial.json", "https://www.quilldesignsystem.com/r/footer.json" ], "docs": "Composition, top to bottom: navbar → hero → feature-section → pricing → testimonial → footer. Install it, then replace the blocks' sample content with your own; keep the order and the spacing.\n\nA **4px base step** (`--space-1` = 0.25rem). Editorial rhythm — sections breathe.\n\n`--space-1` 4px · `--space-2` 8px · `--space-3` 12px · `--space-4` 16px · `--space-5` 20px · `--space-6` 24px · `--space-7` 28px · `--space-8` 32px · `--space-9` 36px · `--space-10` 40px · `--space-12` 48px · `--space-16` 64px · `--space-20` 80px · `--space-24` 96px\n\nComponents sit on `--space-4` / `--space-6`; sections breathe with `--space-24`.\n\n### Layout\nNo layout tokens ship; use the values the site uses. Marketing max-width **1400px** (`max-w-[1400px]`), reading column **800px**, side padding **48px** on desktop (`px-12`) and **24px** on mobile (`px-6`), vertical section rhythm **96px** (`py-24`; `py-14` on mobile).\n\n### Composition\n- Recurring section header: eyebrow → headline (one accent word) → right-aligned italic caption.\n- One idea per section: a heading plus one composition (a grid of cards, a table, a form), never a stack of unrelated widgets.\n- No hero-metric row above an identical card grid — that is the generic dashboard Quill exists to avoid. Lead with the thing the page is about; let numbers sit inside it." }, { "name": "example-auth-page", "type": "registry:component", "title": "Example: auth page", "description": "An example showing how to compose an auth page: login-split-panel alone at full viewport — one task, nothing competing with it.", "files": [ { "path": "registry/examples/example-auth-page.tsx", "type": "registry:component", "target": "components/examples/example-auth-page.tsx" } ], "registryDependencies": [ "https://www.quilldesignsystem.com/r/login-split-panel.json" ], "docs": "Composition, top to bottom: login-split-panel. Install it, then replace the blocks' sample content with your own; keep the order and the spacing.\n\nA **4px base step** (`--space-1` = 0.25rem). Editorial rhythm — sections breathe.\n\n`--space-1` 4px · `--space-2` 8px · `--space-3` 12px · `--space-4` 16px · `--space-5` 20px · `--space-6` 24px · `--space-7` 28px · `--space-8` 32px · `--space-9` 36px · `--space-10` 40px · `--space-12` 48px · `--space-16` 64px · `--space-20` 80px · `--space-24` 96px\n\nComponents sit on `--space-4` / `--space-6`; sections breathe with `--space-24`.\n\n### Layout\nNo layout tokens ship; use the values the site uses. Marketing max-width **1400px** (`max-w-[1400px]`), reading column **800px**, side padding **48px** on desktop (`px-12`) and **24px** on mobile (`px-6`), vertical section rhythm **96px** (`py-24`; `py-14` on mobile).\n\n### Composition\n- Recurring section header: eyebrow → headline (one accent word) → right-aligned italic caption.\n- One idea per section: a heading plus one composition (a grid of cards, a table, a form), never a stack of unrelated widgets.\n- No hero-metric row above an identical card grid — that is the generic dashboard Quill exists to avoid. Lead with the thing the page is about; let numbers sit inside it." }, { "name": "agent-rules", "type": "registry:file", "title": "Quill agent rules", "description": "Claude Code project rules so AI agents build on-brand with Quill — the theming contract, foundations, principles, icon names and the block index, generated from the design system.", "docs": "Installed to .claude/rules/quill.md at the project root, where Claude Code loads it every session. Re-run `npx shadcn@latest add @quill/agent-rules --overwrite` after each Quill release to update it; the library-sync bot does this for apps that carry the file.", "files": [ { "path": "registry/agent-rules/quill.md", "type": "registry:file", "target": "~/.claude/rules/quill.md" } ] }, { "name": "activity-feed", "type": "registry:block", "title": "Activity feed", "description": "A card timeline of recent events — avatar, action text, and a relative timestamp per entry.", "meta": { "intent": [ "data-display" ], "use_when": "You need to show a chronological history of what happened — recent events with who, what, and when." }, "registryDependencies": [ "card", "avatar", "badge", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/activity-feed.tsx", "type": "registry:component", "target": "components/quill/activity-feed.tsx" } ], "docs": "A card timeline of recent events — avatar, action text, and a relative timestamp per entry. Do: Use relative timestamps (\"2 hours ago\") for recent activity — they read faster than absolute dates. Don't: Force users to parse a full timestamp for something that happened minutes ago. Use notifications when the events need an unread/read state and a mark-all-read action, not just a read-only history. Use data-table when the events are really records you need to filter, sort, or act on, not just skim chronologically.", "categories": [ "data-display" ] }, { "name": "alerts", "type": "registry:block", "title": "Alert stack", "description": "A vertical stack of informational, success, and destructive alerts with icons.", "meta": { "intent": [ "feedback" ], "use_when": "You need to surface inline status messages of varying severity (info, success, destructive) within a page." }, "registryDependencies": [ "alert", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/alerts.tsx", "type": "registry:component", "target": "components/quill/alerts.tsx" } ], "docs": "A vertical stack of informational, success, and destructive alerts with icons. Do: Match severity to consequence: destructive for blocking errors, default for neutral information. Don't: Use destructive styling for emphasis on non-error messages. Use sonner when the message is transient feedback about an action just taken — use a toast, not an inline alert. Use announcement-banner when the message is site-wide and dismissible rather than local to a page section. Use empty-state when the \"message\" is really an empty view that needs an explanation and a call to action.", "categories": [ "feedback" ] }, { "name": "analytics-charts", "type": "registry:block", "title": "Analytics charts", "description": "A dashboard pair — an area chart of audience growth beside a bar chart of weekly sales, each on its own card.", "meta": { "intent": [ "data-viz", "data-display" ], "use_when": "You need a dashboard view of trends over time — an area chart plus a bar chart on card surfaces." }, "registryDependencies": [ "card", "chart", "badge" ], "files": [ { "path": "registry/blocks/analytics-charts.tsx", "type": "registry:component", "target": "components/quill/analytics-charts.tsx" } ], "dependencies": [ "recharts" ], "docs": "A dashboard pair — an area chart of audience growth beside a bar chart of weekly sales, each on its own card. Do: Color each series from the chart token set (--chart-1…--chart-5), assigned in a fixed order. Don't: Hardcode a raw accent pigment (--terracotta, --moss, --indigo…) for a series — some pairs are documented as failing colorblind-distinguishability. Do: Pair a multi-series chart with a ChartLegend, as the Audience chart does — color is tied to a series name in text, never left for the reader to infer. Don't: Ship a multi-series chart with no legend — color becomes the only signal distinguishing readers from subscribers. Use stat-cards when you need at-a-glance numbers, not a trend shape — a single KPI reads faster as a number than a chart. Use data-table when the audience needs to inspect exact values per row, not the shape of change over time.", "categories": [ "data-viz", "data-display" ] }, { "name": "announcement-banner", "type": "registry:block", "title": "Announcement banners", "description": "Two dismissible announcement banners — an inline bordered page banner and a full-bleed primary-color variant.", "meta": { "intent": [ "feedback", "marketing" ], "use_when": "You need to announce something site-wide with a dismissible banner, either inline or full-bleed." }, "registryDependencies": [ "badge", "button", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/announcement-banner.tsx", "type": "registry:component", "target": "components/quill/announcement-banner.tsx" } ], "docs": "Two dismissible announcement banners — an inline bordered page banner and a full-bleed primary-color variant. Do: Give every banner variant its own dismiss button with a specific aria-label (e.g. \"Dismiss workshop banner\"), not a generic one. Don't: Ship a banner with no way to dismiss it, or multiple banners sharing one ambiguous \"Dismiss\" label. Use alerts when the message is local to a page section and tied to system status, not a site-wide announcement. Use cookie-consent when the banner requires an explicit choice (accept/reject), not just a dismiss.", "categories": [ "feedback", "marketing" ] }, { "name": "badge-on-card", "type": "registry:block", "title": "Badges on card", "description": "Default, secondary, and destructive badges shown together on a card surface.", "meta": { "intent": [ "data-display" ], "use_when": "You need to show status or category badges attached to a content card." }, "registryDependencies": [ "card", "badge" ], "files": [ { "path": "registry/blocks/badge-on-card.tsx", "type": "registry:component", "target": "components/quill/badge-on-card.tsx" } ], "docs": "Default, secondary, and destructive badges shown together on a card surface. Do: Reserve the destructive variant for a status that actually needs attention (blocked, failed, overdue). Don't: Use destructive styling for emphasis on a badge that isn't actually a warning. Use tone-badge when you need a badge whose color is driven by a semantic tone token rather than the three fixed variants here. Use data-table when the badges are actually per-row status in a list of records, not a single card's labels.", "categories": [ "data-display" ] }, { "name": "calendar-page", "type": "registry:block", "title": "Calendar page", "description": "A single-date calendar paired with the selected day's session list, in one studio-schedule card.", "meta": { "intent": [ "scheduling" ], "use_when": "You need to pick a single date and show what's scheduled that day." }, "registryDependencies": [ "card", "calendar", "badge", "separator" ], "files": [ { "path": "registry/blocks/calendar-page.tsx", "type": "registry:component", "target": "components/quill/calendar-page.tsx" } ], "docs": "A single-date calendar paired with the selected day's session list, in one studio-schedule card. Do: Keep the session list in sync with whatever date is selected in the calendar — the two panes are one control, not two independent widgets. Don't: Let the calendar selection and the listed sessions fall out of sync (e.g. a static list that ignores the picked date). Use calendar-range when the user is booking a span of days, not viewing what's scheduled on one. Use activity-feed when you want a chronological history of past events, not a schedule of upcoming sessions tied to a picked date.", "categories": [ "scheduling" ] }, { "name": "calendar-range", "type": "registry:block", "title": "Calendar range picker", "description": "A stateful two-month range calendar for booking a span of days, with clear and reserve actions.", "meta": { "intent": [ "scheduling", "form" ], "use_when": "You need to book a span of days with a two-month range picker and confirm/clear actions." }, "registryDependencies": [ "card", "calendar", "button", "badge" ], "files": [ { "path": "registry/blocks/calendar-range.tsx", "type": "registry:component", "target": "components/quill/calendar-range.tsx" } ], "dependencies": [ "react-day-picker" ], "docs": "A stateful two-month range calendar for booking a span of days, with clear and reserve actions. Do: Keep the Clear action available whenever a range is selected, separate from Reserve. Don't: Force a user to re-click through the whole range to correct a mis-click — that's what Clear is for. Do: Disable Reserve until both a start and end date are selected. Don't: Let a half-made range (just a start date) submit as if it were a valid booking. Use calendar-page when the user is picking a single day to view, not a multi-day span to reserve. Use checkout when the range is just one field within a larger purchase flow, not the whole card.", "categories": [ "scheduling", "form" ] }, { "name": "chat", "type": "registry:block", "title": "Chat panel", "description": "A one-on-one messaging panel — contact header, message bubbles, and a composer input.", "meta": { "intent": [ "messaging" ], "use_when": "You need a one-on-one messaging panel with a contact header, bubbles, and a composer." }, "registryDependencies": [ "input", "button", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/chat.tsx", "type": "registry:component", "target": "components/quill/chat.tsx" } ], "docs": "A one-on-one messaging panel — contact header, message bubbles, and a composer input. Do: Align the current user's messages to one side (right) and the other party's to the other (left) — position is the primary cue for who said what. Don't: Rely on color alone to distinguish sender — pair it with consistent alignment. Use list-detail when you need a list of conversations alongside the open thread, not just the single open thread. Use notifications when the messages are one-way system alerts, not a two-way conversation with someone.", "categories": [ "messaging" ] }, { "name": "checkout", "type": "registry:block", "title": "Checkout", "description": "A two-column checkout — payment method picker and card form beside an order summary sidebar.", "meta": { "intent": [ "commerce", "form" ], "use_when": "You need to collect payment and card details alongside an order summary." }, "registryDependencies": [ "card", "input", "label", "button", "radio-group", "separator", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/checkout.tsx", "type": "registry:component", "target": "components/quill/checkout.tsx" } ], "docs": "A two-column checkout — payment method picker and card form beside an order summary sidebar. Do: Use a RadioGroup for payment-method choice (Card/Bank/Wallet) — it's a single mutually exclusive choice, styled as cards. Don't: Use checkboxes or a dropdown for a single mutually exclusive payment method. Do: Pair the payment submit button with a lock icon, so the action itself visibly reads as a secure transaction. Don't: Ship the payment submit button with no lock icon — nothing on the button signals that submitting card data is secure. Use order-summary when you only need the cart-review card, not the full payment form beside it. Use wizard when payment is one step in a longer multi-step flow, not a single standalone page.", "categories": [ "commerce", "form" ] }, { "name": "command-palette", "type": "registry:block", "title": "Command palette", "description": "A searchable ⌘K command palette with grouped actions, recent items, and keyboard shortcuts.", "meta": { "intent": [ "navigation" ], "use_when": "You need a searchable ⌘K launcher for actions and quick navigation." }, "registryDependencies": [ "command", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/command-palette.tsx", "type": "registry:component", "target": "components/quill/command-palette.tsx" } ], "docs": "A searchable ⌘K command palette with grouped actions, recent items, and keyboard shortcuts. Do: Group items into labeled sections (Actions, Recent) so a long list stays scannable. Don't: Dump every possible command into one flat, unlabeled list. Use search-results when search results should live inline on the page, not in a global keyboard-triggered overlay. Use dropdown-menu when the list of options is small and tied to a specific trigger element, not a global searchable launcher.", "categories": [ "navigation" ] }, { "name": "contact-form", "type": "registry:block", "title": "Contact form", "description": "A get-in-touch card — name, email, a topic select, and a message field.", "meta": { "intent": [ "form" ], "use_when": "You need a get-in-touch form with name, email, topic, and message fields." }, "registryDependencies": [ "card", "input", "label", "button", "textarea", "select" ], "files": [ { "path": "registry/blocks/contact-form.tsx", "type": "registry:component", "target": "components/quill/contact-form.tsx" } ], "docs": "A get-in-touch card — name, email, a topic select, and a message field. Do: State a response-time expectation in the description (\"We usually reply within one working day.\") so the form doesn't feel like it disappears into a void. Don't: Leave users with no sense of whether or when they'll hear back. Use newsletter when you only need a single email field to grow a list, not a full multi-field inquiry form. Use settings when the fields are updating an existing profile, not sending a one-off message.", "categories": [ "form" ] }, { "name": "cookie-consent", "type": "registry:block", "title": "Cookie consent", "description": "A cookie consent banner offering accept, reject, and preferences actions.", "meta": { "intent": [ "feedback" ], "use_when": "You need a compliance banner offering accept, reject, and preferences choices." }, "registryDependencies": [ "button", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/cookie-consent.tsx", "type": "registry:component", "target": "components/quill/cookie-consent.tsx" } ], "docs": "A cookie consent banner offering accept, reject, and preferences actions. Do: \"Reject non-essential\" gets the same one-click ease as \"Accept all\" — both are top-level buttons, not one button plus a buried settings link. Don't: Make rejecting cookies harder to find or reach than accepting them — that's a dark pattern, not a real choice. Use announcement-banner when the message is informational only and doesn't require an explicit accept/reject decision. Use alerts when the message is a local, in-page status, not a site-wide compliance notice.", "categories": [ "feedback" ] }, { "name": "dashboard", "type": "registry:block", "title": "Dashboard shell", "description": "An app shell with sidebar navigation, a search header, and KPI stat cards.", "meta": { "intent": [ "app-shell", "data-display" ], "use_when": "You need a full application home — sidebar, search header, and KPI cards." }, "registryDependencies": [ "button", "input", "badge", "card", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/dashboard.tsx", "type": "registry:component", "target": "components/quill/dashboard.tsx" } ], "docs": "An app shell with sidebar navigation, a search header, and KPI stat cards. Do: Give the current nav item a distinct active state (background + text color), not just a subtle underline. Don't: Leave every nav item looking identical — users lose track of where they are. Use sidebar-nav when you need the collapsible icon-sidebar variant with grouped menus, not this fixed-width text sidebar. Use stat-cards when you only need the KPI row, not the full shell around it.", "categories": [ "app-shell", "data-display" ] }, { "name": "data-table", "type": "registry:block", "title": "Data table", "description": "A filterable members table with a toolbar, ToneBadge status pills, and a per-row actions menu.", "meta": { "intent": [ "data-display" ], "use_when": "You need a filterable, actionable table of records with tone-mapped status pills and row actions." }, "registryDependencies": [ "table", "https://www.quilldesignsystem.com/r/tone-badge.json", "button", "input", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/data-table.tsx", "type": "registry:component", "target": "components/quill/data-table.tsx" } ], "docs": "A filterable members table with a toolbar, ToneBadge status pills, and a per-row actions menu. Do: Give every icon-only row-action button a per-row aria-label (e.g. \"Actions for Ada Lovelace\"), not a generic one. Don't: Ship a table full of icon-only buttons that all announce as the same unlabeled button to a screen reader. Use activity-feed when you want a read-only chronological list, not sortable/filterable records with row actions. Use kanban when the records are better organized by status columns than by table rows.", "categories": [ "data-display" ] }, { "name": "empty-state", "type": "registry:block", "title": "Empty state", "description": "A dashed-border empty state with an icon, explanatory text, and a primary action.", "meta": { "intent": [ "feedback" ], "use_when": "You need to explain why a view is empty and offer the primary action to fill it." }, "registryDependencies": [ "button", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/empty-state.tsx", "type": "registry:component", "target": "components/quill/empty-state.tsx" } ], "docs": "A dashed-border empty state with an icon, explanatory text, and a primary action. Do: Pair the explanation with a real, primary action button that actually fills the view (e.g. \"New project\"). Don't: Explain that a view is empty and leave the user with no way to act on it from that screen. Use error-404 when the view is empty because the resource doesn't exist or the route is wrong, not because the user hasn't created anything yet. Use onboarding when there's a multi-step setup to walk through, not a single action to take right now.", "categories": [ "feedback" ] }, { "name": "error-404", "type": "registry:block", "title": "404 page", "description": "A full-page 404 error state with go-back and home recovery actions.", "meta": { "intent": [ "feedback" ], "use_when": "You need a full-page not-found state with recovery actions." }, "registryDependencies": [ "button", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/error-404.tsx", "type": "registry:component", "target": "components/quill/error-404.tsx" } ], "docs": "A full-page 404 error state with go-back and home recovery actions. Do: Offer both a contextual escape (Go back) and an absolute one (Take me home) — never strand the user with only one recovery path. Don't: Leave a 404 page with no action at all, or only a single 'Home' link buried in a header the user has to hunt for. Use empty-state when the resource exists but is legitimately empty (no items yet), not missing or misrouted. Use alerts when the error is recoverable inline on the current page, not a full-page dead end that needs its own route.", "categories": [ "feedback" ] }, { "name": "faq", "type": "registry:block", "title": "FAQ section", "description": "A centered FAQ section — an accordion of common questions with a contact call-to-action footer.", "meta": { "intent": [ "content", "marketing" ], "use_when": "You need to answer common questions in an accordion with a contact fallback." }, "registryDependencies": [ "accordion", "button" ], "files": [ { "path": "registry/blocks/faq.tsx", "type": "registry:component", "target": "components/quill/faq.tsx" } ], "docs": "A centered FAQ section — an accordion of common questions with a contact call-to-action footer. Do: Open the first question by default (defaultValue=['item-0']) so the section doesn't read as empty on load. Don't: Start every item collapsed and force a first click just to prove the section has content. Use accordion when you need a bare accordion with no marketing framing (heading, contact footer) around it. Use contact-form when the user needs to ask something not covered — this pattern only offers a CTA button, not the form itself.", "categories": [ "content", "marketing" ] }, { "name": "feature-section", "type": "registry:block", "title": "Feature section", "description": "A marketing section with an editorial heading and a three-column feature grid.", "meta": { "intent": [ "marketing" ], "use_when": "You need to present product features in an editorial multi-column grid." }, "registryDependencies": [ "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/feature-section.tsx", "type": "registry:component", "target": "components/quill/feature-section.tsx" } ], "docs": "A marketing section with an editorial heading and a three-column feature grid. Do: Keep the grid to three (or a multiple of three) features so it reads evenly across the row. Don't: Let an uneven feature count leave a dangling, unbalanced last row on wide screens. Use stats-band when you're presenting numbers, not descriptive feature callouts with icons and body text. Use pricing when the features are tied to specific paid tiers, not the product as a whole.", "categories": [ "marketing" ] }, { "name": "file-upload", "type": "registry:block", "title": "File upload", "description": "An asset-upload card with a drag-and-drop dropzone and a progress-tracked upload queue.", "meta": { "intent": [ "form" ], "use_when": "You need drag-and-drop asset upload with a progress-tracked queue." }, "registryDependencies": [ "card", "button", "progress", "separator", "https://www.quilldesignsystem.com/r/icon.json" ], "files": [ { "path": "registry/blocks/file-upload.tsx", "type": "registry:component", "target": "components/quill/file-upload.tsx" } ], "docs": "An asset-upload card with a drag-and-drop dropzone and a progress-tracked upload queue. Do: Make the dropzone a real, focusable