Unified Post Header — Design
Unified Post Header — Design
Goal
Hoist ContentHeader rendering into page.tsx so all post types share one header call site. Renderers become body-only components.
Current State
All three post types (Observable, DataPackage, Story) already use ContentHeader, but each renderer calls it internally with slightly different props. Observable returns early in page.tsx before shared data (postConfig, stats) is fetched.
Design
page.tsx restructuring
- Fetch
post(already done) - Fetch
postConfig+statsfor ALL post types (move before the type branching) - Resolve authors with unified fallback chain
- Resolve title/description/date/image based on post type and available metadata
- Render
<ContentHeader />once - Render type-specific body:
- OBSERVABLE:
<ObservableEmbed />(iframe only) - datapackage metadata present:
<DataPackageBody />(tables, previews, etc.) - story/default:
<article className="prose ...">{mdxContent}</article>
- OBSERVABLE:
For Observable posts, blob/pageMetadata are not needed — skip that fetch and go straight to the iframe body.
Author resolution (unified in page.tsx)
Fallback chain:
post.authorsfrom DBpostConfig.authors(string-based, from config file)- DataPackage
contributors(from blob metadata) post.publication.owner.ghUsername(last resort)
ContentHeader props per type
| Prop | Observable | DataPackage | Story |
|---|---|---|---|
| title | post.title or projectName | post.title or projectName | pageMetadata.title or projectName |
| description | post.description | post.description | pageMetadata.description or post.description |
| date | post.modifiedAt | post.modifiedAt | pageMetadata.date or post.modifiedAt |
| dateFormat | relative | relative | human |
| image | none | none | resolved from pageMetadata.image |
| showDownloads | false | true | false |
| showImage | false | false | true |
Renderer simplification
- ObservablePage becomes body-only: just the iframe. No header, no postConfig fetch.
- DataPackageLayout drops ContentHeader. Keeps metadata table, data files, previews, premium warning, JSON-LD.
- StoryLayout reduces to the prose
<section>wrapper (or inlined in page.tsx).
Files affected
app/[publication]/[post]/[[...slug]]/page.tsx— main changescomponents/post-renderers/ObservablePage.tsx— remove header, simplify propscomponents/layouts/datapackage.tsx— remove headercomponents/story-layout.tsx— remove header (possibly inline)