@eifi1/ui-kit 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +219 -0
- package/dist/components/account-settings.d.ts +71 -0
- package/dist/components/account-settings.js +159 -0
- package/dist/components/account-settings.js.map +1 -0
- package/dist/components/alert-banner.d.ts +20 -0
- package/dist/components/alert-banner.js +39 -0
- package/dist/components/alert-banner.js.map +1 -0
- package/dist/components/amount-input.d.ts +117 -0
- package/dist/components/amount-input.js +243 -0
- package/dist/components/amount-input.js.map +1 -0
- package/dist/components/calculator.d.ts +42 -0
- package/dist/components/calculator.js +161 -0
- package/dist/components/calculator.js.map +1 -0
- package/dist/components/chart.d.ts +58 -0
- package/dist/components/chart.js +158 -0
- package/dist/components/chart.js.map +1 -0
- package/dist/components/combobox-core.d.ts +77 -0
- package/dist/components/combobox-core.js +263 -0
- package/dist/components/combobox-core.js.map +1 -0
- package/dist/components/combobox.d.ts +141 -0
- package/dist/components/combobox.js +550 -0
- package/dist/components/combobox.js.map +1 -0
- package/dist/components/currency-select.d.ts +37 -0
- package/dist/components/currency-select.js +131 -0
- package/dist/components/currency-select.js.map +1 -0
- package/dist/components/data-table-filter-popover.d.ts +28 -0
- package/dist/components/data-table-filter-popover.js +201 -0
- package/dist/components/data-table-filter-popover.js.map +1 -0
- package/dist/components/data-table-filters.d.ts +5 -0
- package/dist/components/data-table-filters.js +118 -0
- package/dist/components/data-table-filters.js.map +1 -0
- package/dist/components/data-table-labels.d.ts +33 -0
- package/dist/components/data-table-labels.js +53 -0
- package/dist/components/data-table-labels.js.map +1 -0
- package/dist/components/data-table-pagination.d.ts +18 -0
- package/dist/components/data-table-pagination.js +92 -0
- package/dist/components/data-table-pagination.js.map +1 -0
- package/dist/components/data-table-sort.d.ts +23 -0
- package/dist/components/data-table-sort.js +55 -0
- package/dist/components/data-table-sort.js.map +1 -0
- package/dist/components/data-table.d.ts +5 -0
- package/dist/components/data-table.js +926 -0
- package/dist/components/data-table.js.map +1 -0
- package/dist/components/date-picker.d.ts +85 -0
- package/dist/components/date-picker.js +253 -0
- package/dist/components/date-picker.js.map +1 -0
- package/dist/components/dropdown.d.ts +98 -0
- package/dist/components/dropdown.js +122 -0
- package/dist/components/dropdown.js.map +1 -0
- package/dist/components/entity-combobox.d.ts +49 -0
- package/dist/components/entity-combobox.js +115 -0
- package/dist/components/entity-combobox.js.map +1 -0
- package/dist/components/file-dropzone.d.ts +18 -0
- package/dist/components/file-dropzone.js +101 -0
- package/dist/components/file-dropzone.js.map +1 -0
- package/dist/components/full-bleed-dialog.d.ts +57 -0
- package/dist/components/full-bleed-dialog.js +68 -0
- package/dist/components/full-bleed-dialog.js.map +1 -0
- package/dist/components/grouped-picker.d.ts +37 -0
- package/dist/components/grouped-picker.js +87 -0
- package/dist/components/grouped-picker.js.map +1 -0
- package/dist/components/hover-menu.d.ts +16 -0
- package/dist/components/hover-menu.js +113 -0
- package/dist/components/hover-menu.js.map +1 -0
- package/dist/components/mini-calendar.d.ts +33 -0
- package/dist/components/mini-calendar.js +133 -0
- package/dist/components/mini-calendar.js.map +1 -0
- package/dist/components/modal.d.ts +76 -0
- package/dist/components/modal.js +156 -0
- package/dist/components/modal.js.map +1 -0
- package/dist/components/multi-entity-combobox.d.ts +47 -0
- package/dist/components/multi-entity-combobox.js +116 -0
- package/dist/components/multi-entity-combobox.js.map +1 -0
- package/dist/components/multi-select.d.ts +39 -0
- package/dist/components/multi-select.js +132 -0
- package/dist/components/multi-select.js.map +1 -0
- package/dist/components/number-input.d.ts +74 -0
- package/dist/components/number-input.js +114 -0
- package/dist/components/number-input.js.map +1 -0
- package/dist/components/numpad-sheet.d.ts +45 -0
- package/dist/components/numpad-sheet.js +102 -0
- package/dist/components/numpad-sheet.js.map +1 -0
- package/dist/components/picker-sheet.d.ts +44 -0
- package/dist/components/picker-sheet.js +78 -0
- package/dist/components/picker-sheet.js.map +1 -0
- package/dist/components/popover.d.ts +20 -0
- package/dist/components/popover.js +46 -0
- package/dist/components/popover.js.map +1 -0
- package/dist/components/search-field.d.ts +52 -0
- package/dist/components/search-field.js +64 -0
- package/dist/components/search-field.js.map +1 -0
- package/dist/components/settings-fields.d.ts +39 -0
- package/dist/components/settings-fields.js +17 -0
- package/dist/components/settings-fields.js.map +1 -0
- package/dist/components/swipeable-row.d.ts +60 -0
- package/dist/components/swipeable-row.js +115 -0
- package/dist/components/swipeable-row.js.map +1 -0
- package/dist/components/toggle-group.d.ts +34 -0
- package/dist/components/toggle-group.js +90 -0
- package/dist/components/toggle-group.js.map +1 -0
- package/dist/components/tooltip.d.ts +86 -0
- package/dist/components/tooltip.js +171 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/components/ui.d.ts +239 -0
- package/dist/components/ui.js +512 -0
- package/dist/components/ui.js.map +1 -0
- package/dist/components/use-mobile-reveal.d.ts +31 -0
- package/dist/components/use-mobile-reveal.js +33 -0
- package/dist/components/use-mobile-reveal.js.map +1 -0
- package/dist/components/use-table-state.d.ts +54 -0
- package/dist/components/use-table-state.js +153 -0
- package/dist/components/use-table-state.js.map +1 -0
- package/dist/components/user-avatar.d.ts +23 -0
- package/dist/components/user-avatar.js +33 -0
- package/dist/components/user-avatar.js.map +1 -0
- package/dist/components/wizard-stepper.d.ts +14 -0
- package/dist/components/wizard-stepper.js +27 -0
- package/dist/components/wizard-stepper.js.map +1 -0
- package/dist/data-table-filters-aXyf0Xub.d.ts +261 -0
- package/dist/feedback/feedback-attachment.d.ts +63 -0
- package/dist/feedback/feedback-attachment.js +160 -0
- package/dist/feedback/feedback-attachment.js.map +1 -0
- package/dist/feedback/feedback-dialog.d.ts +72 -0
- package/dist/feedback/feedback-dialog.js +109 -0
- package/dist/feedback/feedback-dialog.js.map +1 -0
- package/dist/feedback/feedback-inbox.d.ts +226 -0
- package/dist/feedback/feedback-inbox.js +315 -0
- package/dist/feedback/feedback-inbox.js.map +1 -0
- package/dist/hooks/use-anchored-panel.d.ts +80 -0
- package/dist/hooks/use-anchored-panel.js +71 -0
- package/dist/hooks/use-anchored-panel.js.map +1 -0
- package/dist/hooks/use-anchored-rect.d.ts +24 -0
- package/dist/hooks/use-anchored-rect.js +40 -0
- package/dist/hooks/use-anchored-rect.js.map +1 -0
- package/dist/hooks/use-body-scroll-lock.d.ts +9 -0
- package/dist/hooks/use-body-scroll-lock.js +41 -0
- package/dist/hooks/use-body-scroll-lock.js.map +1 -0
- package/dist/hooks/use-close-transition.d.ts +41 -0
- package/dist/hooks/use-close-transition.js +36 -0
- package/dist/hooks/use-close-transition.js.map +1 -0
- package/dist/hooks/use-dismiss.d.ts +34 -0
- package/dist/hooks/use-dismiss.js +41 -0
- package/dist/hooks/use-dismiss.js.map +1 -0
- package/dist/hooks/use-media-query.d.ts +8 -0
- package/dist/hooks/use-media-query.js +18 -0
- package/dist/hooks/use-media-query.js.map +1 -0
- package/dist/hooks/use-overlay-history.d.ts +10 -0
- package/dist/hooks/use-overlay-history.js +99 -0
- package/dist/hooks/use-overlay-history.js.map +1 -0
- package/dist/hooks/use-row-swipe.d.ts +30 -0
- package/dist/hooks/use-row-swipe.js +128 -0
- package/dist/hooks/use-row-swipe.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/calc.d.ts +89 -0
- package/dist/lib/calc.js +180 -0
- package/dist/lib/calc.js.map +1 -0
- package/dist/lib/cn.d.ts +6 -0
- package/dist/lib/cn.js +7 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/dates.d.ts +84 -0
- package/dist/lib/dates.js +108 -0
- package/dist/lib/dates.js.map +1 -0
- package/dist/lib/logger.d.ts +17 -0
- package/dist/lib/logger.js +30 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/safe-storage.d.ts +23 -0
- package/dist/lib/safe-storage.js +20 -0
- package/dist/lib/safe-storage.js.map +1 -0
- package/dist/search/command-palette.d.ts +71 -0
- package/dist/search/command-palette.js +198 -0
- package/dist/search/command-palette.js.map +1 -0
- package/dist/shell/app-shell.d.ts +64 -0
- package/dist/shell/app-shell.js +237 -0
- package/dist/shell/app-shell.js.map +1 -0
- package/dist/shell/option-switcher-menu.d.ts +24 -0
- package/dist/shell/option-switcher-menu.js +44 -0
- package/dist/shell/option-switcher-menu.js.map +1 -0
- package/dist/shell/role-switcher.d.ts +19 -0
- package/dist/shell/role-switcher.js +28 -0
- package/dist/shell/role-switcher.js.map +1 -0
- package/dist/shell/top-bar.d.ts +15 -0
- package/dist/shell/top-bar.js +29 -0
- package/dist/shell/top-bar.js.map +1 -0
- package/dist/shell/topbar-action-menu.d.ts +44 -0
- package/dist/shell/topbar-action-menu.js +49 -0
- package/dist/shell/topbar-action-menu.js.map +1 -0
- package/dist/shell/topbar-controls.d.ts +54 -0
- package/dist/shell/topbar-controls.js +152 -0
- package/dist/shell/topbar-controls.js.map +1 -0
- package/dist/theme/chart-palette.d.ts +60 -0
- package/dist/theme/chart-palette.js +79 -0
- package/dist/theme/chart-palette.js.map +1 -0
- package/dist/theme/palette-presets.d.ts +39 -0
- package/dist/theme/palette-presets.js +440 -0
- package/dist/theme/palette-presets.js.map +1 -0
- package/dist/theme/palette-store.d.ts +45 -0
- package/dist/theme/palette-store.js +52 -0
- package/dist/theme/palette-store.js.map +1 -0
- package/dist/theme/theme-store.d.ts +57 -0
- package/dist/theme/theme-store.js +96 -0
- package/dist/theme/theme-store.js.map +1 -0
- package/dist/tour/tour.d.ts +104 -0
- package/dist/tour/tour.js +351 -0
- package/dist/tour/tour.js.map +1 -0
- package/dist/wizard/stepper-nav.d.ts +30 -0
- package/dist/wizard/stepper-nav.js +146 -0
- package/dist/wizard/stepper-nav.js.map +1 -0
- package/dist/wizard/types.d.ts +124 -0
- package/dist/wizard/types.js +24 -0
- package/dist/wizard/types.js.map +1 -0
- package/dist/wizard/use-wizard.d.ts +6 -0
- package/dist/wizard/use-wizard.js +222 -0
- package/dist/wizard/use-wizard.js.map +1 -0
- package/dist/wizard/validation.d.ts +23 -0
- package/dist/wizard/validation.js +13 -0
- package/dist/wizard/validation.js.map +1 -0
- package/dist/wizard/wizard-context.d.ts +19 -0
- package/dist/wizard/wizard-context.js +15 -0
- package/dist/wizard/wizard-context.js.map +1 -0
- package/dist/wizard/wizard-step.d.ts +11 -0
- package/dist/wizard/wizard-step.js +12 -0
- package/dist/wizard/wizard-step.js.map +1 -0
- package/dist/wizard/wizard-summary.d.ts +18 -0
- package/dist/wizard/wizard-summary.js +41 -0
- package/dist/wizard/wizard-summary.js.map +1 -0
- package/package.json +87 -0
- package/tokens.css +254 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/theme/chart-palette.ts"],"sourcesContent":["// Chart colour system. Single source of truth lives in the design tokens\n// (:root / .dark in tokens.css): brand = indigo, money = teal/amber/purple,\n// chart-1..9 = Paul Tol \"Muted\" (CVD-safe across protan/deutan/tritan).\n// Returning CSS vars here makes every Recharts series theme-aware for free — the\n// SVG fill/stroke resolves --chart-N against the current light/dark token set.\n\nconst PALETTE_SIZE = 9;\n\n/** CVD-safe categorical colour for series `index`, as a theme-aware CSS var. */\nexport function paletteFor(index: number): string {\n return `var(--chart-${(index % PALETTE_SIZE) + 1})`;\n}\n\n/** Semantic money colours, theme-aware via tokens. Pair with +/- and arrow\n cues at the call site so colour is never the only signal (CVD). */\nexport const CHART_COLORS = {\n income: \"var(--money-income)\",\n expense: \"var(--money-expense)\",\n net: \"var(--money-net)\",\n assigned: \"var(--brand)\",\n activity: \"var(--money-expense)\",\n} as const;\n\n// ── Raw hex stops, by theme ────────────────────────────────────────────────\n// The heatmaps interpolate colours in JS (CSS vars can't be lerped), so they\n// need concrete hex per theme. Keep these in sync with the tokens.\nexport const PALETTE_HEX = {\n light: [\"#332288\", \"#88ccee\", \"#44aa99\", \"#117733\", \"#999933\", \"#ddcc77\", \"#cc6677\", \"#882255\", \"#aa4499\"],\n dark: [\"#7e72d6\", \"#9fd8f2\", \"#5fc4b0\", \"#3fa45f\", \"#bfbf5e\", \"#e8dda0\", \"#e08c9a\", \"#c25a78\", \"#cc78be\"],\n} as const;\n\n/** A heatmap's interpolation stops for one theme. Open string fields so any\n palette preset (not just the built-in default) can supply its own stops. */\nexport interface HeatStops {\n neutral: string;\n under: string;\n over: string;\n seqLow: string;\n seqHigh: string;\n empty: string;\n}\n\n/** Diverging (variance: under←0→over) and sequential (spending intensity)\n heatmap stops, per theme. Teal = under/good, amber = over/spend = bad. */\nexport const HEATMAP_HEX = {\n light: {\n neutral: \"#f1f5f9\", // slate-100\n under: \"#0f766e\", // teal-700\n over: \"#b45309\", // amber-700\n seqLow: \"#fef3c7\", // amber-100\n seqHigh: \"#b45309\", // amber-700\n empty: \"rgba(148,163,184,0.14)\",\n },\n dark: {\n neutral: \"#334155\", // slate-700\n under: \"#2dd4bf\", // teal-400\n over: \"#fbbf24\", // amber-400\n seqLow: \"#3f2d10\", // dim amber, sits just above slate-950\n seqHigh: \"#fbbf24\", // amber-400\n empty: \"rgba(148,163,184,0.10)\",\n },\n} as const;\n\n/** Linear interpolate two #rrggbb hexes; `t` in [0,1]. Returns #rrggbb. */\nexport function lerpHex(a: string, b: string, t: number): string {\n const pa = parseHex(a) ?? UNREADABLE;\n const pb = parseHex(b) ?? UNREADABLE;\n const c = (i: number) => Math.round(pa[i] + (pb[i] - pa[i]) * clamp01(t));\n return `#${[c(0), c(1), c(2)].map((v) => v.toString(16).padStart(2, \"0\")).join(\"\")}`;\n}\n\n/** Pick a legible text colour (near-black / near-white) for a solid hex fill,\n flipping by perceived luminance so cell/treemap labels keep contrast.\n\n A fill this cannot read gets `currentColor` — inherit, i.e. whatever the\n surrounding text already uses. That is the only answer that is right on both\n themes, because an unreadable fill is usually a translucent one (`HEATMAP_HEX.*\n .empty` is an `rgba()` string, and the variance heatmap does pass it here for any\n category with zero assigned and positive activity — a refund). Picking a constant\n instead is what produced the bug: `NaN > 0.6` is false, so the label came back\n near-white on a near-white cell and the figure was invisible. */\nexport function textOn(hex: string): string {\n const rgb = parseHex(hex);\n if (!rgb) return \"currentColor\";\n const [r, g, b] = rgb;\n // Rec.601 luma; >0.6 → dark text, else light text.\n const luma = (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n return luma > 0.6 ? \"#1a1a1a\" : \"#f8fafc\";\n}\n\n/** Mid-grey, for a stop {@link lerpHex} has to interpolate but cannot read. It has\n * to return SOME valid colour, and a grey is the one that misleads least. */\nconst UNREADABLE: [number, number, number] = [0x80, 0x80, 0x80];\n\n/**\n * `#rgb` or `#rrggbb` to components, or **null** when it is neither.\n *\n * This used to `parseInt` whatever it was given and hand the NaNs on, and both\n * callers propagated them silently: {@link lerpHex} produced the literal string\n * `\"#nannannan\"`, and {@link textOn} computed `NaN > 0.6 === false` and returned the\n * LIGHT label colour.\n *\n * That is not hypothetical — a non-hex value ships in this very module.\n * `HEATMAP_HEX.*.empty` is an `rgba(…)` string, and the variance heatmap paints a\n * figure on an `empty` cell whenever a category has zero assigned and positive\n * activity (a refund). On the light theme the cell is near-white and the label came\n * back near-white: the number was there, and unreadable.\n */\nfunction parseHex(hex: string): [number, number, number] | null {\n const h = hex.startsWith(\"#\") ? hex.slice(1) : hex;\n const full =\n h.length === 3\n ? h\n .split(\"\")\n .map((c) => c + c)\n .join(\"\")\n : h;\n if (!/^[0-9a-fA-F]{6}$/.test(full)) return null;\n return [\n parseInt(full.slice(0, 2), 16),\n parseInt(full.slice(2, 4), 16),\n parseInt(full.slice(4, 6), 16),\n ];\n}\n\nfunction clamp01(t: number): number {\n return t < 0 ? 0 : t > 1 ? 1 : t;\n}\n"],"mappings":"AAMA,MAAM,eAAe;AAGd,SAAS,WAAW,OAAuB;AAChD,SAAO,eAAgB,QAAQ,eAAgB,CAAC;AAClD;AAIO,MAAM,eAAe;AAAA,EAC1B,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,KAAK;AAAA,EACL,UAAU;AAAA,EACV,UAAU;AACZ;AAKO,MAAM,cAAc;AAAA,EACzB,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,EACzG,MAAM,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAC1G;AAeO,MAAM,cAAc;AAAA,EACzB,OAAO;AAAA,IACL,SAAS;AAAA;AAAA,IACT,OAAO;AAAA;AAAA,IACP,MAAM;AAAA;AAAA,IACN,QAAQ;AAAA;AAAA,IACR,SAAS;AAAA;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,SAAS;AAAA;AAAA,IACT,OAAO;AAAA;AAAA,IACP,MAAM;AAAA;AAAA,IACN,QAAQ;AAAA;AAAA,IACR,SAAS;AAAA;AAAA,IACT,OAAO;AAAA,EACT;AACF;AAGO,SAAS,QAAQ,GAAW,GAAW,GAAmB;AAC/D,QAAM,KAAK,SAAS,CAAC,KAAK;AAC1B,QAAM,KAAK,SAAS,CAAC,KAAK;AAC1B,QAAM,IAAI,CAAC,MAAc,KAAK,MAAM,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC;AACxE,SAAO,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;AACpF;AAYO,SAAS,OAAO,KAAqB;AAC1C,QAAM,MAAM,SAAS,GAAG;AACxB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,CAAC,GAAG,GAAG,CAAC,IAAI;AAElB,QAAM,QAAQ,QAAQ,IAAI,QAAQ,IAAI,QAAQ,KAAK;AACnD,SAAO,OAAO,MAAM,YAAY;AAClC;AAIA,MAAM,aAAuC,CAAC,KAAM,KAAM,GAAI;AAgB9D,SAAS,SAAS,KAA8C;AAC9D,QAAM,IAAI,IAAI,WAAW,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI;AAC/C,QAAM,OACJ,EAAE,WAAW,IACT,EACG,MAAM,EAAE,EACR,IAAI,CAAC,MAAM,IAAI,CAAC,EAChB,KAAK,EAAE,IACV;AACN,MAAI,CAAC,mBAAmB,KAAK,IAAI,EAAG,QAAO;AAC3C,SAAO;AAAA,IACL,SAAS,KAAK,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IAC7B,SAAS,KAAK,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IAC7B,SAAS,KAAK,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,EAC/B;AACF;AAEA,SAAS,QAAQ,GAAmB;AAClC,SAAO,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AACjC;","names":[]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { HeatStops } from './chart-palette.js';
|
|
2
|
+
|
|
3
|
+
interface TokenSet {
|
|
4
|
+
bgPage: string;
|
|
5
|
+
bgSurface: string;
|
|
6
|
+
bgSurface2: string;
|
|
7
|
+
border: string;
|
|
8
|
+
textPrimary: string;
|
|
9
|
+
textSecondary: string;
|
|
10
|
+
textMuted: string;
|
|
11
|
+
brand: string;
|
|
12
|
+
brandHover: string;
|
|
13
|
+
brandContrast: string;
|
|
14
|
+
moneyIncome: string;
|
|
15
|
+
moneyExpense: string;
|
|
16
|
+
moneyNet: string;
|
|
17
|
+
moneyNeutral: string;
|
|
18
|
+
chart: string[];
|
|
19
|
+
heat: HeatStops;
|
|
20
|
+
}
|
|
21
|
+
interface PalettePreset {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
blurb: string;
|
|
25
|
+
light: TokenSet;
|
|
26
|
+
dark: TokenSet;
|
|
27
|
+
}
|
|
28
|
+
declare const DEFAULT_PRESET: PalettePreset;
|
|
29
|
+
declare const ALTERNATIVE_PRESETS: PalettePreset[];
|
|
30
|
+
declare const IMPRINT_PRESET: PalettePreset;
|
|
31
|
+
declare const PALETTES: PalettePreset[];
|
|
32
|
+
declare function presetById(id: string): PalettePreset;
|
|
33
|
+
declare const TOKEN_VARS: readonly ["--bg-page", "--bg-surface", "--bg-surface-2", "--border", "--text-primary", "--text-secondary", "--text-muted", "--brand", "--brand-hover", "--brand-contrast", "--money-income", "--money-expense", "--money-net", "--money-neutral", "--chart-1", "--chart-2", "--chart-3", "--chart-4", "--chart-5", "--chart-6", "--chart-7", "--chart-8", "--chart-9"];
|
|
34
|
+
/** Write a token set onto an element's inline style as CSS custom properties. */
|
|
35
|
+
declare function applyTokenSet(el: HTMLElement, t: TokenSet): void;
|
|
36
|
+
/** Remove all preset overrides so the tokens.css :root/.dark defaults take over. */
|
|
37
|
+
declare function clearTokenSet(el: HTMLElement): void;
|
|
38
|
+
|
|
39
|
+
export { ALTERNATIVE_PRESETS, DEFAULT_PRESET, IMPRINT_PRESET, PALETTES, type PalettePreset, TOKEN_VARS, type TokenSet, applyTokenSet, clearTokenSet, presetById };
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
const DEFAULT_PRESET = {
|
|
2
|
+
id: "default",
|
|
3
|
+
name: "Default",
|
|
4
|
+
blurb: "Solar-dusk light \xB7 indigo-noir dark",
|
|
5
|
+
light: {
|
|
6
|
+
// Solar Dusk (light) surfaces, with the brand unified to indigo (see above).
|
|
7
|
+
bgPage: "#ede3cf",
|
|
8
|
+
bgSurface: "#f6ecd9",
|
|
9
|
+
bgSurface2: "#f3ead6",
|
|
10
|
+
border: "#e2d6bd",
|
|
11
|
+
textPrimary: "#463f33",
|
|
12
|
+
textSecondary: "#50493c",
|
|
13
|
+
textMuted: "#696153",
|
|
14
|
+
brand: "#4f46e5",
|
|
15
|
+
brandHover: "#4338ca",
|
|
16
|
+
brandContrast: "#ffffff",
|
|
17
|
+
moneyIncome: "#0b6650",
|
|
18
|
+
moneyExpense: "#9c6418",
|
|
19
|
+
moneyNet: "#7a4fa3",
|
|
20
|
+
moneyNeutral: "#6b6453",
|
|
21
|
+
chart: ["#332288", "#88ccee", "#44aa99", "#117733", "#999933", "#ddcc77", "#cc6677", "#882255", "#aa4499"],
|
|
22
|
+
heat: {
|
|
23
|
+
neutral: "#f1e7d2",
|
|
24
|
+
under: "#0b6650",
|
|
25
|
+
over: "#9c6418",
|
|
26
|
+
seqLow: "#f6ecd0",
|
|
27
|
+
seqHigh: "#9c6418",
|
|
28
|
+
empty: "rgba(148,163,184,0.14)"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
dark: {
|
|
32
|
+
// Indigo Noir (dark)
|
|
33
|
+
bgPage: "#0e0f1c",
|
|
34
|
+
bgSurface: "#181a2c",
|
|
35
|
+
bgSurface2: "#21243a",
|
|
36
|
+
border: "#2e3252",
|
|
37
|
+
textPrimary: "#e6e8f4",
|
|
38
|
+
textSecondary: "#adafbe",
|
|
39
|
+
textMuted: "#8d90a0",
|
|
40
|
+
brand: "#8b93f8",
|
|
41
|
+
brandHover: "#aab1fb",
|
|
42
|
+
brandContrast: "#16182b",
|
|
43
|
+
moneyIncome: "#22c3b6",
|
|
44
|
+
// Amber-400 (#fbbf24) sat at OKLab L 0.84 while every other dark token lives
|
|
45
|
+
// at 0.68–0.74, so outflows outshouted the inflows they are paired with. Same
|
|
46
|
+
// hue and chroma, pulled to L 0.785 (dev#434). The heat stops below keep the
|
|
47
|
+
// brighter amber on purpose: a gradient endpoint is meant to be the loudest
|
|
48
|
+
// thing in its scale, and it is a fill, not a figure.
|
|
49
|
+
moneyExpense: "#e4b035",
|
|
50
|
+
moneyNet: "#b39aef",
|
|
51
|
+
moneyNeutral: "#9aa1bd",
|
|
52
|
+
chart: ["#7e72d6", "#9fd8f2", "#5fc4b0", "#3fa45f", "#bfbf5e", "#e8dda0", "#e08c9a", "#c25a78", "#cc78be"],
|
|
53
|
+
heat: {
|
|
54
|
+
neutral: "#363a5a",
|
|
55
|
+
under: "#22c3b6",
|
|
56
|
+
over: "#fbbf24",
|
|
57
|
+
seqLow: "#3a2c14",
|
|
58
|
+
seqHigh: "#fbbf24",
|
|
59
|
+
empty: "rgba(148,163,184,0.10)"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const ALTERNATIVE_PRESETS = [
|
|
64
|
+
{
|
|
65
|
+
id: "warm-paper",
|
|
66
|
+
name: "Warm Paper",
|
|
67
|
+
blurb: "Cream paper \xB7 warm charcoal",
|
|
68
|
+
light: {
|
|
69
|
+
bgPage: "#ece5d6",
|
|
70
|
+
bgSurface: "#f5efe3",
|
|
71
|
+
bgSurface2: "#efe9dc",
|
|
72
|
+
border: "#e2dcce",
|
|
73
|
+
textPrimary: "#2b2622",
|
|
74
|
+
textSecondary: "#4f4a44",
|
|
75
|
+
textMuted: "#68625b",
|
|
76
|
+
brand: "#9a5b34",
|
|
77
|
+
brandHover: "#824827",
|
|
78
|
+
brandContrast: "#fdf8f2",
|
|
79
|
+
moneyIncome: "#0e7490",
|
|
80
|
+
moneyExpense: "#8f3f0a",
|
|
81
|
+
moneyNet: "#7c4dab",
|
|
82
|
+
moneyNeutral: "#6b6258",
|
|
83
|
+
chart: ["#332288", "#88ccee", "#44aa99", "#117733", "#999933", "#ddcc77", "#cc6677", "#882255", "#aa4499"],
|
|
84
|
+
heat: {
|
|
85
|
+
neutral: "#efe9dc",
|
|
86
|
+
under: "#0e7490",
|
|
87
|
+
over: "#b45309",
|
|
88
|
+
seqLow: "#fbeed2",
|
|
89
|
+
seqHigh: "#b45309",
|
|
90
|
+
empty: "rgba(148,163,184,0.14)"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
dark: {
|
|
94
|
+
bgPage: "#211e1a",
|
|
95
|
+
bgSurface: "#2a2622",
|
|
96
|
+
bgSurface2: "#322d27",
|
|
97
|
+
border: "#3d372f",
|
|
98
|
+
textPrimary: "#e8e2d6",
|
|
99
|
+
textSecondary: "#bfb9af",
|
|
100
|
+
textMuted: "#9e998f",
|
|
101
|
+
brand: "#e0986a",
|
|
102
|
+
brandHover: "#ecae85",
|
|
103
|
+
brandContrast: "#2a1c10",
|
|
104
|
+
moneyIncome: "#4dd4c4",
|
|
105
|
+
moneyExpense: "#fbbf3a",
|
|
106
|
+
moneyNet: "#bfa0e0",
|
|
107
|
+
moneyNeutral: "#a39a8c",
|
|
108
|
+
chart: ["#7e72d6", "#9fd8f2", "#5fc4b0", "#3fa45f", "#bfbf5e", "#e8dda0", "#e08c9a", "#cf6488", "#cc78be"],
|
|
109
|
+
heat: {
|
|
110
|
+
neutral: "#3a352e",
|
|
111
|
+
under: "#4dd4c4",
|
|
112
|
+
over: "#fbbf3a",
|
|
113
|
+
seqLow: "#2c2014",
|
|
114
|
+
seqHigh: "#fbbf3a",
|
|
115
|
+
empty: "rgba(148,163,184,0.10)"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "nord-frost",
|
|
121
|
+
name: "Nord Frost",
|
|
122
|
+
blurb: "Cool snow \xB7 polar night",
|
|
123
|
+
light: {
|
|
124
|
+
bgPage: "#e2e7ef",
|
|
125
|
+
bgSurface: "#f0f3f8",
|
|
126
|
+
bgSurface2: "#e1e6ee",
|
|
127
|
+
border: "#d3dae6",
|
|
128
|
+
textPrimary: "#2e3440",
|
|
129
|
+
textSecondary: "#454b56",
|
|
130
|
+
textMuted: "#5e636e",
|
|
131
|
+
brand: "#3b6ea5",
|
|
132
|
+
brandHover: "#305a86",
|
|
133
|
+
brandContrast: "#ffffff",
|
|
134
|
+
moneyIncome: "#0f8060",
|
|
135
|
+
moneyExpense: "#b8431a",
|
|
136
|
+
moneyNet: "#6b4fa0",
|
|
137
|
+
moneyNeutral: "#5b6577",
|
|
138
|
+
chart: ["#3a6ea5", "#56b6c2", "#2f7d4f", "#cdb52f", "#d05f7a", "#9a3f93", "#4d4bbf", "#dd6a2c", "#7a8aa8"],
|
|
139
|
+
heat: {
|
|
140
|
+
neutral: "#e1e6ee",
|
|
141
|
+
under: "#0f8060",
|
|
142
|
+
over: "#b8431a",
|
|
143
|
+
seqLow: "#f0f3f7",
|
|
144
|
+
seqHigh: "#a14708",
|
|
145
|
+
empty: "rgba(148,163,184,0.14)"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
dark: {
|
|
149
|
+
bgPage: "#242933",
|
|
150
|
+
bgSurface: "#2e3440",
|
|
151
|
+
bgSurface2: "#3b4252",
|
|
152
|
+
border: "#434c5e",
|
|
153
|
+
textPrimary: "#eceff4",
|
|
154
|
+
textSecondary: "#d4d7de",
|
|
155
|
+
textMuted: "#afb3bc",
|
|
156
|
+
brand: "#88c0d0",
|
|
157
|
+
brandHover: "#a3d4e0",
|
|
158
|
+
brandContrast: "#1c2027",
|
|
159
|
+
moneyIncome: "#4ecf9c",
|
|
160
|
+
moneyExpense: "#e8a24f",
|
|
161
|
+
moneyNet: "#caa0e0",
|
|
162
|
+
moneyNeutral: "#9aa5b8",
|
|
163
|
+
chart: ["#7fb4e6", "#5ec9d6", "#5cc483", "#dccb6b", "#e87e96", "#bd6fce", "#9389f2", "#ef8f4a", "#8693ad"],
|
|
164
|
+
heat: {
|
|
165
|
+
neutral: "#3b4252",
|
|
166
|
+
under: "#4ecf9c",
|
|
167
|
+
over: "#e8a24f",
|
|
168
|
+
seqLow: "#33373f",
|
|
169
|
+
seqHigh: "#e8a24f",
|
|
170
|
+
empty: "rgba(148,163,184,0.10)"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: "indigo-noir",
|
|
176
|
+
name: "Indigo Noir",
|
|
177
|
+
blurb: "Crisp light \xB7 deep indigo",
|
|
178
|
+
light: {
|
|
179
|
+
bgPage: "#e8eaf2",
|
|
180
|
+
bgSurface: "#f6f7fb",
|
|
181
|
+
bgSurface2: "#eef1f8",
|
|
182
|
+
border: "#dadfeb",
|
|
183
|
+
textPrimary: "#1b1f2e",
|
|
184
|
+
textSecondary: "#494d5a",
|
|
185
|
+
textMuted: "#626572",
|
|
186
|
+
brand: "#4338ca",
|
|
187
|
+
brandHover: "#3730a3",
|
|
188
|
+
brandContrast: "#ffffff",
|
|
189
|
+
moneyIncome: "#0c6478",
|
|
190
|
+
moneyExpense: "#b45309",
|
|
191
|
+
moneyNet: "#7c3aed",
|
|
192
|
+
moneyNeutral: "#5b6478",
|
|
193
|
+
chart: ["#332288", "#88ccee", "#44aa99", "#117733", "#999933", "#ddcc77", "#cc6677", "#882255", "#aa4499"],
|
|
194
|
+
heat: {
|
|
195
|
+
neutral: "#eef1f7",
|
|
196
|
+
under: "#0c6478",
|
|
197
|
+
over: "#b45309",
|
|
198
|
+
seqLow: "#fdeed4",
|
|
199
|
+
seqHigh: "#b45309",
|
|
200
|
+
empty: "rgba(148,163,184,0.14)"
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
dark: {
|
|
204
|
+
bgPage: "#0e0f1c",
|
|
205
|
+
bgSurface: "#181a2c",
|
|
206
|
+
bgSurface2: "#21243a",
|
|
207
|
+
border: "#2e3252",
|
|
208
|
+
textPrimary: "#e6e8f4",
|
|
209
|
+
textSecondary: "#adafbe",
|
|
210
|
+
textMuted: "#8d90a0",
|
|
211
|
+
brand: "#8b93f8",
|
|
212
|
+
brandHover: "#aab1fb",
|
|
213
|
+
brandContrast: "#16182b",
|
|
214
|
+
moneyIncome: "#22c3b6",
|
|
215
|
+
// Kept byte-identical to DEFAULT_PRESET.dark, which IS this preset (dev#434).
|
|
216
|
+
moneyExpense: "#e4b035",
|
|
217
|
+
moneyNet: "#b39aef",
|
|
218
|
+
moneyNeutral: "#9aa1bd",
|
|
219
|
+
chart: ["#7e72d6", "#9fd8f2", "#5fc4b0", "#3fa45f", "#bfbf5e", "#e8dda0", "#e08c9a", "#c25a78", "#cc78be"],
|
|
220
|
+
heat: {
|
|
221
|
+
neutral: "#363a5a",
|
|
222
|
+
under: "#22c3b6",
|
|
223
|
+
over: "#fbbf24",
|
|
224
|
+
seqLow: "#3a2c14",
|
|
225
|
+
seqHigh: "#fbbf24",
|
|
226
|
+
empty: "rgba(148,163,184,0.10)"
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
id: "solar-dusk",
|
|
232
|
+
name: "Solar Dusk",
|
|
233
|
+
blurb: "Solarized warmth, easy on the eyes",
|
|
234
|
+
light: {
|
|
235
|
+
bgPage: "#ede3cf",
|
|
236
|
+
bgSurface: "#f6ecd9",
|
|
237
|
+
bgSurface2: "#f3ead6",
|
|
238
|
+
border: "#e2d6bd",
|
|
239
|
+
textPrimary: "#463f33",
|
|
240
|
+
textSecondary: "#50493c",
|
|
241
|
+
textMuted: "#696153",
|
|
242
|
+
brand: "#2c6979",
|
|
243
|
+
brandHover: "#1f515f",
|
|
244
|
+
brandContrast: "#ffffff",
|
|
245
|
+
moneyIncome: "#0b6650",
|
|
246
|
+
moneyExpense: "#9c6418",
|
|
247
|
+
moneyNet: "#7a4fa3",
|
|
248
|
+
moneyNeutral: "#6b6453",
|
|
249
|
+
chart: ["#332288", "#88ccee", "#44aa99", "#117733", "#999933", "#ddcc77", "#cc6677", "#882255", "#aa4499"],
|
|
250
|
+
heat: {
|
|
251
|
+
neutral: "#f1e7d2",
|
|
252
|
+
under: "#0b6650",
|
|
253
|
+
over: "#9c6418",
|
|
254
|
+
seqLow: "#f6ecd0",
|
|
255
|
+
seqHigh: "#9c6418",
|
|
256
|
+
empty: "rgba(148,163,184,0.14)"
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
dark: {
|
|
260
|
+
bgPage: "#0e1a1f",
|
|
261
|
+
bgSurface: "#15272e",
|
|
262
|
+
bgSurface2: "#1d333c",
|
|
263
|
+
border: "#2a4750",
|
|
264
|
+
textPrimary: "#d6cdb8",
|
|
265
|
+
textSecondary: "#c2bdab",
|
|
266
|
+
textMuted: "#9c9d91",
|
|
267
|
+
brand: "#5fb8cc",
|
|
268
|
+
brandHover: "#82cfe0",
|
|
269
|
+
brandContrast: "#0a161a",
|
|
270
|
+
moneyIncome: "#22b884",
|
|
271
|
+
moneyExpense: "#f0b94e",
|
|
272
|
+
moneyNet: "#bfa0e0",
|
|
273
|
+
moneyNeutral: "#9aa3a0",
|
|
274
|
+
chart: ["#7e72d6", "#9fd8f2", "#5fc4b0", "#3fa45f", "#bfbf5e", "#e8dda0", "#e08c9a", "#c25a78", "#c873c0"],
|
|
275
|
+
heat: {
|
|
276
|
+
neutral: "#26424b",
|
|
277
|
+
under: "#22b884",
|
|
278
|
+
over: "#f0b94e",
|
|
279
|
+
seqLow: "#1f3138",
|
|
280
|
+
seqHigh: "#f0b94e",
|
|
281
|
+
empty: "rgba(148,163,184,0.10)"
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
id: "zinc-mono",
|
|
287
|
+
name: "Zinc Mono",
|
|
288
|
+
blurb: "True-neutral chrome \xB7 data pops",
|
|
289
|
+
light: {
|
|
290
|
+
bgPage: "#ececec",
|
|
291
|
+
bgSurface: "#f7f7f7",
|
|
292
|
+
bgSurface2: "#f4f4f5",
|
|
293
|
+
border: "#e4e4e7",
|
|
294
|
+
textPrimary: "#18181b",
|
|
295
|
+
textSecondary: "#4e4e50",
|
|
296
|
+
textMuted: "#676769",
|
|
297
|
+
brand: "#1d4ed8",
|
|
298
|
+
brandHover: "#1e40af",
|
|
299
|
+
brandContrast: "#ffffff",
|
|
300
|
+
moneyIncome: "#0e7490",
|
|
301
|
+
moneyExpense: "#cf4310",
|
|
302
|
+
moneyNet: "#7c3aed",
|
|
303
|
+
moneyNeutral: "#52525b",
|
|
304
|
+
chart: ["#332288", "#88ccee", "#44aa99", "#117733", "#999933", "#ddcc77", "#cc6677", "#882255", "#aa4499"],
|
|
305
|
+
heat: {
|
|
306
|
+
neutral: "#f4f4f5",
|
|
307
|
+
under: "#0e7490",
|
|
308
|
+
over: "#cf4310",
|
|
309
|
+
seqLow: "#fdeede",
|
|
310
|
+
seqHigh: "#cf4310",
|
|
311
|
+
empty: "rgba(148,163,184,0.14)"
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
dark: {
|
|
315
|
+
bgPage: "#09090b",
|
|
316
|
+
bgSurface: "#18181b",
|
|
317
|
+
bgSurface2: "#27272a",
|
|
318
|
+
border: "#3f3f46",
|
|
319
|
+
textPrimary: "#f4f4f5",
|
|
320
|
+
textSecondary: "#b2b2b3",
|
|
321
|
+
textMuted: "#929294",
|
|
322
|
+
brand: "#60a5fa",
|
|
323
|
+
brandHover: "#93c5fd",
|
|
324
|
+
brandContrast: "#0b1220",
|
|
325
|
+
moneyIncome: "#22d3ee",
|
|
326
|
+
moneyExpense: "#f97316",
|
|
327
|
+
moneyNet: "#c4b5fd",
|
|
328
|
+
moneyNeutral: "#a1a1aa",
|
|
329
|
+
chart: ["#7e72d6", "#9fd8f2", "#5fc4b0", "#3fa45f", "#bfbf5e", "#e8dda0", "#e08c9a", "#c25a78", "#cc78be"],
|
|
330
|
+
heat: {
|
|
331
|
+
neutral: "#3f3f46",
|
|
332
|
+
under: "#22d3ee",
|
|
333
|
+
over: "#f97316",
|
|
334
|
+
seqLow: "#3a2410",
|
|
335
|
+
seqHigh: "#f97316",
|
|
336
|
+
empty: "rgba(148,163,184,0.10)"
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
];
|
|
341
|
+
const IMPRINT_HUES_LIGHT = [
|
|
342
|
+
"#009E73",
|
|
343
|
+
// brand green — first series
|
|
344
|
+
"#C475FD",
|
|
345
|
+
// lavender — creative
|
|
346
|
+
"#4467A3",
|
|
347
|
+
// blue — cool / info
|
|
348
|
+
"#BD8233",
|
|
349
|
+
// ochre — earth / commodity
|
|
350
|
+
"#AE3030",
|
|
351
|
+
// matte red — bad / loss / error
|
|
352
|
+
"#2ABCCD",
|
|
353
|
+
// cyan — sky / tech-cool
|
|
354
|
+
"#954477",
|
|
355
|
+
// rose — wellness / health
|
|
356
|
+
"#99B314",
|
|
357
|
+
// lime — growth / nature
|
|
358
|
+
"#DDCC77"
|
|
359
|
+
// amber — anyplot's semantic anchor, used here as slot 9
|
|
360
|
+
];
|
|
361
|
+
const IMPRINT_HUES_DARK = [
|
|
362
|
+
"#009E73",
|
|
363
|
+
"#C475FD",
|
|
364
|
+
"#4467A3",
|
|
365
|
+
"#BD8233",
|
|
366
|
+
"#BF413E",
|
|
367
|
+
// matte red, L-lifted for our dark surface
|
|
368
|
+
"#2ABCCD",
|
|
369
|
+
"#A25083",
|
|
370
|
+
// rose, L-lifted for our dark surface
|
|
371
|
+
"#99B314",
|
|
372
|
+
"#DDCC77"
|
|
373
|
+
];
|
|
374
|
+
const IMPRINT_PRESET = {
|
|
375
|
+
id: "imprint",
|
|
376
|
+
name: "Imprint",
|
|
377
|
+
blurb: "Colourblind-safe chart hues by anyplot.ai",
|
|
378
|
+
light: { ...DEFAULT_PRESET.light, chart: IMPRINT_HUES_LIGHT },
|
|
379
|
+
dark: { ...DEFAULT_PRESET.dark, chart: IMPRINT_HUES_DARK }
|
|
380
|
+
};
|
|
381
|
+
const PALETTES = [DEFAULT_PRESET, IMPRINT_PRESET];
|
|
382
|
+
function presetById(id) {
|
|
383
|
+
return PALETTES.find((p) => p.id === id) ?? DEFAULT_PRESET;
|
|
384
|
+
}
|
|
385
|
+
const TOKEN_VARS = [
|
|
386
|
+
"--bg-page",
|
|
387
|
+
"--bg-surface",
|
|
388
|
+
"--bg-surface-2",
|
|
389
|
+
"--border",
|
|
390
|
+
"--text-primary",
|
|
391
|
+
"--text-secondary",
|
|
392
|
+
"--text-muted",
|
|
393
|
+
"--brand",
|
|
394
|
+
"--brand-hover",
|
|
395
|
+
"--brand-contrast",
|
|
396
|
+
"--money-income",
|
|
397
|
+
"--money-expense",
|
|
398
|
+
"--money-net",
|
|
399
|
+
"--money-neutral",
|
|
400
|
+
"--chart-1",
|
|
401
|
+
"--chart-2",
|
|
402
|
+
"--chart-3",
|
|
403
|
+
"--chart-4",
|
|
404
|
+
"--chart-5",
|
|
405
|
+
"--chart-6",
|
|
406
|
+
"--chart-7",
|
|
407
|
+
"--chart-8",
|
|
408
|
+
"--chart-9"
|
|
409
|
+
];
|
|
410
|
+
function applyTokenSet(el, t) {
|
|
411
|
+
el.style.setProperty("--bg-page", t.bgPage);
|
|
412
|
+
el.style.setProperty("--bg-surface", t.bgSurface);
|
|
413
|
+
el.style.setProperty("--bg-surface-2", t.bgSurface2);
|
|
414
|
+
el.style.setProperty("--border", t.border);
|
|
415
|
+
el.style.setProperty("--text-primary", t.textPrimary);
|
|
416
|
+
el.style.setProperty("--text-secondary", t.textSecondary);
|
|
417
|
+
el.style.setProperty("--text-muted", t.textMuted);
|
|
418
|
+
el.style.setProperty("--brand", t.brand);
|
|
419
|
+
el.style.setProperty("--brand-hover", t.brandHover);
|
|
420
|
+
el.style.setProperty("--brand-contrast", t.brandContrast);
|
|
421
|
+
el.style.setProperty("--money-income", t.moneyIncome);
|
|
422
|
+
el.style.setProperty("--money-expense", t.moneyExpense);
|
|
423
|
+
el.style.setProperty("--money-net", t.moneyNet);
|
|
424
|
+
el.style.setProperty("--money-neutral", t.moneyNeutral);
|
|
425
|
+
t.chart.forEach((c, i) => el.style.setProperty(`--chart-${i + 1}`, c));
|
|
426
|
+
}
|
|
427
|
+
function clearTokenSet(el) {
|
|
428
|
+
for (const v of TOKEN_VARS) el.style.removeProperty(v);
|
|
429
|
+
}
|
|
430
|
+
export {
|
|
431
|
+
ALTERNATIVE_PRESETS,
|
|
432
|
+
DEFAULT_PRESET,
|
|
433
|
+
IMPRINT_PRESET,
|
|
434
|
+
PALETTES,
|
|
435
|
+
TOKEN_VARS,
|
|
436
|
+
applyTokenSet,
|
|
437
|
+
clearTokenSet,
|
|
438
|
+
presetById
|
|
439
|
+
};
|
|
440
|
+
//# sourceMappingURL=palette-presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/theme/palette-presets.ts"],"sourcesContent":["// Appearance presets — the single source of truth for the \"palette switcher\"\n// (feedback #307). Each preset is a full set of design-token values for BOTH\n// light and dark, covering the page/surface backgrounds, the brand accent, the\n// semantic money trio and the 9-colour categorical chart palette, plus the\n// heatmap stops. A preset is applied at runtime by writing these as CSS custom\n// properties onto <html> (see palette-store.ts), which instantly re-skins every\n// token-driven surface and chart. The two heatmaps and the treemap interpolate\n// concrete hex in JS, so they read the same values from here via the hooks in\n// palette-store.\n//\n// The alternative presets below were designed + accessibility-vetted as a set\n// (each is CVD-safe across protan/deutan/tritan, money is never red/green, and\n// text/background contrast clears WCAG AA on both themes). To promote one to the\n// app-wide default, copy its values into the :root/.dark blocks in tokens.css\n// (the default preset here mirrors those exactly).\n\nimport type { HeatStops } from \"./chart-palette\";\n\nexport interface TokenSet {\n // Backgrounds & chrome\n bgPage: string;\n bgSurface: string;\n bgSurface2: string;\n border: string;\n textPrimary: string;\n // The two quieter text roles. Derived per preset by blending `textPrimary` toward\n // that preset's own surfaces until the contrast against the WORST of bgPage /\n // bgSurface / bgSurface2 hits 7:1 and 4.8:1 — so both clear WCAG AA for normal text\n // (4.5:1) on every surface they can land on, and both inherit the preset's warmth\n // instead of importing a cool grey from Tailwind's palette.\n textSecondary: string;\n textMuted: string;\n // Interactive brand accent\n brand: string;\n brandHover: string;\n brandContrast: string;\n // Semantic money (never red/green — CVD-safe, paired with +/- cues elsewhere)\n moneyIncome: string;\n moneyExpense: string;\n moneyNet: string;\n moneyNeutral: string;\n // Categorical chart series (Paul Tol \"Muted\" by default — CVD-safe), exactly 9\n chart: string[];\n // Heatmap interpolation stops (variance diverging + spending sequential)\n heat: HeatStops;\n}\n\nexport interface PalettePreset {\n id: string;\n name: string;\n blurb: string;\n light: TokenSet;\n dark: TokenSet;\n}\n\n// The shipped default (feedback #328): SOLAR-DUSK warm light + INDIGO-NOIR deep\n// dark surfaces — the two curated presets the user picked per mode — but with a\n// SINGLE unified brand accent (indigo) across both modes rather than each\n// preset's own accent (the user asked for the brand accent to stay the same).\n// So the light block is Solar Dusk with its teal brand overridden to indigo, and\n// the dark block is Indigo Noir (already indigo). The money trio\n// (income/expense/net) drives the chart bars and stays palette-driven so those\n// semantic colours adapt to each mode's contrast (best practice — feedback #328).\nexport const DEFAULT_PRESET: PalettePreset = {\n id: \"default\",\n name: \"Default\",\n blurb: \"Solar-dusk light · indigo-noir dark\",\n light: {\n // Solar Dusk (light) surfaces, with the brand unified to indigo (see above).\n bgPage: \"#ede3cf\",\n bgSurface: \"#f6ecd9\",\n bgSurface2: \"#f3ead6\",\n border: \"#e2d6bd\",\n textPrimary: \"#463f33\",\n textSecondary: \"#50493c\",\n textMuted: \"#696153\",\n brand: \"#4f46e5\",\n brandHover: \"#4338ca\",\n brandContrast: \"#ffffff\",\n moneyIncome: \"#0b6650\",\n moneyExpense: \"#9c6418\",\n moneyNet: \"#7a4fa3\",\n moneyNeutral: \"#6b6453\",\n chart: [\"#332288\", \"#88ccee\", \"#44aa99\", \"#117733\", \"#999933\", \"#ddcc77\", \"#cc6677\", \"#882255\", \"#aa4499\"],\n heat: {\n neutral: \"#f1e7d2\",\n under: \"#0b6650\",\n over: \"#9c6418\",\n seqLow: \"#f6ecd0\",\n seqHigh: \"#9c6418\",\n empty: \"rgba(148,163,184,0.14)\",\n },\n },\n dark: {\n // Indigo Noir (dark)\n bgPage: \"#0e0f1c\",\n bgSurface: \"#181a2c\",\n bgSurface2: \"#21243a\",\n border: \"#2e3252\",\n textPrimary: \"#e6e8f4\",\n textSecondary: \"#adafbe\",\n textMuted: \"#8d90a0\",\n brand: \"#8b93f8\",\n brandHover: \"#aab1fb\",\n brandContrast: \"#16182b\",\n moneyIncome: \"#22c3b6\",\n // Amber-400 (#fbbf24) sat at OKLab L 0.84 while every other dark token lives\n // at 0.68–0.74, so outflows outshouted the inflows they are paired with. Same\n // hue and chroma, pulled to L 0.785 (dev#434). The heat stops below keep the\n // brighter amber on purpose: a gradient endpoint is meant to be the loudest\n // thing in its scale, and it is a fill, not a figure.\n moneyExpense: \"#e4b035\",\n moneyNet: \"#b39aef\",\n moneyNeutral: \"#9aa1bd\",\n chart: [\"#7e72d6\", \"#9fd8f2\", \"#5fc4b0\", \"#3fa45f\", \"#bfbf5e\", \"#e8dda0\", \"#e08c9a\", \"#c25a78\", \"#cc78be\"],\n heat: {\n neutral: \"#363a5a\",\n under: \"#22c3b6\",\n over: \"#fbbf24\",\n seqLow: \"#3a2c14\",\n seqHigh: \"#fbbf24\",\n empty: \"rgba(148,163,184,0.10)\",\n },\n },\n};\n\n// Vetted alternatives to preview (CVD-safe, WCAG-AA on both themes).\nexport const ALTERNATIVE_PRESETS: PalettePreset[] = [\n {\n id: \"warm-paper\",\n name: \"Warm Paper\",\n blurb: \"Cream paper · warm charcoal\",\n light: {\n bgPage: \"#ece5d6\",\n bgSurface: \"#f5efe3\",\n bgSurface2: \"#efe9dc\",\n border: \"#e2dcce\",\n textPrimary: \"#2b2622\",\n textSecondary: \"#4f4a44\",\n textMuted: \"#68625b\",\n brand: \"#9a5b34\",\n brandHover: \"#824827\",\n brandContrast: \"#fdf8f2\",\n moneyIncome: \"#0e7490\",\n moneyExpense: \"#8f3f0a\",\n moneyNet: \"#7c4dab\",\n moneyNeutral: \"#6b6258\",\n chart: [\"#332288\", \"#88ccee\", \"#44aa99\", \"#117733\", \"#999933\", \"#ddcc77\", \"#cc6677\", \"#882255\", \"#aa4499\"],\n heat: {\n neutral: \"#efe9dc\",\n under: \"#0e7490\",\n over: \"#b45309\",\n seqLow: \"#fbeed2\",\n seqHigh: \"#b45309\",\n empty: \"rgba(148,163,184,0.14)\",\n },\n },\n dark: {\n bgPage: \"#211e1a\",\n bgSurface: \"#2a2622\",\n bgSurface2: \"#322d27\",\n border: \"#3d372f\",\n textPrimary: \"#e8e2d6\",\n textSecondary: \"#bfb9af\",\n textMuted: \"#9e998f\",\n brand: \"#e0986a\",\n brandHover: \"#ecae85\",\n brandContrast: \"#2a1c10\",\n moneyIncome: \"#4dd4c4\",\n moneyExpense: \"#fbbf3a\",\n moneyNet: \"#bfa0e0\",\n moneyNeutral: \"#a39a8c\",\n chart: [\"#7e72d6\", \"#9fd8f2\", \"#5fc4b0\", \"#3fa45f\", \"#bfbf5e\", \"#e8dda0\", \"#e08c9a\", \"#cf6488\", \"#cc78be\"],\n heat: {\n neutral: \"#3a352e\",\n under: \"#4dd4c4\",\n over: \"#fbbf3a\",\n seqLow: \"#2c2014\",\n seqHigh: \"#fbbf3a\",\n empty: \"rgba(148,163,184,0.10)\",\n },\n },\n },\n {\n id: \"nord-frost\",\n name: \"Nord Frost\",\n blurb: \"Cool snow · polar night\",\n light: {\n bgPage: \"#e2e7ef\",\n bgSurface: \"#f0f3f8\",\n bgSurface2: \"#e1e6ee\",\n border: \"#d3dae6\",\n textPrimary: \"#2e3440\",\n textSecondary: \"#454b56\",\n textMuted: \"#5e636e\",\n brand: \"#3b6ea5\",\n brandHover: \"#305a86\",\n brandContrast: \"#ffffff\",\n moneyIncome: \"#0f8060\",\n moneyExpense: \"#b8431a\",\n moneyNet: \"#6b4fa0\",\n moneyNeutral: \"#5b6577\",\n chart: [\"#3a6ea5\", \"#56b6c2\", \"#2f7d4f\", \"#cdb52f\", \"#d05f7a\", \"#9a3f93\", \"#4d4bbf\", \"#dd6a2c\", \"#7a8aa8\"],\n heat: {\n neutral: \"#e1e6ee\",\n under: \"#0f8060\",\n over: \"#b8431a\",\n seqLow: \"#f0f3f7\",\n seqHigh: \"#a14708\",\n empty: \"rgba(148,163,184,0.14)\",\n },\n },\n dark: {\n bgPage: \"#242933\",\n bgSurface: \"#2e3440\",\n bgSurface2: \"#3b4252\",\n border: \"#434c5e\",\n textPrimary: \"#eceff4\",\n textSecondary: \"#d4d7de\",\n textMuted: \"#afb3bc\",\n brand: \"#88c0d0\",\n brandHover: \"#a3d4e0\",\n brandContrast: \"#1c2027\",\n moneyIncome: \"#4ecf9c\",\n moneyExpense: \"#e8a24f\",\n moneyNet: \"#caa0e0\",\n moneyNeutral: \"#9aa5b8\",\n chart: [\"#7fb4e6\", \"#5ec9d6\", \"#5cc483\", \"#dccb6b\", \"#e87e96\", \"#bd6fce\", \"#9389f2\", \"#ef8f4a\", \"#8693ad\"],\n heat: {\n neutral: \"#3b4252\",\n under: \"#4ecf9c\",\n over: \"#e8a24f\",\n seqLow: \"#33373f\",\n seqHigh: \"#e8a24f\",\n empty: \"rgba(148,163,184,0.10)\",\n },\n },\n },\n {\n id: \"indigo-noir\",\n name: \"Indigo Noir\",\n blurb: \"Crisp light · deep indigo\",\n light: {\n bgPage: \"#e8eaf2\",\n bgSurface: \"#f6f7fb\",\n bgSurface2: \"#eef1f8\",\n border: \"#dadfeb\",\n textPrimary: \"#1b1f2e\",\n textSecondary: \"#494d5a\",\n textMuted: \"#626572\",\n brand: \"#4338ca\",\n brandHover: \"#3730a3\",\n brandContrast: \"#ffffff\",\n moneyIncome: \"#0c6478\",\n moneyExpense: \"#b45309\",\n moneyNet: \"#7c3aed\",\n moneyNeutral: \"#5b6478\",\n chart: [\"#332288\", \"#88ccee\", \"#44aa99\", \"#117733\", \"#999933\", \"#ddcc77\", \"#cc6677\", \"#882255\", \"#aa4499\"],\n heat: {\n neutral: \"#eef1f7\",\n under: \"#0c6478\",\n over: \"#b45309\",\n seqLow: \"#fdeed4\",\n seqHigh: \"#b45309\",\n empty: \"rgba(148,163,184,0.14)\",\n },\n },\n dark: {\n bgPage: \"#0e0f1c\",\n bgSurface: \"#181a2c\",\n bgSurface2: \"#21243a\",\n border: \"#2e3252\",\n textPrimary: \"#e6e8f4\",\n textSecondary: \"#adafbe\",\n textMuted: \"#8d90a0\",\n brand: \"#8b93f8\",\n brandHover: \"#aab1fb\",\n brandContrast: \"#16182b\",\n moneyIncome: \"#22c3b6\",\n // Kept byte-identical to DEFAULT_PRESET.dark, which IS this preset (dev#434).\n moneyExpense: \"#e4b035\",\n moneyNet: \"#b39aef\",\n moneyNeutral: \"#9aa1bd\",\n chart: [\"#7e72d6\", \"#9fd8f2\", \"#5fc4b0\", \"#3fa45f\", \"#bfbf5e\", \"#e8dda0\", \"#e08c9a\", \"#c25a78\", \"#cc78be\"],\n heat: {\n neutral: \"#363a5a\",\n under: \"#22c3b6\",\n over: \"#fbbf24\",\n seqLow: \"#3a2c14\",\n seqHigh: \"#fbbf24\",\n empty: \"rgba(148,163,184,0.10)\",\n },\n },\n },\n {\n id: \"solar-dusk\",\n name: \"Solar Dusk\",\n blurb: \"Solarized warmth, easy on the eyes\",\n light: {\n bgPage: \"#ede3cf\",\n bgSurface: \"#f6ecd9\",\n bgSurface2: \"#f3ead6\",\n border: \"#e2d6bd\",\n textPrimary: \"#463f33\",\n textSecondary: \"#50493c\",\n textMuted: \"#696153\",\n brand: \"#2c6979\",\n brandHover: \"#1f515f\",\n brandContrast: \"#ffffff\",\n moneyIncome: \"#0b6650\",\n moneyExpense: \"#9c6418\",\n moneyNet: \"#7a4fa3\",\n moneyNeutral: \"#6b6453\",\n chart: [\"#332288\", \"#88ccee\", \"#44aa99\", \"#117733\", \"#999933\", \"#ddcc77\", \"#cc6677\", \"#882255\", \"#aa4499\"],\n heat: {\n neutral: \"#f1e7d2\",\n under: \"#0b6650\",\n over: \"#9c6418\",\n seqLow: \"#f6ecd0\",\n seqHigh: \"#9c6418\",\n empty: \"rgba(148,163,184,0.14)\",\n },\n },\n dark: {\n bgPage: \"#0e1a1f\",\n bgSurface: \"#15272e\",\n bgSurface2: \"#1d333c\",\n border: \"#2a4750\",\n textPrimary: \"#d6cdb8\",\n textSecondary: \"#c2bdab\",\n textMuted: \"#9c9d91\",\n brand: \"#5fb8cc\",\n brandHover: \"#82cfe0\",\n brandContrast: \"#0a161a\",\n moneyIncome: \"#22b884\",\n moneyExpense: \"#f0b94e\",\n moneyNet: \"#bfa0e0\",\n moneyNeutral: \"#9aa3a0\",\n chart: [\"#7e72d6\", \"#9fd8f2\", \"#5fc4b0\", \"#3fa45f\", \"#bfbf5e\", \"#e8dda0\", \"#e08c9a\", \"#c25a78\", \"#c873c0\"],\n heat: {\n neutral: \"#26424b\",\n under: \"#22b884\",\n over: \"#f0b94e\",\n seqLow: \"#1f3138\",\n seqHigh: \"#f0b94e\",\n empty: \"rgba(148,163,184,0.10)\",\n },\n },\n },\n {\n id: \"zinc-mono\",\n name: \"Zinc Mono\",\n blurb: \"True-neutral chrome · data pops\",\n light: {\n bgPage: \"#ececec\",\n bgSurface: \"#f7f7f7\",\n bgSurface2: \"#f4f4f5\",\n border: \"#e4e4e7\",\n textPrimary: \"#18181b\",\n textSecondary: \"#4e4e50\",\n textMuted: \"#676769\",\n brand: \"#1d4ed8\",\n brandHover: \"#1e40af\",\n brandContrast: \"#ffffff\",\n moneyIncome: \"#0e7490\",\n moneyExpense: \"#cf4310\",\n moneyNet: \"#7c3aed\",\n moneyNeutral: \"#52525b\",\n chart: [\"#332288\", \"#88ccee\", \"#44aa99\", \"#117733\", \"#999933\", \"#ddcc77\", \"#cc6677\", \"#882255\", \"#aa4499\"],\n heat: {\n neutral: \"#f4f4f5\",\n under: \"#0e7490\",\n over: \"#cf4310\",\n seqLow: \"#fdeede\",\n seqHigh: \"#cf4310\",\n empty: \"rgba(148,163,184,0.14)\",\n },\n },\n dark: {\n bgPage: \"#09090b\",\n bgSurface: \"#18181b\",\n bgSurface2: \"#27272a\",\n border: \"#3f3f46\",\n textPrimary: \"#f4f4f5\",\n textSecondary: \"#b2b2b3\",\n textMuted: \"#929294\",\n brand: \"#60a5fa\",\n brandHover: \"#93c5fd\",\n brandContrast: \"#0b1220\",\n moneyIncome: \"#22d3ee\",\n moneyExpense: \"#f97316\",\n moneyNet: \"#c4b5fd\",\n moneyNeutral: \"#a1a1aa\",\n chart: [\"#7e72d6\", \"#9fd8f2\", \"#5fc4b0\", \"#3fa45f\", \"#bfbf5e\", \"#e8dda0\", \"#e08c9a\", \"#c25a78\", \"#cc78be\"],\n heat: {\n neutral: \"#3f3f46\",\n under: \"#22d3ee\",\n over: \"#f97316\",\n seqLow: \"#3a2410\",\n seqHigh: \"#f97316\",\n empty: \"rgba(148,163,184,0.10)\",\n },\n },\n },\n];\n\n// ── \"Imprint\" chart hues (feedback #119) ──────────────────────────────────────\n// anyplot's categorical palette (https://anyplot.ai/palette), by a colleague of\n// Marcel's. 8 hues + an amber semantic anchor, derived from Wong 2011 by a\n// Petroff-style max-min ΔE search in CAM02-UCS with Machado 2009 CVD simulation —\n// the same lineage as our default Paul Tol \"Muted\", one generation on, and tuned\n// for exactly the warm cream paper our light theme uses.\n//\n// This preset is DEFAULT_PRESET with ONLY the 9 categorical chart hues swapped;\n// surfaces, brand and the semantic money trio stay put, because those were their\n// own deliberate decisions (#307/#328) and are not what the palette is for. The\n// heatmap stops likewise stay teal/amber: they encode under/over, and imprint's\n// own diverging ramp is red↔blue, which would fight the money semantics.\n//\n// Measured on our surfaces (CIEDE2000, Machado severity-100, 8 like-for-like\n// slots on the cream light surface #f6ecd9) — neither palette dominates:\n// Paul Tol Muted min-contrast 1.38 · worst-CVD ΔE00 11.8 · normal ΔE00 16.1\n// imprint min-contrast 1.95 · worst-CVD ΔE00 7.2 · normal ΔE00 22.2\n// i.e. imprint is punchier and has no near-invisible pale slot (Tol's #88ccee\n// sits at 1.5:1 on cream), while Tol separates better under colour-vision\n// deficiency. So this ships as a CHOICE, not as a new default.\n//\n// The dark set keeps imprint's hues verbatim except matte-red and rose, whose\n// lightness is lifted (oklch L 0.50→0.55) because verbatim they land at 2.67:1\n// and 2.76:1 on our deep-indigo dark surface — under WCAG 2.1 SC 1.4.11's 3:1\n// non-text minimum. Lifted they clear it at 3.30:1 / 3.28:1. anyplot documents\n// the same shortfall on their own dark ground and answers it with a stroke halo;\n// lifting keeps the fix in the token layer instead of every chart component.\nconst IMPRINT_HUES_LIGHT = [\n \"#009E73\", // brand green — first series\n \"#C475FD\", // lavender — creative\n \"#4467A3\", // blue — cool / info\n \"#BD8233\", // ochre — earth / commodity\n \"#AE3030\", // matte red — bad / loss / error\n \"#2ABCCD\", // cyan — sky / tech-cool\n \"#954477\", // rose — wellness / health\n \"#99B314\", // lime — growth / nature\n \"#DDCC77\", // amber — anyplot's semantic anchor, used here as slot 9\n];\nconst IMPRINT_HUES_DARK = [\n \"#009E73\",\n \"#C475FD\",\n \"#4467A3\",\n \"#BD8233\",\n \"#BF413E\", // matte red, L-lifted for our dark surface\n \"#2ABCCD\",\n \"#A25083\", // rose, L-lifted for our dark surface\n \"#99B314\",\n \"#DDCC77\",\n];\n\nexport const IMPRINT_PRESET: PalettePreset = {\n id: \"imprint\",\n name: \"Imprint\",\n blurb: \"Colourblind-safe chart hues by anyplot.ai\",\n light: { ...DEFAULT_PRESET.light, chart: IMPRINT_HUES_LIGHT },\n dark: { ...DEFAULT_PRESET.dark, chart: IMPRINT_HUES_DARK },\n};\n\n// The full-theme switcher from #307 stayed retired (feedback #328) — the default\n// is still the single source of truth for surfaces, brand and money, and\n// ALTERNATIVE_PRESETS above remains a reference bank only. What IS selectable is\n// the categorical chart ramp (feedback #119), so these two presets are the live\n// set; presetById falls back to the default for any stale persisted id.\nexport const PALETTES: PalettePreset[] = [DEFAULT_PRESET, IMPRINT_PRESET];\n\nexport function presetById(id: string): PalettePreset {\n return PALETTES.find((p) => p.id === id) ?? DEFAULT_PRESET;\n}\n\n// The CSS custom properties a preset writes onto <html>. Also used to clear the\n// overrides when returning to the default.\nexport const TOKEN_VARS = [\n \"--bg-page\",\n \"--bg-surface\",\n \"--bg-surface-2\",\n \"--border\",\n \"--text-primary\",\n \"--text-secondary\",\n \"--text-muted\",\n \"--brand\",\n \"--brand-hover\",\n \"--brand-contrast\",\n \"--money-income\",\n \"--money-expense\",\n \"--money-net\",\n \"--money-neutral\",\n \"--chart-1\",\n \"--chart-2\",\n \"--chart-3\",\n \"--chart-4\",\n \"--chart-5\",\n \"--chart-6\",\n \"--chart-7\",\n \"--chart-8\",\n \"--chart-9\",\n] as const;\n\n/** Write a token set onto an element's inline style as CSS custom properties. */\nexport function applyTokenSet(el: HTMLElement, t: TokenSet): void {\n el.style.setProperty(\"--bg-page\", t.bgPage);\n el.style.setProperty(\"--bg-surface\", t.bgSurface);\n el.style.setProperty(\"--bg-surface-2\", t.bgSurface2);\n el.style.setProperty(\"--border\", t.border);\n el.style.setProperty(\"--text-primary\", t.textPrimary);\n el.style.setProperty(\"--text-secondary\", t.textSecondary);\n el.style.setProperty(\"--text-muted\", t.textMuted);\n el.style.setProperty(\"--brand\", t.brand);\n el.style.setProperty(\"--brand-hover\", t.brandHover);\n el.style.setProperty(\"--brand-contrast\", t.brandContrast);\n el.style.setProperty(\"--money-income\", t.moneyIncome);\n el.style.setProperty(\"--money-expense\", t.moneyExpense);\n el.style.setProperty(\"--money-net\", t.moneyNet);\n el.style.setProperty(\"--money-neutral\", t.moneyNeutral);\n t.chart.forEach((c, i) => el.style.setProperty(`--chart-${i + 1}`, c));\n}\n\n/** Remove all preset overrides so the tokens.css :root/.dark defaults take over. */\nexport function clearTokenSet(el: HTMLElement): void {\n for (const v of TOKEN_VARS) el.style.removeProperty(v);\n}\n"],"mappings":"AA+DO,MAAM,iBAAgC;AAAA,EAC3C,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA;AAAA,IAEL,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,aAAa;AAAA,IACb,cAAc;AAAA,IACd,UAAU;AAAA,IACV,cAAc;AAAA,IACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,IACzG,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,MAAM;AAAA;AAAA,IAEJ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMb,cAAc;AAAA,IACd,UAAU;AAAA,IACV,cAAc;AAAA,IACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,IACzG,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAGO,MAAM,sBAAuC;AAAA,EAClD;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACzG,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACzG,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACzG,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACzG,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACzG,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA;AAAA,MAEb,cAAc;AAAA,MACd,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACzG,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACzG,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACzG,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACzG,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,MACX,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU;AAAA,MACV,cAAc;AAAA,MACd,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACzG,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;AA6BA,MAAM,qBAAqB;AAAA,EACzB;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF;AACA,MAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AACF;AAEO,MAAM,iBAAgC;AAAA,EAC3C,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO,EAAE,GAAG,eAAe,OAAO,OAAO,mBAAmB;AAAA,EAC5D,MAAM,EAAE,GAAG,eAAe,MAAM,OAAO,kBAAkB;AAC3D;AAOO,MAAM,WAA4B,CAAC,gBAAgB,cAAc;AAEjE,SAAS,WAAW,IAA2B;AACpD,SAAO,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK;AAC9C;AAIO,MAAM,aAAa;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,SAAS,cAAc,IAAiB,GAAmB;AAChE,KAAG,MAAM,YAAY,aAAa,EAAE,MAAM;AAC1C,KAAG,MAAM,YAAY,gBAAgB,EAAE,SAAS;AAChD,KAAG,MAAM,YAAY,kBAAkB,EAAE,UAAU;AACnD,KAAG,MAAM,YAAY,YAAY,EAAE,MAAM;AACzC,KAAG,MAAM,YAAY,kBAAkB,EAAE,WAAW;AACpD,KAAG,MAAM,YAAY,oBAAoB,EAAE,aAAa;AACxD,KAAG,MAAM,YAAY,gBAAgB,EAAE,SAAS;AAChD,KAAG,MAAM,YAAY,WAAW,EAAE,KAAK;AACvC,KAAG,MAAM,YAAY,iBAAiB,EAAE,UAAU;AAClD,KAAG,MAAM,YAAY,oBAAoB,EAAE,aAAa;AACxD,KAAG,MAAM,YAAY,kBAAkB,EAAE,WAAW;AACpD,KAAG,MAAM,YAAY,mBAAmB,EAAE,YAAY;AACtD,KAAG,MAAM,YAAY,eAAe,EAAE,QAAQ;AAC9C,KAAG,MAAM,YAAY,mBAAmB,EAAE,YAAY;AACtD,IAAE,MAAM,QAAQ,CAAC,GAAG,MAAM,GAAG,MAAM,YAAY,WAAW,IAAI,CAAC,IAAI,CAAC,CAAC;AACvE;AAGO,SAAS,cAAc,IAAuB;AACnD,aAAW,KAAK,WAAY,IAAG,MAAM,eAAe,CAAC;AACvD;","names":[]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as zustand_middleware from 'zustand/middleware';
|
|
2
|
+
import { UseBoundStore, StoreApi } from 'zustand';
|
|
3
|
+
import { HeatStops } from './chart-palette.js';
|
|
4
|
+
import { TokenSet } from './palette-presets.js';
|
|
5
|
+
import { ThemeState, ThemeMode } from './theme-store.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Pre-hydration counterpart to `applyPersistedTheme`: read the palette id
|
|
9
|
+
* persisted under `storageKey` straight from localStorage and apply that preset's
|
|
10
|
+
* tokens for the given resolved `mode` to <html>, BEFORE React mounts (no flash of
|
|
11
|
+
* the default palette). Falls back to the default preset for missing/malformed
|
|
12
|
+
* state, so an app entrypoint never re-types the persist envelope.
|
|
13
|
+
*/
|
|
14
|
+
declare function applyPersistedPalette(storageKey: string, mode: ThemeMode): void;
|
|
15
|
+
interface PaletteState {
|
|
16
|
+
id: string;
|
|
17
|
+
setId: (id: string) => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build a palette store bound to a consumer-supplied localStorage key, wired to
|
|
21
|
+
* that app's theme store (for the active light/dark mode). Returns the palette
|
|
22
|
+
* hook plus the effect + selector hooks that read the active preset's tokens.
|
|
23
|
+
*/
|
|
24
|
+
declare function createPaletteStore(storageKey: string, useTheme: UseBoundStore<StoreApi<ThemeState>>): {
|
|
25
|
+
usePalette: UseBoundStore<Omit<StoreApi<PaletteState>, "setState" | "persist"> & {
|
|
26
|
+
setState(partial: PaletteState | Partial<PaletteState> | ((state: PaletteState) => PaletteState | Partial<PaletteState>), replace?: false | undefined): unknown;
|
|
27
|
+
setState(state: PaletteState | ((state: PaletteState) => PaletteState), replace: true): unknown;
|
|
28
|
+
persist: {
|
|
29
|
+
setOptions: (options: Partial<zustand_middleware.PersistOptions<PaletteState, PaletteState, unknown>>) => void;
|
|
30
|
+
clearStorage: () => void;
|
|
31
|
+
rehydrate: () => Promise<void> | void;
|
|
32
|
+
hasHydrated: () => boolean;
|
|
33
|
+
onHydrate: (fn: (state: PaletteState) => void) => () => void;
|
|
34
|
+
onFinishHydration: (fn: (state: PaletteState) => void) => () => void;
|
|
35
|
+
getOptions: () => Partial<zustand_middleware.PersistOptions<PaletteState, PaletteState, unknown>>;
|
|
36
|
+
};
|
|
37
|
+
}>;
|
|
38
|
+
useApplyPalette: () => void;
|
|
39
|
+
useActiveTokenSet: () => TokenSet;
|
|
40
|
+
useChartHex: () => string[];
|
|
41
|
+
useHeatStops: () => HeatStops;
|
|
42
|
+
};
|
|
43
|
+
type PaletteStore = ReturnType<typeof createPaletteStore>;
|
|
44
|
+
|
|
45
|
+
export { type PaletteStore, applyPersistedPalette, createPaletteStore };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { create } from "zustand";
|
|
3
|
+
import { persist } from "zustand/middleware";
|
|
4
|
+
import { logger } from "../lib/logger.js";
|
|
5
|
+
import { applyTokenSet, DEFAULT_PRESET, presetById } from "./palette-presets.js";
|
|
6
|
+
function applyPersistedPalette(storageKey, mode) {
|
|
7
|
+
let id = DEFAULT_PRESET.id;
|
|
8
|
+
try {
|
|
9
|
+
const blob = JSON.parse(localStorage.getItem(storageKey) ?? "{}");
|
|
10
|
+
if (blob.state?.id) id = blob.state.id;
|
|
11
|
+
} catch {
|
|
12
|
+
}
|
|
13
|
+
applyTokenSet(document.documentElement, presetById(id)[mode]);
|
|
14
|
+
}
|
|
15
|
+
function createPaletteStore(storageKey, useTheme) {
|
|
16
|
+
const usePalette = create()(
|
|
17
|
+
logger(
|
|
18
|
+
persist(
|
|
19
|
+
(set) => ({
|
|
20
|
+
id: DEFAULT_PRESET.id,
|
|
21
|
+
setId: (id) => set({ id })
|
|
22
|
+
}),
|
|
23
|
+
{ name: storageKey, version: 1 }
|
|
24
|
+
),
|
|
25
|
+
"palette"
|
|
26
|
+
)
|
|
27
|
+
);
|
|
28
|
+
function useApplyPalette() {
|
|
29
|
+
const id = usePalette((s) => s.id);
|
|
30
|
+
const mode = useTheme((s) => s.mode);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
applyTokenSet(document.documentElement, presetById(id)[mode]);
|
|
33
|
+
}, [id, mode]);
|
|
34
|
+
}
|
|
35
|
+
function useActiveTokenSet() {
|
|
36
|
+
const id = usePalette((s) => s.id);
|
|
37
|
+
const mode = useTheme((s) => s.mode);
|
|
38
|
+
return presetById(id)[mode];
|
|
39
|
+
}
|
|
40
|
+
function useChartHex() {
|
|
41
|
+
return useActiveTokenSet().chart;
|
|
42
|
+
}
|
|
43
|
+
function useHeatStops() {
|
|
44
|
+
return useActiveTokenSet().heat;
|
|
45
|
+
}
|
|
46
|
+
return { usePalette, useApplyPalette, useActiveTokenSet, useChartHex, useHeatStops };
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
applyPersistedPalette,
|
|
50
|
+
createPaletteStore
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=palette-store.js.map
|