Undo, Redo 기능 추가

This commit is contained in:
2026-05-15 22:24:25 +09:00
parent 31ecf94142
commit a1df424485
4 changed files with 96 additions and 2 deletions
+58 -2
View File
@@ -1,5 +1,6 @@
import { state } from './state.js';
import { showLoading, hideLoading, setStatus } from './ui.js';
import { showLoading, hideLoading, setStatus, showToast } from './ui.js';
import * as history from './history.js';
import {
renderGrid, updateSelCount, updateNumberBadges,
updateNewNameLabels, refreshCardSelection, showEmptyGrid,
@@ -28,10 +29,15 @@ const gridContainer = document.getElementById('grid-container');
const dragGhostEl = document.getElementById('drag-ghost');
const thumbSizeHint = document.getElementById('thumb-size-hint');
const btnPreviewToggle = document.getElementById('btn-preview-toggle');
const btnUndo = document.getElementById('btn-undo');
const btnRedo = document.getElementById('btn-redo');
const fileExplorerContainer = document.querySelector('.file-explorer');
// ── 핸들러 초기화 ─────────────────────────────────
const callbacks = { refreshCardSelection, updateSelCount, updateNumberBadges, updateNewNameLabels };
const callbacks = {
refreshCardSelection, updateSelCount, updateNumberBadges, updateNewNameLabels,
pushHistory: (affectedPaths) => { history.push(state.files, affectedPaths); updateHistoryButtons(); },
};
pinchZoom.init({ gridContainer, thumbSizeHint });
selection.init({ gridContainer, rubberBand, grid, state, callbacks });
@@ -67,6 +73,8 @@ btnOpen.addEventListener('click', openFolder);
btnSortName.addEventListener('click', () => sortFiles('name'));
btnSortDate.addEventListener('click', () => sortFiles('date'));
btnRename.addEventListener('click', doRename);
btnUndo.addEventListener('click', performUndo);
btnRedo.addEventListener('click', performRedo);
btnPreviewToggle.addEventListener('click', () => {
const on = btnPreviewToggle.classList.toggle('active');
hoverPreview.setEnabled(on);
@@ -82,6 +90,8 @@ document.addEventListener('keydown', (e) => {
refreshCardSelection();
updateSelCount();
}
if (e.code === 'KeyU') performUndo();
if (e.code === 'KeyR') performRedo();
});
// ── 폴더 열기 (다이얼로그) ───────────────────────
@@ -131,6 +141,9 @@ async function loadFolder(folder) {
renderGrid();
updatePreview();
btnRename.disabled = false;
history.reset();
history.push(state.files);
updateHistoryButtons();
}
// ── 정렬 ─────────────────────────────────────────
@@ -143,6 +156,8 @@ async function sortFiles(mode) {
updateSortButtons();
await renderGrid();
setStatus(`${mode === 'name' ? '이름순' : '날짜순'}으로 정렬됨`, true);
history.push(state.files);
updateHistoryButtons();
}
function updateSortButtons() {
@@ -150,6 +165,47 @@ function updateSortButtons() {
btnSortDate.classList.toggle('active', state.sortMode === 'date');
}
// ── Undo / Redo ───────────────────────────────────
function updateHistoryButtons() {
btnUndo.disabled = !history.canUndo();
btnRedo.disabled = !history.canRedo();
}
function performUndo() {
if (!history.canUndo()) {
showToast('더 이상 되돌릴 수 없습니다');
return;
}
_applyHistorySnapshot(history.undo());
}
function performRedo() {
if (!history.canRedo()) {
showToast('마지막 작업 상태입니다');
return;
}
_applyHistorySnapshot(history.redo());
}
function _applyHistorySnapshot({ files, affectedPaths }) {
state.files.length = 0;
state.files.push(...files);
state.selectedIdxs.clear();
if (affectedPaths) {
const pathToIdx = new Map(state.files.map((f, i) => [f.path, i]));
affectedPaths.forEach(path => {
const idx = pathToIdx.get(path);
if (idx !== undefined) state.selectedIdxs.add(idx);
});
}
state.sortMode = null;
updateSortButtons();
renderGrid();
updateHistoryButtons();
}
// ── 포맷 미리보기 ─────────────────────────────────
function updatePreview() {
const prefix = inputPrefix.value.trim() || 'photo';