From dc407296462799246dd09c58f713a028ad1735ac Mon Sep 17 00:00:00 2001 From: Masahiko AMANO Date: Tue, 16 Jun 2026 14:54:32 +0300 Subject: [PATCH] fix(frontend): shift-select in gesture direction, not grid order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shift range-select normalized the range with Math.min/Math.max and always iterated ascending, so the selection's insertion order (which the Set preserves and which carries through to e.g. pool add order) ignored the gesture direction. Iterate anchor → target instead via a shared selectRange helper, so selecting first→last and last→first yield correspondingly ordered selections. Co-Authored-By: Claude Opus 4.8 --- frontend/src/routes/files/+page.svelte | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/frontend/src/routes/files/+page.svelte b/frontend/src/routes/files/+page.svelte index 7766e54..89c2b3e 100644 --- a/frontend/src/routes/files/+page.svelte +++ b/frontend/src/routes/files/+page.svelte @@ -94,15 +94,22 @@ // Select via the keyboard: a plain press toggles the focused card and drops the // range anchor there; a Shift press selects everything from the anchor to the // focused card — the same model as Shift+click on the grid. + // Select an inclusive index range in gesture direction (anchor → target) so the + // selection's insertion order follows how the user swept, not grid order. The + // Set preserves insertion order, so this is what later carries through to e.g. + // the order files land in a pool. + function selectRange(anchorIdx: number, targetIdx: number) { + const step = targetIdx >= anchorIdx ? 1 : -1; + for (let i = anchorIdx; i !== targetIdx + step; i += step) { + if (files[i]?.id) selectionStore.select(files[i].id!); + } + } + function selectFocused(range: boolean) { const idx = focusedId ? files.findIndex((f) => f.id === focusedId) : -1; if (idx < 0) return; if (range && lastSelectedIdx !== null) { - const from = Math.min(lastSelectedIdx, idx); - const to = Math.max(lastSelectedIdx, idx); - for (let i = from; i <= to; i++) { - if (files[i]?.id) selectionStore.select(files[i].id!); - } + selectRange(lastSelectedIdx, idx); } else if (files[idx]?.id) { selectionStore.toggle(files[idx].id!); } @@ -634,12 +641,8 @@ return; } if (e.shiftKey && lastSelectedIdx !== null) { - // Range-select between lastSelectedIdx and idx (desktop) - const from = Math.min(lastSelectedIdx, idx); - const to = Math.max(lastSelectedIdx, idx); - for (let i = from; i <= to; i++) { - if (files[i]?.id) selectionStore.select(files[i].id!); - } + // Range-select from the anchor toward idx (desktop), in gesture order. + selectRange(lastSelectedIdx, idx); lastSelectedIdx = idx; } else { if (file.id) selectionStore.toggle(file.id);