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:
@@ -1,4 +1,5 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import type { ShapeSettings, ShapeType, ShapeStore as IShapeStore } from '@/types/shape';
|
||||
|
||||
const DEFAULT_SETTINGS: ShapeSettings = {
|
||||
@@ -15,66 +16,73 @@ const DEFAULT_SETTINGS: ShapeSettings = {
|
||||
arrowHeadAngle: 30,
|
||||
};
|
||||
|
||||
export const useShapeStore = create<IShapeStore>((set) => ({
|
||||
settings: { ...DEFAULT_SETTINGS },
|
||||
export const useShapeStore = create<IShapeStore>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
settings: { ...DEFAULT_SETTINGS },
|
||||
|
||||
setShapeType: (type) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, type },
|
||||
})),
|
||||
setShapeType: (type) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, type },
|
||||
})),
|
||||
|
||||
setFill: (fill) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, fill },
|
||||
})),
|
||||
setFill: (fill) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, fill },
|
||||
})),
|
||||
|
||||
setFillColor: (fillColor) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, fillColor },
|
||||
})),
|
||||
setFillColor: (fillColor) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, fillColor },
|
||||
})),
|
||||
|
||||
setStroke: (stroke) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, stroke },
|
||||
})),
|
||||
setStroke: (stroke) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, stroke },
|
||||
})),
|
||||
|
||||
setStrokeColor: (strokeColor) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, strokeColor },
|
||||
})),
|
||||
setStrokeColor: (strokeColor) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, strokeColor },
|
||||
})),
|
||||
|
||||
setStrokeWidth: (strokeWidth) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, strokeWidth: Math.max(1, Math.min(100, strokeWidth)) },
|
||||
})),
|
||||
setStrokeWidth: (strokeWidth) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, strokeWidth: Math.max(1, Math.min(100, strokeWidth)) },
|
||||
})),
|
||||
|
||||
setCornerRadius: (cornerRadius) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, cornerRadius: Math.max(0, Math.min(100, cornerRadius)) },
|
||||
})),
|
||||
setCornerRadius: (cornerRadius) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, cornerRadius: Math.max(0, Math.min(100, cornerRadius)) },
|
||||
})),
|
||||
|
||||
setSides: (sides) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, sides: Math.max(3, Math.min(20, sides)) },
|
||||
})),
|
||||
setSides: (sides) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, sides: Math.max(3, Math.min(20, sides)) },
|
||||
})),
|
||||
|
||||
setInnerRadius: (innerRadius) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, innerRadius: Math.max(0.1, Math.min(0.9, innerRadius)) },
|
||||
})),
|
||||
setInnerRadius: (innerRadius) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, innerRadius: Math.max(0.1, Math.min(0.9, innerRadius)) },
|
||||
})),
|
||||
|
||||
setArrowHeadSize: (arrowHeadSize) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, arrowHeadSize: Math.max(5, Math.min(100, arrowHeadSize)) },
|
||||
})),
|
||||
setArrowHeadSize: (arrowHeadSize) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, arrowHeadSize: Math.max(5, Math.min(100, arrowHeadSize)) },
|
||||
})),
|
||||
|
||||
setArrowHeadAngle: (arrowHeadAngle) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, arrowHeadAngle: Math.max(10, Math.min(60, arrowHeadAngle)) },
|
||||
})),
|
||||
setArrowHeadAngle: (arrowHeadAngle) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, arrowHeadAngle: Math.max(10, Math.min(60, arrowHeadAngle)) },
|
||||
})),
|
||||
|
||||
updateSettings: (settings) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, ...settings },
|
||||
})),
|
||||
}));
|
||||
updateSettings: (settings) =>
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, ...settings },
|
||||
})),
|
||||
}),
|
||||
{
|
||||
name: 'shape-storage',
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user