- htmlGate.ts mirrors the four editor-output rules of the Go policy:
figure data-embed (^youtube$) and data-id (^[A-Za-z0-9_-]{11}$),
img alt with any text, ol start (integer)
- embeds.ts: EMBED_PROVIDERS (youtube on youtube-nocookie.com),
EMBED_PLACEHOLDER and expandEmbeds
- JournalPostBody and JournalCategoryHeader render
expandEmbeds(sanitizeJournalHtml(html)); payload transforms only sanitize
- .journal-embed styles (16 / 9 block, borderless iframe)
- tests: byte copy of the editor corpus, mirror and pipeline cases;
acme hello-acme carries a placeholder and the SSR smoke checks the iframe
- README Embeds section and decision note Policy amendment
23 lines
1.1 KiB
Vue
23 lines
1.1 KiB
Vue
<script setup lang="ts">
|
|
// Heading of a category page: name, description and the category's rich
|
|
// content, which goes through the Journal sanitizer before v-html. The page
|
|
// payload keeps embed placeholders; expandEmbeds turns them into iframes as
|
|
// the last step, after sanitizing, and its output is never sanitized again.
|
|
import type { JournalCategory } from '../../utils/types.ts'
|
|
import { expandEmbeds } from '../../utils/embeds.ts'
|
|
import { sanitizeJournalHtml } from '../../utils/htmlGate.ts'
|
|
|
|
const props = defineProps<{ category: JournalCategory; page?: number }>()
|
|
const content = computed(() => expandEmbeds(sanitizeJournalHtml(props.category.content)))
|
|
</script>
|
|
|
|
<template>
|
|
<header class="journal-category-header">
|
|
<h1 class="journal-category-header__title">
|
|
{{ category.name }}<template v-if="page && page > 1"> · {{ $t('journal.pagination.pageTitle', { page }) }}</template>
|
|
</h1>
|
|
<p v-if="category.description" class="journal-category-header__description">{{ category.description }}</p>
|
|
<div v-if="content" class="journal-category-header__content journal-post-body" v-html="content" />
|
|
</header>
|
|
</template>
|