157 lines
6.7 KiB
JavaScript
157 lines
6.7 KiB
JavaScript
// ============================================================================
|
||
// 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 }
|
||
};
|