conversion astryx

This commit is contained in:
2026-08-13 11:07:54 +05:30
parent 7c26470c52
commit d935542b11
36 changed files with 3843 additions and 684 deletions

102
src/theme/nearle.ts Normal file
View File

@@ -0,0 +1,102 @@
/**
* The Nearle theme for Astryx — PHASE 2.
*
* Every value here already existed in the codebase; nothing was invented for
* aesthetics. The light column is lifted verbatim from the eleven hardcoded
* constants at the top of `components/consoleUi.tsx` and from the two status
* colour maps beneath them. The dark column is new, because the console has
* never had a dark mode and there was nothing to lift.
*
* Written by hand rather than by `astryx theme`: that CLI command is an
* interactive wizard, and a generated file would still have needed every value
* below typed into it.
*
* TOKEN VALUES take one of two forms (see defineTheme's contract):
* 'string' — same in both modes
* ['light', 'dark'] — compiled to CSS light-dark()
*
* HOW MODE IS CHOSEN. `theme-neutral` ships no `prefers-color-scheme` block at
* all; Astryx switches on a `data-theme` attribute that the `<Theme>` provider
* stamps. So `mode="system"` on the provider is what connects this to the OS
* setting — the stylesheet alone will not do it.
*/
import { defineTheme } from '@astryxdesign/core';
/**
* The dark accent is the one value in this file that is not simply lifted, and
* it is the one that needs a human's approval.
*
* `BRAND` #662582 scores 9.76:1 on white — comfortably AA. On Astryx's dark
* surface #1F1F22 it is unreadable, and `BRAND_LIGHT` #9255AB only reaches
* **3.22:1**, which is below the 4.5:1 threshold. Measured candidates:
*
* #9255AB 3.22:1 BRAND_LIGHT as-is fails AA
* #A96FC4 4.51:1 passes by 0.01 no headroom
* #B57FD0 5.41:1 passes with room ← chosen
* #C48FDD 6.51:1 passes, drifts pastel
*
* #B57FD0 is the lightest value that still reads as the Nearle purple rather
* than as lilac. **Brand owner to confirm before dark mode ships.**
*/
const BRAND_DARK = '#B57FD0';
export const nearleTheme = defineTheme({
name: 'nearle',
typography: {
// Both families are already pulled in by the Google Fonts @import at the
// top of index.css, so this re-points Astryx at them rather than adding a
// request. Astryx does not load fonts itself — the consumer must.
body: { family: 'Public Sans', fallbacks: 'ui-sans-serif, system-ui, sans-serif' },
heading: { family: 'Public Sans', fallbacks: 'ui-sans-serif, system-ui, sans-serif' },
code: { family: 'JetBrains Mono', fallbacks: 'ui-monospace, SFMono-Regular, monospace' },
},
tokens: {
// ── Brand ───────────────────────────────────────────────────────────────
'--color-accent': ['#662582', BRAND_DARK],
'--color-on-accent': ['#FFFFFF', '#1B1420'],
// The alpha suffixes mirror consoleUi's `soft()` helper (18 ≈ 9%), which is
// what every tinted brand surface in the app is currently built from.
'--color-accent-muted': ['#66258218', `${BRAND_DARK}24`],
'--color-text-accent': ['#662582', BRAND_DARK],
'--color-icon-accent': ['#662582', BRAND_DARK],
// ── Text ── TEXT / TEXT_2 / TEXT_3 ──────────────────────────────────────
'--color-text-primary': ['#0f172a', '#ECE6F1'],
'--color-text-secondary': ['#64748b', '#B3A8BD'],
'--color-text-disabled': ['#94a3b8', '#85798F'],
// ── Surfaces ── SURFACE_ALT / DIVIDER ───────────────────────────────────
// The dark greys carry a slight violet bias so they sit under the accent
// as a chosen neutral rather than a stock grey.
'--color-background-surface': ['#FFFFFF', '#1C1724'],
'--color-background-body': ['#f8fafc', '#14101A'],
'--color-background-card': ['#FFFFFF', '#1C1724'],
'--color-background-popover': ['#FFFFFF', '#241D2E'],
'--color-background-muted': ['#f1f5f9', '#241D2E'],
// ── Lines ── BORDER / DIVIDER ───────────────────────────────────────────
'--color-border': ['#e2e8f0', '#352C40'],
'--color-border-emphasized': ['#cbd5e1', '#4A3E58'],
'--color-skeleton': ['#f1f5f9', '#241D2E'],
// ── Semantic ────────────────────────────────────────────────────────────
// Taken from ORDER_STATUS / DELIVERY_STATUS so a Badge and a status pill
// agree. Dark variants are lightened for the same contrast reason as the
// accent — the source values are tuned for white.
'--color-success': ['#10b981', '#34D399'],
'--color-error': ['#ef4444', '#F87171'],
'--color-warning': ['#f59e0b', '#FBBF24'],
// ── Elevation ── SHADOW_MD / SOFT / POP ─────────────────────────────────
// Dark mode gets its own shadows rather than the same rgba: a shadow tuned
// for a white ground is invisible on a dark one, so the alpha is raised.
'--shadow-low': ['0 8px 24px rgba(15, 23, 42, 0.08)', '0 8px 24px rgba(0, 0, 0, 0.45)'],
'--shadow-med': ['0 14px 40px rgba(15, 23, 42, 0.10)', '0 14px 40px rgba(0, 0, 0, 0.55)'],
'--shadow-high': ['0 18px 50px rgba(15, 23, 42, 0.18)', '0 18px 50px rgba(0, 0, 0, 0.65)'],
},
});
export default nearleTheme;