mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 10:12:34 +00:00
Add pane show/hide toggle strip with persisted visibility (M6, §01A)
A persistent left-rail toolbar (APG toolbar + roving tabindex) toggles the library / editor / preview panes; a hidden pane frees its space and the rest redistribute proportionally to their remembered widths. Visibility persists to astrolabe:ux-prefs (separate key from widths, so a hidden pane keeps its width). Adds the positional pane-* glyph sub-family to Icon and a Datasets shortcut button in the strip.
This commit is contained in:
@@ -93,3 +93,48 @@ describe('usePanesStore', () => {
|
||||
expect(store().previewWidth).toBe(PANE_DEFAULT.preview);
|
||||
});
|
||||
});
|
||||
|
||||
describe('pane visibility (§01A)', () => {
|
||||
test('all panes are visible by default', () => {
|
||||
store().hydrate({}, undefined);
|
||||
expect(store().libraryVisible).toBe(true);
|
||||
expect(store().editorVisible).toBe(true);
|
||||
expect(store().previewVisible).toBe(true);
|
||||
});
|
||||
|
||||
test('togglePane flips only the targeted pane', () => {
|
||||
store().hydrate({}, {});
|
||||
store().togglePane('editor');
|
||||
expect(store().editorVisible).toBe(false);
|
||||
expect(store().libraryVisible).toBe(true);
|
||||
expect(store().previewVisible).toBe(true);
|
||||
|
||||
store().togglePane('editor');
|
||||
expect(store().editorVisible).toBe(true);
|
||||
});
|
||||
|
||||
test('hiding all panes is permitted', () => {
|
||||
store().hydrate({}, {});
|
||||
store().togglePane('library');
|
||||
store().togglePane('editor');
|
||||
store().togglePane('preview');
|
||||
expect(store().libraryVisible).toBe(false);
|
||||
expect(store().editorVisible).toBe(false);
|
||||
expect(store().previewVisible).toBe(false);
|
||||
});
|
||||
|
||||
test('hydrate restores explicit visibility; missing flags default to shown', () => {
|
||||
store().hydrate({}, { library: false });
|
||||
expect(store().libraryVisible).toBe(false);
|
||||
expect(store().editorVisible).toBe(true);
|
||||
expect(store().previewVisible).toBe(true);
|
||||
});
|
||||
|
||||
test('a hidden pane keeps its remembered width (re-shows at it)', () => {
|
||||
store().hydrate({ libraryWidth: 250 }, {});
|
||||
store().togglePane('library'); // hide
|
||||
expect(store().libraryWidth).toBe(250);
|
||||
store().togglePane('library'); // re-show
|
||||
expect(store().libraryWidth).toBe(250);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,6 +22,9 @@ import { create } from 'zustand';
|
||||
/** Which side pane a drag handle controls. */
|
||||
export type PaneSide = 'library' | 'preview';
|
||||
|
||||
/** Every pane that can be shown/hidden via the toggle strip (spec §01A). */
|
||||
export type PaneName = 'library' | 'editor' | 'preview';
|
||||
|
||||
/** Minimum widths (px) enforced while resizing, so no pane collapses (§01A). */
|
||||
export const PANE_MIN = { library: 180, preview: 240, editor: 320 } as const;
|
||||
|
||||
@@ -79,25 +82,56 @@ export function sideWidthValue(
|
||||
return Math.round(Math.min(100, Math.max(0, pct)));
|
||||
}
|
||||
|
||||
/** Per-pane visibility (spec §01A). Widths are kept *independently* of visibility,
|
||||
* so a hidden pane keeps its remembered width and re-shows at it (not a default). */
|
||||
export interface PaneVisibility {
|
||||
library?: boolean;
|
||||
editor?: boolean;
|
||||
preview?: boolean;
|
||||
}
|
||||
|
||||
export interface PanesState {
|
||||
libraryWidth: number;
|
||||
previewWidth: number;
|
||||
/** Whether each pane is currently shown. All visible by default (§01A). */
|
||||
libraryVisible: boolean;
|
||||
editorVisible: boolean;
|
||||
previewVisible: boolean;
|
||||
/** Set a side pane's width (already clamped by the caller). */
|
||||
setWidth: (side: PaneSide, width: number) => void;
|
||||
/** Restore persisted widths on startup; missing values keep their defaults. */
|
||||
hydrate: (layout: { libraryWidth?: number; previewWidth?: number }) => void;
|
||||
/** Show/hide one pane. Hiding all panes is permitted (§01A) — the strip stays. */
|
||||
togglePane: (pane: PaneName) => void;
|
||||
/** Restore persisted widths + visibility on startup; missing values keep defaults. */
|
||||
hydrate: (
|
||||
layout: { libraryWidth?: number; previewWidth?: number },
|
||||
visibility?: PaneVisibility,
|
||||
) => void;
|
||||
}
|
||||
|
||||
const VISIBLE_KEY = {
|
||||
library: 'libraryVisible',
|
||||
editor: 'editorVisible',
|
||||
preview: 'previewVisible',
|
||||
} as const;
|
||||
|
||||
export const usePanesStore = create<PanesState>((set) => ({
|
||||
libraryWidth: PANE_DEFAULT.library,
|
||||
previewWidth: PANE_DEFAULT.preview,
|
||||
libraryVisible: true,
|
||||
editorVisible: true,
|
||||
previewVisible: true,
|
||||
|
||||
setWidth: (side, width) =>
|
||||
set(side === 'library' ? { libraryWidth: width } : { previewWidth: width }),
|
||||
|
||||
hydrate: (layout) =>
|
||||
togglePane: (pane) => set((s) => ({ [VISIBLE_KEY[pane]]: !s[VISIBLE_KEY[pane]] })),
|
||||
|
||||
hydrate: (layout, visibility) =>
|
||||
set({
|
||||
libraryWidth: layout.libraryWidth ?? PANE_DEFAULT.library,
|
||||
previewWidth: layout.previewWidth ?? PANE_DEFAULT.preview,
|
||||
libraryVisible: visibility?.library ?? true,
|
||||
editorVisible: visibility?.editor ?? true,
|
||||
previewVisible: visibility?.preview ?? true,
|
||||
}),
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user