feat(LayoutManager): create layout manager with persistent store support to manage SampleList items layout
This commit is contained in:
@@ -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<LayoutMode>(DEFAULT_CONFIG.mode);
|
||||||
|
#store = createPersistentStore<LayoutConfig>(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();
|
||||||
Reference in New Issue
Block a user