그리드 줌 · 사진 줌/팬 · 영상 재생목록 추가

- 그리드 썸네일 줌: Ctrl+휠 + 툴바 슬라이더(110~420px), localStorage 유지
- 라이트박스 사진 줌/팬: 휠(커서 기준)·드래그·더블클릭·+/-/0 키,
  파일 이동 시 리셋, 확대율 배지
- 영상 재생목록: 종료 시 다음 항목 자동재생, 🔁 반복 토글

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
강 한
2026-07-17 05:46:48 +09:00
co-authored by Claude Opus 4.8
parent cb0207154d
commit dd9d6bfa0c
5 changed files with 188 additions and 10 deletions
+13 -3
View File
@@ -14,6 +14,7 @@ import LayoutWorker from "./layout.worker?worker";
import {
anchorIndex,
clearSelection,
gridRowHeight,
info,
openLightbox,
selected,
@@ -23,6 +24,7 @@ import {
selectRange,
snapshot,
thumbVersions,
zoomGrid,
} from "../../state/store";
import { fileDetails, setThumbPriority, thumbUrl, type Snapshot } from "../../ipc/commands";
import { ko } from "../../i18n/ko";
@@ -33,7 +35,6 @@ import {
performUndo,
} from "../fileops/ContextMenu";
const TARGET_ROW_HEIGHT = 200;
const GAP = 6;
const OVERSCAN_PX = 800;
@@ -65,10 +66,11 @@ export const JustifiedGrid: Component = () => {
};
onCleanup(() => worker.terminate());
// 스냅샷/폭 변경 → 레이아웃 재계산
// 스냅샷/폭/줌 변경 → 레이아웃 재계산
createEffect(() => {
const snap = snapshot();
const w = containerW();
const rowH = gridRowHeight();
if (!snap || w <= 0) {
setLayout(undefined);
return;
@@ -76,7 +78,7 @@ export const JustifiedGrid: Component = () => {
layoutSeq++;
const ratios = snap.aspectRatios();
worker.postMessage(
{ seq: layoutSeq, ratios, containerWidth: w, targetRowHeight: TARGET_ROW_HEIGHT, gap: GAP },
{ seq: layoutSeq, ratios, containerWidth: w, targetRowHeight: rowH, gap: GAP },
[ratios.buffer],
);
});
@@ -91,6 +93,13 @@ export const JustifiedGrid: Component = () => {
onCleanup(() => ro.disconnect());
});
// Ctrl+휠 → 그리드 줌 (썸네일 크기)
const onWheel = (e: WheelEvent) => {
if (!e.ctrlKey && !e.metaKey) return;
e.preventDefault();
zoomGrid(e.deltaY < 0 ? 1.12 : 1 / 1.12);
};
// rAF 스로틀 스크롤
let rafPending = false;
const onScroll = () => {
@@ -315,6 +324,7 @@ export const JustifiedGrid: Component = () => {
<div
ref={containerRef}
onScroll={onScroll}
onWheel={onWheel}
onKeyDown={onKeyDown}
onMouseDown={onBgMouseDown}
tabindex={0}