diff --git a/web/src/lib/components/preview/PreviewCarousel.svelte b/web/src/lib/components/preview/PreviewCarousel.svelte index 097836c..6893173 100644 --- a/web/src/lib/components/preview/PreviewCarousel.svelte +++ b/web/src/lib/components/preview/PreviewCarousel.svelte @@ -22,7 +22,7 @@ setFocused, toggle } from '$lib/stores/selection.svelte'; - import { primaryFile, type PpPhoto } from '$lib/types/photoprism'; + import { isVideo, primaryFile, type PpPhoto } from '$lib/types/photoprism'; const qc = useQueryClient(); @@ -30,22 +30,22 @@ * any time, plenty to cover normal arrow-skim without bloating. */ const WINDOW = 50; - function lookup(uid: string): string | null { + function lookup(uid: string): PpPhoto | null { const direct = qc.getQueryData(['photo', uid]); - if (direct) return primaryFile(direct).Hash ?? null; + if (direct) return direct; const lists = qc.getQueriesData({ queryKey: ['photos'] }); for (const [, data] of lists) { if (!data) continue; if (Array.isArray(data)) { const hit = (data as PpPhoto[]).find((p) => p.UID === uid); - if (hit) return primaryFile(hit).Hash ?? null; + if (hit) return hit; continue; } const pages = (data as { pages?: PpPhoto[][] }).pages; if (!Array.isArray(pages)) continue; for (const page of pages) { const hit = page?.find?.((p) => p.UID === uid); - if (hit) return primaryFile(hit).Hash ?? null; + if (hit) return hit; } } return null; @@ -58,6 +58,7 @@ interface Tile { uid: string; hash: string | null; + video: boolean; idx: number; } const slice = $derived.by(() => { @@ -66,7 +67,13 @@ const hi = Math.min(order.length, focusedIdx + WINDOW + 1); const out: Tile[] = []; for (let i = lo; i < hi; i++) { - out.push({ uid: order[i], hash: lookup(order[i]), idx: i }); + const photo = lookup(order[i]); + out.push({ + uid: order[i], + hash: photo ? (primaryFile(photo).Hash ?? null) : null, + video: photo ? isVideo(photo) : false, + idx: i + }); } return out; }); @@ -154,6 +161,12 @@ {#if isSelected}
{/if} + {#if tile.video} + VIDEO + {/if} {/each} diff --git a/web/src/lib/components/sidebar/BulkMetadataSidebar.svelte b/web/src/lib/components/sidebar/BulkMetadataSidebar.svelte index e26fbde..f31352e 100644 --- a/web/src/lib/components/sidebar/BulkMetadataSidebar.svelte +++ b/web/src/lib/components/sidebar/BulkMetadataSidebar.svelte @@ -18,6 +18,7 @@ type UpdatePhotoBody } from '$lib/services/photoprism'; import { patchTargets } from '$lib/services/bulk'; + import { COLOR_SWATCHES } from '$lib/utils/tagGroups'; const qc = useQueryClient(); @@ -119,13 +120,6 @@ colorDraft = null; } - const COLOR_SWATCHES: { key: string; bg: string; title: string }[] = [ - { key: 'red', bg: 'bg-red-500', title: 'Red — reject' }, - { key: 'orange', bg: 'bg-orange-500', title: 'Orange — review' }, - { key: 'yellow', bg: 'bg-yellow-400', title: 'Yellow — pick' }, - { key: 'green', bg: 'bg-green-500', title: 'Green — keep' } - ]; - async function applyKeyword() { if (busy) return; const kw = keywordDraft.trim().replace(/,/g, ''); @@ -270,16 +264,18 @@ - +
-
Color label
-
+
Colors
+
{#each COLOR_SWATCHES as c (c.key)} + {@const picked = colorDraft === c.key}