mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Modal system: break import cycles — component map moves to the shell
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
/**
|
||||
* Modal registry (docs/architecture/03 → Layer 1).
|
||||
*
|
||||
* One metadata entry per feature modal — the single source of truth the
|
||||
* coordinator and shell read, so adding a modal is one entry plus its component
|
||||
* rather than edits scattered across the shell, URL sync, and close logic.
|
||||
* One **metadata** entry per feature modal — the single source of truth the
|
||||
* coordinator, URL sync, and shell read, so adding a modal is one entry here,
|
||||
* one row in the shell's `MODAL_COMPONENTS` map, and its component — rather than
|
||||
* edits scattered across the shell, URL sync, and close logic. The component
|
||||
* map lives in `components/ModalShell` (its only consumer), NOT here: a registry
|
||||
* that imported components would close an import cycle (coordinator → registry →
|
||||
* component → coordinator).
|
||||
*
|
||||
* Divergence from the arch sketch's optional generic footer: each modal renders
|
||||
* its OWN action row inside its body (the Datasets manager is multi-view, so a
|
||||
@@ -15,15 +19,8 @@
|
||||
* see components/SettingsPopover).
|
||||
*/
|
||||
|
||||
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';
|
||||
@@ -34,8 +31,6 @@ export interface ModalConfig {
|
||||
name: ModalName;
|
||||
/** Header title (literal for now; an i18n key once strings are centralized). */
|
||||
title: string;
|
||||
/** The body rendered inside the shell. */
|
||||
component: ComponentType;
|
||||
/** Initialize transient state on open. `arg` carries an optional sub-target. */
|
||||
init?: (arg?: string) => void;
|
||||
/**
|
||||
@@ -54,13 +49,12 @@ export interface ModalConfig {
|
||||
dismissOnBackdrop?: boolean;
|
||||
}
|
||||
|
||||
export const MODAL_REGISTRY: Partial<Record<ModalName, ModalConfig>> = {
|
||||
const MODAL_REGISTRY: Partial<Record<ModalName, ModalConfig>> = {
|
||||
// Navigable, multi-view manager. The snapshot captures only the open create/edit
|
||||
// form, so browsing list↔detail never trips a false discard prompt.
|
||||
datasets: {
|
||||
name: 'datasets',
|
||||
title: 'Datasets',
|
||||
component: DatasetsModal,
|
||||
isUrlNavigable: true,
|
||||
init: (datasetId) => useDatasetStore.getState().select(datasetId ? Number(datasetId) : null),
|
||||
getState: () => {
|
||||
@@ -73,7 +67,6 @@ export const MODAL_REGISTRY: Partial<Record<ModalName, ModalConfig>> = {
|
||||
extract: {
|
||||
name: 'extract',
|
||||
title: 'Extract to Dataset',
|
||||
component: ExtractModal,
|
||||
init: () => useExtractStore.getState().init(),
|
||||
getState: () => ({ name: useExtractStore.getState().name }),
|
||||
},
|
||||
@@ -86,7 +79,6 @@ export const MODAL_REGISTRY: Partial<Record<ModalName, ModalConfig>> = {
|
||||
chartBuilder: {
|
||||
name: 'chartBuilder',
|
||||
title: 'Chart Builder',
|
||||
component: ChartBuilderModal,
|
||||
isUrlNavigable: true,
|
||||
dismissOnBackdrop: false,
|
||||
init: (datasetId) => useChartBuilderStore.getState().init(datasetId ? Number(datasetId) : null),
|
||||
@@ -100,7 +92,6 @@ export const MODAL_REGISTRY: Partial<Record<ModalName, ModalConfig>> = {
|
||||
themeBuilder: {
|
||||
name: 'themeBuilder',
|
||||
title: 'Theme Builder',
|
||||
component: ThemeBuilderModal,
|
||||
dismissOnBackdrop: false,
|
||||
init: () => {
|
||||
const store = useCustomThemeStore.getState();
|
||||
@@ -124,12 +115,10 @@ export const MODAL_REGISTRY: Partial<Record<ModalName, ModalConfig>> = {
|
||||
about: {
|
||||
name: 'about',
|
||||
title: 'About & Help',
|
||||
component: AboutModal,
|
||||
},
|
||||
donate: {
|
||||
name: 'donate',
|
||||
title: 'Donate',
|
||||
component: DonateModal,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -137,6 +126,3 @@ export const getModalConfig = (name: ActiveModal): ModalConfig | undefined =>
|
||||
name ? MODAL_REGISTRY[name] : undefined;
|
||||
|
||||
export const getModalTitle = (name: ActiveModal): string => getModalConfig(name)?.title ?? '';
|
||||
|
||||
export const isUrlNavigable = (name: ActiveModal): boolean =>
|
||||
getModalConfig(name)?.isUrlNavigable ?? false;
|
||||
|
||||
Reference in New Issue
Block a user