import type { ComponentRecipe, DesignSystem, DesignToken, RecipeParts, TokenMap } from "./types.ts"; import { catalogRecipes } from "./catalog-recipes.ts"; const ref = (name: string) => ({ ref: name }); const token = ( type: DesignToken["type"], value: DesignToken["value"], legacy?: string, ): DesignToken => ({ type, value, ...(legacy ? { legacy } : {}) }); function colors(values: Record): TokenMap { const expanded = { ...values, "surface-raised": values.surface!, "surface-muted": values["surface-2"]!, "surface-soft": values["surface-2"]!, "text-subtle": values["text-muted"]!, "border-strong": values.border!, "primary-muted": values["primary-soft"]!, }; return Object.fromEntries( Object.entries(expanded).map(([key, value]) => [ `color.${key}`, token("color", value, `color-${key}`), ]), ); } function recipes(angular: boolean, outlined: boolean): Record { const recipe = (base: RecipeParts): ComponentRecipe => ({ contractVersion: 1, base }); const surface = { borderRadius: ref("shape.panel"), borderWidth: "1px", borderStyle: "solid", borderColor: ref("color.border"), boxShadow: ref("elevation.panel"), }; const field = { borderRadius: ref("shape.control"), borderWidth: "1px", borderStyle: "solid", borderColor: ref("color.border"), backgroundColor: ref("color.surface"), color: ref("color.text"), fontFamily: ref("type.body"), }; const result: Record = { Button: { contractVersion: 1, base: { control: { borderRadius: ref("shape.control"), borderWidth: "1px", borderStyle: "solid", paddingInline: ref("space.control"), boxShadow: ref("elevation.panel"), fontFamily: ref("type.body"), ...(angular ? { rotate: "-2deg" } : {}), }, }, variants: [ { when: { variant: "default" }, parts: { control: { backgroundImage: "none", backgroundColor: outlined ? "transparent" : ref("color.primary"), color: outlined ? ref("color.primary") : ref("color.primary-contrast"), borderColor: ref("color.primary"), }, }, }, ], states: [ { state: "focusVisible", parts: { control: { outlineColor: ref("color.primary") } } }, { state: "disabled", parts: { control: { opacity: 0.55, ...(angular ? { rotate: "0deg" } : {}) } }, }, ], }, Input: recipe({ control: field }), Textarea: recipe({ control: field }), Select: recipe({ control: field }), Checkbox: recipe({ control: { borderRadius: ref("shape.control"), borderWidth: "1px" } }), Radio: recipe({ control: { borderWidth: "1px" } }), Switch: recipe({ control: { borderRadius: ref("shape.control") } }), Card: recipe({ panel: { ...surface, ...(angular ? { rotate: "1deg" } : {}) }, body: { paddingInline: ref("space.panel"), paddingBlock: ref("space.panel") }, heading: { fontFamily: ref("type.heading") }, }), Alert: recipe({ root: { borderRadius: ref("shape.panel"), boxShadow: ref("elevation.panel") }, }), Modal: recipe({ panel: { ...surface, borderRadius: ref("shape.dialog") }, heading: { fontFamily: ref("type.heading") }, }), ContextMenu: recipe({ panel: { ...surface, borderRadius: ref("shape.dialog") }, item: { borderRadius: ref("shape.control"), fontFamily: ref("type.body") }, }), Nav: { contractVersion: 1, base: { link: { borderRadius: ref("shape.control"), fontFamily: ref("type.body") } }, states: [{ state: "selected", parts: { link: { fontWeight: 700 } } }], }, PageHeader: recipe({ title: { fontFamily: ref("type.heading"), letterSpacing: "-0.025em" } }), Container: recipe({ root: { paddingInline: ref("space.page") } }), }; return { ...catalogRecipes(), ...result }; } function preset(id: string, name: string, soft: boolean, angular: boolean): DesignSystem { const mono = '"IBM Plex Mono", "Courier New", monospace'; const body = soft ? "Georgia, serif" : angular ? "Arial, sans-serif" : mono; const heading = angular ? '"Times New Roman", serif' : body; const light = soft ? { bg: "#E8DCC7", background: "#E8DCC7", surface: "#D4B895", "surface-2": "#E8DCC7", text: "#292D24", foreground: "#292D24", "text-muted": "#4B5141", border: "#606C38", primary: "#606C38", "primary-hover": "#4B542C", "primary-active": "#3D4424", "primary-contrast": "#FFFFFF", "primary-text": "#3D4424", "primary-soft": "#D4B895", } : angular ? { bg: "#E8E0C0", background: "#E8E0C0", surface: "#EDE4CF", "surface-2": "#E8E0C0", text: "#232320", foreground: "#232320", "text-muted": "#535146", border: "#535146", primary: "#8F2448", "primary-hover": "#701C39", "primary-active": "#59172D", "primary-contrast": "#FFFFFF", "primary-text": "#701C39", "primary-soft": "#E8E0C0", } : { bg: "#FFFFFF", background: "#FFFFFF", surface: "#F7F7F8", "surface-2": "#FFFFFF", text: "#0B0C0A", foreground: "#0B0C0A", "text-muted": "#454741", border: "#696C63", primary: "#705000", "primary-hover": "#594000", "primary-active": "#443100", "primary-contrast": "#FFFFFF", "primary-text": "#594000", "primary-soft": "#F7F7F8", }; const dark = soft ? { bg: "#292D24", background: "#292D24", surface: "#363D2F", "surface-2": "#414B37", text: "#E8DCC7", foreground: "#E8DCC7", "text-muted": "#C9C0AA", border: "#8B9D83", primary: "#D4B895", "primary-hover": "#E8DCC7", "primary-active": "#E8DCC7", "primary-contrast": "#292D24", "primary-text": "#E8DCC7", "primary-soft": "#414B37", } : angular ? { bg: "#25221E", background: "#25221E", surface: "#353128", "surface-2": "#454032", text: "#EDE4CF", foreground: "#EDE4CF", "text-muted": "#D0C7B2", border: "#B0A78D", primary: "#FF9FC6", "primary-hover": "#FFC0DA", "primary-active": "#FFD2E5", "primary-contrast": "#25221E", "primary-text": "#FF9FC6", "primary-soft": "#454032", } : { bg: "#0B0C0A", background: "#0B0C0A", surface: "#000000", "surface-2": "#0B0C0A", text: "#F7F7F8", foreground: "#F7F7F8", "text-muted": "#BEC0B9", border: "#696C63", primary: "#FFB800", "primary-hover": "#FFD15C", "primary-active": "#FFE099", "primary-contrast": "#000000", "primary-text": "#FFB800", "primary-soft": "#0B0C0A", }; const tokens: TokenMap = { "shape.control": token("dimension", soft ? "16px" : "0", "radius-sm"), "shape.panel": token("dimension", soft ? "24px" : "0", "radius-md"), "shape.dialog": token("dimension", soft ? "32px" : "0", "radius-lg"), "shape.base": token("dimension", soft ? "24px" : "0", "radius"), "space.control": token("dimension", soft ? "1.25rem" : "0.75rem"), "space.panel": token("dimension", soft ? "1.5rem" : "1rem", "space-panel"), "space.page": token("dimension", soft ? "1.5rem" : "1rem"), "control.height": token("dimension", soft ? "2.75rem" : "2.5rem", "control-height"), "type.body": token("fontFamily", body, "font-sans"), "type.heading": token("fontFamily", heading), "elevation.panel": token("shadow", angular ? "3px 3px 0 #535146" : "none", "shadow-1"), ...colors(dark), }; return { schemaVersion: 1, id, name, version: "1.0.0", defaultMode: soft || angular ? "light" : "dark", tokens, modes: { light: { ...colors(light), scheme: token("colorScheme", "light", "color-scheme") }, dark: { ...colors(dark), scheme: token("colorScheme", "dark", "color-scheme") }, }, recipes: recipes(angular, !soft), }; } /** Industrial: black/amber, monospace, square outlined controls and flat panels. */ export const SQUARE_DESIGN_SYSTEM = preset("square", "Square / Industrial", false, false); /** Organic: sand/sage surfaces, warm serif typography, generous rounded controls. */ export const SOFT_DESIGN_SYSTEM = preset("soft", "Soft / Organic", true, false); /** Lo-Fi: paper-yellow, mixed system typography, rotated actions and hard shadows. */ export const ANGULAR_DESIGN_SYSTEM = preset("angular", "Angular / Lo-Fi", false, true); export const CORE_DESIGN_SYSTEMS = { square: SQUARE_DESIGN_SYSTEM, soft: SOFT_DESIGN_SYSTEM, angular: ANGULAR_DESIGN_SYSTEM, } as const;