From c86b5f5db8e25fcc4c33a41dda369eef875b958f Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Fri, 27 Feb 2026 18:40:08 +0300 Subject: [PATCH] feat(LayoutManager): create layout manager with persistent store support to manage SampleList items layout --- .../stores/layoutStore/layoutStore.svelte.ts | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/widgets/SampleList/model/stores/layoutStore/layoutStore.svelte.ts diff --git a/src/widgets/SampleList/model/stores/layoutStore/layoutStore.svelte.ts b/src/widgets/SampleList/model/stores/layoutStore/layoutStore.svelte.ts new file mode 100644 index 0000000..b0f7154 --- /dev/null +++ b/src/widgets/SampleList/model/stores/layoutStore/layoutStore.svelte.ts @@ -0,0 +1,113 @@ +import { createPersistentStore } from '$shared/lib'; +import { responsiveManager } from '$shared/lib'; + +export type LayoutMode = 'list' | 'grid'; + +interface LayoutConfig { + mode: LayoutMode; +} + +const STORAGE_KEY = 'glyphdiff:sample-list-layout'; +const SM_GAP_PX = 16; +const MD_GAP_PX = 24; + +const DEFAULT_CONFIG: LayoutConfig = { + mode: 'list', +}; + +/** + * LayoutManager manages the layout configuration for SampleList widget. + * Handles mode switching between list/grid and responsive column calculation. + */ +class LayoutManager { + // Private reactive state + #mode = $state(DEFAULT_CONFIG.mode); + #store = createPersistentStore(STORAGE_KEY, DEFAULT_CONFIG); + + constructor() { + // Load saved layout preference + const saved = this.#store.value; + if (saved && saved.mode) { + this.#mode = saved.mode; + } + } + + get mode(): LayoutMode { + return this.#mode; + } + + get gap(): number { + return responsiveManager.isMobile || responsiveManager.isTabletPortrait ? SM_GAP_PX : MD_GAP_PX; + } + + get isListMode(): boolean { + return this.#mode === 'list'; + } + + get isGridMode(): boolean { + return this.#mode === 'grid'; + } + + /** + * Get current number of columns based on mode and screen size. + * List mode always uses 1 column. + * Grid mode uses responsive column counts: + * - Mobile: 1 column + * - Tablet Portrait: 1 column + * - Tablet: 2 columns + * - Desktop: 3 columns + * - Desktop Large: 4 columns + */ + get columns(): number { + if (this.#mode === 'list') { + return 1; + } + + // Grid mode: responsive columns + switch (true) { + case responsiveManager.isMobile: + return 1; + case responsiveManager.isTabletPortrait: + return 1; + case responsiveManager.isTablet: + return 2; + case responsiveManager.isDesktop: + return 3; + case responsiveManager.isDesktopLarge: + return 4; + default: + return 1; + } + } + + /** + * Set the layout mode. + * @param mode - The new layout mode ('list' or 'grid') + */ + setMode(mode: LayoutMode): void { + if (this.#mode === mode) { + return; + } + + this.#mode = mode; + this.#store.value = { mode }; + } + + /** + * Toggle between list and grid modes. + */ + toggleMode(): void { + this.setMode(this.#mode === 'list' ? 'grid' : 'list'); + } + + /** + * Reset to default layout mode. + */ + reset(): void { + this.#mode = DEFAULT_CONFIG.mode; + this.#store.clear(); + } +} + +// Export a singleton — one instance for the whole app +export const layoutManager = new LayoutManager();