Initial commit: nick docs

This commit is contained in:
moojttaba
2026-05-23 20:35:34 +03:30
commit 0da235ae27
90 changed files with 18268 additions and 0 deletions

View File

@@ -0,0 +1,222 @@
---
title: Settings & Theming
tags: [design-system, settings, theming]
created: 2026-05-23
---
# Settings & Theming
A drawer-based UI lets the end user toggle visual preferences. Settings persist in `localStorage` and rebuild the MUI theme on the fly.
> [!info]
> Implementation: `frontend/src/settings/context/` (state) + `frontend/src/settings/drawer/` (UI) + `frontend/src/components/settings/` (helpers).
---
## 1. What's user-controllable
| Axis | Values | Default | Persisted |
|---|---|---|---|
| **Mode** | `light` · `dark` · `system` | `system` | localStorage |
| **Contrast** | `default` · `bold` | `default` | localStorage |
| **Layout** | `vertical` · `mini` · `horizontal` | `vertical` | localStorage |
| **Direction** | `ltr` · `rtl` | derived from locale | localStorage (overrides locale default) |
| **Color preset** | one of `default`, `purple`, `cyan`, `blue`, `orange`, `red` | `default` | localStorage |
| **Font family** | `Public Sans Variable`, `DM Sans Variable`, `Inter Variable`, `Nunito Sans Variable` | `Public Sans Variable` | localStorage |
| **Compact navigation** | boolean | `false` | localStorage |
| **Border radius** | 024 | 8 | localStorage |
| **Stretched container** | boolean | `false` | localStorage |
---
## 2. State shape
```ts
// frontend/src/settings/types.ts (approx)
export interface Settings {
mode: 'light' | 'dark' | 'system';
contrast: 'default' | 'bold';
layout: 'vertical' | 'mini' | 'horizontal';
direction: 'ltr' | 'rtl';
colorPreset: string;
fontFamily: string;
compactLayout: boolean;
primaryColor?: string;
stretch: boolean;
}
```
Stored in a single `localStorage` key (`settings` or `settings-key`). The context provider hydrates on mount, falls back to defaults if absent.
---
## 3. Context API
```ts
// frontend/src/settings/context/use-settings.ts (approx)
export interface SettingsContext {
state: Settings;
canReset: boolean;
onReset(): void;
onUpdate<K extends keyof Settings>(key: K, value: Settings[K]): void;
onUpdateField<K extends keyof Settings>(key: K, value: Settings[K]): void;
openDrawer: boolean;
onToggleDrawer(): void;
}
const { state, onUpdate, onToggleDrawer } = useSettings();
```
Use `onUpdate` to change any value. The context fires a re-render that:
1. Updates localStorage.
2. Triggers a new `buildTheme()` invocation up at `ThemeProvider`.
3. Components re-render with the new theme tokens.
---
## 4. Drawer UI
The drawer (`settings/drawer/SettingsDrawer.tsx`) is a right-side `MuiDrawer` with sections:
```
┌──────────────────────────────┐
│ Settings [reset] │
├──────────────────────────────┤
│ Mode [☀] [🌙] [⌐] │
│ │
│ Contrast ◯ Default ◯ Bold │
│ │
│ Direction ⬅ LTR ➡ RTL │
│ │
│ Layout ▤ Vertical │
│ ▣ Mini │
│ ━ Horizontal │
│ │
│ Color [●●●●●●] │
│ │
│ Font [Public Sans ▼] │
│ │
│ Border radius [—•—] 8 │
└──────────────────────────────┘
```
Each section uses the `BlockOption` helper component for consistent styling.
---
## 5. Wiring at the root
```tsx
// frontend/src/app/layout.tsx (simplified)
<SettingsProvider defaultSettings={defaults}>
<ThemeProviderFromSettings>
{children}
<SettingsDrawer />
</ThemeProviderFromSettings>
</SettingsProvider>
```
`ThemeProviderFromSettings` reads the settings context and rebuilds the theme on every change.
---
## 6. Locale ↔ direction coupling
By default, switching to `fa` / `ar` flips `direction: 'rtl'`. The user CAN override (a Persian-speaker on a desktop might prefer LTR sometimes).
```ts
// In a settings change handler:
onUpdate('direction', i18n.language === 'fa' ? 'rtl' : 'ltr');
```
Or let the user pin direction independently — saved direction wins over locale-derived direction.
---
## 7. Mode = `system`
When `mode === 'system'`:
```ts
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const effectiveMode = prefersDark ? 'dark' : 'light';
```
Subscribe to changes:
```ts
useEffect(() => {
if (settings.mode !== 'system') return;
const mql = window.matchMedia('(prefers-color-scheme: dark)');
const onChange = () => forceUpdate();
mql.addEventListener('change', onChange);
return () => mql.removeEventListener('change', onChange);
}, [settings.mode]);
```
---
## 8. Color presets
Defined in `frontend/src/theme/options/presets/` or similar. Each preset only swaps `primary` (and optionally `secondary`) — `grey`, semantic colors, and background stay constant so layouts feel consistent across presets.
Adding a preset:
1. Add a `<name>.ts` exporting `{ lighter, light, main, dark, darker, contrastText }`.
2. Register in `colorPresets` map.
3. Add a swatch entry in the drawer's color picker block.
---
## 9. Font preset
Switching the font family applies at the theme level:
```ts
typography: { fontFamily: settings.fontFamily, ... }
```
If a font isn't bundled, dynamically `import('@fontsource-variable/<name>')` first to avoid FOUC.
---
## 10. Compact / stretched layout
| Setting | Effect |
|---|---|
| `compactLayout: true` | Reduces top spacing / padding on dashboard pages |
| `stretch: true` | Removes the centered max-width on content (full-bleed) |
---
## 11. Border radius
Slider exposed as 0 → 24. Affects `theme.shape.borderRadius`, cascading to every component using `sx={{ borderRadius: 1 }}` semantics.
---
## 12. Reset to defaults
`onReset()` clears localStorage and re-hydrates with the default object. `canReset` is true when current state differs from defaults — used to enable/disable the Reset button.
---
## 13. Hydration mismatch hazard
Because settings live in `localStorage`, the server render can't know them. The provider implements a 2-pass strategy:
1. First render uses **defaults** (matches what the server emits → no hydration mismatch).
2. After mount, the provider reads localStorage and re-renders with the user's settings.
Brief flash possible. To mitigate, either:
- Suppress the first paint (split layout into client-only).
- Or set the user's settings into a cookie at sign-in so server can pre-render correctly.
---
## 14. Related
- [[Design System Overview]] · [[Theme Configuration]] · [[Colors]] · [[Typography]]
- [[Layouts]] — layout variants drive sidebar
- [[Internationalization & RTL]] — direction coupling
- [[Frontend Architecture]] — provider tree