diff --git a/src/renderer/index.html b/src/renderer/index.html index 96ed881..2a16674 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -92,6 +92,19 @@ +
선택된 파일들만 저장합니다
+변경할 이름의 파일이 이미 존재합니다.
diff --git a/src/renderer/rename.js b/src/renderer/rename.js index 1354f0d..63a473f 100644 --- a/src/renderer/rename.js +++ b/src/renderer/rename.js @@ -5,10 +5,27 @@ import * as history from './history.js'; const inputPrefix = document.getElementById('input-prefix'); const inputDigits = document.getElementById('input-digits'); +const renameConfirmModal = document.getElementById('rename-confirm-modal'); +const renameConfirmTitle = document.getElementById('rename-confirm-title'); +const renameConfirmMsg = document.getElementById('rename-confirm-msg'); +const renameConfirmWarning = document.getElementById('rename-confirm-selection-warning'); +const renameConfirmList = document.getElementById('rename-confirm-list'); +const renameConfirmCancelBtn = document.getElementById('rename-confirm-cancel'); +const renameConfirmOkBtn = document.getElementById('rename-confirm-ok'); const renameConflictModal = document.getElementById('rename-conflict-modal'); const renameConflictCloseBtn = document.getElementById('rename-conflict-close'); const renameConflictList = document.getElementById('rename-conflict-list'); +let _renameConfirmResolve = null; + +renameConfirmCancelBtn.addEventListener('click', () => { + closeRenameConfirm(false); +}); + +renameConfirmOkBtn.addEventListener('click', () => { + closeRenameConfirm(true); +}); + renameConflictCloseBtn.addEventListener('click', () => { renameConflictModal.style.display = 'none'; }); @@ -49,10 +66,16 @@ export async function doRename() { const examples = filesToRename.slice(0, 3).map((f, i) => { const ext = f.name.split('.').pop().toLowerCase(); return `${f.name} → ${prefix}_${String(i + 1).padStart(digits, '0')}.${ext}`; - }).join('\n'); - const more = filesToRename.length > 3 ? `\n... 외 ${filesToRename.length - 3}개` : ''; + }); + const more = filesToRename.length > 3 ? `... 외 ${filesToRename.length - 3}개` : ''; - if (!confirm(`📂 ${filesToRename.length}개 파일을 이름 변경합니다:\n\n${examples}${more}\n\n계속하시겠습니까?`)) return; + const confirmed = await showRenameConfirm({ + count: filesToRename.length, + examples, + more, + isPartial: selectedArr.length > 0, + }); + if (!confirmed) return; showLoading('파일 이름 변경 중...'); setStatus('이름 변경 중...', false); @@ -83,3 +106,32 @@ export async function doRename() { alert('오류 발생: ' + e.message); } } + +function showRenameConfirm({ count, examples, more, isPartial }) { + renameConfirmTitle.textContent = isPartial ? '선택된 이미지 저장' : '전체 이미지 저장'; + renameConfirmMsg.textContent = `${count}개 파일을 이름 변경합니다. 계속하시겠습니까?`; + renameConfirmWarning.style.display = isPartial ? 'block' : 'none'; + + const items = [...examples]; + if (more) items.push(more); + renameConfirmList.replaceChildren(...items.map(text => { + const li = document.createElement('li'); + li.textContent = text; + return li; + })); + + renameConfirmModal.style.display = 'flex'; + renameConfirmOkBtn.focus(); + + return new Promise(resolve => { + _renameConfirmResolve = resolve; + }); +} + +function closeRenameConfirm(confirmed) { + renameConfirmModal.style.display = 'none'; + if (_renameConfirmResolve) { + _renameConfirmResolve(confirmed); + _renameConfirmResolve = null; + } +} diff --git a/src/renderer/style.css b/src/renderer/style.css index 47f4e74..b502d8d 100644 --- a/src/renderer/style.css +++ b/src/renderer/style.css @@ -535,9 +535,32 @@ footer span { font-size: 11px; color: var(--muted); } display: flex; flex-direction: column; gap: 20px; box-shadow: 0 24px 60px rgba(0,0,0,.6); } +.modal-box-with-title { + padding-top: 0; +} +.modal-titlebar { + margin: 0 -32px; + padding: 14px 32px; + border-bottom: 1px solid var(--border); + border-radius: 14px 14px 0 0; + background: var(--card); + color: var(--text); + font-size: 15px; + font-weight: 700; +} .modal-msg { font-size: 14px; color: var(--text); line-height: 1.7; } +.modal-warning { + font-size: 13px; + font-weight: 700; + line-height: 1.5; + color: var(--warning); + background: rgba(247,194,106,.12); + border: 1px solid rgba(247,194,106,.35); + border-radius: 8px; + padding: 9px 12px; +} .modal-fields { display: flex; flex-direction: column; gap: 10px; } @@ -564,6 +587,9 @@ footer span { font-size: 11px; color: var(--muted); } font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--warning); } +.modal-preview-list li { + color: var(--text); +} .modal-actions { display: flex; justify-content: flex-end; gap: 10px; }