diff --git a/.playground/nuxt.config.ts b/.playground/nuxt.config.ts index 3298c98..e8d5999 100644 --- a/.playground/nuxt.config.ts +++ b/.playground/nuxt.config.ts @@ -3,7 +3,6 @@ export default defineNuxtConfig({ extends: ['..'], compatibilityDate: '2025-07-15', - site: { url: 'https://acme.test', name: 'Acme Blog' }, // Route-cached like a real host, so testing/purge-check.mjs can prove a // purge clears cached pages. routeRules: { '/**': { swr: 300 } }, diff --git a/app/assets/css/journal-base.css b/app/assets/css/journal-base.css index c0b45f5..8561a2b 100644 --- a/app/assets/css/journal-base.css +++ b/app/assets/css/journal-base.css @@ -58,8 +58,14 @@ margin: 0 auto; } +/* The title is an h1 or a p (the Journal H1 setting, UI-SPEC L6); the class + carries its look, so both elements render the same. */ .journal-post__title { margin: 0 0 var(--journal-space-3); + font-family: var(--journal-font-heading); + font-size: var(--journal-post-title-size); + font-weight: var(--journal-post-title-weight); + line-height: var(--journal-post-title-line-height); } .journal-post-meta { diff --git a/app/assets/css/journal-tokens.css b/app/assets/css/journal-tokens.css index 229c538..7718049 100644 --- a/app/assets/css/journal-tokens.css +++ b/app/assets/css/journal-tokens.css @@ -20,6 +20,9 @@ --journal-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; /* code */ --journal-font-size-base: 1.0625rem; /* body size */ --journal-line-height: 1.7; /* body leading */ + --journal-post-title-size: 2em; /* post title, h1 or p (browser h1 look) */ + --journal-post-title-weight: 700; /* post title weight */ + --journal-post-title-line-height: 1.2; /* post title leading */ /* Spacing scale */ --journal-space-1: 0.25rem; /* hairline gaps */ diff --git a/app/components/Journal/PostBody.vue b/app/components/Journal/PostBody.vue index 4cd7eae..fc71513 100644 --- a/app/components/Journal/PostBody.vue +++ b/app/components/Journal/PostBody.vue @@ -6,11 +6,13 @@ // gives the same string on server and client. expandEmbeds runs last: it // turns the Blog Editor's embed placeholders into privacy-enhanced iframes, // and its output is never sanitized again (the sanitizer would strip them). +// demoteH1 turns body h1 headings into h2 while the Journal H1 setting is on +// (the page passes the post's content_h1_to_h2). import { expandEmbeds } from '../../utils/embeds.ts' import { sanitizeJournalHtml } from '../../utils/htmlGate.ts' -const props = defineProps<{ html: string | null | undefined }>() -const html = computed(() => expandEmbeds(sanitizeJournalHtml(props.html))) +const props = defineProps<{ html: string | null | undefined; demoteH1?: boolean }>() +const html = computed(() => expandEmbeds(sanitizeJournalHtml(props.html, { demoteH1: props.demoteH1 === true })))