+{{/* Used by
+ 1. list.html and term.html (when the cardView option is enabled)
+ 2. Recent articles template (when the cardView option is enabled)
+ 3. Shortcode list.html
+*/}}
+{{ $disableImageOptimization := site.Store.Get "disableImageOptimization" }}
- {{- with $.Params.images -}}
- {{- range first 6 . }}
-
{{ end -}}
- {{- else -}}
- {{- $images := $.Resources.ByType "image" -}}
- {{- $featured := $images.GetMatch "*feature*" -}}
- {{- if not $featured }}{{ $featured = $images.GetMatch "{*cover*,*thumbnail*}" }}{{ end -}}
- {{ if and .Params.featureimage (not $featured) }}
- {{- $url:= .Params.featureimage -}}
- {{ $featured = resources.GetRemote $url }}
+{{ $page := .Page }}
+{{ $featured := "" }}
+{{ $featuredURL := "" }}
+{{ if not .Params.hideFeatureImage }}
+ {{/* frontmatter */}}
+ {{ with $page }}
+ {{ with .Params.featureimage }}
+ {{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
+ {{ if site.Params.hotlinkFeatureImage }}
+ {{ $featuredURL = . }}
+ {{ else }}
+ {{ $featured = resources.GetRemote . }}
+ {{ end }}
+ {{ else }}
+ {{ $featured = resources.Get . }}
{{ end }}
+ {{ end }}
- {{ if .Params.featureAsset }}
- {{- $genericImage := .Params.featureAsset -}}
- {{- if not $featured }}{{ $featured = resources.Get $genericImage }}{{ end -}}
+ {{/* Allow adding feature images from the assets folder */}}
+ {{ if .Params.featureAsset }}
+ {{- $genericImage := .Params.featureAsset -}}
+ {{- if not $featured }}{{ $featured = resources.Get $genericImage }}{{ end -}}
{{ end }}
- {{- if not $featured }}{{ with .Site.Params.defaultFeaturedImage }}{{ $featured = resources.Get . }}{{ end }}{{ end -}}
- {{ if .Params.hideFeatureImage }}{{ $featured = false }}{{ end }}
- {{- with $featured -}}
- {{ if $disableImageOptimization }}
- {{ with . }}
-
- {{ end }}
- {{ else }}
- {{ with .Resize "600x" }}
-
- {{ end }}
+ {{/* page resources */}}
+ {{ if not (or $featured $featuredURL) }}
+ {{ $images := .Resources.ByType "image" }}
+ {{ range slice "*feature*" "*cover*" "*thumbnail*" }}
+ {{ if not $featured }}{{ $featured = $images.GetMatch . }}{{ end }}
{{ end }}
- {{- else -}}
- {{- with $.Site.Params.images }}
-
{{ end -}}
- {{- end -}}
- {{- end -}}
+ {{ end }}
+ {{/* fallback to default */}}
+ {{ if not (or $featured $featuredURL) }}
+ {{ $default := site.Store.Get "defaultFeaturedImage" }}
+ {{ if $default.url }}
+ {{ $featuredURL = $default.url }}
+ {{ else if $default.obj }}
+ {{ $featured = $default.obj }}
+ {{ end }}
+ {{ end }}
- {{ if and .Draft .Site.Params.article.showDraftLabel }}
-
- {{ partial "badge.html" (i18n "article.draft" | emojify) }}
-
+ {{/* generate image URL if not hotlink */}}
+ {{ if not $featuredURL }}
+ {{ with $featured }}
+ {{ $featuredURL = .RelPermalink }}
+ {{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
+ {{ $featuredURL = (.Resize "600x").RelPermalink }}
+ {{ end }}
{{ end }}
+ {{ end }}
+ {{ end }}
+{{ end }}
-
- {{ with .Params.externalUrl }}
-
-
- {{ $.Title | emojify }}
-
+
+ {{ with $featuredURL }}
+
+

+
+ {{ end }}
+ {{ if and .Draft .Site.Params.article.showDraftLabel }}
+
+ {{ partial "badge.html" (i18n "article.draft" | emojify) }}
+
+ {{ end }}
+
-
- {{ else }}
-
{{ .Title | emojify }}
- {{ end }}
-
-
- {{ partial "article-meta/basic.html" . }}
-
-
- {{ if .Params.showSummary | default (.Site.Params.list.showSummary | default false) }}
-
- {{ .Summary | emojify }}
-
- {{ end }}
-
-
-
-
+ {{ end }}
+
+
+
+
+ {{ partial "article-meta/basic.html" . }}
-
\ No newline at end of file
+ {{ if .Params.showSummary | default (.Site.Params.list.showSummary | default false) }}
+
{{ .Summary | plainify }}
+ {{ end }}
+
+
+
diff --git a/layouts/partials/dynamic_md_block.html b/layouts/partials/features/dynamic_md_block.html
similarity index 100%
rename from layouts/partials/dynamic_md_block.html
rename to layouts/partials/features/dynamic_md_block.html
diff --git a/layouts/partials/features/giscus-auto.html b/layouts/partials/features/giscus-auto.html
new file mode 100644
index 000000000..071bf9034
--- /dev/null
+++ b/layouts/partials/features/giscus-auto.html
@@ -0,0 +1,12 @@
+{{/*
+ Injects the correct Giscus component depending on the default appearance.
+ - If the site default theme is "light": loads giscus_light.
+ - Otherwise: loads giscus_dark.
+ This only switches on first render; user theme switching handled by Giscus itself.
+*/}}
+
+{{ if (eq (.Site.Params.defaultAppearance | default "light") "light") }}
+ {{ partial "features/giscus_light" . }}
+{{ else }}
+ {{ partial "features/giscus_dark" . }}
+{{ end }}
diff --git a/layouts/partials/giscus_dark.html b/layouts/partials/features/giscus_dark.html
similarity index 100%
rename from layouts/partials/giscus_dark.html
rename to layouts/partials/features/giscus_dark.html
diff --git a/layouts/partials/giscus_light.html b/layouts/partials/features/giscus_light.html
similarity index 100%
rename from layouts/partials/giscus_light.html
rename to layouts/partials/features/giscus_light.html
diff --git a/layouts/partials/features/kapa-widget.html b/layouts/partials/features/kapa-widget.html
new file mode 100644
index 000000000..fb6b40491
--- /dev/null
+++ b/layouts/partials/features/kapa-widget.html
@@ -0,0 +1,29 @@
+
diff --git a/layouts/partials/learn_custom.html b/layouts/partials/features/learn_custom.html
similarity index 100%
rename from layouts/partials/learn_custom.html
rename to layouts/partials/features/learn_custom.html
diff --git a/layouts/partials/features/mermaid-init.html b/layouts/partials/features/mermaid-init.html
new file mode 100644
index 000000000..e149263ff
--- /dev/null
+++ b/layouts/partials/features/mermaid-init.html
@@ -0,0 +1,11 @@
+{{/*
+ If the page includes Mermaid diagrams (`.Store.Get "hasMermaid"`),
+ this script loads Mermaid from CDN and initializes it automatically.
+*/}}
+
+{{ if .Store.Get "hasMermaid" }}
+
+{{ end }}
diff --git a/layouts/partials/vendor_custom.html b/layouts/partials/features/vendor_custom.html
similarity index 100%
rename from layouts/partials/vendor_custom.html
rename to layouts/partials/features/vendor_custom.html
diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html
index 8149a1a2e..5695b1c79 100644
--- a/layouts/partials/footer.html
+++ b/layouts/partials/footer.html
@@ -2,67 +2,81 @@
{{/* Footer menu */}}
{{ if .Site.Params.footer.showMenu | default true }}
{{ if .Site.Menus.footer }}
-
+ {{ end }}
+ {{ $navClass := printf "flex flex-row pb-4 text-base font-medium text-neutral-500 dark:text-neutral-400 %s" (cond $onlyIcon "overflow-x-auto py-2" "") }}
+ {{ $ulClass := printf "flex list-none %s" (cond $onlyIcon "flex-row" "flex-col sm:flex-row") }}
+ {{ $liClass := printf "flex mb-1 text-end sm:mb-0 sm:me-7 sm:last:me-0 %s" (cond $onlyIcon "me-4" "") }}
+
{{ end }}
{{ end }}
-
{{/* Copyright */}}
{{ if .Site.Params.footer.showCopyright | default true }}
-
- {{- with replace .Site.Params.copyright "{ year }" now.Year }}
- {{ . | emojify | markdownify }}
- {{- else }}
- ©
- {{ now.Format "2006" }}
- {{ .Site.Params.Author.name | markdownify | emojify }}
- {{- end }}
-
+
+ {{- with replace .Site.Params.copyright "{ year }" now.Year }}
+ {{ . | markdownify | emojify }}
+ {{- else }}
+ ©
+ {{ now.Format "2006" }}
+ {{ .Site.Params.Author.name | markdownify | emojify }}
+ {{- end }}
+
{{ end }}
{{/* Theme attribution */}}
{{ if .Site.Params.footer.showThemeAttribution | default true }}
-
- {{ $hugo := printf `Hugo`
- }}
- {{ $blowfish := printf `Blowfish` }}
- {{ i18n "footer.powered_by" (dict "Hugo" $hugo "Theme" $blowfish) | safeHTML }}
-
+
+ {{ $hugo := printf `Hugo`
+ }}
+ {{ $blowfish := printf `Blowfish`
+ }}
+ {{ i18n "footer.powered_by" (dict "Hugo" $hugo "Theme" $blowfish) | safeHTML }}
+
{{ end }}
-
-
+ {{ if not .Site.Params.disableImageZoom | default true }}
+
+ {{ end }}
{{ $jsProcess := resources.Get "js/process.js" }}
- {{ $jsProcess = $jsProcess | resources.Minify | resources.Fingerprint "sha512" }}
-
+ {{ $jsProcess = $jsProcess | resources.Minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
+
{{/* Extend footer - eg. for extra scripts, etc. */}}
{{ if templates.Exists "partials/extend-footer.html" }}
- {{ partialCached "extend-footer.html" . }}
+ {{ partialCached "extend-footer.html" . }}
{{ end }}
diff --git a/layouts/partials/head.html b/layouts/partials/head.html
index c81e43b80..1880b8c68 100644
--- a/layouts/partials/head.html
+++ b/layouts/partials/head.html
@@ -1,145 +1,219 @@
-
+
{{ with .Site.Language.Params.htmlCode | default .Site.LanguageCode }}
-
+
{{ end }}
-
-
+
+
+
+
{{/* Title */}}
- {{ if .IsHome -}}
-
{{ .Site.Title | emojify }}
-
- {{- else -}}
-
{{ .Title | emojify }} · {{ .Site.Title | emojify }}
-
- {{- end }}
+ {{ if .IsHome }}
+
{{ .Site.Title | emojify }}
+
+ {{ else }}
+
{{ .Title | emojify }} · {{ .Site.Title | emojify }}
+
+ {{ end }}
+
{{/* Metadata */}}
- {{ with (.Params.Summary | default .Params.Description) | default .Site.Params.description -}}
-
- {{- end }}
- {{ with .Params.Tags | default .Site.Params.keywords -}}
-
- {{- end }}
+ {{ with (.Params.Summary | default .Params.Description) | default .Site.Params.description }}
+
+ {{ end }}
+ {{ with .Params.Tags | default .Site.Params.keywords }}
+
+ {{ end }}
{{ with .Site.Params.robots }}
-
+
{{ end }}
{{ with .Params.robots }}
-
- {{ end }}
-
- {{ range .AlternativeOutputFormats -}}
- {{ printf `
-
` .Rel .MediaType.Type .RelPermalink ($.Site.Title | emojify) |
- safeHTML }}
- {{ end -}}
- {{/* Asset bundles */}}
- {{ $assets := newScratch }}
- {{ $cssScheme := resources.Get (printf "css/schemes/%s.css" (.Site.Params.colorScheme | default "blowfish")) }}
- {{ if not $cssScheme }}
- {{ $cssScheme = resources.Get "css/schemes/blowfish.css" }}
- {{ end }}
- {{ $assets.Add "css" (slice $cssScheme) }}
- {{ $cssMain := resources.Get "css/compiled/main.css" }}
- {{ $assets.Add "css" (slice $cssMain) }}
- {{ $cssCustom := resources.Get "css/custom.css" }}
- {{ if $cssCustom }}
- {{ $assets.Add "css" (slice $cssCustom) }}
- {{ end }}
- {{ $bundleCSS := $assets.Get "css" | resources.Concat "css/main.bundle.css" | resources.Minify | resources.Fingerprint
- "sha512" }}
- {{ $cssCustom := resources.Get "css/custom.css" }}
-
-
- {{ $jsAppearance := resources.Get "js/appearance.js" }}
- {{ $jsAppearance = $jsAppearance | resources.ExecuteAsTemplate "js/appearance.js" . | resources.Minify | resources.Fingerprint "sha512" }}
-
- {{ if .Site.Params.enableSearch | default false }}
- {{ $jsFuse := resources.Get "lib/fuse/fuse.min.js" }}
- {{ $jsSearch := resources.Get "js/search.js" }}
- {{ $assets.Add "js" (slice $jsFuse $jsSearch) }}
+
{{ end }}
- {{ if .Site.Params.enableCodeCopy | default false }}
- {{ $jsCode := resources.Get "js/code.js" }}
- {{ $assets.Add "js" (slice $jsCode) }}
+
+ {{ range .AlternativeOutputFormats }}
+ {{ printf `
+
` .Rel .MediaType.Type .RelPermalink ($.Site.Title | emojify) |
+ safeHTML
+ }}
{{ end }}
- {{ if .Site.Params.rtl | default false }}
- {{ $jsRTL := resources.Get "js/rtl.js" }}
- {{ $assets.Add "js" (slice $jsRTL) }}
- {{ end }}
- {{ $jsMobileMenu := resources.Get "js/mobilemenu.js" }}
- {{ $assets.Add "js" (slice $jsMobileMenu) }}
- {{ if $assets.Get "js" }}
- {{ $bundleJS := $assets.Get "js" | resources.Concat "js/main.bundle.js" | resources.Minify | resources.Fingerprint
- "sha512" }}
-
+
+ {{/* Me */}}
+ {{ with .Site.Params.Author.name }}
+
{{ end }}
- {{ if not .Site.Params.disableImageZoom | default true }}
- {{ $zoomJS := resources.Get "lib/zoom/zoom.min.js" | resources.Fingerprint "sha512" }}
-
+ {{ with .Site.Params.Author.links }}
+ {{ range $links := . }}
+ {{ range $name, $url := $links }}
+ {{ if not (strings.HasPrefix $url "mailto:") }}
+
+ {{ end }}
+ {{ end }}
+ {{ end }}
{{ end }}
- {{/* Icons */}}
- {{ if templates.Exists "partials/favicons.html" }}
- {{ partialCached "favicons.html" .Site }}
- {{ else }}
-
-
-
-
+
+ {{/* Social */}}
+ {{ template "_internal/opengraph.html" . }}
+ {{ template "_internal/twitter_cards.html" . }}
+ {{/* Use defaultSocialImage if feature image does not exist */}}
+ {{ $featureImage := "" }}
+ {{ $pageImages := .Resources.ByType "image" }}
+ {{ range slice "*featured*" "*cover*" "*thumbnail*" }}
+ {{ if not $featureImage }}
+ {{ $featureImage = $pageImages.GetMatch . }}
+ {{ end }}
+ {{ end }}
+ {{ if not $featureImage }}
+ {{ with .Site.Params.defaultSocialImage }}
+ {{ $socialImage := "" }}
+ {{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
+ {{ $socialImage = resources.GetRemote . }}
+ {{ else }}
+ {{ $socialImage = resources.Get . }}
+ {{ end }}
+ {{ with $socialImage }}
+
+
+ {{ end }}
+ {{ end }}
{{ end }}
+
{{/* Site Verification */}}
{{ with .Site.Params.verification.google }}
-
+
{{ end }}
{{ with .Site.Params.verification.bing }}
-
+
{{ end }}
{{ with .Site.Params.verification.pinterest }}
-
+
{{ end }}
{{ with .Site.Params.verification.yandex }}
-
+
{{ end }}
- {{/* Social */}}
- {{ template "_internal/opengraph.html" . }}
- {{ template "_internal/twitter_cards.html" . }}
- {{/* Schema */}}
- {{ partial "schema.html" . }}
- {{/* Me */}}
- {{ with .Site.Params.Author.name }}
-
{{ end }}
- {{ with .Site.Params.Author.links }}
- {{ range $links := . }}
- {{ range $name, $url := $links }}
-
{{ end }}
+ {{ with .Site.Params.verification.fediverse }}
+
{{ end }}
+
+ {{ $alg := .Site.Params.fingerprintAlgorithm | default "sha512" }}
+
+ {{/* CSS */}}
+ {{ $cssResources := slice }}
+ {{ $schemeName := .Site.Params.colorScheme | default "blowfish" }}
+ {{ $cssScheme := resources.Get (printf "css/schemes/%s.css" $schemeName) | default (resources.Get "css/schemes/blowfish.css") }}
+ {{ $cssResources = $cssResources | append $cssScheme }}
+ {{ $cssResources = $cssResources | append (resources.Get "css/compiled/main.css") }}
+ {{ with resources.Get "css/custom.css" }}
+ {{ $cssResources = $cssResources | append . }}
+ {{ end }}
+ {{ if not .Site.Params.disableImageZoom | default true }}
+ {{ $cssResources = $cssResources | append (resources.Get "lib/zoom/style.css") }}
+ {{ end }}
+ {{ $bundleCSS := $cssResources | resources.Concat "css/main.bundle.css" | resources.Minify | resources.Fingerprint $alg }}
+
+
+ {{/* JS loaded immediately */}}
+ {{ $jsAppearance := resources.Get "js/appearance.js" | resources.ExecuteAsTemplate "js/appearance.js" . | resources.Minify | resources.Fingerprint $alg }}
+
+ {{ $enableA11y := .Site.Params.enableA11y | default false }}
+ {{ if $enableA11y }}
+ {{ $jsA11y := resources.Get "js/a11y.js" | resources.Minify | resources.Fingerprint $alg }}
+
+ {{ end }}
+ {{ $showZenMode := .Params.showZenMode | default (.Site.Params.article.showZenMode | default false) }}
+ {{ $shouldIncludeZenMode := or $enableA11y $showZenMode }}
+ {{ if and .IsPage $shouldIncludeZenMode }}
+ {{ $jsZenMode := resources.Get "js/zen-mode.js" | resources.Minify | resources.Fingerprint $alg }}
+
+ {{ end }}
+ {{ if not .Site.Params.disableImageZoom | default true }}
+ {{ $zoomJS := resources.Get "lib/zoom/zoom.min.umd.js" | resources.Fingerprint $alg }}
+
+ {{ end }}
+
+ {{/* JS deferred */}}
+ {{ $jsResources := slice }}
+ {{ if site.Params.footer.showScrollToTop | default true }}
+ {{ $jsResources = $jsResources | append (resources.Get "js/scroll-to-top.js") }}
+ {{ end }}
+ {{ if .Site.Params.enableSearch | default false }}
+ {{ $jsResources = $jsResources | append (resources.Get "lib/fuse/fuse.min.js") | append (resources.Get "js/search.js") }}
+ {{ end }}
+ {{ if .Site.Params.enableCodeCopy | default false }}
+ {{ $jsResources = $jsResources | append (resources.Get "js/code.js") }}
+ {{ end }}
+ {{ if .Site.Params.rtl | default false }}
+ {{ $jsResources = $jsResources | append (resources.Get "js/rtl.js") }}
+ {{ end }}
+ {{ $jsResources = $jsResources | append (resources.Get "js/mobilemenu.js") }}
+ {{ $jsResources = $jsResources | append (resources.Get "js/button-likes.js") }}
+ {{ $jsResources = $jsResources | append (resources.Get "js/katex-render.js") }}
+ {{ if $jsResources }}
+ {{ $bundleJS := $jsResources | resources.Concat "js/main.bundle.js" | resources.Minify | resources.Fingerprint $alg }}
+
{{ end }}
- {{/* Vendor */}}
+
+ {{/* Conditional loaded resources */}}
{{ partial "vendor.html" . }}
- {{ partial "vendor_custom.html" . }}
- {{ partial "learn_custom.html" . }}
- {{ partial "dynamic_md_block.html" . }}
+ {{ partial "features/vendor_custom.html" . }}
+ {{ partial "features/learn_custom.html" . }}
+ {{ partial "features/dynamic_md_block.html" . }}
+
+ {{/* Icons */}}
+ {{ if templates.Exists "partials/favicons.html" }}
+ {{ partialCached "favicons.html" .Site }}
+ {{ else }}
+
+
+
+
+ {{ end }}
+
+ {{/* Schema */}}
+ {{ partial "schema.html" . }}
+
{{/* Analytics */}}
- {{ partial "analytics/main.html" .Site }}
+ {{ if hugo.IsProduction }}
+ {{ partial "analytics/main.html" . }}
+ {{ end }}
+
{{/* Extend head - eg. for custom analytics scripts, etc. */}}
{{ if templates.Exists "partials/extend-head.html" }}
- {{ partialCached "extend-head.html" .Site }}
+ {{ partialCached "extend-head.html" .Site }}
{{ end }}
-
+
+ {{/* Uncached extend head - Example: https://gohugo.io/methods/page/hasshortcode/ */}}
+ {{ if templates.Exists "partials/extend-head-uncached.html" }}
+ {{ partial "extend-head-uncached.html" . }}
+ {{ end }}
+
{{/* Firebase */}}
{{ with $.Site.Params.firebase }}
- {{ if isset $.Site.Params "firebase" }}
-
-
-
-
+
+
+
+
+ {{ end }}
{{ end }}
+
+ {{/* Advertisement */}}
+ {{ with .Site.Params.advertisement.adsense }}
+
+
{{ end }}
diff --git a/layouts/partials/header/basic.html b/layouts/partials/header/basic.html
index 008c0ec03..a593c14a4 100644
--- a/layouts/partials/header/basic.html
+++ b/layouts/partials/header/basic.html
@@ -1,179 +1,307 @@
-
-
- {{ if .Site.Params.Logo }}
+{{/* Logo section */}}
+{{ define "HeaderLogo" }}
+ {{ if .Site.Params.Logo }}
{{ $logo := resources.Get .Site.Params.Logo }}
{{ if $logo }}
- {{ $scalingFactor := 0.125 }}
-
-
+ {{ $scalingFactor := 0.125 }}
+
+
{{ end }}
- {{- end }}
+ {{- end }}
+{{ end }}
-
-