mirror of https://github.com/luizdepra/hugo-coder.git

John Feminella
29.46.2022 3762d3a24cf1b77e6d9bf1223ebdda173e53f498
Modularize <head> and baseof templates (#639)

* Add extension points for template customization

Today, if you use the hugo-coder template, you can't modify <head>
without having to write the entire template from scratch. This makes
small point modifications or adjustments impractical and means that
downstream consumers will quickly be out of sync with upstream
changes.

To remedy this, we split up the template into more modular extension
points. This commit adds one extension point to <body> for arbitrary
scripting and several more to <head> for different existing
touchpoints.

* Add John Feminella to CONTRIBUTORS.md

* Modularize home.html template

Co-authored-by: Luiz F. A. de PrĂ¡ <luizdepra@users.noreply.github.com>
3 files modified
13 files added
372 ■■■■ changed files
CONTRIBUTORS.md 1 ●●●● patch | view | raw | blame | history
layouts/_default/baseof.html 193 ●●●● patch | view | raw | blame | history
layouts/partials/body/extensions.html 5 ●●●●● patch | view | raw | blame | history
layouts/partials/head.html 23 ●●●●● patch | view | raw | blame | history
layouts/partials/head/alternative-output-formats.html 3 ●●●●● patch | view | raw | blame | history
layouts/partials/head/color-scheme.html 11 ●●●●● patch | view | raw | blame | history
layouts/partials/head/custom-icons.html 5 ●●●●● patch | view | raw | blame | history
layouts/partials/head/custom-styles.html 21 ●●●●● patch | view | raw | blame | history
layouts/partials/head/extensions.html 4 ●●●● patch | view | raw | blame | history
layouts/partials/head/hugo-generator.html 1 ●●●● patch | view | raw | blame | history
layouts/partials/head/meta-tags.html 15 ●●●●● patch | view | raw | blame | history
layouts/partials/head/theme-styles.html 23 ●●●●● patch | view | raw | blame | history
layouts/partials/home.html 36 ●●●● patch | view | raw | blame | history
layouts/partials/home/author.html 6 ●●●●● patch | view | raw | blame | history
layouts/partials/home/avatar.html 8 ●●●●● patch | view | raw | blame | history
layouts/partials/home/social.html 17 ●●●●● patch | view | raw | blame | history
CONTRIBUTORS.md
@@ -108,4 +108,5 @@
- [Xiaoyang Luo](https://github.com/ccviolett/)
- [Michiel Appelman](https://appelman.se)
- [Mark Wood](https://digitalnotions.net)
- [John Feminella](https://jxf.me)
- [zzsqwq](https://zzsqwq.cn)
layouts/_default/baseof.html
@@ -1,160 +1,71 @@
<!DOCTYPE html>
<html lang="{{ .Site.Language.Lang }}">
{{ partial "head.html" . }}
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="color-scheme" content="light dark">
{{ $csClass := "colorscheme-light" }}
{{ if eq .Site.Params.colorScheme "dark" }}
{{ $csClass = "colorscheme-dark" }}
{{ else if eq .Site.Params.colorScheme "auto" }}
{{ $csClass = "colorscheme-auto" }}
{{ end }}
    {{ if .Site.Params.csp }}
      {{ partial "csp.html" . }}
    {{ end }}
<body class="preload-transitions {{ $csClass }}{{ if .Site.Params.rtl }} rtl{{ end }}">
  {{ partial "float" . }}
  <main class="wrapper">
    {{ partial "header.html" . }}
    {{ with .Site.Params.author }}<meta name="author" content="{{ . }}">{{ end }}
    <meta name="description" content="{{ .Description | default (.Summary | default .Site.Params.description ) }}">
    <meta name="keywords" content="{{ (delimit .Keywords ",") | default .Site.Params.keywords }}">
    <div class="content">
      {{ block "content" . }}{{ end }}
    </div>
    {{ template "_internal/twitter_cards.html" . }}
    {{ template "_internal/opengraph.html" . }}
    {{ partial "footer.html" . }}
  </main>
    <title>{{ block "title" . }}{{ .Site.Title }}{{ end }}</title>
    {{ if .Permalink }}
      <link rel="canonical" href="{{ .Permalink }}">
    {{ end }}
    <link rel="preload" href="/fonts/forkawesome-webfont.woff2?v=1.2.0" as="font" type="font/woff2" crossorigin>
    {{ if .Site.IsServer }}
      {{ $cssOpts := (dict "targetPath" "css/coder.css" "enableSourceMap" true ) }}
      {{ $styles := resources.Get "scss/coder.scss" | resources.ExecuteAsTemplate "style.coder.css" . | toCSS $cssOpts }}
      <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
    {{ else }}
      {{ $cssOpts := (dict "targetPath" "css/coder.css" ) }}
      {{ $styles := resources.Get "scss/coder.scss" | resources.ExecuteAsTemplate "style.coder.css" . | toCSS $cssOpts | minify | fingerprint }}
      <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
    {{ end }}
    {{ if .Site.Params.rtl }}
      {{ if .Site.IsServer }}
        {{ $cssOpts := (dict "targetPath" "css/coder-rtl.css" "enableSourceMap" true ) }}
        {{ $styles := resources.Get "scss/coder-rtl.scss" | resources.ExecuteAsTemplate "style.coder-rtl.css" . | toCSS $cssOpts }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
      {{ else }}
        {{ $cssOpts := (dict "targetPath" "css/coder-rtl.css" ) }}
        {{ $styles := resources.Get "scss/coder-rtl.scss" | resources.ExecuteAsTemplate "style.coder-rtl.css" . | toCSS $cssOpts | minify | fingerprint }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
      {{ end }}
    {{ end }}
    {{ if  or (eq .Site.Params.colorScheme "auto") (eq .Site.Params.colorScheme "dark") }}
      {{ if .Site.IsServer }}
        {{ $cssOpts := (dict "targetPath" "css/coder-dark.css" "enableSourceMap" true ) }}
        {{ $styles := resources.Get "scss/coder-dark.scss" | resources.ExecuteAsTemplate "style.coder-dark.css" . | toCSS $cssOpts }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
      {{ else }}
        {{ $cssOpts := (dict "targetPath" "css/coder-dark.css" ) }}
        {{ $styles := resources.Get "scss/coder-dark.scss" | resources.ExecuteAsTemplate "style.coder-dark.css" . | toCSS $cssOpts | minify | fingerprint }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
      {{ end }}
    {{ end }}
    {{ range .Site.Params.customCSS }}
      {{ if $.Site.IsServer }}
        {{ $styles := resources.Get . }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
      {{ else }}
        {{ $styles := resources.Get . | minify | fingerprint }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
      {{ end }}
    {{ end }}
    {{ range .Site.Params.customSCSS }}
      {{/* We don't change the targetPath to because it's transparent to users */}}
      {{ if $.Site.IsServer }}
        {{ $cssOpts := (dict "enableSourceMap" true ) }}
        {{ $styles := resources.Get . | toCSS $cssOpts }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
      {{ else }}
        {{ $styles := resources.Get . | toCSS | minify | fingerprint }}
        <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
      {{ end }}
    {{ end }}
    <link rel="icon" type="image/png" href="{{ .Site.Params.favicon_32 | default "/images/favicon-32x32.png" | relURL }}" sizes="32x32">
    <link rel="icon" type="image/png" href="{{ .Site.Params.favicon_16 | default "/images/favicon-16x16.png" | relURL }}" sizes="16x16">
    <link rel="apple-touch-icon" href="{{ .Site.Params.touchicon | default "/images/apple-touch-icon.png" | relURL }}">
    <link rel="apple-touch-icon" sizes="180x180" href="{{ .Site.Params.touchicon | default "/images/apple-touch-icon.png" | relURL }}">
    {{ range .AlternativeOutputFormats -}}
      {{ printf `<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .RelPermalink $.Site.Title | safeHTML }}
    {{ end -}}
    {{ hugo.Generator }}
  </head>
  {{ $csClass := "colorscheme-light" }}
  {{ if eq .Site.Params.colorScheme "dark" }}
    {{ $csClass = "colorscheme-dark" }}
  {{ else if eq .Site.Params.colorScheme "auto" }}
    {{ $csClass = "colorscheme-auto" }}
  {{ if .Site.IsServer }}
  {{ $script := resources.Get "js/coder.js" }}
  <script src="{{ $script.RelPermalink }}"></script>
  {{ else }}
  {{ $script := resources.Get "js/coder.js" | minify | fingerprint }}
  <script src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>
  {{ end }}
  <body class="preload-transitions {{ $csClass }}{{ if .Site.Params.rtl }} rtl{{ end }}">
    {{ partial "float" . }}
    <main class="wrapper">
      {{ partial "header.html" . }}
      <div class="content">
        {{ block "content" . }}{{ end }}
      </div>
  {{ range .Site.Params.customJS }}
  {{ if $.Site.IsServer }}
  {{ $script := resources.Get . }}
  <script src="{{ $script.RelPermalink }}"></script>
  {{ else }}
  {{ $script := resources.Get . | minify | fingerprint }}
  <script src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>
  {{ end }}
  {{ end }}
      {{ partial "footer.html" . }}
    </main>
  {{ template "_internal/google_analytics.html" . }}
    {{ if .Site.IsServer }}
      {{ $script := resources.Get "js/coder.js" }}
      <script src="{{ $script.RelPermalink }}"></script>
    {{ else }}
      {{ $script := resources.Get "js/coder.js" | minify | fingerprint }}
      <script src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>
    {{ end }}
  {{ if and .Site.Params.fathomAnalytics .Site.Params.fathomAnalytics.siteID }}
  {{- partial "analytics/fathom" . -}}
  {{ end }}
    {{ range .Site.Params.customJS }}
      {{ if $.Site.IsServer }}
        {{ $script := resources.Get . }}
        <script src="{{ $script.RelPermalink }}"></script>
      {{ else }}
        {{ $script := resources.Get . | minify | fingerprint }}
        <script src="{{ $script.RelPermalink }}" integrity="{{ $script.Data.Integrity }}"></script>
      {{ end }}
    {{ end }}
  {{ if and .Site.Params.plausibleAnalytics .Site.Params.plausibleAnalytics.domain }}
  {{- partial "analytics/plausible" . -}}
  {{ end }}
    {{ template "_internal/google_analytics.html" . }}
  {{ if and .Site.Params.goatCounter .Site.Params.goatCounter.code }}
  {{- partial "analytics/goatcounter" . -}}
  {{ end }}
    {{ if and .Site.Params.fathomAnalytics .Site.Params.fathomAnalytics.siteID }}
      {{- partial "analytics/fathom" . -}}
    {{ end }}
  {{ if and .Site.Params.cloudflare .Site.Params.cloudflare.token }}
  {{- partial "analytics/cloudflare" . -}}
  {{ end }}
    {{ if and .Site.Params.plausibleAnalytics .Site.Params.plausibleAnalytics.domain }}
      {{- partial "analytics/plausible" . -}}
    {{ end }}
  {{ if and .Site.Params.matomo .Site.Params.matomo.serverURL }}
  {{- partial "analytics/matomo" . -}}
  {{ end }}
    {{ if and .Site.Params.goatCounter .Site.Params.goatCounter.code }}
      {{- partial "analytics/goatcounter" . -}}
    {{ end }}
  {{ if and .Site.Params.googleTagManager .Site.Params.googleTagManager.id }}
  {{- partial "analytics/googletagmanager" . -}}
  {{ end }}
    {{ if and .Site.Params.cloudflare .Site.Params.cloudflare.token }}
      {{- partial "analytics/cloudflare" . -}}
    {{ end }}
    {{ if and .Site.Params.matomo .Site.Params.matomo.serverURL }}
      {{- partial "analytics/matomo" . -}}
    {{ end }}
    {{ if and .Site.Params.googleTagManager .Site.Params.googleTagManager.id }}
      {{- partial "analytics/googletagmanager" . -}}
    {{ end }}
  </body>
  {{- partial "body/extensions" . -}}
</body>
</html>
layouts/partials/body/extensions.html
New file
@@ -0,0 +1,5 @@
{{/*
  This extension point occurs just before the end of each page's <body> tag.
  You can add further theme extensions or customizations here if needed.
*/}}
layouts/partials/head.html
New file
@@ -0,0 +1,23 @@
<head>
  {{ partial "head/meta-tags.html" . }}
  <title>{{ block "title" . }}{{ .Site.Title }}{{ end }}</title>
  {{ if .Permalink }}
  <link rel="canonical" href="{{ .Permalink }}">
  {{ end }}
  {{ partialCached "head/theme-styles.html" . }}
  {{ partialCached "head/color-scheme.html" . }}
  {{ partialCached "head/custom-styles.html" . }}
  {{ partialCached "head/custom-icons.html" . }}
  {{ partialCached "head/alternative-output-formats.html" . }}
  {{ partialCached "head/hugo-generator.html" . }}
  {{ partial "head/extensions.html" . }}
</head>
layouts/partials/head/alternative-output-formats.html
New file
@@ -0,0 +1,3 @@
{{ range .AlternativeOutputFormats -}}
  {{ printf `<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .RelPermalink $.Site.Title | safeHTML }}
{{ end -}}
layouts/partials/head/color-scheme.html
New file
@@ -0,0 +1,11 @@
{{ if or (eq .Site.Params.colorScheme "auto") (eq .Site.Params.colorScheme "dark") }}
  {{ if .Site.IsServer }}
    {{ $cssOpts := (dict "targetPath" "css/coder-dark.css" "enableSourceMap" true ) }}
    {{ $styles := resources.Get "scss/coder-dark.scss" | resources.ExecuteAsTemplate "style.coder-dark.css" . | toCSS $cssOpts }}
    <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
  {{ else }}
    {{ $cssOpts := (dict "targetPath" "css/coder-dark.css" ) }}
    {{ $styles := resources.Get "scss/coder-dark.scss" | resources.ExecuteAsTemplate "style.coder-dark.css" . | toCSS $cssOpts | minify | fingerprint }}
    <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
  {{ end }}
{{ end }}
layouts/partials/head/custom-icons.html
New file
@@ -0,0 +1,5 @@
<link rel="icon" type="image/png" href="{{ .Site.Params.favicon_32 | default "/images/favicon-32x32.png" | relURL }}" sizes="32x32">
<link rel="icon" type="image/png" href="{{ .Site.Params.favicon_16 | default "/images/favicon-16x16.png" | relURL }}" sizes="16x16">
<link rel="apple-touch-icon" href="{{ .Site.Params.touchicon | default "/images/apple-touch-icon.png" | relURL }}">
<link rel="apple-touch-icon" sizes="180x180" href="{{ .Site.Params.touchicon | default "/images/apple-touch-icon.png" | relURL }}">
layouts/partials/head/custom-styles.html
New file
@@ -0,0 +1,21 @@
 {{ range .Site.Params.customCSS }}
  {{ if $.Site.IsServer }}
    {{ $styles := resources.Get . }}
    <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
  {{ else }}
    {{ $styles := resources.Get . | minify | fingerprint }}
    <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
  {{ end }}
{{ end }}
{{ range .Site.Params.customSCSS }}
  {{/* We don't change the targetPath to because it's transparent to users */}}
  {{ if $.Site.IsServer }}
    {{ $cssOpts := (dict "enableSourceMap" true ) }}
    {{ $styles := resources.Get . | toCSS $cssOpts }}
    <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
  {{ else }}
    {{ $styles := resources.Get . | toCSS | minify | fingerprint }}
    <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
  {{ end }}
{{ end }}
layouts/partials/head/extensions.html
New file
@@ -0,0 +1,4 @@
{{/*
  You can add further theme extensions or customizations here if they should
  appear in <head>.
*/}}
layouts/partials/head/hugo-generator.html
New file
@@ -0,0 +1 @@
{{ hugo.Generator }}
layouts/partials/head/meta-tags.html
New file
@@ -0,0 +1,15 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
{{ if .Site.Params.csp }}
{{ partial "csp.html" . }}
{{ end }}
{{ with .Site.Params.author }}
<meta name="author" content="{{ . }}">{{ end }}
<meta name="description" content="{{ .Description | default (.Summary | default .Site.Params.description ) }}">
<meta name="keywords" content="{{ (delimit .Keywords " ,") | default .Site.Params.keywords }}">
{{ template "_internal/twitter_cards.html" . }}
{{ template "_internal/opengraph.html" . }}
layouts/partials/head/theme-styles.html
New file
@@ -0,0 +1,23 @@
<link rel="preload" href="/fonts/forkawesome-webfont.woff2?v=1.2.0" as="font" type="font/woff2" crossorigin>
{{ if .Site.IsServer }}
  {{ $cssOpts := (dict "targetPath" "css/coder.css" "enableSourceMap" true ) }}
  {{ $styles := resources.Get "scss/coder.scss" | resources.ExecuteAsTemplate "style.coder.css" . | toCSS $cssOpts }}
  <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
{{ else }}
  {{ $cssOpts := (dict "targetPath" "css/coder.css" ) }}
  {{ $styles := resources.Get "scss/coder.scss" | resources.ExecuteAsTemplate "style.coder.css" . | toCSS $cssOpts | minify | fingerprint }}
  <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
{{ end }}
{{ if .Site.Params.rtl }}
  {{ if .Site.IsServer }}
    {{ $cssOpts := (dict "targetPath" "css/coder-rtl.css" "enableSourceMap" true ) }}
    {{ $styles := resources.Get "scss/coder-rtl.scss" | resources.ExecuteAsTemplate "style.coder-rtl.css" . | toCSS $cssOpts }}
    <link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
  {{ else }}
    {{ $cssOpts := (dict "targetPath" "css/coder-rtl.css" ) }}
    {{ $styles := resources.Get "scss/coder-rtl.scss" | resources.ExecuteAsTemplate "style.coder-rtl.css" . | toCSS $cssOpts | minify | fingerprint }}
    <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
  {{ end }}
{{ end }}
layouts/partials/home.html
@@ -1,35 +1,9 @@
<section class="container centered">
  <div class="about">
    {{ if and (isset .Site.Params "avatarurl") (not (isset .Site.Params "gravatar")) }}
      {{ with .Site.Params.avatarURL }}
        <div class="avatar"><img src="{{ . | relURL }}" alt="avatar"></div>
      {{ end }}
    {{ end }}
    {{ with .Site.Params.gravatar }}
      <div class="avatar"><img src="https://www.gravatar.com/avatar/{{md5 .}}?s=240&d=mp" alt="gravatar"></div>
    {{ end }}
    <h1>{{ .Site.Params.author }}</h1>
    {{ if reflect.IsSlice .Site.Params.info }}
    <h2>{{ range .Site.Params.info }}{{.}}<br>{{ end}}</h2>
    {{ else }}
    <h2>{{ .Site.Params.info }}</h2>
    {{ end }}
    {{ with .Site.Params.social }}
    <ul>
      {{ range sort . "weight" }}
        {{ if .icon }}
          <li>
            <a href="{{ .url | safeURL }}" aria-label="{{ .name }}" {{ if .rel }}rel="{{ .rel }}"{{ end }} {{ if .target }}target="{{ .target }}"{{ end }} {{ if .type }}type="{{ .type }}"{{ end }}>
              <i class="{{ .icon }}" aria-hidden="true"></i>
            </a>
          </li>
        {{ else }}
          <li>
            <a href="{{ .url | safeURL }}" aria-label="{{ .name }}" {{ if .rel }}rel="{{ .rel }}"{{ end }} {{ if .target }}target="{{ .target }}"{{ end }}>{{ .name }}</a>
          </li>
        {{ end }}
      {{ end }}
    </ul>
    {{ end }}
    {{ partialCached "home/avatar.html" . }}
    {{ partialCached "home/author.html" . }}
    {{ partialCached "home/social.html" . }}
  </div>
</section>
layouts/partials/home/author.html
New file
@@ -0,0 +1,6 @@
<h1>{{ .Site.Params.author }}</h1>
{{ if reflect.IsSlice .Site.Params.info }}
<h2>{{ range .Site.Params.info }}{{.}}<br>{{ end}}</h2>
{{ else }}
<h2>{{ .Site.Params.info }}</h2>
{{ end }}
layouts/partials/home/avatar.html
New file
@@ -0,0 +1,8 @@
{{ if and (isset .Site.Params "avatarurl") (not (isset .Site.Params "gravatar")) }}
  {{ with .Site.Params.avatarURL }}
    <div class="avatar"><img src="{{ . | relURL }}" alt="avatar"></div>
  {{ end }}
{{ end }}
{{ with .Site.Params.gravatar }}
  <div class="avatar"><img src="https://www.gravatar.com/avatar/{{md5 .}}?s=240&d=mp" alt="gravatar"></div>
{{ end }}
layouts/partials/home/social.html
New file
@@ -0,0 +1,17 @@
{{ with .Site.Params.social }}
<ul>
  {{ range sort . "weight" }}
    {{ if .icon }}
      <li>
        <a href="{{ .url | safeURL }}" aria-label="{{ .name }}" {{ if .rel }}rel="{{ .rel }}"{{ end }} {{ if .target }}target="{{ .target }}"{{ end }} {{ if .type }}type="{{ .type }}"{{ end }}>
          <i class="{{ .icon }}" aria-hidden="true"></i>
        </a>
      </li>
    {{ else }}
      <li>
        <a href="{{ .url | safeURL }}" aria-label="{{ .name }}" {{ if .rel }}rel="{{ .rel }}"{{ end }} {{ if .target }}target="{{ .target }}"{{ end }}>{{ .name }}</a>
      </li>
    {{ end }}
  {{ end }}
</ul>
{{ end }}