diff --git a/frontend/src/components/posts/PostCard.vue b/frontend/src/components/posts/PostCard.vue index 9b2388d..4fdce08 100644 --- a/frontend/src/components/posts/PostCard.vue +++ b/frontend/src/components/posts/PostCard.vue @@ -200,13 +200,13 @@ async function fullImageIds () { } async function openModal (imageId) { - modal.open(imageId, { postImageIds: await fullImageIds() }) + modal.open(imageId, { playlistIds: await fullImageIds() }) } async function openModalAtMore () { const ids = await fullImageIds() const first = ids[visibleCount.value] ?? ids[0] - if (first != null) modal.open(first, { postImageIds: ids }) + if (first != null) modal.open(first, { playlistIds: ids }) } // --- description "Show more" (text-only, in place, only when truncated) ---- diff --git a/frontend/src/stores/modal.js b/frontend/src/stores/modal.js index 567f867..0ec62ec 100644 --- a/frontend/src/stores/modal.js +++ b/frontend/src/stores/modal.js @@ -17,12 +17,13 @@ export const useModalStore = defineStore('modal', () => { // chip rail. Audit 2026-06-02. const inflight = useInflightToken() - // Post-scoped cycle. When set, prev/next cycles within this array - // (used by PostCard image clicks — the modal is scoped to that post's - // images). When null, prev/next falls back to current.value.neighbors - // (the gallery-store-driven /api/gallery/image/ neighbors). - const postImageIds = ref(null) - const postImageIndex = ref(0) + // Scoped playlist. When set, prev/next cycles within THIS ordered id array — + // the current gallery filter (GalleryView) or a post's images (PostCard) — so + // the modal walks exactly what the user was looking at, not a global order. + // When null, prev/next falls back to current.value.neighbors (the + // /api/gallery/image/ global neighbours). + const playlistIds = ref(null) + const playlistIndex = ref(0) async function open (id, opts = {}) { // Cancel any in-flight tag mutation or reloadTags from the @@ -32,13 +33,13 @@ export const useModalStore = defineStore('modal', () => { current.value = null // cleared upfront so it stays null on error // Update post-scoped state if caller passed it; otherwise clear so // the next open() from gallery context uses neighbors mode. - if (opts.postImageIds != null) { - postImageIds.value = opts.postImageIds - postImageIndex.value = opts.postImageIds.indexOf(id) - if (postImageIndex.value < 0) postImageIndex.value = 0 - } else if (opts.clearPostScope !== false && postImageIds.value != null) { - postImageIds.value = null - postImageIndex.value = 0 + if (opts.playlistIds != null) { + playlistIds.value = opts.playlistIds + playlistIndex.value = opts.playlistIds.indexOf(id) + if (playlistIndex.value < 0) playlistIndex.value = 0 + } else if (opts.clearPlaylist !== false && playlistIds.value != null) { + playlistIds.value = null + playlistIndex.value = 0 } const t = inflight.claim() await run(async () => { @@ -53,17 +54,17 @@ export const useModalStore = defineStore('modal', () => { currentImageId.value = null current.value = null error.value = null - postImageIds.value = null - postImageIndex.value = 0 + playlistIds.value = null + playlistIndex.value = 0 } async function goPrev () { - if (postImageIds.value != null) { - if (postImageIndex.value > 0) { - const newIdx = postImageIndex.value - 1 - const newId = postImageIds.value[newIdx] - postImageIndex.value = newIdx - await open(newId, { postImageIds: postImageIds.value }) + if (playlistIds.value != null) { + if (playlistIndex.value > 0) { + const newIdx = playlistIndex.value - 1 + const newId = playlistIds.value[newIdx] + playlistIndex.value = newIdx + await open(newId, { playlistIds: playlistIds.value }) } return } @@ -73,12 +74,12 @@ export const useModalStore = defineStore('modal', () => { } async function goNext () { - if (postImageIds.value != null) { - if (postImageIndex.value < postImageIds.value.length - 1) { - const newIdx = postImageIndex.value + 1 - const newId = postImageIds.value[newIdx] - postImageIndex.value = newIdx - await open(newId, { postImageIds: postImageIds.value }) + if (playlistIds.value != null) { + if (playlistIndex.value < playlistIds.value.length - 1) { + const newIdx = playlistIndex.value + 1 + const newId = playlistIds.value[newIdx] + playlistIndex.value = newIdx + await open(newId, { playlistIds: playlistIds.value }) } return } @@ -177,19 +178,19 @@ export const useModalStore = defineStore('modal', () => { const isOpen = computed(() => currentImageId.value !== null) const canPrev = computed(() => { - if (postImageIds.value != null) return postImageIndex.value > 0 + if (playlistIds.value != null) return playlistIndex.value > 0 return current.value?.neighbors?.prev_id != null }) const canNext = computed(() => { - if (postImageIds.value != null) { - return postImageIndex.value < (postImageIds.value.length - 1) + if (playlistIds.value != null) { + return playlistIndex.value < (playlistIds.value.length - 1) } return current.value?.neighbors?.next_id != null }) return { currentImageId, current, loading, error, - postImageIds, postImageIndex, + playlistIds, playlistIndex, isOpen, canPrev, canNext, open, close, goPrev, goNext, reloadTags, removeTag, addExistingTag, createAndAdd, diff --git a/frontend/src/views/GalleryView.vue b/frontend/src/views/GalleryView.vue index fa64033..0358a77 100644 --- a/frontend/src/views/GalleryView.vue +++ b/frontend/src/views/GalleryView.vue @@ -54,7 +54,10 @@ watch(() => route.query, (q) => { }) function openImage(id) { - modal.open(id) + // Walk the current gallery filter in the modal (#1322) — prev/next moves + // through exactly the filtered set the operator is viewing, not global + // neighbours. Snapshot of the currently-loaded, filtered, ordered ids. + modal.open(id, { playlistIds: store.images.map((i) => i.id) }) }