Backend correctness was already sound (companion files travel as a
group, coordinated collision suffixes, EXDEV fallback, per-file scope
checks, blocking scoped reindex) — this pass adds reversibility and
brings the modal up to standard.
Sidecar:
- movePhotoFiles records per-file {from,to} pairs (move mode) —
including siblings of photos that failed partway, since undo must
restore whatever actually left its folder. Both POST /photos/move
and POST /albums/:uid/convert return them as movedFiles.
- New POST /files/restore-moves plays those pairs backwards: both ends
scope-checked (sources aren't quarantined like the duplicates
restore), never clobbers an existing destination, EXDEV fallback,
blocking reindex of affected parents so the client's refetch already
sees the restored layout.
Dialog (all three subjects — photos, heap convert, folder reparent):
- Search field on top (autofocused) filtering the tree live: matches +
ancestors, force-expanded without touching the sidebar's persisted
open/collapse state (new FolderTree forceExpand prop).
- Arrow keys rove through visible rows with selection following focus
(data-move-row attributes in FolderTree's readonly picker mode);
Enter confirms from anywhere once a destination is set.
- Recent destinations as one-click chips (last 5, per library base).
- Live destination preview line and count-labeled confirm buttons
("Move 12 photos", "Move “2024”") with a disabled-reason tooltip.
- Client-side subfolder validation mirroring the sidecar's
sanitizeFilename rules (inline error, aria-invalid, confirm gated).
- Pre-disables Move when every selected photo is already in the target.
- Undo everywhere it's safe: photo/heap moves restore via the new
endpoint, folder moves invert to another folder move, copies stay
toast-only (their inverse would be deletion). Success toasts carry
an inline Undo action; ⌘Z works through the shared undo stack.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
sv
Everything you need to build a Svelte project, powered by sv.
Creating a project
If you're seeing this, you've probably already done this step. Congrats!
# create a new project
npx sv create my-app
To recreate this project with the same configuration:
# recreate this project
npx sv@0.15.3 create --template minimal --types ts --install npm web
Developing
Once you've created a project and installed dependencies with npm install (or pnpm install or yarn), start a development server:
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
Building
To create a production version of your app:
npm run build
You can preview the production build with npm run preview.
To deploy your app, you may need to install an adapter for your target environment.