migrate to decoupled Blowfish layout, fix TOC scrollspy, and update docs
- Theme Decoupling & Cleanup:
- Fully decoupled and vendored the Blowfish theme directly into root directories (layouts/,
assets/, static/, data/, i18n/).
- De-registered and cleaned up legacy Git submodules (themes/blowfish, themes/hugo-admonitions)
from the Git index to protect the build from upstream breakages.
- Configured .gitignore to ignore development preview symlinks (content, static,
config/_default/menus.en.toml), build folders (public/, resources/), and locks.
- TOC & Layout Fixes:
- Replaced the custom layouts/_default/single.html template with the Blowfish default to restore
native container widths and the side-by-side flex layout.
- Restored TOC to float on the right sidebar on desktop viewports and render inline on mobile
viewports.
- Fixed a parameter resolution bug in layouts/partials/toc.html by checking both .Site.Params.
smartTOC and .Site.Params.article.smartTOC (where it is defined in params.toml).
- Upgraded the TOC scrollspy JavaScript to target all '#TableOfContents' containers on the page,
enabling highlight tracking on both desktop and mobile layouts.
- Documentation Updates (README.md):
- Restored YAML front matter metadata block at the top.
- Added detailed notes on the CI/CD build process and Gitea runner deployment targets
(/srv/www/docs-public and /srv/www/docs-private).
- Added a categorized and sorted "Shortcodes Quick Reference" table at the top of the shortcodes
section (ordered by Custom, Hugo Default, and Blowfish).
- Documented custom shortcodes (Include, Screenshot, Raw HTML) and missing Hugo default
shortcodes (Highlight, Instagram, Param, Ref, Relref, Twitter, Vimeo, Youtube).
- Restructured headings to ensure all sub-shortcodes are H3, removed block break tags (<br/>),
and appended horizontal separators (---) after H2 sections.
This commit is contained in:
123
layouts/partials/article-meta/basic.html
Normal file
123
layouts/partials/article-meta/basic.html
Normal file
@@ -0,0 +1,123 @@
|
||||
{{/* Determine the correct context and scope */}}
|
||||
{{/* This allows for different logic depending on where the partial is called */}}
|
||||
{{ $context := . }}
|
||||
{{ $scope := default nil }}
|
||||
|
||||
{{ if (reflect.IsMap . ) }}
|
||||
{{ $context = .context }}
|
||||
{{ $scope = cond (not .scope) nil .scope }}
|
||||
{{ end }}
|
||||
|
||||
{{ with $context }}
|
||||
{{ $meta := newScratch }}
|
||||
|
||||
{{/* Gather partials for this context */}}
|
||||
{{ $shouldShowDate := false }}
|
||||
{{ if .Params.showDate | default (.Site.Params.article.showDate | default true) }}
|
||||
{{ $shouldShowDate = true }}
|
||||
{{ else }}
|
||||
{{ $shouldShowDate = false }}
|
||||
{{ end }}
|
||||
|
||||
{{ if (.Params.showDateOnlyInArticle | default (.Site.Params.article.showDateOnlyInArticle | default false)) }}
|
||||
{{ if (ne $scope "single") }}
|
||||
{{/* only takes effect when not called directly in the header of single.html */}}
|
||||
{{ $shouldShowDate = false }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if $shouldShowDate }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/date.html" .Date)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (.Params.showDateUpdated | default (.Site.Params.article.showDateUpdated | default false)) (ne (partial
|
||||
"functions/date.html" .Date) (partial "functions/date.html" .Lastmod)) (gt (.Lastmod | time.Format "2006") 1)
|
||||
}}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/date-updated.html" .Lastmod)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (.Params.showWordCount | default (.Site.Params.article.showWordCount | default false)) (ne .WordCount 0) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/word-count.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (.Params.showReadingTime | default (.Site.Params.article.showReadingTime | default true)) (ne .ReadingTime 0) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/reading-time.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (not .Params.externalURL) (.Params.showViews | default (.Site.Params.article.showViews | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/views.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (not .Params.externalURL) (.Params.showLikes | default (.Site.Params.article.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (not .Params.externalURL) (.Params.showLikes | default (.Site.Params.article.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes_button.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (.Params.showEdit | default (.Site.Params.article.showEdit | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/edit.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (.Params.showZenMode | default (.Site.Params.article.showZenMode | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/zen-mode.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{/* Output partials */}}
|
||||
{{ with ($meta.Get "partials") }}
|
||||
{{ delimit . "<span class=\"px-2 text-primary-500\">·</span>" | safeHTML }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Output draft label */}}
|
||||
{{ if and (eq $scope "single") (and .Draft .Site.Params.article.showDraftLabel) }}
|
||||
<span class="ps-2">{{ partial "badge.html" (i18n "article.draft" | emojify) }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{ if .Params.showAuthorsBadges | default (.Site.Params.article.showAuthorsBadges | default false) }}
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{ range $taxonomy, $terms := .Site.Taxonomies }}
|
||||
{{ if (eq $taxonomy "authors") }}
|
||||
{{ if (gt (len ($context.GetTerms $taxonomy)) 0) }}
|
||||
{{ range $i, $a := $context.GetTerms $taxonomy }}
|
||||
{{ if not (eq $i 0) }}
|
||||
,
|
||||
{{ end }}
|
||||
<a href="{{ $a.RelPermalink }}" class="relative">{{ $a.LinkTitle }}</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{/* Output taxonomies */}}
|
||||
{{ if .Params.showTaxonomies | default (.Site.Params.article.showTaxonomies | default false) }}
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{ range $taxonomy, $terms := .Site.Taxonomies }}
|
||||
{{ if (gt (len ($context.GetTerms $taxonomy)) 0) }}
|
||||
{{ range $context.GetTerms $taxonomy }}
|
||||
{{ if .Params.showCategories | default (.Site.Params.article.showCategories | default true) }}
|
||||
{{ if (eq $taxonomy "categories") }}
|
||||
<a class="relative mt-[0.5rem] me-2" href="{{ .RelPermalink }}">
|
||||
{{ $useSecondaryColor := .Params.showCategoriesInSecondaryColor | default (.Site.Params.article.showCategoriesInSecondaryColor | default false) }}
|
||||
{{ partial "badge.html" (dict "linkTitle" .LinkTitle "useSecondaryColor" $useSecondaryColor) }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if .Params.showTags | default (.Site.Params.article.showTags | default true) }}
|
||||
{{ if (eq $taxonomy "tags") }}
|
||||
<a class="relative mt-[0.5rem] me-2" href="{{ .RelPermalink }}">
|
||||
{{ partial "badge.html" .LinkTitle }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
35
layouts/partials/article-meta/list.html
Normal file
35
layouts/partials/article-meta/list.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{{/* Determine the correct context and scope */}}
|
||||
{{/* This allows for different logic depending on where the partial is called */}}
|
||||
{{ $context := . }}
|
||||
{{ $scope := default nil }}
|
||||
|
||||
{{ if (reflect.IsMap . ) }}
|
||||
{{ $context = .context }}
|
||||
{{ $scope = cond (not .scope) nil .scope }}
|
||||
{{ end }}
|
||||
|
||||
{{ with $context }}
|
||||
{{ $meta := newScratch }}
|
||||
|
||||
{{/* Gather partials for this context */}}
|
||||
|
||||
{{ if (.Params.showViews | default (.Site.Params.list.showViews | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/views.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if (.Params.showLikes | default (.Site.Params.list.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (.Params.showLikes | default (.Site.Params.list.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes_button.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{/* Output partials */}}
|
||||
{{ with ($meta.Get "partials") }}
|
||||
{{ delimit . "<span class=\"px-2 text-primary-500\">·</span>" | safeHTML }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
35
layouts/partials/article-meta/taxonomy.html
Normal file
35
layouts/partials/article-meta/taxonomy.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{{/* Determine the correct context and scope */}}
|
||||
{{/* This allows for different logic depending on where the partial is called */}}
|
||||
{{ $context := . }}
|
||||
{{ $scope := default nil }}
|
||||
|
||||
{{ if (reflect.IsMap . ) }}
|
||||
{{ $context = .context }}
|
||||
{{ $scope = cond (not .scope) nil .scope }}
|
||||
{{ end }}
|
||||
|
||||
{{ with $context }}
|
||||
{{ $meta := newScratch }}
|
||||
|
||||
{{/* Gather partials for this context */}}
|
||||
|
||||
{{ if (.Params.showViews | default (.Site.Params.taxonomy.showViews | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/views.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if (.Params.showLikes | default (.Site.Params.taxonomy.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (.Params.showLikes | default (.Site.Params.taxonomy.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes_button.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{/* Output partials */}}
|
||||
{{ with ($meta.Get "partials") }}
|
||||
{{ delimit . "<span class=\"px-2 text-primary-500\">·</span>" | safeHTML }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
35
layouts/partials/article-meta/term.html
Normal file
35
layouts/partials/article-meta/term.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{{/* Determine the correct context and scope */}}
|
||||
{{/* This allows for different logic depending on where the partial is called */}}
|
||||
{{ $context := . }}
|
||||
{{ $scope := default nil }}
|
||||
|
||||
{{ if (reflect.IsMap . ) }}
|
||||
{{ $context = .context }}
|
||||
{{ $scope = cond (not .scope) nil .scope }}
|
||||
{{ end }}
|
||||
|
||||
{{ with $context }}
|
||||
{{ $meta := newScratch }}
|
||||
|
||||
{{/* Gather partials for this context */}}
|
||||
|
||||
{{ if (.Params.showViews | default (.Site.Params.term.showViews | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/views.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if (.Params.showLikes | default (.Site.Params.term.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (.Params.showLikes | default (.Site.Params.term.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes_button.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{/* Output partials */}}
|
||||
{{ with ($meta.Get "partials") }}
|
||||
{{ delimit . "<span class=\"px-2 text-primary-500\">·</span>" | safeHTML }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
Reference in New Issue
Block a user