diff --git a/store/layer-store.ts b/store/layer-store.ts index 102fcd6..fbf3dd0 100644 --- a/store/layer-store.ts +++ b/store/layer-store.ts @@ -40,6 +40,16 @@ interface LayerStore { invertMask: (id: string) => void; /** Apply mask (merge and remove) */ applyMask: (id: string) => void; + /** Create a layer group */ + createGroup: (name: string) => Layer; + /** Add layer to group */ + addToGroup: (layerId: string, groupId: string) => void; + /** Remove layer from group */ + removeFromGroup: (layerId: string) => void; + /** Toggle group collapsed state */ + toggleGroupCollapsed: (groupId: string) => void; + /** Get layers in a group */ + getGroupLayers: (groupId: string) => Layer[]; } export const useLayerStore = create((set, get) => ({ @@ -62,6 +72,9 @@ export const useLayerStore = create((set, get) => ({ x: params.x ?? 0, y: params.y ?? 0, mask: null, + groupId: null, + isGroup: false, + collapsed: false, createdAt: now, updatedAt: now, }; @@ -350,4 +363,59 @@ export const useLayerStore = create((set, get) => ({ // Remove mask get().removeMask(id); }, + + createGroup: (name) => { + const now = Date.now(); + const group: Layer = { + id: uuidv4(), + name: name || `Group ${get().layers.filter(l => l.isGroup).length + 1}`, + canvas: null, + visible: true, + opacity: 1, + blendMode: 'normal', + order: get().layers.length, + locked: false, + width: 0, + height: 0, + x: 0, + y: 0, + mask: null, + groupId: null, + isGroup: true, + collapsed: false, + createdAt: now, + updatedAt: now, + }; + + set((state) => ({ + layers: [...state.layers, group], + activeLayerId: group.id, + })); + + return group; + }, + + addToGroup: (layerId, groupId) => { + const layer = get().getLayer(layerId); + const group = get().getLayer(groupId); + + if (!layer || !group || !group.isGroup) return; + + get().updateLayer(layerId, { groupId }); + }, + + removeFromGroup: (layerId) => { + get().updateLayer(layerId, { groupId: null }); + }, + + toggleGroupCollapsed: (groupId) => { + const group = get().getLayer(groupId); + if (!group || !group.isGroup) return; + + get().updateLayer(groupId, { collapsed: !group.collapsed }); + }, + + getGroupLayers: (groupId) => { + return get().layers.filter(l => l.groupId === groupId); + }, })); diff --git a/types/layer.ts b/types/layer.ts index 1f6cadc..e4915db 100644 --- a/types/layer.ts +++ b/types/layer.ts @@ -59,6 +59,12 @@ export interface Layer { y: number; /** Layer mask for non-destructive editing */ mask: LayerMask | null; + /** Parent group ID (null if not in a group) */ + groupId: string | null; + /** Whether this layer is a group */ + isGroup: boolean; + /** Whether group is collapsed (only relevant if isGroup=true) */ + collapsed: boolean; /** Timestamp of creation */ createdAt: number; /** Timestamp of last modification */