리펙토링 - 수정 작업한 코드 최적화

This commit is contained in:
2026-05-22 10:33:45 +09:00
parent bb5fd0a0e9
commit cc88aecac2
3 changed files with 12 additions and 45 deletions
+8 -5
View File
@@ -68,7 +68,7 @@ src/
├── sidebar-resize.js # Pointer-drag resizing for the aside/main split; persisted 340500px width
├── selection.js # Rubber-band, Shift-click, Cmd+click, resetAnchor
├── pinch-zoom.js # Ctrl+scroll to resize thumbnails (CSS --thumb-size, 150400px)
└── image-preview.js # Hover preview overlay with circular loading indicator
└── image-preview.js # Hover preview overlay; immediate show/hide when enabled/disabled
```
### IPC surface
@@ -80,7 +80,7 @@ Defined in `src/main/ipc/`, bridged via `src/preload/index.js` as `window.api`:
| `select-folder` | invoke | Opens native folder picker, returns path or null |
| `list-images` | invoke | Reads directory, returns `{name, path, mtime}[]` filtered to image extensions, sorted by filename |
| `read-image` | invoke | Reads file, returns base64 data URL (supports jpg/png/gif/webp/tiff/bmp/heic) |
| `rename-files({folderPath, files, prefix, digits})` | invoke | Two-phase rename: temp names (crypto.randomUUID) first, then final names |
| `rename-files({folderPath, files, prefix, digits, postfix})` | invoke | Two-phase rename: temp names (crypto.randomUUID) first, then final names using `prefix + padded sequence + postfix + ext` |
| `check-files-exist(folderPath, names[])` | invoke | Returns subset of names that already exist in folderPath |
| `move-files({targetFolder, files[]})` | invoke | Moves files; each file may have optional `newName`; handles cross-device (EXDEV) |
| `stage-delete-files(paths[])` | invoke | Moves files to userData deleted_staging for undoable deletion; handles cross-device (EXDEV) |
@@ -122,7 +122,7 @@ Prefer narrow utility modules (`utils/file-names.js`, `utils/dom.js`) over broad
- `A` — 전체 선택
- `Cmd+Z` — Undo (되돌리기)
- `Cmd+Shift+Z` — Redo (다시하기)
- `P` — 미리보기 on/off 토글
- `Space` — 미리보기 on/off 토글
- `Backspace` / `Delete` — 선택 파일 삭제 팝업
Global shortcuts are registered in `keyboard.js`. They do not fire while any `.modal-overlay` is open.
@@ -164,6 +164,9 @@ Global shortcuts are registered in `keyboard.js`. They do not fire while any `.m
**Rename** (`rename.js`):
- 선택된 파일만 이름 변경 (선택 없으면 전체)
- 파일명 포맷은 `input-prefix` + 자리순번 + `input-postfix` + 확장자이다. 구분자 `_`는 자동 삽입하지 않고 입력값 자체에 포함한다.
- `input-prefix`의 HTML 기본값은 `photo_`, `input-postfix`의 HTML 기본값은 `_`이다. 접미사를 비우면 접두사와 자리순번만으로 저장한다.
- 상단 파일명 preview, 카드별 새 이름 라벨, rename 확인 목록은 모두 `utils/file-names.js``getNameFormat()``buildSequentialName()`을 사용해 같은 규칙을 공유한다.
- 변경될 이름이 미선택 파일과 충돌하면 충돌 목록 모달 표시
- 완료 후 history 리셋 (rename은 파일 경로가 바뀌므로 undo 대상 아님)
@@ -181,9 +184,9 @@ Global shortcuts are registered in `keyboard.js`. They do not fire while any `.m
**Thumbnail loading:** `IntersectionObserver` with `rootMargin: '400px 0px'` — lazy load as cards enter viewport. `entry.target.isConnected` 체크로 폴더 전환 중 스탈 카드 방지. Drag reorder remaps card elements via `card.dataset.filepath` to avoid re-fetching.
**Hover preview** (`image-preview.js`): 1초 지연 후 전체 크기 팝업. 썸네일 캐시 우선 사용. 상태는 config.json에 영속.
**Hover preview** (`image-preview.js`): 활성화 상태에서 카드 hover 시 대기 없이 전체 크기 팝업을 표시한다. 썸네일 캐시 우선 사용. 상태는 config.json에 영속. `Space`로 preview를 켤 때 커서가 카드 위에 있으면 즉시 팝업을 표시하고, 끌 때는 열린 팝업을 즉시 닫는다.
**Sidebar tree** (`file-explorer.js`): Lazy-load 자식 폴더. 접근 불가 폴더는 `null` 반환 → "접근 불가" 표시. 행 클릭 시 항상 펼침, 화살표 클릭 시 토글.
**Sidebar tree** (`file-explorer.js`): Lazy-load 자식 폴더. 접근 불가 폴더는 `null` 반환 → "접근 불가" 표시. 행 클릭 시 항상 펼침, 화살표 클릭 시 토글. 폴더 로드 후 `folder-controller.js`가 폴더명 뒤에 `_`를 붙여 `input-prefix`로 설정한다.
**Thumbnail size** (`pinch-zoom.js`): Ctrl+scroll changes CSS `--thumb-size` in the 150400px range. The latest size is persisted as `thumbSize` in config.json and restored on startup without showing the size hint.
+4 -6
View File
@@ -7,7 +7,7 @@ import {
import { doRename } from './rename.js';
import { handleFolderDrop } from './move.js';
import { initModalControls } from './modal.js';
import { clampDigits, getExtension } from './utils/file-names.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';
@@ -146,10 +146,8 @@ 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')}${postfix}.${ext}`;
const format = getNameFormat(inputPrefix, inputDigits, 3, inputPostfix);
const fileName = state.files[0]?.name || 'preview.jpg';
previewName.textContent = buildSequentialName(fileName, 0, format);
updateNewNameLabels();
}
-34
View File
@@ -443,40 +443,6 @@ footer span { font-size: 11px; color: var(--muted); }
@keyframes spin { to { transform: rotate(360deg); } }
#loading p { color: var(--text); font-size: 14px; }
/* ── 카드 호버 원형 로딩바 ── */
.card-hover-loader {
position: absolute;
top: calc(var(--thumb-size) / 2);
left: 50%;
transform: translate(-50%, -50%);
width: 52px;
height: 52px;
pointer-events: none;
z-index: 10;
overflow: visible;
}
.card-hover-loader .loader-bg {
fill: rgba(0, 0, 0, 0.55);
}
.card-hover-loader .loader-track {
fill: none;
stroke: rgba(255, 255, 255, 0.15);
stroke-width: 3;
}
.card-hover-loader .loader-progress {
fill: none;
stroke: var(--accent);
stroke-width: 3;
stroke-linecap: round;
transform-origin: 24px 24px;
transform: rotate(-90deg);
animation: hover-loader-fill 1s linear forwards;
}
@keyframes hover-loader-fill {
from { stroke-dashoffset: 125.66; }
to { stroke-dashoffset: 0; }
}
/* ── 호버 이미지 팝업 ── */
.hover-preview {
position: fixed;