Files
astrolabe/src/app/stores/AppStore.ts
T

53 lines
2.1 KiB
TypeScript

import { create } from 'zustand';
import type { FitMode } from '@core/rendering';
import type { UiTheme } from '@core/theme';
import type { ModalName } from '../modals/types';
/**
* Centralized cross-cutting application state, as a Zustand store. Keep this
* lean — durable, feature-specific state (snippets, datasets, settings) lands
* in its own store module (e.g. stores/SnippetStore) as the app grows.
*
* Usable inside React via the `useAppStore` hook (with a selector) and outside
* React via `useAppStore.getState()` / `.setState()` / `.subscribe()` — see
* docs/architecture/01-state-and-stores.md.
*/
export type { UiTheme };
// The modal union is defined once in the modal system (docs/architecture/03) and
// re-exported here for the many callers that reach it through the app store.
export type { ModalName };
export interface AppState {
/** Active UI theme; mirrored onto <html data-theme> by a subscriber. */
uiTheme: UiTheme;
/** Preview sizing mode (spec §04); persisted to Settings as `previewFitMode`. */
previewFitMode: FitMode;
/** The currently open modal, or null. */
activeModal: ModalName | null;
setTheme: (theme: UiTheme) => void;
/** Flip between light and dark — the header ThemeToggle's action. */
toggleTheme: () => void;
/** Set the preview fit mode — the Live Preview Fit control's action. */
setPreviewFitMode: (mode: FitMode) => void;
/**
* Low-level modal setter — the single primitive that mutates `activeModal`.
* High-level open/close (snapshot for unsaved-change detection, URL sync,
* discard confirmation) lives in the modal coordinator (docs/architecture/03),
* which calls this; arrives with the modal system in M3.
*/
setActiveModal: (modal: ModalName | null) => void;
}
export const useAppStore = create<AppState>((set) => ({
uiTheme: 'light',
previewFitMode: 'default',
activeModal: null,
setTheme: (uiTheme) => set({ uiTheme }),
toggleTheme: () => set((s) => ({ uiTheme: s.uiTheme === 'dark' ? 'light' : 'dark' })),
setPreviewFitMode: (previewFitMode) => set({ previewFitMode }),
setActiveModal: (activeModal) => set({ activeModal }),
}));