mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Data inspector: input/resolved rows below the chart, with a resizable divider
A collapsible Data panel under the Live Preview and Chart Builder charts shows the rows the chart actually uses, switching between Input (parsed source) and Resolved (post-transform) views read from the live Vega view. Collapsed by default; the open-state and a draggable height divider persist. Rows come through a new RenderHandle.inspectData() accessor, so no component touches the view: core/result-data picks the most-upstream source and most-downstream result from the compiled dataflow, read lazily. The divider reuses the window-splitter pattern (horizontal variant). Consolidations: a shared DataTable primitive replaces the inspector's and the builder's duplicate read-only tables; useResizeDrag merges the col/row drag-gesture twins. Docs: spec 04/06 and arch 05/10 updated; the now-shipped exploration memo removed.
This commit is contained in:
@@ -4,6 +4,38 @@ import type { UiTheme } from '@core/theme';
|
||||
import type { ChartThemeSelection } from '@core/vega-themes';
|
||||
import type { ModalName } from '../modals/types';
|
||||
|
||||
/** Default data-inspector height (px) when first expanded, before any drag. */
|
||||
const DATA_INSPECTOR_DEFAULT_HEIGHT = 220;
|
||||
|
||||
/** Floor (px) for the inspector and for the chart above it while the divider drags. */
|
||||
const DATA_INSPECTOR_MIN_HEIGHT = 96;
|
||||
const CHART_MIN_HEIGHT = 120;
|
||||
|
||||
/**
|
||||
* Clamp a desired inspector height so it keeps its own minimum and leaves the
|
||||
* chart above it at least its minimum. `availForBoth` is the height the chart and
|
||||
* inspector share (the preview body, minus the divider). Pure — the single place
|
||||
* the divider constraint lives, unit-tested without a DOM. Mirrors PanesStore's
|
||||
* `clampSideWidth`.
|
||||
*/
|
||||
export function clampInspectorHeight(desired: number, availForBoth: number): number {
|
||||
const max = Math.max(DATA_INSPECTOR_MIN_HEIGHT, availForBoth - CHART_MIN_HEIGHT);
|
||||
return Math.max(DATA_INSPECTOR_MIN_HEIGHT, Math.min(desired, max));
|
||||
}
|
||||
|
||||
/**
|
||||
* The inspector's 0–100 position for the divider's `aria-valuenow` (WAI-ARIA APG →
|
||||
* Window Splitter): 0 = inspector at its minimum, 100 = at its maximum (chart at
|
||||
* its minimum). Null when the span has no range, so the caller omits the attribute.
|
||||
*/
|
||||
export function inspectorHeightValue(height: number, availForBoth: number): number | null {
|
||||
const min = DATA_INSPECTOR_MIN_HEIGHT;
|
||||
const max = Math.max(min, availForBoth - CHART_MIN_HEIGHT);
|
||||
if (max <= min) return null;
|
||||
const pct = ((height - min) / (max - min)) * 100;
|
||||
return Math.round(Math.min(100, Math.max(0, pct)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralized cross-cutting application state, as a Zustand store. Keep this
|
||||
* lean — durable, feature-specific state (snippets, datasets, settings) lands
|
||||
@@ -21,6 +53,16 @@ export interface AppState {
|
||||
previewFitMode: FitMode;
|
||||
/** Chart theme selection (spec §04); persisted to Settings as `chartTheme`. */
|
||||
chartTheme: ChartThemeSelection;
|
||||
/**
|
||||
* Whether the live-preview data inspector is expanded (spec §04). A preview-pane
|
||||
* preference like `previewFitMode`; persisted to Settings as `dataInspectorOpen`.
|
||||
*/
|
||||
dataInspectorOpen: boolean;
|
||||
/**
|
||||
* Height (px) of the expanded data inspector — set by its resizable divider, so
|
||||
* the chart above keeps the rest of the pane. Persisted as `dataInspectorHeight`.
|
||||
*/
|
||||
dataInspectorHeight: number;
|
||||
/** The currently open modal, or null. */
|
||||
activeModal: ModalName | null;
|
||||
|
||||
@@ -31,6 +73,10 @@ export interface AppState {
|
||||
setPreviewFitMode: (mode: FitMode) => void;
|
||||
/** Set the chart theme — the Live Preview settings cluster's action. */
|
||||
setChartTheme: (theme: ChartThemeSelection) => void;
|
||||
/** Show/hide the data inspector — its disclosure toggle. */
|
||||
setDataInspectorOpen: (open: boolean) => void;
|
||||
/** Set the data inspector's height (caller clamps via `clampInspectorHeight`). */
|
||||
setDataInspectorHeight: (height: number) => void;
|
||||
/**
|
||||
* Low-level modal setter — the single primitive that mutates `activeModal`.
|
||||
* High-level open/close (snapshot for unsaved-change detection, URL sync,
|
||||
@@ -44,11 +90,15 @@ export const useAppStore = create<AppState>((set) => ({
|
||||
uiTheme: 'light',
|
||||
previewFitMode: 'default',
|
||||
chartTheme: 'astrolabe',
|
||||
dataInspectorOpen: false,
|
||||
dataInspectorHeight: DATA_INSPECTOR_DEFAULT_HEIGHT,
|
||||
activeModal: null,
|
||||
|
||||
setTheme: (uiTheme) => set({ uiTheme }),
|
||||
toggleTheme: () => set((s) => ({ uiTheme: s.uiTheme === 'dark' ? 'light' : 'dark' })),
|
||||
setPreviewFitMode: (previewFitMode) => set({ previewFitMode }),
|
||||
setChartTheme: (chartTheme) => set({ chartTheme }),
|
||||
setDataInspectorOpen: (dataInspectorOpen) => set({ dataInspectorOpen }),
|
||||
setDataInspectorHeight: (dataInspectorHeight) => set({ dataInspectorHeight }),
|
||||
setActiveModal: (activeModal) => set({ activeModal }),
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user