feat(explore): show Provenance in the tag rail (post often names the character)
The post title/description frequently names the character, so surface it while tagging in Explore (operator-asked 2026-06-26). ProvenancePanel gains optional imageId/image props (default = modal store, so the modal is unchanged) since provenance is its own system loaded by id; ExploreView renders it above TagPanel in the right rail, hosted on the anchor. Self-collapses when the image has no provenance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -97,9 +97,19 @@ import { useProvenanceStore } from '../../stores/provenance.js'
|
|||||||
import { formatPostDate } from '../../utils/date.js'
|
import { formatPostDate } from '../../utils/date.js'
|
||||||
import { toPlainText } from '../../utils/htmlSanitize.js'
|
import { toPlainText } from '../../utils/htmlSanitize.js'
|
||||||
|
|
||||||
|
// `imageId`/`image` let a non-modal surface (the Explore workspace) render
|
||||||
|
// provenance for its anchor. Default to the modal store's current image so the
|
||||||
|
// image modal is unchanged. Provenance is its own system (loaded by id via the
|
||||||
|
// provenance store), so it only needs the right id + the artist fallback.
|
||||||
|
const props = defineProps({
|
||||||
|
imageId: { type: Number, default: null },
|
||||||
|
image: { type: Object, default: null },
|
||||||
|
})
|
||||||
const modal = useModalStore()
|
const modal = useModalStore()
|
||||||
const prov = useProvenanceStore()
|
const prov = useProvenanceStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const effectiveId = computed(() => props.imageId ?? modal.currentImageId)
|
||||||
|
const effectiveImage = computed(() => props.image ?? modal.current)
|
||||||
|
|
||||||
// Per-post description collapse state (keyed by provenance_id). Default
|
// Per-post description collapse state (keyed by provenance_id). Default
|
||||||
// collapsed so multiple posts don't each eat ~180px of the panel — the
|
// collapsed so multiple posts don't each eat ~180px of the panel — the
|
||||||
@@ -107,21 +117,21 @@ const router = useRouter()
|
|||||||
// 2026-05-28. Reset when the viewed image changes.
|
// 2026-05-28. Reset when the viewed image changes.
|
||||||
const expanded = reactive({})
|
const expanded = reactive({})
|
||||||
function toggleDesc(id) { expanded[id] = !expanded[id] }
|
function toggleDesc(id) { expanded[id] = !expanded[id] }
|
||||||
watch(() => modal.currentImageId, () => {
|
watch(() => effectiveId.value, () => {
|
||||||
for (const k of Object.keys(expanded)) delete expanded[k]
|
for (const k of Object.keys(expanded)) delete expanded[k]
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => modal.currentImageId,
|
() => effectiveId.value,
|
||||||
(id) => { if (id != null) prov.loadForImage(id) },
|
(id) => { if (id != null) prov.loadForImage(id) },
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
const state = computed(() =>
|
const state = computed(() =>
|
||||||
modal.currentImageId == null ? null : prov.imageProv(modal.currentImageId)
|
effectiveId.value == null ? null : prov.imageProv(effectiveId.value)
|
||||||
)
|
)
|
||||||
|
|
||||||
const fallbackArtist = computed(() => modal.current?.artist || null)
|
const fallbackArtist = computed(() => effectiveImage.value?.artist || null)
|
||||||
|
|
||||||
const showArtistFallback = computed(() => {
|
const showArtistFallback = computed(() => {
|
||||||
const st = state.value
|
const st = state.value
|
||||||
|
|||||||
@@ -96,12 +96,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- RIGHT: the modal's tag rail, hosted on the anchor. -->
|
<!-- RIGHT: provenance (post/source — often names the character) above
|
||||||
<aside class="fc-ex__rail" aria-label="Tags for the focused image">
|
the modal's tag rail, both hosted on the anchor. -->
|
||||||
<TagPanel
|
<aside class="fc-ex__rail" aria-label="Provenance and tags for the focused image">
|
||||||
v-if="store.currentImageId != null"
|
<template v-if="store.currentImageId != null">
|
||||||
ref="tagPanelRef" :host="store"
|
<ProvenancePanel :image-id="store.currentImageId" :image="store.anchor" />
|
||||||
/>
|
<TagPanel ref="tagPanelRef" :host="store" />
|
||||||
|
</template>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -117,6 +118,7 @@ import { useModalStore } from '../stores/modal.js'
|
|||||||
import { isTextEntry } from '../utils/textEntry.js'
|
import { isTextEntry } from '../utils/textEntry.js'
|
||||||
import ImageCanvas from '../components/modal/ImageCanvas.vue'
|
import ImageCanvas from '../components/modal/ImageCanvas.vue'
|
||||||
import ImageMetaBar from '../components/modal/ImageMetaBar.vue'
|
import ImageMetaBar from '../components/modal/ImageMetaBar.vue'
|
||||||
|
import ProvenancePanel from '../components/modal/ProvenancePanel.vue'
|
||||||
import TagPanel from '../components/modal/TagPanel.vue'
|
import TagPanel from '../components/modal/TagPanel.vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|||||||
Reference in New Issue
Block a user