diff --git a/frontend/src/components/modal/ProvenancePanel.vue b/frontend/src/components/modal/ProvenancePanel.vue index 507a9e6..b4d641e 100644 --- a/frontend/src/components/modal/ProvenancePanel.vue +++ b/frontend/src/components/modal/ProvenancePanel.vue @@ -19,7 +19,7 @@ {{ postDate(e) }}
- {{ e.post.title || `Post ${e.post.external_post_id}` }} + {{ postTitle(e) }}
@@ -30,12 +30,8 @@
- ↗ View original post - View images from this post + View post { const attachments = computed(() => state.value?.attachments || []) function postDate(e) { return formatPostDate(e.post.date) } +function postTitle(e) { + // Titles can arrive as stored HTML (e.g. ""); render + // as plain text (the CSS makes it bold). + return toPlainText(e.post.title) || `Post ${e.post.external_post_id}` +} function openPost(postId) { - router.push({ path: '/gallery', query: { post_id: postId } }) + // Land on the post in the posts feed (in context), not the gallery + // image grid. Operator-flagged 2026-05-28. + router.push({ path: '/posts', query: { post_id: postId } }) modal.close() } @@ -159,7 +163,7 @@ function openPost(postId) { text-transform: lowercase; } .fc-prov__post { - font-weight: 600; margin: 4px 0; + font-weight: 700; margin: 4px 0; color: rgb(var(--v-theme-on-surface)); } .fc-prov__meta { diff --git a/frontend/src/components/posts/PostCard.vue b/frontend/src/components/posts/PostCard.vue index 65194a0..de62df4 100644 --- a/frontend/src/components/posts/PostCard.vue +++ b/frontend/src/components/posts/PostCard.vue @@ -56,8 +56,8 @@
-

- {{ post.post_title }} +

+ {{ plainTitle }}

Post {{ post.external_post_id }} @@ -80,8 +80,8 @@
-

- {{ post.post_title }} +

+ {{ plainTitle }}

Post {{ post.external_post_id }} @@ -125,7 +125,7 @@ import { computed, ref } from 'vue' import { RouterLink } from 'vue-router' import { usePostsStore } from '../../stores/posts.js' -import { sanitizeHtml } from '../../utils/htmlSanitize.js' +import { sanitizeHtml, toPlainText } from '../../utils/htmlSanitize.js' import PostEmptyThumbs from './PostEmptyThumbs.vue' import PostImageGrid from './PostImageGrid.vue' @@ -149,6 +149,10 @@ const merged = computed(() => detail.value || props.post) const images = computed(() => merged.value.thumbnails || []) const attachments = computed(() => merged.value.attachments || []) +// Titles can arrive as stored HTML (e.g. ""); render as +// plain text — the CSS makes the title bold. +const plainTitle = computed(() => toPlainText(props.post.post_title)) + // Compact-view hero+rail derived from the feed-shape (capped 6). const hero = computed(() => props.post.thumbnails?.[0]) const rail = computed(() => (props.post.thumbnails || []).slice(1, 4)) @@ -312,7 +316,7 @@ function formatBytes (n) { .fc-post-card__title { font-family: 'Fraunces', Georgia, serif; - font-size: 18px; font-weight: 500; + font-size: 18px; font-weight: 700; margin: 0 0 8px 0; color: rgb(var(--v-theme-on-surface)); display: -webkit-box; @@ -369,7 +373,7 @@ function formatBytes (n) { .fc-post-card__title-full { font-family: 'Fraunces', Georgia, serif; font-size: 22px; - font-weight: 500; + font-weight: 700; margin: 0; color: rgb(var(--v-theme-on-surface)); } diff --git a/frontend/src/utils/htmlSanitize.js b/frontend/src/utils/htmlSanitize.js index 7978fca..5733c52 100644 --- a/frontend/src/utils/htmlSanitize.js +++ b/frontend/src/utils/htmlSanitize.js @@ -29,6 +29,17 @@ export function sanitizeHtml (html) { return doc.body.innerHTML } +// Strip all tags + decode entities to plain text. Used for titles that +// arrive as stored HTML (e.g. "Edelgard at the Sex-Arcade") +// which must render as text, not literal markup. DOMParser yields an inert +// document (no script execution, no resource loads), so reading textContent +// is safe. +export function toPlainText (html) { + if (typeof html !== 'string' || !html) return '' + const doc = new DOMParser().parseFromString(html, 'text/html') + return (doc.body.textContent || '').trim() +} + function _scrubNode (node) { const children = Array.from(node.children) for (const child of children) {