feat(phase-13): implement layer groups/folders system
Add comprehensive layer groups system for organizing layers hierarchically. Features: - Create layer groups (folders) - Add layers to groups - Remove layers from groups - Toggle group collapsed/expanded state - Get all layers in a group - Group properties: * groupId: Parent group ID (null if not in group) * isGroup: Whether layer is a group * collapsed: Whether group is collapsed - Groups are special layers with isGroup=true - Groups have no canvas (width/height = 0) - Groups can contain multiple layers - Layers track their parent group via groupId Changes: - Updated types/layer.ts with group properties: * groupId: string | null * isGroup: boolean * collapsed: boolean - Updated store/layer-store.ts: * createLayer initializes group properties * createGroup() - Create new group * addToGroup() - Add layer to group * removeFromGroup() - Remove from group * toggleGroupCollapsed() - Toggle collapsed * getGroupLayers() - Get group's layers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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<LayerStore>((set, get) => ({
|
||||
@@ -62,6 +72,9 @@ export const useLayerStore = create<LayerStore>((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<LayerStore>((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);
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user