diff --git a/resources/views/rd/planning-design/index.blade.php b/resources/views/rd/planning-design/index.blade.php index e40b6187..87cb4e7f 100644 --- a/resources/views/rd/planning-design/index.blade.php +++ b/resources/views/rd/planning-design/index.blade.php @@ -1961,6 +1961,7 @@ function planningCanvas() { _sbBlockDragIdx: null, _sbDrag: null, // { blk, startX, startY, origX, origY } _sbResize: null, // { blk, dir, startX, startY, origW, origH } + _sbClipboard: null, // copied block data sbTplOpen: false, sbTplTab: 'preset', sbTplSearch: '', @@ -2760,6 +2761,31 @@ function planningCanvas() { if ((e.ctrlKey || e.metaKey) && e.key === 'y') { e.preventDefault(); this.redoAction(); } if ((e.ctrlKey || e.metaKey) && e.key === 's') { e.preventDefault(); this.saveProject(); } if ((e.ctrlKey || e.metaKey) && e.key === 'd') { e.preventDefault(); this.duplicateNode(); } + // 스토리보드 블록 Ctrl+C / Ctrl+V / Delete + if (this.viewMode === 'storyboard' && this.sbSelectedBlock) { + if ((e.ctrlKey || e.metaKey) && (e.key === 'c' || e.key === 'C')) { + e.preventDefault(); + this.sbCopyBlock(); + return; + } + if ((e.ctrlKey || e.metaKey) && (e.key === 'v' || e.key === 'V')) { + e.preventDefault(); + this.sbPasteBlock(); + return; + } + if (e.key === 'Delete' || e.key === 'Backspace') { + e.preventDefault(); + this.sbDeleteSelectedBlock(); + return; + } + } + if (this.viewMode === 'storyboard' && !this.sbSelectedBlock) { + if ((e.ctrlKey || e.metaKey) && (e.key === 'v' || e.key === 'V') && this._sbClipboard) { + e.preventDefault(); + this.sbPasteBlock(); + return; + } + } if ((e.ctrlKey || e.metaKey) && e.key === 'f') { if (this.viewMode === 'kanban' || this.viewMode === 'list') { e.preventDefault(); @@ -2990,6 +3016,39 @@ function planningCanvas() { } }, + sbCopyBlock() { + const page = this.sbCurrentPage; + if (!page || !page.blocks) return; + const blk = page.blocks.find(b => b.id === this.sbSelectedBlock); + if (!blk) return; + this._sbClipboard = JSON.parse(JSON.stringify(blk)); + }, + + sbPasteBlock() { + if (!this._sbClipboard) return; + const page = this.sbCurrentPage; + if (!page) return; + if (!page.blocks) page.blocks = []; + const copy = JSON.parse(JSON.stringify(this._sbClipboard)); + copy.id = 'blk_' + Date.now() + '_' + Math.random().toString(36).slice(2, 5); + copy.x = (copy.x || 0) + 24; + copy.y = (copy.y || 0) + 24; + page.blocks.push(copy); + this.sbSelectedBlock = copy.id; + this._sbClipboard = copy; // 연속 붙여넣기 시 오프셋 누적 + this.autoSave(); + }, + + sbDeleteSelectedBlock() { + const page = this.sbCurrentPage; + if (!page || !page.blocks) return; + const idx = page.blocks.findIndex(b => b.id === this.sbSelectedBlock); + if (idx < 0) return; + page.blocks.splice(idx, 1); + this.sbSelectedBlock = null; + this.autoSave(); + }, + sbTableAddRow(blk) { const colCount = blk.cols.length; blk.rows.push(Array(colCount).fill(''));