Files
Doormilexpress_console/src/themes/dt/tokens.js

157 lines
6.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================================
// 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 → <TableScroll> from themes/dt/primitives (also supplies
// the sticky header MUI's TableContainer used to provide).
// tableHeadSx → <Table density dividers hasHover> — 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 <TableContainer>/<TableHead>/<TableRow>, which
// is how pages drifted apart (grey scrollbars on some, brand-red on others).
// Spread them instead of restating the rules:
//
// <TableContainer sx={{ maxHeight: ..., ...tableScrollSx }}>
// <Table stickyHeader>
// <TableHead><TableRow sx={tableHeadSx}>...
// <TableBody><TableRow sx={tableRowSx}>...
// ---------------------------------------------------------------------------
// 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 }
};