diff --git a/.design-sync/NOTES.md b/.design-sync/NOTES.md index 15c529677..4b8c0b3ff 100644 --- a/.design-sync/NOTES.md +++ b/.design-sync/NOTES.md @@ -29,6 +29,21 @@ - Default `guidelinesGlob` swept 46 repo process docs into `guidelines/` — the config pins a curated 5-file design set; keep it curated. +## Known claude.ai/design validator findings (accepted, do not "fix") + +From the July 2026 design-side review (CLAUDE_CODE_FIXES.md): the design app's +validator flags on our compiled-Tailwind output that are heuristic noise, not +repo defects — re-flag to the design agent instead of restructuring CSS: + +- "56 unregistered component-scoped custom properties" — all `--tw-*` Tailwind + runtime vars + `--footer-scrim-height` (component-local by design). +- "126 pseudo theme scopes" — Tailwind utility classes misread as themes. +- README token count vs stylesheet count — converter/validator counting + difference (`317 defined` includes non-`:root` definitions). +- `--text-hero` font-family misparse — mitigated 2026-07-14 by adding the + `--text-hero--line-height` companion; if the warning persists it is + design-app-side. + ## Known render warns - None — 10/10 render clean, no thin/blank/variantsIdentical flags. diff --git a/.design-sync/config.json b/.design-sync/config.json index d9554e530..a08d135e9 100644 --- a/.design-sync/config.json +++ b/.design-sync/config.json @@ -16,6 +16,18 @@ "docs/redesign/09-ui-primitives-recipes.md", "docs/redesign/permanent-colour-direction.md" ], + "dtsPropsFor": { + "InlineNotice": "tone: \"success\" | \"info\" | \"warning\" | \"danger\" | \"neutral\"; children?: React.ReactNode; onDismiss?: () => void; dismissLabel?: string; animated?: boolean; className?: string;", + "ToggleSwitch": "enabled: boolean; onToggle?: () => void; disabled?: boolean; className?: string; \"aria-label\"?: string;", + "SourceStatusBadge": "metadata?: { document_status?: \"current\" | \"review_due\" | \"outdated\" | \"unknown\" }; className?: string; showTitle?: boolean;", + "SourceProvenance": "metadata?: { clinical_validation_status?: \"unverified\" | \"locally_reviewed\" | \"approved\"; review_date?: string; jurisdiction?: string; extraction_quality?: \"good\" | \"partial\" | \"poor\" | \"unknown\" };", + "PanelHeading": "icon?: React.ComponentType<{ className?: string }>; title: string; description?: string;", + "LoadingPanel": "label: string; variant?: \"spinner\" | \"skeleton\"; lines?: number;", + "EmptyState": "icon?: React.ComponentType<{ className?: string }>; title: string; body: string;", + "Sheet": "open: boolean; onClose: () => void; title?: string; description?: string; children?: React.ReactNode; footer?: React.ReactNode; closeLabel?: string; headerActions?: React.ReactNode; placement?: \"default\" | \"left\"; mobilePlacement?: \"bottom\" | \"top\" | \"fullscreen\"; mobileSize?: \"content\" | \"viewport\"; portal?: boolean; contentClassName?: string; bodyClassName?: string;", + "SafeBoldText": "text: string;", + "AccessibleTable": "caption?: string | null; markdown?: string | null; rows?: string[][] | null; columns?: string[] | null; compact?: boolean; expandOnMobile?: boolean; previewRows?: number; hidePreviewCaption?: boolean; hidePreviewRowCount?: boolean; densePreview?: boolean; dialogTitle?: string | null; clinicalOnly?: boolean; rowActions?: Array; actionsHeader?: string; lowConfidenceFallback?: React.ReactNode;" + }, "overrides": { "Sheet": { "cardMode": "single", "primaryStory": "OpenDialog", "viewport": "480x640" }, "AccessibleTable": { "cardMode": "column" } diff --git a/.design-sync/conventions.md b/.design-sync/conventions.md index 357dd25e1..7a726287f 100644 --- a/.design-sync/conventions.md +++ b/.design-sync/conventions.md @@ -40,8 +40,7 @@ Join with the exported `cn(...)` helper. ## Example ```tsx -import { PanelHeading, quietPanel, primaryControl, cn } from ""; -import { FileText } from "lucide-react"; +import { PanelHeading, quietPanel, primaryControl, cn, FileText } from "";
@@ -49,8 +48,19 @@ import { FileText } from "lucide-react";
; ``` +## Icons + +The bundle ships a curated lucide icon set — import icons from the package +itself, never from `lucide-react` (it is not available to designs): `Search`, +`SearchX`, `FileText`, `File`, `Inbox`, `Upload`, `Download`, `ShieldCheck`, +`ShieldAlert`, `TriangleAlert`, `AlertCircle`, `Ban`, `X`, `Check`, +`CheckCircle2`, `Info`, `Loader2`, `ChevronDown`, `ChevronRight`, `ArrowLeft`, +`ArrowRight`, `Plus`, `Trash2`, `Pencil`, `Filter`, `Settings`, `Database`, +`BookOpen`, `Stethoscope`, `HeartPulse`, `Pill`, `Calendar`, `Clock`, +`ExternalLink`, `Copy`, `Maximize2`. The `icon` prop on `PanelHeading` / +`EmptyState` is optional — omit it rather than inventing an icon. + ## Where the truth lives Read `styles.css` for the full token set (`:root` and `.dark` blocks) and each -component's `.d.ts` + `.prompt.md` for its API. Icons are `lucide-react` -components passed as the `icon` prop where accepted. +component's `.d.ts` + `.prompt.md` for its API. diff --git a/.design-sync/entry.tsx b/.design-sync/entry.tsx index 8c323b170..b82f6a389 100644 --- a/.design-sync/entry.tsx +++ b/.design-sync/entry.tsx @@ -5,3 +5,45 @@ export * from "@/components/ui-primitives"; export { Sheet } from "@/components/ui/sheet"; export { SafeBoldText } from "@/components/SafeBoldText"; export { AccessibleTable } from "@/components/AccessibleTable"; + +// Curated lucide-react icon set: consumers of the synced bundle have no +// lucide-react install, so the icons PanelHeading/EmptyState-style `icon` +// props need must ship with the bundle itself. +export { + AlertCircle, + ArrowLeft, + ArrowRight, + Ban, + BookOpen, + Calendar, + Check, + CheckCircle2, + ChevronDown, + ChevronRight, + Clock, + Copy, + Database, + Download, + ExternalLink, + File, + FileText, + Filter, + HeartPulse, + Inbox, + Info, + Loader2, + Maximize2, + Pencil, + Pill, + Plus, + Search, + SearchX, + Settings, + ShieldAlert, + ShieldCheck, + Stethoscope, + Trash2, + TriangleAlert, + Upload, + X, +} from "lucide-react"; diff --git a/.design-sync/previews/AccessibleTable.tsx b/.design-sync/previews/AccessibleTable.tsx index 47715f004..3ab91f261 100644 --- a/.design-sync/previews/AccessibleTable.tsx +++ b/.design-sync/previews/AccessibleTable.tsx @@ -1,17 +1,14 @@ import { AccessibleTable } from "prompt-for-codex-medical-knowledge-base"; -const doseRows = [ - ["Amoxicillin", "500 mg", "8-hourly", "Oral", "5 days"], - ["Doxycycline", "100 mg", "12-hourly", "Oral", "7 days"], - ["Benzylpenicillin", "1.2 g", "6-hourly", "IV", "Until stable"], -]; -const doseColumns = ["Antibiotic", "Dose", "Frequency", "Route", "Duration"]; - export const ClinicalDoseTable = () => ( ); diff --git a/.design-sync/previews/EmptyState.tsx b/.design-sync/previews/EmptyState.tsx index 8e4a8f77a..faba14551 100644 --- a/.design-sync/previews/EmptyState.tsx +++ b/.design-sync/previews/EmptyState.tsx @@ -9,6 +9,10 @@ export const NoDocuments = () => ( /> ); +export const NoIcon = () => ( + +); + export const NoResults = () => ( ( ); export const TitleOnly = () => ; + +export const NoIcon = () => ; diff --git a/src/app/globals.css b/src/app/globals.css index 0ef8f5acb..9ce9b7b87 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -90,6 +90,11 @@ by ~1033px — no breakpoint jumps. Generates the `text-hero` utility. clamp() font sizes are not flagged by scripts/check-type-scale.mjs. */ --text-hero: clamp(1.45rem, 1.02rem + 1.75vw, 2.15rem); + /* Companion line-height marks --text-hero as a font-SIZE token (Tailwind v4 + `--text---line-height` convention) so downstream tooling never + misreads the clamp() value as a font-family list. Call sites that set an + explicit leading-* utility still win over this default. */ + --text-hero--line-height: 1.15; /* Font families: bind Tailwind's font-sans / font-mono to the loaded Geist faces (variables set on by next/font). font-mono is used for diff --git a/src/components/ui-primitives.tsx b/src/components/ui-primitives.tsx index 3edd00b35..4a8f18b41 100644 --- a/src/components/ui-primitives.tsx +++ b/src/components/ui-primitives.tsx @@ -358,15 +358,17 @@ export function PanelHeading({ title, description, }: { - icon: IconComponent; + icon?: IconComponent; title: string; description?: string; }) { return (
- - - + {Icon && ( + + + + )}

{title}

{description &&

{description}

} @@ -417,13 +419,15 @@ export function LoadingPanel({ ); } -export function EmptyState({ icon: Icon, title, body }: { icon: IconComponent; title: string; body: string }) { +export function EmptyState({ icon: Icon, title, body }: { icon?: IconComponent; title: string; body: string }) { return (
- - - + {Icon && ( + + + + )}

{title}

{body}