The rendering split is dictated by CI building with no database. /blog, /blog/rss.xml and /content-sitemap.xml have no dynamic params, so Next prerenders them at build time and the build fails on a missing Payload secret — caught here, not on staging. They are force-dynamic instead: one indexed query against Postgres on the same Docker network, and a newly published post appears immediately rather than waiting on a revalidation. /blog/[slug] keeps ISR, because with no generateStaticParams there is nothing to prerender; it is generated on first request and cached, which is exactly what the collection's afterChange hook exists to invalidate. RichText takes `converters`, not `blocks`, in Payload 3.88, and the default converters must be spread or every paragraph and heading loses its renderer and the body comes out empty. BlogPosting references the Person and Organization by @id rather than repeating them, so every post and the About page resolve to one author entity instead of declaring several people with the same name. /sitemap.xml is proxied from FastAPI, which knows nothing about Payload, so the Next-owned URLs get their own sitemap and robots.txt lists both. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017YmbBhr8s7GusjDE12hrZM
88 lines
1.7 KiB
CSS
88 lines
1.7 KiB
CSS
.page {
|
|
max-width: 42rem;
|
|
margin: 0 auto;
|
|
padding: 2.5rem 1.25rem 4rem;
|
|
}
|
|
|
|
.crumb {
|
|
font-family: var(--font-ui);
|
|
font-size: 0.85rem;
|
|
margin-bottom: 1.25rem;
|
|
}
|
|
|
|
.heading {
|
|
font-family: var(--font-display);
|
|
font-size: clamp(1.6rem, 5vw, 2.25rem);
|
|
font-weight: 700;
|
|
line-height: 1.2;
|
|
color: var(--text-primary);
|
|
margin: 0 0 0.75rem;
|
|
}
|
|
|
|
.byline {
|
|
font-family: var(--font-ui);
|
|
font-size: 0.9rem;
|
|
color: var(--text-muted);
|
|
margin: 0 0 2rem;
|
|
}
|
|
|
|
.hero {
|
|
width: 100%;
|
|
height: auto;
|
|
border-radius: 10px;
|
|
border: 1px solid var(--border);
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
/* Rich-text output: the editor emits plain elements, so these are styled by
|
|
descendant selector rather than by class. */
|
|
.prose p {
|
|
font-family: var(--font-ui);
|
|
font-size: 1rem;
|
|
line-height: 1.7;
|
|
color: var(--text-secondary);
|
|
margin: 0 0 1.1rem;
|
|
}
|
|
|
|
.prose h2 {
|
|
font-family: var(--font-display);
|
|
font-size: 1.25rem;
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
margin: 2.25rem 0 0.75rem;
|
|
}
|
|
|
|
.prose h3 {
|
|
font-family: var(--font-display);
|
|
font-size: 1.05rem;
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
margin: 1.75rem 0 0.6rem;
|
|
}
|
|
|
|
.prose ul,
|
|
.prose ol {
|
|
font-family: var(--font-ui);
|
|
font-size: 1rem;
|
|
line-height: 1.7;
|
|
color: var(--text-secondary);
|
|
padding-left: 1.35rem;
|
|
margin: 0 0 1.1rem;
|
|
}
|
|
|
|
.prose li { margin-bottom: 0.4rem; }
|
|
|
|
.prose a { color: var(--brand); font-weight: 500; }
|
|
.prose a:hover { color: var(--brand-strong); }
|
|
|
|
.prose blockquote {
|
|
border-left: 3px solid var(--border-strong);
|
|
padding-left: 1rem;
|
|
margin: 1.5rem 0;
|
|
color: var(--text-muted);
|
|
font-style: italic;
|
|
}
|
|
|
|
.link { color: var(--brand); font-weight: 600; }
|
|
.link:hover { color: var(--brand-strong); }
|