mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Chart theming: selectable chart theme + spec↔config merge/extract
This commit is contained in:
@@ -243,7 +243,7 @@ Small, frequently-read structured records live in `localStorage`, not IndexedDB:
|
||||
The pattern is **load-with-fallback, per-slice write-through merge.**
|
||||
|
||||
- **Load-with-fallback:** merge the parsed stored object over a complete `DEFAULTS` constant. Missing keys (a setting added in a later build) and malformed JSON silently fall back to defaults — the app always gets a fully-populated object and never `undefined`-crashes on a new field. For `UserSettings`, the normalization is **pure and lives in `@core/settings` (`loadSettings(raw)` / `defaultSettings()`)** — it clamps ranges and validates enums; the infra adapter is just the thin localStorage reader (`loadUserSettings()` = `loadSettings(readRaw())`).
|
||||
- **Per-slice write-through merge:** every update reads current, merges in **just its slice**, and writes back. **The one `astrolabe:settings` record has multiple independent writers**, because settings are distributed and live-applied (spec §07 — no central save, no Apply step): the header theme toggle writes `ui.theme`, the preview Fit control writes `ui.previewFitMode`, and the per-pane settings clusters write `editor`/`performance`/`formatting`. **A writer that replaced the whole record would clobber the slices it doesn't own** — so each must field-merge. (There is deliberately no whole-record `saveSettings`.)
|
||||
- **Per-slice write-through merge:** every update reads current, merges in **just its slice**, and writes back. **The one `astrolabe:settings` record has multiple independent writers**, because settings are distributed and live-applied (spec §07 — no central save, no Apply step): the header theme toggle writes `ui.theme`, the preview Fit control writes `ui.previewFitMode`, the preview Chart-theme picker writes `ui.chartTheme`, and the per-pane settings clusters write `editor`/`performance`/`formatting`. **A writer that replaced the whole record would clobber the slices it doesn't own** — so each must field-merge. (There is deliberately no whole-record `saveSettings`.)
|
||||
- **Environment-guarded:** `localStorage` is absent or throws in some test/SSR contexts; guard access and degrade to defaults rather than throwing.
|
||||
|
||||
```ts
|
||||
@@ -263,7 +263,11 @@ export interface UserSettings {
|
||||
tabSize: number;
|
||||
};
|
||||
performance: { renderDebounce: number };
|
||||
ui: { theme: 'light' | 'dark'; previewFitMode: 'default' | 'width' | 'height' | 'full' };
|
||||
ui: {
|
||||
theme: 'light' | 'dark';
|
||||
previewFitMode: 'default' | 'width' | 'height' | 'full';
|
||||
chartTheme: ChartThemeId; // 'astrolabe' | 'stock' | vega-themes preset id
|
||||
};
|
||||
formatting: { dateFormat: 'smart' | 'iso' | 'custom'; customDateFormat: string };
|
||||
}
|
||||
|
||||
@@ -280,7 +284,7 @@ const DEFAULTS: UserSettings = {
|
||||
tabSize: 2,
|
||||
},
|
||||
performance: { renderDebounce: 1500 },
|
||||
ui: { theme: 'light', previewFitMode: 'default' },
|
||||
ui: { theme: 'light', previewFitMode: 'default', chartTheme: 'astrolabe' },
|
||||
formatting: { dateFormat: 'smart', customDateFormat: '' },
|
||||
};
|
||||
|
||||
@@ -324,6 +328,7 @@ export function loadSettings(): UserSettings {
|
||||
// record, so the others survive (see the per-slice rule above):
|
||||
// saveUiTheme(theme) -> { ...current, ui: { ...current.ui, theme } }
|
||||
// savePreviewFitMode(mode) -> { ...current, ui: { ...current.ui, previewFitMode } }
|
||||
// saveChartTheme(chartTheme) -> { ...current, ui: { ...current.ui, chartTheme } }
|
||||
// saveManagedSettings(managed) -> { ...current, editor, performance, formatting }
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user