153 lines
3.3 KiB
TypeScript
153 lines
3.3 KiB
TypeScript
|
|
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',
|
||
|
|
}
|
||
|
|
)
|
||
|
|
);
|