import { BaseCommand } from './base-command'; import { useLayerStore } from '@/store'; import type { Layer, LayerUpdate, CreateLayerParams, Command } from '@/types'; /** * Command to create a new layer */ export class CreateLayerCommand extends BaseCommand { private layerId: string | null = null; private layer: Layer | null = null; constructor(private params: CreateLayerParams) { super('Create Layer'); } execute(): void { const store = useLayerStore.getState(); this.layer = store.createLayer(this.params); this.layerId = this.layer.id; } undo(): void { if (!this.layerId) return; const store = useLayerStore.getState(); store.deleteLayer(this.layerId); } } /** * Command to delete a layer */ export class DeleteLayerCommand extends BaseCommand { private layer: Layer | null = null; private wasActive: boolean = false; constructor(private layerId: string) { super('Delete Layer'); } execute(): void { const store = useLayerStore.getState(); this.layer = store.getLayer(this.layerId) || null; this.wasActive = store.activeLayerId === this.layerId; if (this.layer) { store.deleteLayer(this.layerId); } } undo(): void { if (!this.layer) return; const store = useLayerStore.getState(); const layers = [...store.layers]; // Re-insert layer at its original position layers.splice(this.layer.order, 0, this.layer); // Update order for all layers const reorderedLayers = layers.map((l, index) => ({ ...l, order: index, })); // Manually update the store useLayerStore.setState({ layers: reorderedLayers, activeLayerId: this.wasActive ? this.layerId : store.activeLayerId, }); } } /** * Command to update layer properties */ export class UpdateLayerCommand extends BaseCommand { private oldValues: LayerUpdate; private newValues: LayerUpdate; constructor( private layerId: string, updates: LayerUpdate, commandName?: string ) { super(commandName || 'Update Layer'); const store = useLayerStore.getState(); const layer = store.getLayer(layerId); if (!layer) { throw new Error(`Layer ${layerId} not found`); } // Store old values this.oldValues = {}; this.newValues = updates; Object.keys(updates).forEach((key) => { this.oldValues[key as keyof LayerUpdate] = layer[key as keyof Layer] as any; }); } execute(): void { const store = useLayerStore.getState(); store.updateLayer(this.layerId, this.newValues); } undo(): void { const store = useLayerStore.getState(); store.updateLayer(this.layerId, this.oldValues); } /** * Merge consecutive updates to the same layer */ merge(other: Command): boolean { if (!(other instanceof UpdateLayerCommand)) return false; if (other.layerId !== this.layerId) return false; // Merge within 1 second if (other.timestamp - this.timestamp > 1000) return false; // Update new values with the latest changes Object.assign(this.newValues, other.newValues); this.timestamp = other.timestamp; return true; } } /** * Command to duplicate a layer */ export class DuplicateLayerCommand extends BaseCommand { private newLayerId: string | null = null; constructor(private sourceLayerId: string) { super('Duplicate Layer'); } execute(): void { const store = useLayerStore.getState(); const newLayer = store.duplicateLayer(this.sourceLayerId); this.newLayerId = newLayer?.id || null; } undo(): void { if (!this.newLayerId) return; const store = useLayerStore.getState(); store.deleteLayer(this.newLayerId); } } /** * Command to reorder a layer */ export class ReorderLayerCommand extends BaseCommand { private oldOrder: number; private newOrder: number; constructor(private layerId: string, newOrder: number) { super('Reorder Layer'); const store = useLayerStore.getState(); const layer = store.getLayer(layerId); if (!layer) { throw new Error(`Layer ${layerId} not found`); } this.oldOrder = layer.order; this.newOrder = newOrder; } execute(): void { const store = useLayerStore.getState(); store.reorderLayer(this.layerId, this.newOrder); } undo(): void { const store = useLayerStore.getState(); store.reorderLayer(this.layerId, this.oldOrder); } } /** * Command to merge layer down */ export class MergeLayerDownCommand extends BaseCommand { private topLayer: Layer | null = null; private bottomLayerBefore: HTMLCanvasElement | null = null; private bottomLayerId: string | null = null; constructor(private layerId: string) { super('Merge Down'); } execute(): void { const store = useLayerStore.getState(); const layers = store.layers; const layerIndex = layers.findIndex((l) => l.id === this.layerId); if (layerIndex === -1 || layerIndex === 0) return; this.topLayer = { ...layers[layerIndex] }; const bottomLayer = layers[layerIndex - 1]; this.bottomLayerId = bottomLayer.id; // Clone bottom layer canvas before merge if (bottomLayer.canvas) { const canvas = document.createElement('canvas'); canvas.width = bottomLayer.canvas.width; canvas.height = bottomLayer.canvas.height; const ctx = canvas.getContext('2d'); if (ctx) { ctx.drawImage(bottomLayer.canvas, 0, 0); } this.bottomLayerBefore = canvas; } store.mergeDown(this.layerId); } undo(): void { if (!this.topLayer || !this.bottomLayerId || !this.bottomLayerBefore) return; const store = useLayerStore.getState(); // Restore bottom layer canvas const bottomLayer = store.getLayer(this.bottomLayerId); if (bottomLayer && bottomLayer.canvas) { const ctx = bottomLayer.canvas.getContext('2d'); if (ctx) { ctx.clearRect(0, 0, bottomLayer.canvas.width, bottomLayer.canvas.height); ctx.drawImage(this.bottomLayerBefore, 0, 0); } } // Re-create top layer const layers = [...store.layers]; layers.splice(this.topLayer.order, 0, this.topLayer); useLayerStore.setState({ layers: layers.map((l, index) => ({ ...l, order: index })), }); } }