Files
nick-doc/05 - Design System/Colors.md
2026-05-23 20:35:34 +03:30

208 lines
5.8 KiB
Markdown
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.
---
title: Colors
tags: [design-system, colors, palette]
created: 2026-05-23
---
# Colors
The palette is built from semantic groups (`primary`, `secondary`, `info`, `success`, `warning`, `error`, plus a 9-step `grey` scale) and exposed via the MUI theme. **Never hard-code hex values in components.**
> [!warning]
> Hardcoded colors break dark mode and any future preset switch. Use `sx={{ color: 'primary.main' }}` or `theme.palette.primary.main`.
---
## 1. Semantic groups
Every color group has the shape:
```ts
{
lighter: '#…', // tint background, alerts
light: '#…', // hover surfaces, badges
main: '#…', // primary use (buttons, links)
dark: '#…', // hover state of `main`
darker: '#…', // pressed state
contrastText: '#…', // WCAG AA on `main`
}
```
### 1.1 Primary
| Token | Light hex (default preset) | Dark hex |
|---|---|---|
| `primary.lighter` | `#D0ECFE` | `#CCF4FE` |
| `primary.light` | `#73BAFB` | `#68CDF9` |
| `primary.main` | `#1877F2` | `#078DEE` |
| `primary.dark` | `#0C44AE` | `#0351AB` |
| `primary.darker` | `#042174` | `#012972` |
| `primary.contrastText` | `#FFFFFF` | `#FFFFFF` |
Used for primary actions, links, focused inputs.
### 1.2 Secondary
Typical: a complementary purple/teal. Confirm by reading `theme/options/palette.ts`.
### 1.3 Info / Success / Warning / Error
Standard semantic colors:
| Group | Hue | Used for |
|---|---|---|
| `info` | cyan/blue | Neutral informative banners |
| `success` | green | Confirmed payments, accepted offers |
| `warning` | amber | Pending state, mild alerts |
| `error` | red | Disputes, validation errors, destructive |
Each follows the same `lighter/light/main/dark/darker/contrastText` shape.
### 1.4 Grey
Nine-step scale (100 → 900). Use for:
- `grey.100``grey.300` → backgrounds, dividers, disabled
- `grey.500` → secondary text, muted icons
- `grey.700``grey.900` → primary text, dark headings
### 1.5 Text & Background
```ts
text: {
primary: grey[800], // body
secondary: grey[600], // muted
disabled: grey[500],
},
background: {
default: '#FFFFFF', // light mode page
paper: '#FFFFFF', // cards, dialogs
neutral: grey[200], // page wash
},
```
In dark mode these invert (`default` becomes near-black, `paper` slightly lighter, `text.primary` near-white).
---
## 2. Action states
```ts
action: {
active: alpha(grey[600], 1),
hover: alpha(grey[500], 0.08),
selected: alpha(grey[500], 0.16),
disabled: alpha(grey[500], 0.8),
disabledBackground: alpha(grey[500], 0.24),
focus: alpha(grey[500], 0.24),
hoverOpacity: 0.08,
disabledOpacity: 0.48,
}
```
Use via `sx={{ bgcolor: 'action.hover' }}` etc.
---
## 3. Color presets
The settings drawer ships several **color presets** that swap only `primary` (and optionally `secondary`) while keeping every other group stable. Typical presets (confirm in `theme/options/presets/`):
| Preset | Primary hue | Vibe |
|---|---|---|
| `default` | Blue | Trust, finance |
| `purple` | Indigo/Purple | Premium |
| `cyan` | Cyan | Tech, fresh |
| `blue` | Vibrant blue | Strong CTA |
| `orange` | Orange | Energetic |
| `red` | Brand red | Bold |
To add a preset:
1. Add a `<name>.ts` file in `theme/options/presets/` exporting `{ lighter, light, main, dark, darker, contrastText }`.
2. Register in the presets index map.
3. Surface in the settings drawer color picker (`src/settings/drawer/`).
---
## 4. Contrast verification
WCAG AA targets:
| Element | Min contrast |
|---|---|
| Body text (≥18 px regular or ≥14 px bold) | **4.5 : 1** |
| Large text (≥24 px regular or ≥18 px bold) | **3 : 1** |
| Icon-only buttons | **3 : 1** for their boundary |
| Form input borders | **3 : 1** |
> [!tip]
> When picking a new `main` color, run it through [Stark](https://stark.co/) or the Chrome DevTools "Inspect color" checker against `background.paper` AND `background.default` for both light and dark modes.
---
## 5. Using colors in `sx`
```tsx
// Token-based — preferred
<Box sx={{ bgcolor: 'primary.main', color: 'primary.contrastText' }} />
// Function form when you need to derive
<Box sx={(theme) => ({ bgcolor: alpha(theme.palette.primary.main, 0.08) })} />
// In styled component
const Item = styled('div')(({ theme }) => ({
background: theme.palette.background.paper,
color: theme.palette.text.primary,
}));
```
---
## 6. Charts & data viz
Use the helper `theme.palette.<group>.main` array for series colors. The `chart/` component family (ApexCharts wrapper) reads these tokens so the chart palette stays in sync with the theme.
For categorical data with >7 series, layer in `secondary.main`, `info.main`, `success.main`, `warning.main`, `error.main`, then darker variants — never invent ad-hoc hex.
---
## 7. Diff visualisation (chat, evidence)
| Concept | Color token |
|---|---|
| Added / accepted | `success.main` with `success.lighter` background |
| Removed / rejected | `error.main` with `error.lighter` background |
| Pending review | `warning.main` |
| Informational | `info.main` |
---
## 8. Avatar backgrounds
`MuiAvatar` override hashes the user's name to one of the semantic `main` colors so the same person always gets the same background. Implementation in `components/user-avatar/`.
---
## 9. Brand vs semantic
| Use case | Token |
|---|---|
| Primary CTA button | `primary.main` |
| Success snackbar | `success.main` |
| Error border on form field | `error.main` |
| Page background | `background.default` |
| Card background | `background.paper` |
| Sidebar background | `background.neutral` |
| Divider line | `divider` |
| Primary text | `text.primary` |
| Muted helper text | `text.secondary` |
---
## 10. Related
- [[Theme Configuration]] · [[Design System Overview]] · [[Typography]]
- [[Components]] — components consuming these tokens
- [[Settings & Theming]] — preset switcher