fix: tile overlay reactivity + facets showing all marked/noted photos

Problem 1 — per-photo progress overlay never rendered on the grid:
- bulkPhotoStates was `$state(new Map())`; a `.get(uid)` read in PhotoTile
  didn't reliably re-run when the entry flipped, so the spinner/check/X
  overlay never appeared. Switch to SvelteMap (svelte/reactivity).

Problem 2 — Notes / Colors / Ratings only showed the newest ~1000 photos:
- All three derived from `listPhotos({ count: 1000 })`, silently hiding
  older marked/noted photos.
- listPhotosWithNotes now pages the whole library.
- Add listPhotosByUids() and resolve the Colors/Ratings marks-pool from the
  complete marked-UID set (from getAllMarks) instead of the newest slice;
  wire it into the TagsBrowserSidebar panel and the tag drill page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 00:37:30 +02:00
parent ccf2c6b7c7
commit 259adb6a41
4 changed files with 61 additions and 20 deletions

View File

@@ -4,7 +4,7 @@
aggregateKeywords,
getAllMarks,
listLabels,
listPhotos,
listPhotosByUids,
listSubjects,
type AggregatedKeyword,
type PhotoMarksMap,
@@ -72,12 +72,17 @@
}));
// Same marks-pool query the drill page uses — colors/ratings need a
// representative photo per bucket for the count rollup. Cheap once
// cached; the drill page kicks the same key.
// representative photo per bucket for the count rollup. Resolved from the
// marked UIDs (complete set, any age) so the rollup counts every marked
// photo, not just those in the newest-N timeline slice.
const markedUids = $derived(Object.keys(marksQuery.data ?? {}));
const marksPoolQuery = createQuery<PpPhoto[]>(() => ({
queryKey: ['photos', 'marks-pool'],
queryFn: () => listPhotos({ count: 1000, order: 'newest', merged: true }),
enabled: isAuthenticated() && (category === 'ratings' || category === 'colors')
queryKey: ['photos', 'marks-pool', [...markedUids].sort()],
queryFn: () => listPhotosByUids(markedUids),
enabled:
isAuthenticated() &&
(category === 'ratings' || category === 'colors') &&
markedUids.length > 0
}));
// PhotoPrism returns labels in arbitrary order; sort by photo count