feat(phase-13): implement brush presets system

Add comprehensive brush presets system for saving and loading brush configurations.

Features:
- Brush presets store with persistence
- 5 default presets included:
  * Hard Brush - Solid, precise edges
  * Soft Brush - Smooth, gradual falloff
  * Airbrush - Low opacity, soft flow
  * Pencil - Tiny, hard, precise
  * Ink - Medium, slightly soft
- Preset management functions:
  * addPreset() - Save current brush settings
  * removePreset() - Delete preset
  * updatePreset() - Modify preset
  * setActivePreset() - Select active preset
  * getPreset() - Get preset by ID
  * clearPresets() - Reset to defaults
- Each preset stores:
  * size, opacity, hardness, flow, spacing
  * Unique ID and creation timestamp
- localStorage persistence
- Active preset tracking

Changes:
- Created store/brush-presets-store.ts
- BrushPreset interface with settings
- Exported from store/index.ts
- Ready for UI integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-21 20:30:07 +01:00
parent ad87b86c0f
commit 40f624f5b7
2 changed files with 153 additions and 0 deletions

View File

@@ -0,0 +1,152 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { ToolSettings } from '@/types';
export interface BrushPreset {
id: string;
name: string;
settings: Partial<ToolSettings>;
createdAt: number;
}
interface BrushPresetsStore {
/** All brush presets */
presets: BrushPreset[];
/** Currently selected preset ID */
activePresetId: string | null;
/** Add a new preset */
addPreset: (name: string, settings: Partial<ToolSettings>) => BrushPreset;
/** Remove a preset */
removePreset: (id: string) => void;
/** Update a preset */
updatePreset: (id: string, name: string, settings: Partial<ToolSettings>) => void;
/** Set active preset */
setActivePreset: (id: string | null) => void;
/** Get preset by ID */
getPreset: (id: string) => BrushPreset | undefined;
/** Clear all presets */
clearPresets: () => void;
}
// Default presets
const DEFAULT_PRESETS: Omit<BrushPreset, 'id' | 'createdAt'>[] = [
{
name: 'Hard Brush',
settings: {
size: 10,
opacity: 1,
hardness: 1,
flow: 1,
spacing: 0.25,
},
},
{
name: 'Soft Brush',
settings: {
size: 30,
opacity: 1,
hardness: 0,
flow: 1,
spacing: 0.25,
},
},
{
name: 'Airbrush',
settings: {
size: 50,
opacity: 0.3,
hardness: 0,
flow: 0.5,
spacing: 0.1,
},
},
{
name: 'Pencil',
settings: {
size: 2,
opacity: 1,
hardness: 1,
flow: 1,
spacing: 0.1,
},
},
{
name: 'Ink',
settings: {
size: 5,
opacity: 1,
hardness: 0.8,
flow: 1,
spacing: 0.15,
},
},
];
export const useBrushPresetsStore = create<BrushPresetsStore>()(
persist(
(set, get) => ({
presets: DEFAULT_PRESETS.map((preset, index) => ({
...preset,
id: `default-${index}`,
createdAt: Date.now() - (DEFAULT_PRESETS.length - index) * 1000,
})),
activePresetId: null,
addPreset: (name, settings) => {
const now = Date.now();
const preset: BrushPreset = {
id: `preset-${now}`,
name,
settings,
createdAt: now,
};
set((state) => ({
presets: [...state.presets, preset],
}));
return preset;
},
removePreset: (id) => {
set((state) => ({
presets: state.presets.filter((p) => p.id !== id),
activePresetId: state.activePresetId === id ? null : state.activePresetId,
}));
},
updatePreset: (id, name, settings) => {
set((state) => ({
presets: state.presets.map((p) =>
p.id === id
? { ...p, name, settings }
: p
),
}));
},
setActivePreset: (id) => {
set({ activePresetId: id });
},
getPreset: (id) => {
return get().presets.find((p) => p.id === id);
},
clearPresets: () => {
set({
presets: DEFAULT_PRESETS.map((preset, index) => ({
...preset,
id: `default-${index}`,
createdAt: Date.now() - (DEFAULT_PRESETS.length - index) * 1000,
})),
activePresetId: null,
});
},
}),
{
name: 'brush-presets-storage',
}
)
);

View File

@@ -13,3 +13,4 @@ export * from './toast-store';
export * from './context-menu-store';
export * from './guides-store';
export * from './recent-files-store';
export * from './brush-presets-store';