From 634cc090072fbc2f99eaef4a19639c016e3e245c Mon Sep 17 00:00:00 2001
From: Patrick Kollitsch <83281+davidsneighbour@users.noreply.github.com>
Date: Sun, 07 Jun 2026 03:47:14 +0000
Subject: [PATCH] fix: make header height configurable (#972)
---
layouts/_partials/site-header.html | 6 +
scripts/test-hugo-quickstart.ts | 133 ++++++++++++++++++++++++++++++++++++++++++++
layouts/_partials/page-header.html | 3
3 files changed, 139 insertions(+), 3 deletions(-)
diff --git a/layouts/_partials/page-header.html b/layouts/_partials/page-header.html
index 10d290e..393988c 100644
--- a/layouts/_partials/page-header.html
+++ b/layouts/_partials/page-header.html
@@ -4,6 +4,7 @@
{{/* Trimming the slash and adding absURL make sure the image works no matter where our site lives */}}
{{ $featured_image_class := .Params.featured_image_class | compare.Default "cover bg-center" }}
{{ $cover_dimming_class := .Params.cover_dimming_class | compare.Default "bg-black-60" }}
+ {{ $header_section_class := .Param "header_section_class" | compare.Default "tc-l pv6 ph3 ph4-ns" }}
{{ $responsive_image_widths := .Site.Params.ananke.responsive_image_widths | compare.Default (slice 480 960 1440 1920) }}
{{ $responsive_header_id := "" }}
{{ $background_image := $featured_image }}
@@ -31,7 +32,7 @@
<header {{ with $responsive_header_id }}id="{{ . }}" {{ end }}class="{{ $featured_image_class }}" style="background-image: url('{{ $background_image }}');">
<div class="{{ $cover_dimming_class }}">
{{ partials.Include "site-navigation.html" . }}
- <div class="tc-l pv6 ph3 ph4-ns">
+ <div class="{{ $header_section_class }}">
{{ if not .Params.omit_header_text }}
<div class="f2 f1-l fw2 white-90 mb0 lh-title">{{ .Title | compare.Default .Site.Title }}</div>
{{ with .Params.description }}
diff --git a/layouts/_partials/site-header.html b/layouts/_partials/site-header.html
index 7a67967..19ba931 100644
--- a/layouts/_partials/site-header.html
+++ b/layouts/_partials/site-header.html
@@ -2,11 +2,12 @@
{{ if $featured_image }}
{{/* Trimming the slash and adding absURL make sure the image works no matter where our site lives */}}
{{ $featured_image_class := site.Params.featured_image_class | compare.Default "cover bg-top" }}
+ {{ $header_section_class := .Param "header_section_class" | compare.Default "tc-l pv4 pv6-l ph3 ph4-ns" }}
<header class="{{ $featured_image_class }}" style="background-image: url('{{ $featured_image }}');">
{{ $cover_dimming_class := site.Params.cover_dimming_class | compare.Default "bg-black-60" }}
<div class="{{ $cover_dimming_class }}">
{{ partials.Include "site-navigation.html" .}}
- <div class="tc-l pv4 pv6-l ph3 ph4-ns">
+ <div class="{{ $header_section_class }}">
<h1 class="f2 f-subheadline-l fw2 white-90 mb0 lh-title">
{{ .Title | compare.Default .Site.Title }}
</h1>
@@ -22,7 +23,8 @@
<header>
<div class="pb3-m pb6-l {{ .Site.Params.background_color_class | compare.Default "bg-black" }}">
{{ partials.Include "site-navigation.html" . }}
- <div class="tc-l pv3 ph3 ph4-ns">
+ {{ $header_section_class := .Param "header_section_class" | compare.Default "tc-l pv3 ph3 ph4-ns" }}
+ <div class="{{ $header_section_class }}">
<h1 class="f2 f-subheadline-l fw2 light-silver mb0 lh-title">
{{ .Title | compare.Default .Site.Title }}
</h1>
diff --git a/scripts/test-hugo-quickstart.ts b/scripts/test-hugo-quickstart.ts
index 0c83ad8..d80d64d 100644
--- a/scripts/test-hugo-quickstart.ts
+++ b/scripts/test-hugo-quickstart.ts
@@ -711,6 +711,104 @@
}
/**
+ * Sentinel CSS class used to verify the configurable hero header spacing.
+ *
+ * Issue #504: the height of the hero header is controlled by the
+ * `header_section_class` parameter. The value is unique so it can only appear in
+ * the output when the front matter override is honoured.
+ */
+const HEADER_SECTION_CLASS_MARKER = "ananke-header-test-pv7";
+
+/**
+ * Default header section spacing rendered by `page-header.html` for a single
+ * page with a featured image when `header_section_class` is not set.
+ */
+const DEFAULT_PAGE_HEADER_SECTION_CLASS = "tc-l pv6 ph3 ph4-ns";
+
+/**
+ * Create two single pages that exercise the configurable header section class:
+ * one overrides `header_section_class` in front matter, the other relies on the
+ * theme default. Both set `featured_image` so the hero header branch renders.
+ *
+ * @param contentDir Absolute path to the project `content` directory.
+ */
+async function writeHeaderSectionClassFixtures(
+ contentDir: string,
+): Promise<void> {
+ const overridePage = [
+ "+++",
+ "title = 'Custom Header Height'",
+ "featured_image = '/images/custom-hero.jpg'",
+ `header_section_class = '${HEADER_SECTION_CLASS_MARKER} ph3 ph4-ns'`,
+ "+++",
+ "",
+ "Body.",
+ "",
+ ].join("\n");
+
+ const defaultPage = [
+ "+++",
+ "title = 'Default Header Height'",
+ "featured_image = '/images/default-hero.jpg'",
+ "+++",
+ "",
+ "Body.",
+ "",
+ ].join("\n");
+
+ await writeTextFile(join(contentDir, "custom-header.md"), overridePage);
+ await writeTextFile(join(contentDir, "default-header.md"), defaultPage);
+}
+
+/**
+ * Assert that the configurable `header_section_class` parameter is honoured on
+ * hero headers and that omitting it keeps the historical default spacing.
+ *
+ * @param projectRoot Absolute path to the temporary quickstart project.
+ * @throws Error when the override is dropped, leaks, or the default changes.
+ */
+async function assertHeaderSectionClassConfigurable(
+ projectRoot: string,
+): Promise<void> {
+ const failures: string[] = [];
+
+ const overrideHtml = await readTextFile(
+ join(projectRoot, "public", "custom-header", "index.html"),
+ );
+ const defaultHtml = await readTextFile(
+ join(projectRoot, "public", "default-header", "index.html"),
+ );
+
+ if (!overrideHtml.includes(HEADER_SECTION_CLASS_MARKER)) {
+ failures.push(
+ `- custom 'header_section_class' value '${HEADER_SECTION_CLASS_MARKER}' was not applied to the hero header`,
+ );
+ }
+
+ if (defaultHtml.includes(HEADER_SECTION_CLASS_MARKER)) {
+ failures.push(
+ "- custom 'header_section_class' value leaked onto a page that did not set it",
+ );
+ }
+
+ if (!defaultHtml.includes(DEFAULT_PAGE_HEADER_SECTION_CLASS)) {
+ failures.push(
+ `- default header section spacing '${DEFAULT_PAGE_HEADER_SECTION_CLASS}' was missing when 'header_section_class' was not set`,
+ );
+ }
+
+ if (failures.length > 0) {
+ throw new Error(
+ [
+ "Strict assertion failed: configurable header section class did not behave as expected.",
+ "Failed assertions:",
+ ...failures,
+ ].join("\n"),
+ );
+ }
+}
+
+/**
* Determine whether a directory is the work tree of a Git repository.
*
* @param path Absolute directory path.
@@ -1103,6 +1201,41 @@
await assertDraftHiddenInProduction(projectRoot, homepagePath);
console.log("[OK ] Production build should exclude draft content");
+ console.log("\n[RUN] Configurable hero header section class (issue #504)");
+ await writeHeaderSectionClassFixtures(join(projectRoot, "content"));
+ const headerSectionBuildStep: StepDefinition = {
+ name: "Build site with configurable header section fixtures",
+ command: "hugo",
+ args: [],
+ cwd: projectRoot,
+ expectedFiles: [
+ "public/custom-header/index.html",
+ "public/default-header/index.html",
+ ],
+ };
+ const headerSectionBuildReport = await executeHugoBuildStep(
+ headerSectionBuildStep,
+ projectRoot,
+ );
+ reports.push(headerSectionBuildReport);
+
+ if (options.verbose) {
+ console.log(
+ ` ${formatCommand(headerSectionBuildStep.command, headerSectionBuildStep.args)}`,
+ );
+ console.log(
+ `[OK ] ${headerSectionBuildStep.name} (${headerSectionBuildReport.result.durationMs} ms, exit ${String(headerSectionBuildReport.result.code)})`,
+ );
+
+ const trimmedOutput = headerSectionBuildReport.result.combined.trim();
+ if (trimmedOutput) {
+ console.log(trimmedOutput);
+ }
+ }
+
+ await assertHeaderSectionClassConfigurable(projectRoot);
+ console.log("[OK ] Configurable hero header section class (issue #504)");
+
console.log("\nResult: PASS");
if (options.keepOnSuccess) {
--
Gitblit v1.10.0