diff --git a/CLAUDE.md b/CLAUDE.md index 6669853..4821ef8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -178,7 +178,8 @@ When `.hugo.html` components call Hugo partials, they pass a dict with kebab-cas ## Key Constraints - **Bookshop live editing**: Components must access arguments directly (not through helper partials) -- **Dual parameter names**: Support both snake_case (CloudCannon) and kebab-case (Hugo) using `(or .snake_case (index . "kebab-case"))` +- **Dual parameter names**: Support both snake_case (CloudCannon) and kebab-case (Hugo) using `(or .snake_case (index . "kebab-case"))`. For arguments where `0` or `false` is a meaningful value (such as `heading_level`), test key presence instead: `(cond (isset . "snake_case") .snake_case (index . "kebab-case"))` +- **Heading injection contract**: `page/blocks.html` injects a heading level only into blocks whose component sidecar (`component-library/components//.yml`) declares a `heading-level` argument. A component that renders a section title but omits that entry silently keeps rendering `
` titles instead of failing validation - **Hugo version**: Requires Hugo Extended 0.147.6+ - **Conventional Commits**: All commits must follow the specification (enforced by commitlint + husky) - **Semantic versioning**: Releases are automated via semantic-release on the `main` branch diff --git a/component-library/components/about/about.bookshop.yml b/component-library/components/about/about.bookshop.yml index affa772..3d99dbb 100644 --- a/component-library/components/about/about.bookshop.yml +++ b/component-library/components/about/about.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/about/about.hugo.html b/component-library/components/about/about.hugo.html index d6c5976..50f7be2 100644 --- a/component-library/components/about/about.hugo.html +++ b/component-library/components/about/about.hugo.html @@ -39,8 +39,9 @@ {{ $ratio := index $settings "ratio" | default "auto" }} {{/* Generate the hero */}} - {{ $raw := partial "assets/hero.html" (dict + {{ $raw := partial "assets/hero.html" (dict "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) "heading" (merge (dict "arrangement" "above" "width" 8) .heading) "illustration" (merge (dict "ratio" $ratio) .illustration) "order" .order diff --git a/component-library/components/approach/approach.bookshop.yml b/component-library/components/approach/approach.bookshop.yml index 2574641..af01c40 100644 --- a/component-library/components/approach/approach.bookshop.yml +++ b/component-library/components/approach/approach.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/approach/approach.hugo.html b/component-library/components/approach/approach.hugo.html index bdfd868..8fc5c1a 100644 --- a/component-library/components/approach/approach.hugo.html +++ b/component-library/components/approach/approach.hugo.html @@ -71,10 +71,11 @@ {{ if $split }} {{/* Split layout: heading left, elements stacked right (50-50 on md+). */}} {{ $title := partial "assets/section-title.html" (dict - "page" $page - "heading" (merge (dict "size" 5) (or .heading dict)) - "justify" .justify - "class" "text-start mb-0" + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" (merge (dict "size" 5) (or .heading dict)) + "justify" .justify + "class" "text-start mb-0" ) }} {{ $items := "" }} @@ -140,10 +141,11 @@ {{ end}} {{- $raw = printf "%s%s" $raw (partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y))) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y))) -}} {{/* Add featured illustration */}} diff --git a/component-library/components/articles/articles.bookshop.yml b/component-library/components/articles/articles.bookshop.yml index a2f2069..addfa98 100644 --- a/component-library/components/articles/articles.bookshop.yml +++ b/component-library/components/articles/articles.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/articles/articles.hugo.html b/component-library/components/articles/articles.hugo.html index 76d2368..1e242a3 100644 --- a/component-library/components/articles/articles.hugo.html +++ b/component-library/components/articles/articles.hugo.html @@ -103,10 +103,11 @@ {{/* Main code */}} {{ if or (gt (len $pages) 0) (not .hide_empty) }} {{- $raw = printf "%s%s" $raw (partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y))) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y))) -}} {{ $partial := "assets/card-group.html" }} diff --git a/component-library/components/cards/cards.bookshop.yml b/component-library/components/cards/cards.bookshop.yml index ae477a5..ba6dc16 100644 --- a/component-library/components/cards/cards.bookshop.yml +++ b/component-library/components/cards/cards.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/cards/cards.hugo.html b/component-library/components/cards/cards.hugo.html index 75244c1..7c33b4a 100644 --- a/component-library/components/cards/cards.hugo.html +++ b/component-library/components/cards/cards.hugo.html @@ -53,10 +53,11 @@ {{/* Main code */}} {{- $raw = printf "%s%s" $raw (partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y))) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y))) -}} {{/* Init base arguments for card group */}} diff --git a/component-library/components/contact-form/contact-form.bookshop.yml b/component-library/components/contact-form/contact-form.bookshop.yml index c932ce6..ba89f1b 100644 --- a/component-library/components/contact-form/contact-form.bookshop.yml +++ b/component-library/components/contact-form/contact-form.bookshop.yml @@ -16,6 +16,7 @@ blueprint: content: align: width: + heading_level: background: backdrop: color: diff --git a/component-library/components/contact-form/contact-form.hugo.html b/component-library/components/contact-form/contact-form.hugo.html index dbc37ab..4d1adec 100644 --- a/component-library/components/contact-form/contact-form.hugo.html +++ b/component-library/components/contact-form/contact-form.hugo.html @@ -61,9 +61,10 @@ {{ if .illustration }} {{/* Embed the form in a horizontal hero with an illustration */}} {{ $width := sub 12 (.illustration.width | default 6) }} - {{ $raw = partial "assets/hero.html" (dict + {{ $raw = partial "assets/hero.html" (dict "page" $page "raw" (printf `
%s` $padding.y $form) + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) "heading" (merge .heading (dict "width" $width)) "illustration" (merge .illustration (dict "width" 12)) "order" .order @@ -75,10 +76,11 @@ }} {{ else }} {{- $raw = partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y)) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y)) -}} {{ $raw = printf "%s%s" $raw $form }} {{ end }} diff --git a/component-library/components/cta/cta.bookshop.yml b/component-library/components/cta/cta.bookshop.yml index 37f05d4..25389aa 100644 --- a/component-library/components/cta/cta.bookshop.yml +++ b/component-library/components/cta/cta.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/cta/cta.hugo.html b/component-library/components/cta/cta.hugo.html index b2602bb..2fc9e80 100644 --- a/component-library/components/cta/cta.hugo.html +++ b/component-library/components/cta/cta.hugo.html @@ -42,9 +42,10 @@ {{ end }} {{ end }} - {{ $raw := partial "assets/contact.html" (dict + {{ $raw := partial "assets/contact.html" (dict "page" $page "orientation" "horizontal" + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) "heading" .heading "contact" .contact "caption-url" (or .caption_url (index . "caption-url")) diff --git a/component-library/components/faq/faq.bookshop.yml b/component-library/components/faq/faq.bookshop.yml index 4cc5f22..ca16138 100644 --- a/component-library/components/faq/faq.bookshop.yml +++ b/component-library/components/faq/faq.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/faq/faq.hugo.html b/component-library/components/faq/faq.hugo.html index 4bb48ba..9925b9d 100644 --- a/component-library/components/faq/faq.hugo.html +++ b/component-library/components/faq/faq.hugo.html @@ -38,10 +38,11 @@ {{ $color := "" }} {{ if .contrast }}{{ $color = "white" }}{{ end }} {{- $raw := partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y)) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y)) -}} {{ $class := "" }} diff --git a/component-library/components/featured/featured.bookshop.yml b/component-library/components/featured/featured.bookshop.yml index 9ff83c2..638376f 100644 --- a/component-library/components/featured/featured.bookshop.yml +++ b/component-library/components/featured/featured.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/featured/featured.hugo.html b/component-library/components/featured/featured.hugo.html index 1c7be27..62569a5 100644 --- a/component-library/components/featured/featured.hugo.html +++ b/component-library/components/featured/featured.hugo.html @@ -31,8 +31,9 @@ {{ $page := or ._page page }} {{ if not $error }} - {{ $raw := partial "assets/hero.html" (dict + {{ $raw := partial "assets/hero.html" (dict "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) "heading" (merge (dict "width" 8) (or .heading dict)) "illustration" (merge (dict "ratio" "auto") (or .illustration dict)) "order" .order diff --git a/component-library/components/heading/heading.bookshop.yml b/component-library/components/heading/heading.bookshop.yml index 19f1d89..adde3d0 100644 --- a/component-library/components/heading/heading.bookshop.yml +++ b/component-library/components/heading/heading.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/heading/heading.hugo.html b/component-library/components/heading/heading.hugo.html index 2f5b8b1..5618b90 100644 --- a/component-library/components/heading/heading.hugo.html +++ b/component-library/components/heading/heading.hugo.html @@ -43,9 +43,10 @@ {{/* Main code */}} {{- $raw := partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify) -}} {{ if $raw }} diff --git a/component-library/components/hero/hero.bookshop.yml b/component-library/components/hero/hero.bookshop.yml index 9c970d4..1a64202 100644 --- a/component-library/components/hero/hero.bookshop.yml +++ b/component-library/components/hero/hero.bookshop.yml @@ -18,6 +18,7 @@ blueprint: arrangement: width: 8 size: + heading_level: background: backdrop: color: diff --git a/component-library/components/hero/hero.hugo.html b/component-library/components/hero/hero.hugo.html index c1bb4ed..a8a199f 100644 --- a/component-library/components/hero/hero.hugo.html +++ b/component-library/components/hero/hero.hugo.html @@ -32,17 +32,18 @@ {{ if not $error }} {{ $raw := partial "assets/hero.html" (dict - "page" $page - "breadcrumb" .breadcrumb - "heading" .heading - "illustration" .illustration - "align" .align - "order" .order - "link-type" (or .link_type (index . "link-type")) - "links" .links - "orientation" .orientation - "width" .width - "cover" .cover + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "breadcrumb" .breadcrumb + "heading" .heading + "illustration" .illustration + "align" .align + "order" .order + "link-type" (or .link_type (index . "link-type")) + "links" .links + "orientation" .orientation + "width" .width + "cover" .cover ) }} diff --git a/component-library/components/list/list.bookshop.yml b/component-library/components/list/list.bookshop.yml index b840ffe..ba84809 100644 --- a/component-library/components/list/list.bookshop.yml +++ b/component-library/components/list/list.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/list/list.hugo.html b/component-library/components/list/list.hugo.html index 39f973a..757bc01 100644 --- a/component-library/components/list/list.hugo.html +++ b/component-library/components/list/list.hugo.html @@ -86,10 +86,11 @@ {{ $hideEmpty := or .hide_empty (index . "hide-empty") }} {{ if or (gt (len $pages) 0) (not $hideEmpty) }} {{- $raw := partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y)) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y)) -}} {{ if gt (len $pages) 0 }} {{ $content := "" }} diff --git a/component-library/components/menu/menu.bookshop.yml b/component-library/components/menu/menu.bookshop.yml index ab43df0..b67dd94 100644 --- a/component-library/components/menu/menu.bookshop.yml +++ b/component-library/components/menu/menu.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/menu/menu.hugo.html b/component-library/components/menu/menu.hugo.html index d8554f7..1bd89d8 100644 --- a/component-library/components/menu/menu.hugo.html +++ b/component-library/components/menu/menu.hugo.html @@ -36,10 +36,11 @@ {{/* Main code */}} {{- $raw := partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y)) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y)) -}} {{- $raw = printf "%s%s" $raw (partial "assets/menu.html" (dict diff --git a/component-library/components/panels/panels.bookshop.yml b/component-library/components/panels/panels.bookshop.yml index 45dfaf0..dc925cb 100644 --- a/component-library/components/panels/panels.bookshop.yml +++ b/component-library/components/panels/panels.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/panels/panels.hugo.html b/component-library/components/panels/panels.hugo.html index bb422ca..1537b63 100644 --- a/component-library/components/panels/panels.hugo.html +++ b/component-library/components/panels/panels.hugo.html @@ -79,10 +79,11 @@ {{/* Main code */}} {{- $raw := partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y)) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y)) -}} {{- $raw = printf "%s%s" $raw (partial "assets/nav.html" (dict diff --git a/component-library/components/preview/preview.bookshop.yml b/component-library/components/preview/preview.bookshop.yml index 39d85d1..69b4b87 100644 --- a/component-library/components/preview/preview.bookshop.yml +++ b/component-library/components/preview/preview.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/preview/preview.hugo.html b/component-library/components/preview/preview.hugo.html index a2b6656..2227e4e 100644 --- a/component-library/components/preview/preview.hugo.html +++ b/component-library/components/preview/preview.hugo.html @@ -49,6 +49,7 @@ {{/* Main code */}} {{ $raw := partial "assets/preview.html" (dict "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) "url" .url "device" .device "controls-placement" (or .controls_placement (index . "controls-placement")) diff --git a/component-library/components/team/team.bookshop.yml b/component-library/components/team/team.bookshop.yml index 3a675a0..b008dcf 100644 --- a/component-library/components/team/team.bookshop.yml +++ b/component-library/components/team/team.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/team/team.hugo.html b/component-library/components/team/team.hugo.html index 45e64ab..70d35a1 100644 --- a/component-library/components/team/team.hugo.html +++ b/component-library/components/team/team.hugo.html @@ -83,10 +83,11 @@ {{ $hideEmpty := or .hide_empty (index . "hide-empty") }} {{ if or (gt (len $pages) 0) (not $hideEmpty) }} {{- $raw := partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y)) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y)) -}} {{ $partial := "assets/card-group.html" }} diff --git a/component-library/components/testimonials/testimonials.bookshop.yml b/component-library/components/testimonials/testimonials.bookshop.yml index 3009e89..7e7c5c0 100644 --- a/component-library/components/testimonials/testimonials.bookshop.yml +++ b/component-library/components/testimonials/testimonials.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/testimonials/testimonials.hugo.html b/component-library/components/testimonials/testimonials.hugo.html index 74c5654..e89ffc1 100644 --- a/component-library/components/testimonials/testimonials.hugo.html +++ b/component-library/components/testimonials/testimonials.hugo.html @@ -36,10 +36,11 @@ {{/* Main code */}} {{- $raw := partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y)) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y)) -}} {{ $partial := partial "assets/testimonial-carousel.html" (dict diff --git a/component-library/components/video-message/video-message.bookshop.yml b/component-library/components/video-message/video-message.bookshop.yml index f531f37..05ec411 100644 --- a/component-library/components/video-message/video-message.bookshop.yml +++ b/component-library/components/video-message/video-message.bookshop.yml @@ -17,6 +17,7 @@ blueprint: arrangement: width: size: + heading_level: background: backdrop: color: diff --git a/component-library/components/video-message/video-message.hugo.html b/component-library/components/video-message/video-message.hugo.html index c4d574d..f4fe201 100644 --- a/component-library/components/video-message/video-message.hugo.html +++ b/component-library/components/video-message/video-message.hugo.html @@ -155,10 +155,11 @@ {{ end}} {{- $raw := partial "assets/section-title.html" (dict - "page" $page - "heading" .heading - "justify" .justify - "class" (printf "pb-%d" $padding.y)) + "page" $page + "heading-level" (cond (isset . "heading_level") .heading_level (index . "heading-level")) + "heading" .heading + "justify" .justify + "class" (printf "pb-%d" $padding.y)) -}} {{ $video := "" }} diff --git a/data/structures/contact.yml b/data/structures/contact.yml index b862bc3..1507b09 100644 --- a/data/structures/contact.yml +++ b/data/structures/contact.yml @@ -2,6 +2,8 @@ comment: >- Displays a contact banner, typically placed at the bottom or right-hand side of the page. group: partial arguments: + heading-level: + release: v2.4.0 page: data: optional: true diff --git a/data/structures/hero.yml b/data/structures/hero.yml index ee3a2c5..a15e3d5 100644 --- a/data/structures/hero.yml +++ b/data/structures/hero.yml @@ -3,6 +3,8 @@ comment: >- supports a heading, featured illustration, and navigation links. You can also add a background image with an overlay to improve contrast. arguments: + heading-level: + release: v2.4.0 page: breadcrumb: heading: diff --git a/data/structures/preview.yml b/data/structures/preview.yml index 77e4e68..4f0fd83 100644 --- a/data/structures/preview.yml +++ b/data/structures/preview.yml @@ -1,6 +1,8 @@ comment: >- Renders a live URL preview with switchable device views (desktop, tablet, mobile). arguments: + heading-level: + release: v2.4.0 page: optional: true comment: >- diff --git a/exampleSite/assets/jsconfig.json b/exampleSite/assets/jsconfig.json new file mode 100644 index 0000000..89453fc --- /dev/null +++ b/exampleSite/assets/jsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "paths": { + "*": [ + "../../../../../../go/pkg/mod/github.com/gethinode/hinode/v3@v3.19.3/assets/*", + "../../../../../../go/pkg/mod/github.com/nextapps-de/flexsearch@v0.0.0-20260529083235-f7ed963096a0/dist/*", + "../../../../../../go/pkg/mod/github.com/twbs/bootstrap@v5.3.8+incompatible/dist/js/*" + ] + } + } +} \ No newline at end of file diff --git a/exampleSite/go.mod b/exampleSite/go.mod index f56ccdd..82e0cc5 100644 --- a/exampleSite/go.mod +++ b/exampleSite/go.mod @@ -6,7 +6,7 @@ require ( github.com/FortAwesome/Font-Awesome v0.0.0-20260715180930-14c65a3747d0 // indirect github.com/airbnb/lottie-web v5.13.0+incompatible // indirect github.com/cloudcannon/bookshop/hugo/v3 v3.19.0 // indirect - github.com/gethinode/hinode/v3 v3.19.2 // indirect + github.com/gethinode/hinode/v3 v3.19.3 // indirect github.com/gethinode/mod-blocks/v2 v2.3.6 // indirect github.com/gethinode/mod-bootstrap v1.5.0 // indirect github.com/gethinode/mod-csp v1.0.14 // indirect @@ -18,7 +18,7 @@ require ( github.com/gethinode/mod-lottie/v3 v3.0.4 // indirect github.com/gethinode/mod-mermaid/v5 v5.0.4 // indirect github.com/gethinode/mod-simple-datatables/v4 v4.1.1 // indirect - github.com/gethinode/mod-utils/v6 v6.8.5 // indirect + github.com/gethinode/mod-utils/v6 v6.9.0 // indirect github.com/nextapps-de/flexsearch v0.0.0-20260529083235-f7ed963096a0 // indirect github.com/twbs/bootstrap v5.3.8+incompatible // indirect ) diff --git a/exampleSite/go.sum b/exampleSite/go.sum index a13db42..670639d 100644 --- a/exampleSite/go.sum +++ b/exampleSite/go.sum @@ -36,6 +36,8 @@ github.com/gethinode/hinode/v3 v3.18.0 h1:9ITPE1I0JlyGKwirYiZM759kPYd5YRD+mFtvPO github.com/gethinode/hinode/v3 v3.18.0/go.mod h1:PqmewfbVBnwMVs6C4ZAKxjt9pYTAsOz+YF9gznJKHsk= github.com/gethinode/hinode/v3 v3.19.2 h1:7WmBNZyS3R+hIi2BBMkZIh31MQix830wpCWwl65u+UA= github.com/gethinode/hinode/v3 v3.19.2/go.mod h1:AAIoKEtwZGLcUQA0l+G/RKs9XPLX1TU61GfTYxZ+Yrs= +github.com/gethinode/hinode/v3 v3.19.3 h1:gykPH9leoa1i69ATzGLRRSyeKUNtpEequxwvsnB/eDA= +github.com/gethinode/hinode/v3 v3.19.3/go.mod h1:9yBDgansb+wj1ingsqt2odSS8NMY+iRglICyLLgkIjo= github.com/gethinode/mod-blocks/v2 v2.2.5 h1:8glKSX7OENSgbRAp+Bc1JL68Ix3DSWcHWh5dlsNrNsk= github.com/gethinode/mod-blocks/v2 v2.2.5/go.mod h1:1a4A2RrNSEoqgUjJoNPc2T+JtfPe0GvjHNrxjXauWCA= github.com/gethinode/mod-blocks/v2 v2.2.6 h1:gTrTTyUcFLjcjuqvr5Ex923F2E777vOzkbFJDzNaSz0= @@ -120,6 +122,8 @@ github.com/gethinode/mod-utils/v6 v6.8.4 h1:L8x3IcWEn2kms7WWuYwtbi/x7lIR18z+eJhU github.com/gethinode/mod-utils/v6 v6.8.4/go.mod h1:E5tO9w3VKaidJpu1nI8zAKmh0bddFHOIIQnudAaXQTs= github.com/gethinode/mod-utils/v6 v6.8.5 h1:hzJgNjw6NIORMvxeJ3Q6+qPaPzLc4CQtNTWRXFVjFPM= github.com/gethinode/mod-utils/v6 v6.8.5/go.mod h1:E5tO9w3VKaidJpu1nI8zAKmh0bddFHOIIQnudAaXQTs= +github.com/gethinode/mod-utils/v6 v6.9.0 h1:+7RsNAfYCaM3rAzwrkTC6Ui3vcpGYWj1Ek1CmUVcaq0= +github.com/gethinode/mod-utils/v6 v6.9.0/go.mod h1:E5tO9w3VKaidJpu1nI8zAKmh0bddFHOIIQnudAaXQTs= github.com/nextapps-de/flexsearch v0.0.0-20260529083235-f7ed963096a0 h1:QDKcU3q39lFGzdVwM6kgCGnW3ibbMfYIi0Rwl62iJpo= github.com/nextapps-de/flexsearch v0.0.0-20260529083235-f7ed963096a0/go.mod h1:5GdMfPAXzbA2gXBqTjC6l27kioSYzHlqDMh0+wyx7sU= github.com/twbs/bootstrap v5.3.8+incompatible h1:eK1fsXP7R/FWFt+sSNmmvUH9usPocf240nWVw7Dh02o= diff --git a/go.mod b/go.mod index 312918d..044ca96 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,5 @@ go 1.19 require ( github.com/cloudcannon/bookshop/hugo/v3 v3.19.0 // indirect github.com/gethinode/mod-fontawesome/v6 v6.1.1 // indirect - github.com/gethinode/mod-utils/v6 v6.8.5 // indirect + github.com/gethinode/mod-utils/v6 v6.9.0 // indirect ) diff --git a/go.sum b/go.sum index 925be6d..a9ef8a6 100644 --- a/go.sum +++ b/go.sum @@ -24,3 +24,5 @@ github.com/gethinode/mod-utils/v6 v6.8.4 h1:L8x3IcWEn2kms7WWuYwtbi/x7lIR18z+eJhU github.com/gethinode/mod-utils/v6 v6.8.4/go.mod h1:E5tO9w3VKaidJpu1nI8zAKmh0bddFHOIIQnudAaXQTs= github.com/gethinode/mod-utils/v6 v6.8.5 h1:hzJgNjw6NIORMvxeJ3Q6+qPaPzLc4CQtNTWRXFVjFPM= github.com/gethinode/mod-utils/v6 v6.8.5/go.mod h1:E5tO9w3VKaidJpu1nI8zAKmh0bddFHOIIQnudAaXQTs= +github.com/gethinode/mod-utils/v6 v6.9.0 h1:+7RsNAfYCaM3rAzwrkTC6Ui3vcpGYWj1Ek1CmUVcaq0= +github.com/gethinode/mod-utils/v6 v6.9.0/go.mod h1:E5tO9w3VKaidJpu1nI8zAKmh0bddFHOIIQnudAaXQTs= diff --git a/layouts/partials/assets/contact.html b/layouts/partials/assets/contact.html index 280730b..ab6f019 100644 --- a/layouts/partials/assets/contact.html +++ b/layouts/partials/assets/contact.html @@ -66,6 +66,7 @@ {{ partial "assets/hero.html" (dict "page" $page + "heading-level" $args.headingLevel "heading" (merge $heading (dict "size" 4 "width" 10)) "background" $args.background "illustration" $illustration diff --git a/layouts/partials/assets/hero.html b/layouts/partials/assets/hero.html index 43b9360..b94e4cd 100644 --- a/layouts/partials/assets/hero.html +++ b/layouts/partials/assets/hero.html @@ -123,6 +123,7 @@ {{ $title := partial "assets/section-title.html" (dict "page" $page "heading" $heading + "heading-level" $args.headingLevel "use-title" $args.useTitle "links" $args.links "link-type" $args.linkType diff --git a/layouts/partials/assets/preview.html b/layouts/partials/assets/preview.html index 4f7a728..3df7cb2 100644 --- a/layouts/partials/assets/preview.html +++ b/layouts/partials/assets/preview.html @@ -309,8 +309,9 @@ {{/* Optional section heading */}} {{ if $args.heading.title }} {{ partial "assets/section-title.html" (dict - "page" $page - "heading" $args.heading + "page" $page + "heading" $args.heading + "heading-level" $args.headingLevel ) }} {{ end }} diff --git a/layouts/partials/page/blocks.html b/layouts/partials/page/blocks.html index 70118f4..d2944fb 100644 --- a/layouts/partials/page/blocks.html +++ b/layouts/partials/page/blocks.html @@ -1,24 +1,76 @@ {{/* Renders the content blocks of a page. Callers either pass the page itself (legacy) or a dict - with the arguments "page" (owning page) and "embed" (optional flag to indicate the blocks are - embedded within another element). + with the arguments "page" (owning page), "embed" (optional flag to indicate the blocks are + embedded within another element) and "heading-level" (optional level for the first block that + carries a title). */}} {{/* Initialize arguments */}} {{ $none := dict }} {{ $page := . }} {{ $embed := $none.missing }} +{{ $headingLevel := 0 }} {{ if reflect.IsMap . }} {{ $page = .page }} {{ $embed = .embed }} + {{ $headingLevel = or (index . "heading-level") 0 }} {{ end }} {{ with $page.Params.content_blocks }} + {{/* Locate the block that opens the page. Blocks stand in for the page header when the layout + renders none, so the first one carrying a title takes the level the caller asked for and + every block after it becomes a subsection. Deriving this from the block list rather than + from the order in which blocks render keeps the outline stable, because Hugo decides for + itself when a page's content is rendered. A block that suppresses its own heading (an + explicit level of 0) or whose component does not declare heading_level in its blueprint + is passed over. A block that hides itself when its section is empty (hide_empty) + ranks last: a later titled block wins over it, and the first such block leads only when + no other candidate exists. Whether such a block will render is unknown here; when every + candidate hides itself and the first turns out empty while a later one renders, the + page has no h1. */}} + {{ $components := site.Data.structures.components | default dict }} + {{ $lead := -1 }} + {{ if gt $headingLevel 0 }} + {{ $fallback := -1 }} + {{ range $k, $v := . }} + {{ if lt $lead 0 }} + {{- $name := index $v "_bookshop_name" | default "" }} + {{- $blueprint := (index (index $components $name | default dict) (printf "%s.bookshop" $name) | default dict).blueprint | default dict }} + {{- $leveled := isset $blueprint "heading_level" }} + {{- $titled := index (index $v "heading" | default dict) "title" }} + {{- $hidden := or (index $v "hide_empty") (index $v "hide-empty") }} + {{- $suppressed := false }} + {{- if isset $v "heading_level" }} + {{- $suppressed = eq (index $v "heading_level") 0 }} + {{- else if isset $v "heading-level" }} + {{- $suppressed = eq (index $v "heading-level") 0 }} + {{- end }} + {{- if and $leveled $titled (not $suppressed) }} + {{- if not $hidden }} + {{- $lead = $k }} + {{- else if lt $fallback 0 }} + {{- $fallback = $k }} + {{- end }} + {{- end }} + {{- end }} + {{ end }} + {{ if lt $lead 0 }} + {{ $lead = $fallback }} + {{ end }} + {{ end }} + {{/* Inject an ordinal number and the owning page for each block */}} {{ $blocks := slice }} {{ range $k, $v := . }} {{ $b := merge $v (dict "_ordinal" $k "_page" $page) }} {{ if ne $embed nil }}{{ $b = merge $b (dict "_embed" $embed) }}{{ end }} + {{ if and (gt $headingLevel 0) (not (or (isset $v "heading_level") (isset $v "heading-level"))) }} + {{- $name := index $v "_bookshop_name" | default "" }} + {{- $blueprint := (index (index $components $name | default dict) (printf "%s.bookshop" $name) | default dict).blueprint | default dict }} + {{- if isset $blueprint "heading_level" }} + {{- $b = merge $b (dict "heading_level" (cond (eq $k $lead) $headingLevel (cond (lt $headingLevel 2) 2 $headingLevel))) }} + {{- end }} + {{ end }} {{ $blocks = $blocks | append $b }} {{ end }}