feat(move): "move to folder" for grid selections, folders, and m shortcut
Extends the heap-only "move to folder" action to grid single/bulk selections, sidebar folders, and an `m` keyboard shortcut — all through one shared dialog driven by a moveDialog store. Backend (sidecar): - Extract the heap move/copy + reindex loop into a reusable movePhotoFiles helper plus resolveMoveTarget - POST /photos/move: move/copy an arbitrary UID list into a folder - POST /folders/:rel/move: reparent a folder dir (whole subtree) under a new parent, guarding against moving into itself/a descendant Frontend: - moveDialog store + generalized MoveToFolderDialog (heap | photos | folder subjects); mounted once in +layout.svelte. Replaces HeapConvertDialog - movePhotosToFolder / moveFolder service fns - Entry points: BulkActionBar button, gridKeyNav `m`, FolderTree kebab, heap kebab — all call openMove() Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
import { filters } from '$lib/stores/filters.svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import { untrack } from 'svelte';
|
||||
import { FolderPlus, Pencil, Trash2 } from 'lucide-svelte';
|
||||
import { FolderInput, FolderPlus, Pencil, Trash2 } from 'lucide-svelte';
|
||||
import Self from './FolderTree.svelte';
|
||||
import KebabMenu, { Item, Separator } from './KebabMenu.svelte';
|
||||
|
||||
@@ -50,10 +50,13 @@
|
||||
depth?: number;
|
||||
onPick: (path: string) => void;
|
||||
/** Mutating callbacks are only required when readonly !== true. The
|
||||
* picker (HeapConvertDialog) reuses the tree just for `onPick`. */
|
||||
* picker (MoveToFolderDialog) reuses the tree just for `onPick`. */
|
||||
onRename?: (path: string) => void;
|
||||
onDelete?: (path: string) => void;
|
||||
onCreateChild?: (parent: string) => void;
|
||||
/** Reparent this folder under a chosen destination (opens the shared
|
||||
* move-to-folder dialog). Sidebar only; the readonly picker omits it. */
|
||||
onMove?: (path: string) => void;
|
||||
/** Read-only mode: hides the kebab menu and disables double-click
|
||||
* rename, so the tree can be reused as a folder picker. */
|
||||
readonly?: boolean;
|
||||
@@ -74,6 +77,7 @@
|
||||
onRename,
|
||||
onDelete,
|
||||
onCreateChild,
|
||||
onMove,
|
||||
readonly = false,
|
||||
selectedPath,
|
||||
counts
|
||||
@@ -219,6 +223,13 @@
|
||||
<Pencil class="h-3.5 w-3.5 text-muted-foreground" />
|
||||
Rename
|
||||
</Item>
|
||||
<Item
|
||||
class="flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[12px] outline-none hover:bg-accent focus:bg-accent"
|
||||
onSelect={() => onMove?.(node.path)}
|
||||
>
|
||||
<FolderInput class="h-3.5 w-3.5 text-muted-foreground" />
|
||||
Move to folder…
|
||||
</Item>
|
||||
<Separator class="my-1 h-px bg-border" />
|
||||
<Item
|
||||
class="flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[12px] text-destructive outline-none hover:bg-destructive/10 focus:bg-destructive/10"
|
||||
@@ -239,6 +250,7 @@
|
||||
{onRename}
|
||||
{onDelete}
|
||||
{onCreateChild}
|
||||
{onMove}
|
||||
{readonly}
|
||||
{selectedPath}
|
||||
{counts}
|
||||
|
||||
Reference in New Issue
Block a user