// ============================================================================ // Shared "DT" design tokens — canonical values extracted from the polished // pages (originally deliveries.js's "Batch" dropdown design language). // Every redesigned operator page should import from here instead of // redefining its own DT object, so radius/shadow/color decisions stay in one // place. See CLAUDE.md §6 for the full page-anatomy convention these tokens // support. // ============================================================================ export const DT = { radiusPill: 999, radiusCard: 14, radiusInner: 10, radiusField: 10, // Restrained, low-contrast elevation — corporate (Linear/Stripe), not flashy. shadowSoft: '0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.05)', shadowMd: '0 1px 3px rgba(15, 23, 42, 0.06)', shadowPop: '0 12px 32px rgba(15, 23, 42, 0.12)', textPrimary: '#0f172a', textSecondary: '#64748b', textMuted: '#94a3b8', borderSubtle: '#e2e8f0', borderHover: '#cbd5e1', divider: '#f1f5f9', surface: '#ffffff', surfaceAlt: '#f8fafc', brand: '#000000' }; // --------------------------------------------------------------------------- // Semantic status palette — lifecycle colours, deliberately distinct from the // brand (see root CLAUDE.md §6). Pages have historically inlined these hexes; // new code should reference STATUS so there is one place to change them. // // This map is the RAW HEX layer, for surfaces that take an arbitrary accent // (StatCard, AccentAvatar, chart series). To RENDER a status — a row badge or // a filter tab — use `themes/dt/status.js` instead: it resolves backend enums // and aliases, and carries the matching Astryx Badge/StatusDot variants and // icon alongside the hex. Reach for STATUS only when you need the bare colour. // This also replaces the `theme.palette.error/success/...` lookups that used // to pull the same colours out of the MUI theme. // --------------------------------------------------------------------------- export const STATUS = { pending: '#f59e0b', // amber accepted: '#6366f1', // indigo arrived: '#06b6d4', // cyan picked: '#8b5cf6', // light purple active: '#14b8a6', // teal skipped: '#f97316', // orange delivered: '#10b981', // emerald cancelled: '#ef4444', // red info: '#0ea5e9', // sky muted: '#94a3b8', // slate // Aliases for non-lifecycle usage (network banners, validation, …). success: '#10b981', warning: '#f59e0b', error: '#ef4444' }; // Quick alpha helpers (hex + percentage suffix). export const a = (c, suffix) => `${c}${suffix}`; export const tint = (c) => a(c, '08'); // very subtle surface tint export const soft = (c) => a(c, '18'); // soft chip / avatar bg export const ring = (c) => a(c, '26'); // focus ring color export const edge = (c) => a(c, '55'); // resting border // --------------------------------------------------------------------------- // ⛔ LEGACY — MUI-ONLY. Everything from here to the end of this file emits MUI // `sx` objects and cannot be used by an Astryx page. // // They stay only because the pages still awaiting conversion import them // (`pillFieldSx` ×3 files, `tableScrollSx` ×4, `tableHeadSx` ×3, // `tableRowSx` ×3). They are deleted along with the MUI dependency once the // last page converts — do NOT add a new call site. // // Astryx equivalents: // pillFieldSx → nothing. Field chrome comes from the theme // (`themes/astryx.js` → components['text-input']), so every // input matches without a per-call-site helper. // tableScrollSx → from themes/dt/primitives (also supplies // the sticky header MUI's TableContainer used to provide). // tableHeadSx → — header casing and // row rules are the component's own chrome. // tableRowSx → same; `hasHover` covers the hover tint. // --------------------------------------------------------------------------- // Pill input sx — used by every filter Autocomplete/TextField on a page. // Neutral, corporate filter field: white surface, hairline border, brand // focus ring. Width is driven by parent flex/grid so this helper stays // width-agnostic. export const pillFieldSx = () => ({ cursor: 'pointer', '& .MuiOutlinedInput-root': { borderRadius: DT.radiusField + 'px', bgcolor: DT.surface, fontWeight: 600, color: DT.textPrimary, paddingRight: '8px', cursor: 'pointer', transition: 'border-color 0.15s, box-shadow 0.15s', '& fieldset': { borderColor: DT.borderSubtle, borderWidth: 1 }, '&:hover fieldset': { borderColor: DT.borderHover }, '&.Mui-focused': { boxShadow: `0 0 0 3px ${ring(DT.brand)}` }, '&.Mui-focused fieldset': { borderColor: DT.brand, borderWidth: 1.5 } }, '& .MuiAutocomplete-endAdornment .MuiSvgIcon-root': { color: DT.textMuted } }); // --------------------------------------------------------------------------- // Table chrome — lifted verbatim from deliveries.js, the design reference for // every operator list page (root CLAUDE.md §6). These three used to be // copy-pasted into each page's //, which // is how pages drifted apart (grey scrollbars on some, brand-red on others). // Spread them instead of restating the rules: // // //
// ... // ... // --------------------------------------------------------------------------- // Brand-red scrollbar. Track is the page's alt surface so the gutter reads as // part of the table rather than a hole in it. export const tableScrollSx = { overflow: 'auto', '&::-webkit-scrollbar': { width: '10px', height: '10px', cursor: 'pointer' }, '&::-webkit-scrollbar-thumb': { backgroundColor: edge(DT.brand), borderRadius: '8px', cursor: 'pointer', '&:hover': { backgroundColor: DT.brand } }, '&::-webkit-scrollbar-track': { backgroundColor: DT.surfaceAlt } }; // Uppercase muted header row on the alt surface. export const tableHeadSx = { '& th': { backgroundColor: DT.surfaceAlt, color: DT.textSecondary, fontSize: { xs: 10, md: 11 }, fontWeight: 800, letterSpacing: 0.6, textTransform: 'uppercase', whiteSpace: 'nowrap', borderBottom: `1px solid ${DT.borderSubtle}`, py: { xs: 1, md: 1.25 }, px: { xs: 1, md: 2 } } }; // Body row: hairline divider, tinted hover. No shadow on hover — see the // design-system "don'ts" in root CLAUDE.md §6. export const tableRowSx = { '& td': { borderBottom: `1px solid ${DT.divider}` }, '&:hover': { backgroundColor: DT.surfaceAlt } };