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:
@@ -4,7 +4,6 @@
|
||||
import { browser } from '$app/environment';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/state';
|
||||
import type { Component } from 'svelte';
|
||||
import { QueryClientProvider } from '@tanstack/svelte-query';
|
||||
import { ModeWatcher } from 'mode-watcher';
|
||||
import { Toaster } from 'svelte-sonner';
|
||||
@@ -13,7 +12,6 @@
|
||||
import { setLeftSidebarWidth, view } from '$lib/stores/view.svelte';
|
||||
import { resizable } from '$lib/actions/resizable';
|
||||
import { queryClient } from '$lib/queryClient';
|
||||
import { preview } from '$lib/stores/preview.svelte';
|
||||
import { startIndexerWatch, stopIndexerWatch } from '$lib/stores/indexer.svelte';
|
||||
import IndexerStatusPill from '$lib/components/layout/IndexerStatusPill.svelte';
|
||||
import LeftSidebar from '$lib/components/layout/LeftSidebar.svelte';
|
||||
@@ -56,22 +54,6 @@
|
||||
else stopIndexerWatch();
|
||||
});
|
||||
|
||||
// PreviewOverlay is the full-screen lightbox — keyboard nav, map
|
||||
// pane, exif sidebar. Users who never click into a photo never need
|
||||
// it, so we lazy-import the first time `preview.uid` flips non-null
|
||||
// and keep the loaded module around for the rest of the session
|
||||
// (re-opens skip the network round-trip). Closing the overlay leaves
|
||||
// the component mounted but renders nothing — its internal
|
||||
// `{#if preview.uid !== null}` guard collapses the DOM tree.
|
||||
let PreviewOverlay = $state<Component | null>(null);
|
||||
$effect(() => {
|
||||
if (!browser) return;
|
||||
if (preview.uid !== null && PreviewOverlay === null) {
|
||||
void import('$lib/components/preview/PreviewOverlay.svelte').then((m) => {
|
||||
PreviewOverlay = m.default as Component;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -129,7 +111,4 @@
|
||||
{:else}
|
||||
{@render children?.()}
|
||||
{/if}
|
||||
{#if PreviewOverlay}
|
||||
<PreviewOverlay />
|
||||
{/if}
|
||||
</QueryClientProvider>
|
||||
|
||||
Reference in New Issue
Block a user