mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 10:12:34 +00:00
Chart theming: custom named themes + Theme Builder
This commit is contained in:
@@ -17,12 +17,16 @@
|
||||
|
||||
import type { ComponentType } from 'react';
|
||||
import type { ActiveModal, ModalName } from './types';
|
||||
import { customThemeIdOf } from '@core/vega-themes';
|
||||
import { AboutModal } from '../components/AboutModal';
|
||||
import { ChartBuilderModal } from '../components/ChartBuilderModal';
|
||||
import { DatasetsModal } from '../components/DatasetsModal';
|
||||
import { DonateModal } from '../components/DonateModal';
|
||||
import { ExtractModal } from '../components/ExtractModal';
|
||||
import { ThemeBuilderModal } from '../components/ThemeBuilderModal';
|
||||
import { useAppStore } from '../stores/AppStore';
|
||||
import { useChartBuilderStore } from '../stores/ChartBuilderStore';
|
||||
import { selectIsDraftDirty, useCustomThemeStore } from '../stores/CustomThemeStore';
|
||||
import { useDatasetStore } from '../stores/DatasetStore';
|
||||
import { useExtractStore } from '../stores/ExtractStore';
|
||||
|
||||
@@ -88,6 +92,32 @@ export const MODAL_REGISTRY: Partial<Record<ModalName, ModalConfig>> = {
|
||||
init: (datasetId) => useChartBuilderStore.getState().init(datasetId ? Number(datasetId) : null),
|
||||
},
|
||||
|
||||
// Opened from the chart-theme picker's "Edit themes…" entry. Re-seeds the open
|
||||
// draft from its saved record on open (clean baseline), keeping whichever theme
|
||||
// was last edited — or the active custom selection — in view. The snapshot is
|
||||
// the dirty draft only, so browsing themes never trips a false discard prompt.
|
||||
// Backdrop dismissal is off: config edits are real in-progress work.
|
||||
themeBuilder: {
|
||||
name: 'themeBuilder',
|
||||
title: 'Theme Builder',
|
||||
component: ThemeBuilderModal,
|
||||
dismissOnBackdrop: false,
|
||||
init: () => {
|
||||
const store = useCustomThemeStore.getState();
|
||||
const activeCustomId = customThemeIdOf(useAppStore.getState().chartTheme);
|
||||
const id =
|
||||
store.selectedId ??
|
||||
(activeCustomId !== null && store.themes.some((t) => t.id === activeCustomId)
|
||||
? activeCustomId
|
||||
: (store.themes[0]?.id ?? null));
|
||||
store.select(id);
|
||||
},
|
||||
getState: () => {
|
||||
const s = useCustomThemeStore.getState();
|
||||
return selectIsDraftDirty(s) ? { selectedId: s.selectedId, draft: s.draft } : null;
|
||||
},
|
||||
},
|
||||
|
||||
// Pure info modals — no state, no validity check, no discard prompt on close.
|
||||
// `about` is URL-navigable (reload-restore); `donate` is not (spec §01E hash
|
||||
// table omits both, but `about` is still a permanent, bookmark-worthy surface).
|
||||
|
||||
@@ -12,7 +12,8 @@ export type ModalName =
|
||||
| 'about' // About & Help (M6)
|
||||
| 'donate' // Donate (M6)
|
||||
| 'chartBuilder' // Visual no-JSON chart composition for a dataset (M4)
|
||||
| 'extract'; // Extract inline spec data into a new dataset (M3)
|
||||
| 'extract' // Extract inline spec data into a new dataset (M3)
|
||||
| 'themeBuilder'; // Custom chart theme editor with a live preview gallery (spec §04)
|
||||
// Settings is NOT a modal — preferences are distributed to per-pane disclosure
|
||||
// popovers (spec §07; see components/SettingsPopover).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user