preview: full-screen modal replaces inline split + tags route reorg

The old SplitGrid + InlinePreview pane is replaced by a full-screen
PreviewModal mounted once at the layout root. Open via Space on the
focused tile or double-click; close on Esc (or X / Space again).
Inside, PreviewPane renders the focused photo, RightSidebar carries
the metadata, BulkActionBar reuses the existing per-photo actions,
and PreviewCarousel windows ±50 thumbs around the focused index.

Selection contract matches the grid: plain click reduces, shift
extends the range, ⌘/Ctrl toggles, plain arrow drops the multi-
selection, shift-arrow extends. New clearBulkToFirst() helper makes
Esc / Clear collapse a bulk back to single-focus on its first member
before the next press fully dismisses (modal closes, grid clears
focus).

Tags route reorganised into /tags/[category]/[[value]] with its own
+layout and TagsBrowserSidebar; the old monolithic /tags/+page is
trimmed to a legacy redirect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 00:13:20 +02:00
parent 680fa90cbe
commit 0d5f380948
24 changed files with 1593 additions and 1068 deletions

View File

@@ -35,6 +35,7 @@
setOrder,
} from "$lib/stores/selection.svelte";
import {
openPreview,
setRightSidebarWidth,
setThumbnailSize,
THUMBNAIL_SIZE_LABELS,
@@ -51,11 +52,9 @@
} from "$lib/actions/visibleRange";
import BulkActionBar from "$lib/components/timeline/BulkActionBar.svelte";
import BulkMetadataSidebar from "$lib/components/sidebar/BulkMetadataSidebar.svelte";
import InlinePreview from "$lib/components/preview/InlinePreview.svelte";
import PhotoTile from "$lib/components/timeline/PhotoTile.svelte";
import RightSidebar from "$lib/components/sidebar/RightSidebar.svelte";
import SkeletonGrid from "$lib/components/timeline/SkeletonGrid.svelte";
import SplitGrid from "$lib/components/preview/SplitGrid.svelte";
import Toolbar from "$lib/components/layout/Toolbar.svelte";
import { type PpPhoto } from "$lib/types/photoprism";
@@ -668,6 +667,7 @@
selection.ids.add(uid);
setFocused(uid);
setAnchor(uid);
openPreview();
}
// Scroll root for the infinite-scroll IntersectionObserver. Bound by
@@ -815,11 +815,6 @@
sibling at row level and stays full height when the bar appears.
-->
<div class="flex min-w-0 flex-1 flex-col overflow-hidden">
<SplitGrid>
{#snippet preview()}
<InlinePreview uid={selection.focused} order={selection.order} />
{/snippet}
{#snippet grid()}
<main
bind:this={scrollRoot}
class="flex-1 overflow-y-auto outline-none focus:outline-none"
@@ -932,8 +927,6 @@
{/if}
</div>
</main>
{/snippet}
</SplitGrid>
<BulkActionBar />
</div>