diff --git a/src/main/ipc/files.js b/src/main/ipc/files.js index be0b236..83ecd97 100644 --- a/src/main/ipc/files.js +++ b/src/main/ipc/files.js @@ -92,9 +92,10 @@ function register() { return { restored, errors }; }); - ipcMain.handle('rename-files', async (_event, { folderPath, files, prefix, digits }) => { + ipcMain.handle('rename-files', async (_event, { folderPath, files, prefix, digits, postfix = '' }) => { const errors = []; const pad = (n) => String(n + 1).padStart(digits, '0'); + const suffix = postfix ? `_${postfix}` : ''; // 1단계: 임시 이름으로 이동 (충돌 방지) const tmpMap = []; @@ -113,7 +114,7 @@ function register() { // 2단계: 최종 이름으로 이동 const renamed = []; for (const { tmp, ext, idx } of tmpMap) { - const newName = `${prefix}_${pad(idx)}${ext}`; + const newName = `${prefix}_${pad(idx)}${suffix}${ext}`; const dest = path.join(folderPath, newName); try { fs.renameSync(tmp, dest); diff --git a/src/renderer/grid.js b/src/renderer/grid.js index 53508e0..4084783 100644 --- a/src/renderer/grid.js +++ b/src/renderer/grid.js @@ -11,6 +11,7 @@ const fileCount = document.getElementById('file-count'); const selCount = document.getElementById('sel-count'); const inputPrefix = document.getElementById('input-prefix'); const inputDigits = document.getElementById('input-digits'); +const inputPostfix = document.getElementById('input-postfix'); let _cardObserver = null; @@ -111,7 +112,7 @@ export function updateNumberBadges() { } export function updateNewNameLabels() { - const format = getNameFormat(inputPrefix, inputDigits); + const format = getNameFormat(inputPrefix, inputDigits, 3, inputPostfix); Array.from(grid.children).forEach((card, i) => { const el = card.querySelector('.card-new-name'); const file = state.files[i]; diff --git a/src/renderer/index.html b/src/renderer/index.html index 5575eea..5fba393 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -45,6 +45,8 @@ _ 자리 순번 + _ + photo_001.jpg diff --git a/src/renderer/rename.js b/src/renderer/rename.js index a559643..df8c992 100644 --- a/src/renderer/rename.js +++ b/src/renderer/rename.js @@ -8,6 +8,7 @@ import { buildSequentialName, getNameFormat } from './utils/file-name const inputPrefix = document.getElementById('input-prefix'); const inputDigits = document.getElementById('input-digits'); +const inputPostfix = document.getElementById('input-postfix'); const renameConfirmModal = document.getElementById('rename-confirm-modal'); const renameConfirmSelectedTitle = renameConfirmModal.querySelector('.rename-title-selected'); const renameConfirmAllTitle = renameConfirmModal.querySelector('.rename-title-all'); @@ -30,8 +31,8 @@ renameConfirmModal.addEventListener('modal:closed', () => { export async function doRename() { if (!state.files.length || !state.currentFolder) return; - const { prefix, digits } = getNameFormat(inputPrefix, inputDigits); - const format = { prefix, digits }; + const { prefix, digits, postfix } = getNameFormat(inputPrefix, inputDigits, 3, inputPostfix); + const format = { prefix, digits, postfix }; const selectedArr = [...state.selectedIdxs].sort((a, b) => a - b); const filesToRename = selectedArr.length > 0 @@ -75,6 +76,7 @@ export async function doRename() { files: filesToRename, prefix, digits, + postfix, }); hideLoading(); if (result.errors.length) { diff --git a/src/renderer/renderer.js b/src/renderer/renderer.js index 45b6e0d..aebf236 100644 --- a/src/renderer/renderer.js +++ b/src/renderer/renderer.js @@ -27,6 +27,7 @@ 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'); @@ -113,6 +114,7 @@ window.api.onFullscreenChange((isFullscreen) => { // ── 버튼 / 키보드 이벤트 ───────────────────────── inputPrefix.addEventListener('input', updatePreview); inputDigits.addEventListener('input', updatePreview); +inputPostfix.addEventListener('input', updatePreview); btnOpen.addEventListener('click', () => { log('ui', 'open button clicked'); folderController.openFolder(); @@ -146,7 +148,9 @@ initKeyboardShortcuts({ function updatePreview() { const prefix = inputPrefix.value.trim() || 'photo'; const digits = clampDigits(inputDigits.value); + const postfix = inputPostfix.value.trim(); const ext = state.files.length ? getExtension(state.files[0].name) : 'jpg'; - previewName.textContent = `${prefix}_${'1'.padStart(digits, '0')}.${ext}`; + const suffix = postfix ? `_${postfix}` : ''; + previewName.textContent = `${prefix}_${'1'.padStart(digits, '0')}${suffix}.${ext}`; updateNewNameLabels(); } diff --git a/src/renderer/style.css b/src/renderer/style.css index 338063d..aab3083 100644 --- a/src/renderer/style.css +++ b/src/renderer/style.css @@ -216,6 +216,7 @@ main { #format-bar input:focus { border-color: var(--accent); } #input-prefix { width: 160px; } #input-digits { width: 50px; text-align: center; } +#input-postfix { width: 54px; } .format-sep { color: var(--muted); font-family: 'JetBrains Mono', monospace; font-size: 14px; } .format-arrow { color: var(--muted); font-size: 12px; } #preview-name { diff --git a/src/renderer/utils/file-names.js b/src/renderer/utils/file-names.js index 4458a7a..95e7096 100644 --- a/src/renderer/utils/file-names.js +++ b/src/renderer/utils/file-names.js @@ -7,14 +7,17 @@ export function clampDigits(value, fallback = 3) { return Math.max(1, Math.min(6, parseInt(value, 10) || fallback)); } -export function buildSequentialName(fileName, index, { prefix, digits }) { +export function buildSequentialName(fileName, index, { prefix, digits, postfix = '' }) { const ext = getExtension(fileName); - return `${prefix}_${String(index + 1).padStart(digits, '0')}.${ext}`; + const sequence = `${prefix}_${String(index + 1).padStart(digits, '0')}`; + const suffix = postfix ? `_${postfix}` : ''; + return `${sequence}${suffix}.${ext}`; } -export function getNameFormat(prefixInput, digitsInput, digitsFallback = 3) { +export function getNameFormat(prefixInput, digitsInput, digitsFallback = 3, postfixInput = null) { return { prefix: prefixInput.value.trim() || 'photo', digits: clampDigits(digitsInput.value, digitsFallback), + postfix: postfixInput?.value.trim() || '', }; }