feat: implement UI state persistence and theme toggle
Major improvements to UI state management and user preferences: - Add theme toggle with dark/light mode support - Implement Zustand persist middleware for UI state - Add ui-store for panel layout preferences (dock width, heights, tabs) - Persist tool settings (active tool, size, opacity, hardness, etc.) - Persist canvas view preferences (grid, rulers, snap-to-grid) - Persist shape tool settings - Persist collapsible section states - Fix canvas coordinate transformation for centered rendering - Constrain checkerboard and grid to canvas bounds - Add icons to all tab buttons and collapsible sections - Restructure panel-dock to use persisted state Storage impact: ~3.5KB total across all preferences Storage keys: tool-storage, canvas-view-storage, shape-storage, ui-storage 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
92
store/ui-store.ts
Normal file
92
store/ui-store.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
type PanelTab = 'adjustments' | 'tools' | 'history';
|
||||
|
||||
interface CollapsibleState {
|
||||
filters: boolean;
|
||||
selection: boolean;
|
||||
transform: boolean;
|
||||
shapeSettings: boolean;
|
||||
}
|
||||
|
||||
interface PanelDockState {
|
||||
activeTab: PanelTab;
|
||||
width: number;
|
||||
layersHeight: number;
|
||||
colorsHeight: number;
|
||||
}
|
||||
|
||||
interface UIStore {
|
||||
panelDock: PanelDockState;
|
||||
collapsed: CollapsibleState;
|
||||
|
||||
/** Set active tab in panel dock */
|
||||
setActiveTab: (tab: PanelTab) => void;
|
||||
/** Set panel dock width */
|
||||
setPanelWidth: (width: number) => void;
|
||||
/** Set layers panel height percentage */
|
||||
setLayersHeight: (height: number) => void;
|
||||
/** Set colors panel height percentage */
|
||||
setColorsHeight: (height: number) => void;
|
||||
/** Toggle collapsible section */
|
||||
toggleCollapsed: (section: keyof CollapsibleState) => void;
|
||||
/** Set collapsible section state */
|
||||
setCollapsed: (section: keyof CollapsibleState, collapsed: boolean) => void;
|
||||
}
|
||||
|
||||
const DEFAULT_PANEL_DOCK: PanelDockState = {
|
||||
activeTab: 'adjustments',
|
||||
width: 280,
|
||||
layersHeight: 40,
|
||||
colorsHeight: 20,
|
||||
};
|
||||
|
||||
const DEFAULT_COLLAPSED: CollapsibleState = {
|
||||
filters: true,
|
||||
selection: true,
|
||||
transform: true,
|
||||
shapeSettings: true,
|
||||
};
|
||||
|
||||
export const useUIStore = create<UIStore>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
panelDock: { ...DEFAULT_PANEL_DOCK },
|
||||
collapsed: { ...DEFAULT_COLLAPSED },
|
||||
|
||||
setActiveTab: (tab) =>
|
||||
set((state) => ({
|
||||
panelDock: { ...state.panelDock, activeTab: tab },
|
||||
})),
|
||||
|
||||
setPanelWidth: (width) =>
|
||||
set((state) => ({
|
||||
panelDock: { ...state.panelDock, width: Math.max(280, Math.min(600, width)) },
|
||||
})),
|
||||
|
||||
setLayersHeight: (height) =>
|
||||
set((state) => ({
|
||||
panelDock: { ...state.panelDock, layersHeight: Math.max(15, Math.min(70, height)) },
|
||||
})),
|
||||
|
||||
setColorsHeight: (height) =>
|
||||
set((state) => ({
|
||||
panelDock: { ...state.panelDock, colorsHeight: Math.max(10, Math.min(40, height)) },
|
||||
})),
|
||||
|
||||
toggleCollapsed: (section) =>
|
||||
set((state) => ({
|
||||
collapsed: { ...state.collapsed, [section]: !state.collapsed[section] },
|
||||
})),
|
||||
|
||||
setCollapsed: (section, collapsed) =>
|
||||
set((state) => ({
|
||||
collapsed: { ...state.collapsed, [section]: collapsed },
|
||||
})),
|
||||
}),
|
||||
{
|
||||
name: 'ui-storage',
|
||||
}
|
||||
)
|
||||
);
|
||||
Reference in New Issue
Block a user