feat(preview): inline split-pane preview + sidebar metadata pass
Replace the fullscreen PreviewOverlay with an inline top pane above
each grid surface. SplitGrid + InlinePreview render the focused
photo/video inside the host page; a resizableVertical action drives
the divider and the height persists via the view store. Applied to
the timeline, /tags drill-in, /review cause tabs, /photo/[uid], and
/map. selection.focused is now the single source of truth for both
the inline pane and the right sidebar — preview.svelte store and
PreviewOverlay are removed.
Sidebar: drop the thumb; lead with icon-led filename and folder
rows that match the date/place rhythm. Move dims+size to the top
(below date) and camera/lens/exposure into the collapsible File
section. Read-only spans share the input padding so the text column
aligns across rows. Folder row sits between date and dims+size.
VideoPlayer: stop forcing width/height: 100% so videos honour their
intrinsic aspect ratio inside the pane. Key the player on file hash
in InlinePreview so navigating between videos remounts the element
and autoplay fires again.
Sidebar (LeftSidebar): switch the labels badge to a dedicated
countPhotos('label:*') query so it reports photos with a label
rather than PhotoPrism's category roll-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,8 @@
|
||||
import BulkMetadataSidebar from '$lib/components/sidebar/BulkMetadataSidebar.svelte';
|
||||
import CauseGroupCard from '$lib/components/review/CauseGroupCard.svelte';
|
||||
import DuplicatesView from '$lib/components/duplicates/DuplicatesView.svelte';
|
||||
import InlinePreview from '$lib/components/preview/InlinePreview.svelte';
|
||||
import SplitGrid from '$lib/components/preview/SplitGrid.svelte';
|
||||
|
||||
type DupTab = 'stacks' | 'cross-folder';
|
||||
type Tab = CauseKey | DupTab;
|
||||
@@ -224,31 +226,38 @@
|
||||
{:else}
|
||||
<div class="flex min-h-0 flex-1">
|
||||
<div class="flex min-w-0 flex-1 flex-col">
|
||||
<main class="min-h-0 flex-1 overflow-y-auto px-6 py-4 pb-6" use:gridKeyNav={{}}>
|
||||
{#if reviewQuery.isPending}
|
||||
<p class="text-sm text-muted-foreground">Loading review queue…</p>
|
||||
{:else if reviewQuery.error}
|
||||
<p class="text-sm text-destructive">
|
||||
Could not load review queue: {reviewQuery.error instanceof Error
|
||||
? reviewQuery.error.message
|
||||
: 'unknown error'}
|
||||
</p>
|
||||
{:else if groups.length === 0}
|
||||
<div class="max-w-prose space-y-2 text-sm text-muted-foreground">
|
||||
<p>The review queue is empty.</p>
|
||||
<p class="text-xs">
|
||||
PhotoPrism's indexer flags photos with a low quality score for human
|
||||
review. New arrivals with missing EXIF, low resolution, or unknown
|
||||
cameras will land here. The Stacks and Cross-folder tabs above stay
|
||||
available for duplicate cleanup.
|
||||
</p>
|
||||
</div>
|
||||
{:else if activeGroup}
|
||||
{#key activeGroup.cause}
|
||||
<CauseGroupCard group={activeGroup} />
|
||||
{/key}
|
||||
{/if}
|
||||
</main>
|
||||
<SplitGrid>
|
||||
{#snippet preview()}
|
||||
<InlinePreview uid={selection.focused} order={selection.order} />
|
||||
{/snippet}
|
||||
{#snippet grid()}
|
||||
<main class="min-h-0 flex-1 overflow-y-auto px-6 py-4 pb-6" use:gridKeyNav={{}}>
|
||||
{#if reviewQuery.isPending}
|
||||
<p class="text-sm text-muted-foreground">Loading review queue…</p>
|
||||
{:else if reviewQuery.error}
|
||||
<p class="text-sm text-destructive">
|
||||
Could not load review queue: {reviewQuery.error instanceof Error
|
||||
? reviewQuery.error.message
|
||||
: 'unknown error'}
|
||||
</p>
|
||||
{:else if groups.length === 0}
|
||||
<div class="max-w-prose space-y-2 text-sm text-muted-foreground">
|
||||
<p>The review queue is empty.</p>
|
||||
<p class="text-xs">
|
||||
PhotoPrism's indexer flags photos with a low quality score for human
|
||||
review. New arrivals with missing EXIF, low resolution, or unknown
|
||||
cameras will land here. The Stacks and Cross-folder tabs above stay
|
||||
available for duplicate cleanup.
|
||||
</p>
|
||||
</div>
|
||||
{:else if activeGroup}
|
||||
{#key activeGroup.cause}
|
||||
<CauseGroupCard group={activeGroup} />
|
||||
{/key}
|
||||
{/if}
|
||||
</main>
|
||||
{/snippet}
|
||||
</SplitGrid>
|
||||
<BulkActionBar />
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user