154 lines
6.4 KiB
JavaScript
154 lines
6.4 KiB
JavaScript
import { state } from './state.js';
|
|
import * as history from './history.js';
|
|
import {
|
|
updateSelCount, updateNumberBadges,
|
|
updateNewNameLabels, refreshCardSelection,
|
|
} from './grid.js';
|
|
import { doRename } from './rename.js';
|
|
import { handleFolderDrop } from './move.js';
|
|
import { initModalControls } from './modal.js';
|
|
import { buildSequentialName, getNameFormat } from './utils/file-names.js';
|
|
import { initKeyboardShortcuts } from './keyboard.js';
|
|
import { createFolderController } from './folder-controller.js';
|
|
import { createHistoryController } from './history-controller.js';
|
|
import * as deleteHandler from './delete.js';
|
|
import * as pinchZoom from './handlers/pinch-zoom.js';
|
|
import * as selection from './handlers/selection.js';
|
|
import * as dragDrop from './handlers/drag-drop.js';
|
|
import * as hoverPreview from './handlers/image-preview.js';
|
|
import * as fileExplorer from './handlers/file-explorer.js';
|
|
import * as sidebarResize from './handlers/sidebar-resize.js';
|
|
import { log } from './logger.js';
|
|
|
|
// ── DOM ──────────────────────────────────────────────
|
|
const btnOpen = document.getElementById('btn-open');
|
|
const btnSortName = document.getElementById('btn-sort-name');
|
|
const btnSortDate = document.getElementById('btn-sort-date');
|
|
const btnRename = document.getElementById('btn-rename');
|
|
const inputPrefix = document.getElementById('input-prefix');
|
|
const inputDigits = document.getElementById('input-digits');
|
|
const inputPostfix = document.getElementById('input-postfix');
|
|
const previewName = document.getElementById('preview-name');
|
|
const dirPath = document.getElementById('dir-path');
|
|
const rubberBand = document.getElementById('rubber-band');
|
|
const grid = document.getElementById('grid');
|
|
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 aside = document.querySelector('aside');
|
|
const sidebarResizer = document.getElementById('sidebar-resizer');
|
|
|
|
const folderController = createFolderController({
|
|
btnRename,
|
|
btnSortName,
|
|
btnSortDate,
|
|
dirPath,
|
|
inputPrefix,
|
|
updatePreview,
|
|
});
|
|
const historyController = createHistoryController({
|
|
btnRename,
|
|
btnUndo,
|
|
btnRedo,
|
|
updateSortButtons: folderController.updateSortButtons,
|
|
});
|
|
|
|
// ── 핸들러 초기화 ─────────────────────────────────
|
|
history.setOnUpdate(historyController.updateButtons);
|
|
initModalControls();
|
|
|
|
const callbacks = {
|
|
refreshCardSelection, updateSelCount, updateNumberBadges, updateNewNameLabels,
|
|
pushHistory: (affectedPaths) => history.pushReorder(state.files, affectedPaths),
|
|
};
|
|
|
|
selection.init({ gridContainer, rubberBand, grid, state, callbacks });
|
|
dragDrop.init({ grid, gridContainer, dragGhostEl, state, callbacks, fileExplorerEl: fileExplorerContainer, onFolderDrop: handleFolderDrop });
|
|
hoverPreview.init();
|
|
deleteHandler.init(grid);
|
|
fileExplorer.init(fileExplorerContainer, folderController.loadFolder);
|
|
|
|
window.api.onFullscreenChange((isFullscreen) => {
|
|
document.body.classList.toggle('fullscreen', isFullscreen);
|
|
});
|
|
|
|
// ── 앱 시작 ───────────────────────────────────────
|
|
(async () => {
|
|
log('startup', 'init start');
|
|
const [lastFolder, homeDir, previewOn, sidebarWidth, thumbSize] = await Promise.all([
|
|
window.api.getLastFolder(),
|
|
window.api.getHomeDir(),
|
|
window.api.getPreviewOn(),
|
|
window.api.getSidebarWidth(),
|
|
window.api.getThumbSize(),
|
|
]);
|
|
log('startup', 'settings loaded', { lastFolder, homeDir, previewOn, sidebarWidth, thumbSize });
|
|
folderController.setHomeDir(homeDir);
|
|
|
|
btnPreviewToggle.classList.toggle('active', previewOn);
|
|
hoverPreview.setEnabled(previewOn);
|
|
sidebarResize.init({
|
|
aside,
|
|
handle: sidebarResizer,
|
|
initialWidth: sidebarWidth,
|
|
onResizeEnd: width => window.api.setSidebarWidth(width),
|
|
});
|
|
pinchZoom.init({
|
|
gridContainer,
|
|
thumbSizeHint,
|
|
initialSize: thumbSize,
|
|
onChange: size => window.api.setThumbSize(size),
|
|
});
|
|
|
|
const target = lastFolder || homeDir;
|
|
log('startup', 'initial folder target', { target, fromLastFolder: Boolean(lastFolder) });
|
|
await fileExplorer.loadTree(homeDir, target);
|
|
await folderController.loadFolder(target);
|
|
log('startup', 'init done');
|
|
})();
|
|
|
|
// ── 버튼 / 키보드 이벤트 ─────────────────────────
|
|
inputPrefix.addEventListener('input', updatePreview);
|
|
inputDigits.addEventListener('input', updatePreview);
|
|
inputPostfix.addEventListener('input', updatePreview);
|
|
btnOpen.addEventListener('click', () => {
|
|
log('ui', 'open button clicked');
|
|
folderController.openFolder();
|
|
});
|
|
btnSortName.addEventListener('click', () => folderController.sortFiles('name'));
|
|
btnSortDate.addEventListener('click', () => folderController.sortFiles('date'));
|
|
btnRename.addEventListener('click', doRename);
|
|
btnUndo.addEventListener('click', historyController.performUndo);
|
|
btnRedo.addEventListener('click', historyController.performRedo);
|
|
btnPreviewToggle.addEventListener('click', () => {
|
|
const on = btnPreviewToggle.classList.toggle('active');
|
|
hoverPreview.setEnabled(on);
|
|
window.api.setPreviewOn(on);
|
|
});
|
|
|
|
initKeyboardShortcuts({
|
|
btnOpen,
|
|
btnRename,
|
|
btnPreviewToggle,
|
|
deleteSelected: deleteHandler.deleteSelected,
|
|
performUndo: historyController.performUndo,
|
|
performRedo: historyController.performRedo,
|
|
refreshSelection: () => {
|
|
refreshCardSelection();
|
|
updateSelCount();
|
|
},
|
|
selectAll: () => state.files.forEach((_, i) => state.selectedIdxs.add(i)),
|
|
});
|
|
|
|
// ── 포맷 미리보기 ─────────────────────────────────
|
|
function updatePreview() {
|
|
const format = getNameFormat(inputPrefix, inputDigits, 3, inputPostfix);
|
|
const fileName = state.files[0]?.name || 'preview.jpg';
|
|
previewName.textContent = buildSequentialName(fileName, 0, format);
|
|
updateNewNameLabels();
|
|
}
|