Introduction
PostHeader is Palo’s header for content detail pages — individual blog posts (/blog/{slug}) and portfolio projects (/portfolio/{slug}). It renders a full-width cover image, optional breadcrumbs, title + description, author metadata, and optional Source / Live Demo buttons.
PostHeader 是 Palo 的内容详情页页头——用于博客文章(/blog/{slug})和作品集项目(/portfolio/{slug})。它渲染全宽封面、可选面包屑、标题与摘要、作者信息,以及可选的 Source / Live Demo 按钮。
Component path: src/components/PostHeader.astro
Used by: src/pages/blog/[post].astro, src/pages/portfolio/[project].astro
PostHeader vs PaloPageHeader
| PostHeader | PaloPageHeader | |
|---|---|---|
| Use on | Blog post & project detail pages | List pages, static pages, MDX layouts |
| Cover | Full-viewport hero (60vh) via coverImage | Optional bg.image / video / color |
| Default heading | h2 (config) | h1 (config) |
| Config block | components.postHeader | components.paloPageHeader |
See PaloPageHeader Component for list/static page headers.
列表页与静态页头部见 PaloPageHeader 组件。
Configuration (config.yaml)
Global defaults live under components.postHeader:
components:
postHeader:
headingLevel: "h2" # Detail page title tag (h2–h6)
descClass: "text-lg" # Tailwind class on description/subtitle
coverImagePosition: "head" # top | head | bottom | none
divider: "both" # top | bottom | both | none
showBreadcrumbs: true
showShare: true # Social share block (page layout, not PostHeader)| Key | Values | Effect |
|---|---|---|
headingLevel | h2–h6 | HTML tag for the post/project title |
descClass | Tailwind class | Styles the description paragraph (from frontmatter description) |
coverImagePosition | top | head | bottom | none | Default cover placement when frontmatter omits it |
divider | top | bottom | both | none | Section border dividers around the header |
showBreadcrumbs | boolean | Default breadcrumb visibility |
showShare | boolean | Default for the share block below the article (handled by page template) |
Restart dev after editing config.
修改 config 后需重启 dev。
See also Config: Everything You Like.
Resolution Order
PostHeader merges three layers:
PostHeader 合并三层配置:
frontmatter field → config.yaml (components.postHeader) → component fallbackSpecial behavior:
- Empty string (
'') in frontmatter → treated as unset → uses config default - Zod catch sentinel: if frontmatter equals the schema default (e.g.
divider: both) but config differs, config wins — avoids accidental overrides when a field was never explicitly set
Frontmatter Fields
These fields in index.md / index.mdx are passed to PostHeader by the page template:
| Field | Type | Schema default | Maps to |
|---|---|---|---|
title | string | — | PostHeader title |
description | string | '' | PostHeader subtitle (sanitized HTML) |
coverImage | string | — | Resolved cover via resolveCollectionCoverImage() |
coverImagePosition | enum | head | Cover placement |
breadcrumbs | boolean | true | Breadcrumb nav |
customBreadcrumbLabels | object | — | Per-segment label overrides |
joinLastBreadcrumb | boolean | false | Merge last two crumbs |
divider | enum | both | top | bottom | both | none |
source | string | — | Source code button URL |
liveDemo | string | — | Live Demo button URL |
coverImagePosition: falseis accepted and normalized tonone(legacy shorthand).
Not part of PostHeader (same frontmatter, different layer)
| Field | Handled by |
|---|---|
toc | Article layout — sticky Table of Contents sidebar |
share | Article layout — SocialShares below content |
narrow | Article layout — prose column width |
publishDate, tags, draft, featuredOrder | Lists, SEO, filtering — not rendered in PostHeader |
There are no built-in publish date, reading time, or view count in PostHeader.
PostHeader 不包含发布日期、阅读时长或浏览量显示。
Component Props
When using PostHeader directly in Astro:
| Prop | Type | Default source | Description |
|---|---|---|---|
title | string | (required) | Main heading text |
subtitle | string | — | Description; limited HTML via sanitize-html |
coverImage | string | ImageMetadata | default asset | Resolved cover image |
coverImagePosition | enum | config / head | Cover placement |
author | { name, image?, bio? } | — | Author metadata |
authorImageResolved | ResolvedImage | — | Optimized avatar from resolveAuthorImageResolved() |
breadcrumbs | boolean | config / true | Show breadcrumb trail |
customBreadcrumbLabels | Record<string, string> | — | Override segment labels; "current" for last item |
joinLastBreadcrumb | boolean | false | Join last two segments as "Prev: Current" |
divider | enum | config / both | Border placement |
source | string | — | GitHub / repo link |
liveDemo | string | — | Demo URL |
headingLevel | string | config / h2 | Title heading tag |
descClass | string | config / text-lg | Subtitle Tailwind classes |
class | string | — | Extra classes on root <section> |
---
import PostHeader from '@components/PostHeader.astro'
---
<PostHeader
title="My Post"
subtitle="A short <strong>intro</strong>"
coverImage={resolvedCover}
author={{ name: 'Pete', bio: 'PetePa.com' }}
authorImageResolved={resolvedAvatar}
/>Cover Image
Co-location (recommended)
coverImage: ./cover.jpg
coverImagePosition: headPlace the file next to index.md / index.mdx. Palo resolves it through resolveCollectionCoverImage(). See Asset Co-Location Guide.
Placement
Render order inside PostHeader:
top → cover (full viewport width) → breadcrumbs → title block → [bottom cover]
head → breadcrumbs → cover → title block → [bottom cover]
bottom → breadcrumbs → title block → cover
none → breadcrumbs → title block (no cover)| Value | Effect |
|---|---|
top | Cover above everything, including breadcrumbs |
head | Cover after breadcrumbs, before title (config default) |
bottom | Cover below title/author/actions |
none | Hide cover (falls back to internal default image if coverImage unset) |
Visual & loading behavior
- Layout:
100vwbreakout,60vh/60dvhheight,object-cover - Progressive load:
ContentImagewith dominant-color placeholder (zero CLS) - PNG covers: placeholder uses dominant color → fades to contrast background after load
- Non-PNG covers: placeholder uses dominant color → fades to transparent after load
- Missing cover: falls back to
src/assets/images/posts/default.png - Cover images use
alt=""(decorative hero); meaning is conveyed by the visible title
Title & Description
- Title renders via
accessible-astro-componentsHeadingatheadingLevel(defaulth2on detail pages) - Description (
descriptionfrontmatter) maps tosubtitle— supports:<b>,<i>,<em>,<strong>,<a>,<span>,<br>
title: Mastering PostHeader
description: A guide to <strong>all parameters</strong> and config defaultsStyle the description globally:
# config.yaml
components:
postHeader:
descClass: "text-base text-neutral-600"Breadcrumbs
Auto-generated from the URL path (Home → segment → … → current).
breadcrumbs: true
customBreadcrumbLabels:
"blog": "Blog"
"portfolio": "Work"
"current": "" # Empty string hides the current page label
joinLastBreadcrumb: falseWith joinLastBreadcrumb: true, the last two segments merge:
joinLastBreadcrumb: true
# /blog/my-post → "Blog: My Post" as the final crumbDisable globally:
components:
postHeader:
showBreadcrumbs: falseOr per post: breadcrumbs: false
Author Block
author:
name: "Pete"
image: "/branding/avatar.png" # public path or co-located ./avatar.png
bio: "PetePa.com"- With a resolved avatar image → custom round avatar + name + bio
- Without image →
Avatarcomponent fromaccessible-astro-components - String shorthand also works in schema:
author: "Pete"
Source & Live Demo
Optional action buttons in the meta row (right on desktop, stacked on mobile):
source: "https://github.com/petepapa/palo"
liveDemo: "https://palo.petepa.com/"Both open in a new tab with rel="noopener noreferrer".
Dividers
divider: both # top | bottom | both | none| Value | Effect |
|---|---|
top | Top border on the header section |
bottom | Bottom border on the header section |
both | Top and bottom borders (config default) |
none | No section borders |
A subtle inner divider line always separates the cover/title area from the article body.
封面/标题区与正文之间始终有一条内部分割线。
Customization Recipes
Dramatic top cover (this page)
coverImage: ./cover.jpg
coverImagePosition: top
divider: bothText-first, no hero image
coverImagePosition: none
divider: bottomMinimal breadcrumbs + centered description
# config.yaml
components:
postHeader:
showBreadcrumbs: false
descClass: "text-xl text-center"Portfolio project with demo links
title: Palo Theme
description: Accessible Astro starter theme
coverImage: ./cover.jpg
source: "https://github.com/petepapa/palo"
liveDemo: "https://palo.petepa.com/"Tips
Use
./cover.jpgco-located paths — filename extension must match exactlyDefault
coverImagePosition: head— breadcrumbs stay above the hero; usetopfor full-bleed impactDetail pages use
h2— keeps a single logicalh1elsewhere in the page outline; adjust via config if neededEdit
config.yamlfor site-wide defaults — only override in frontmatter when a single post differstocandshareare separate — they live in the article layout below PostHeader, not inside the componentPNG covers get a contrast-color stage after load — good for logos and transparent artwork
封面用
./cover.jpg同域路径 — 扩展名必须完全一致默认
coverImagePosition: head— 面包屑在封面之上;top适合全屏冲击感详情页标题默认
h2— 可通过 config 调整全站默认值改 config — 单篇差异再用 frontmatter 覆盖
toc与share独立于 PostHeader — 由文章布局渲染PNG 封面 加载后会过渡到反差色背景
Accessibility
- Semantic
<section>with proper heading level viaHeadingcomponent - Breadcrumbs use
accessible-astro-componentsBreadcrumbs/BreadcrumbsItemwithcurrentPage - Decorative cover images use
alt="" - Source / Demo links are real
<a>elements wrapping accessibleButtoncomponents - Subtitle HTML is sanitized — no arbitrary tags or scripts
- Responsive meta grid stacks on narrow viewports
Troubleshooting
Cover not showing
- Check
coverImagePositionis notnone - Verify
./filenamematches the actual file extension - Run
npm run copy-imagesin dev if using co-located frontmatter covers
Config change not applied
Restart npm run dev. For fields with Zod defaults, ensure you explicitly set frontmatter or rely on config override logic.
divider: true not valid
Use divider: both (or top / bottom / none). Boolean true is not in the schema.
Conclusion
PostHeader is Palo’s config-driven detail-page hero: components.postHeader sets heading level, description styling, cover placement, dividers, and breadcrumb defaults; frontmatter fine-tunes per post. Pair it with co-located ./cover.jpg, breadcrumb labels, and optional Source / Live Demo links for a consistent, accessible reading entry on every blog post and portfolio project.
PostHeader 是 Palo 由 config 驱动的详情页页头:components.postHeader 设定标题层级、摘要样式、封面位置、分割线与面包屑默认值;frontmatter 按篇微调。配合同域 ./cover.jpg、面包屑标签和 Source / Live Demo 链接,为每篇文章和项目提供一致、无障碍的阅读入口。
Share this post
Like this post? Share it with your network!
