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:
@@ -102,8 +102,8 @@ export function CanvasWithTools() {
|
||||
ctx.scale(zoom, zoom);
|
||||
ctx.translate(-width / 2, -height / 2);
|
||||
|
||||
// Draw checkerboard background
|
||||
drawCheckerboard(ctx, 10, '#ffffff', '#e0e0e0');
|
||||
// Draw checkerboard background (only within canvas bounds)
|
||||
drawCheckerboard(ctx, 10, '#ffffff', '#e0e0e0', width, height);
|
||||
|
||||
// Draw background color if not transparent
|
||||
if (backgroundColor && backgroundColor !== 'transparent') {
|
||||
@@ -127,9 +127,9 @@ export function CanvasWithTools() {
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = 'source-over';
|
||||
|
||||
// Draw grid if enabled
|
||||
// Draw grid if enabled (only within canvas bounds)
|
||||
if (showGrid) {
|
||||
drawGrid(ctx, gridSize, 'rgba(0, 0, 0, 0.15)');
|
||||
drawGrid(ctx, gridSize, 'rgba(0, 0, 0, 0.15)', width, height);
|
||||
}
|
||||
|
||||
// Draw selection if active (marching ants)
|
||||
@@ -172,7 +172,7 @@ export function CanvasWithTools() {
|
||||
|
||||
const screenX = e.clientX - rect.left;
|
||||
const screenY = e.clientY - rect.top;
|
||||
const canvasPos = screenToCanvas(screenX, screenY);
|
||||
const canvasPos = screenToCanvas(screenX, screenY, rect.width, rect.height);
|
||||
|
||||
// Check for panning
|
||||
if (e.button === 1 || (e.button === 0 && e.shiftKey)) {
|
||||
@@ -259,7 +259,7 @@ export function CanvasWithTools() {
|
||||
|
||||
const screenX = e.clientX - rect.left;
|
||||
const screenY = e.clientY - rect.top;
|
||||
const canvasPos = screenToCanvas(screenX, screenY);
|
||||
const canvasPos = screenToCanvas(screenX, screenY, rect.width, rect.height);
|
||||
|
||||
// Panning
|
||||
if (isPanning) {
|
||||
|
||||
@@ -51,8 +51,8 @@ export function CanvasWrapper() {
|
||||
ctx.scale(zoom, zoom);
|
||||
ctx.translate(-width / 2, -height / 2);
|
||||
|
||||
// Draw checkerboard background
|
||||
drawCheckerboard(ctx, 10, '#ffffff', '#e0e0e0');
|
||||
// Draw checkerboard background (only within canvas bounds)
|
||||
drawCheckerboard(ctx, 10, '#ffffff', '#e0e0e0', width, height);
|
||||
|
||||
// Draw background color if not transparent
|
||||
if (backgroundColor && backgroundColor !== 'transparent') {
|
||||
@@ -76,9 +76,9 @@ export function CanvasWrapper() {
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.globalCompositeOperation = 'source-over';
|
||||
|
||||
// Draw grid if enabled
|
||||
// Draw grid if enabled (only within canvas bounds)
|
||||
if (showGrid) {
|
||||
drawGrid(ctx, gridSize, 'rgba(0, 0, 0, 0.15)');
|
||||
drawGrid(ctx, gridSize, 'rgba(0, 0, 0, 0.15)', width, height);
|
||||
}
|
||||
|
||||
// Draw selection if active
|
||||
|
||||
Reference in New Issue
Block a user