前言 #
從我創建個人部落格「YoZ Blog 」以來,我在主頁與文章列表頁面都是使用「卡片列表」的樣式呈現文章,我認為較美觀,但後來發現文章越寫越多,這樣的樣式比起簡單的「列表」,似乎會妨礙到快速地找尋文章,且許多寫部落格的人也都使用單純的列表樣式,便產生了增加一個功能,透過按鈕切換文章列表樣式的功能,於是我透過 Cursor 稍微更改(vibecode)了 Blowfish 主題(2.93 版本)。
成品可以直接到 YoZ Blog 的主頁觀看。
下面直接說明這個過程。
創建切換按鍵 Javascript #
首先先建立/assets/js/switch-article-view.js:
(() => {
const activeClasses = ["bg-primary-500", "border-primary-500", "text-white"];
const inactiveClasses = [
"bg-transparent",
"border-neutral-300",
"text-neutral-700",
"dark:text-neutral-200",
"dark:border-neutral-600",
];
const setupToggle = (config) => {
const container = document.getElementById(config.toggleId);
const card = document.getElementById(config.cardId);
const list = document.getElementById(config.listId);
if (!container || !card || !list) return;
const buttons = Array.from(container.querySelectorAll("[data-view]"));
if (!buttons.length) return;
const setView = (view) => {
card.classList.toggle("hidden", view !== "card");
list.classList.toggle("hidden", view !== "list");
buttons.forEach((btn) => {
const isActive = btn.dataset.view === view;
btn.setAttribute("aria-pressed", isActive ? "true" : "false");
btn.classList.remove(...(isActive ? inactiveClasses : activeClasses));
btn.classList.add(...(isActive ? activeClasses : inactiveClasses));
});
};
buttons.forEach((btn) => {
btn.addEventListener("click", () => setView(btn.dataset.view || "card"));
});
setView(container.dataset.defaultView || "card");
};
[
{ toggleId: "recent-articles-toggle", cardId: "recent-articles-card", listId: "recent-articles-list" },
{ toggleId: "posts-view-toggle", cardId: "posts-card-view", listId: "posts-list-view" },
{ toggleId: "term-view-toggle", cardId: "term-card-view", listId: "term-list-view" },
].forEach(setupToggle);
})();
創建列表模式模板 #
列表模板的樣式相當簡單,只顯示「文章日期」與「文章標題」,例如:2026-03-07 Hugo Blowfish 主題|切換文章列表樣式按鈕。
創建/layouts/partials/recent-articles/title-list.html:
{{ $recentArticles := 5 }}
{{ if index .Site.Params.homepage "showRecentItems" }}
{{ $recentArticles = .Site.Params.homepage.showRecentItems }}
{{ end }}
<ul class="divide-y divide-neutral-200 dark:divide-neutral-800">
{{ range first $recentArticles (.Paginate (where .Site.RegularPages "Type" "in" .Site.Params.mainSections)).Pages }}
<li class="py-3">
<div class="flex items-center">
<span class="text-sm text-neutral-500 dark:text-neutral-400 whitespace-nowrap mr-3">
{{ .Date.Format "2006-01-02" }}
</span>
<a
href="{{ .RelPermalink }}"
class="font-semibold text-neutral-800 dark:text-neutral-100 hover:underline hover:underline-offset-2">
{{ .Title | emojify }}
</a>
</div>
</li>
{{ end }}
</ul>
主頁最新文章 #
接著要套用到主頁上的最新文章段落。
先複製/themes/blowfish/layouts/partials/recent-articles/路徑下的main.html到/layouts/partials/recent-articles。
將原本的程式碼:
{{ $recentArticles := 5 }}
{{ $showMoreLinkDest := "/posts/" }}
{{ if .Site.Params.homepage.showRecent | default false }}
{{ if index .Site.Params.homepage "showRecentItems" }}
{{ $recentArticles = .Site.Params.homepage.showRecentItems }}
{{ end }}
<h2 class="mt-8 text-2xl font-extrabold mb-10">{{ i18n "shortcode.recent_articles" | emojify }}</h2>
{{ if and .Site.Params.homepage.cardView (not .Site.Params.homepage.cardViewScreenWidth) | default false }}
{{ partial "recent-articles/cardview.html" . }}
{{ else if and .Site.Params.homepage.cardView .Site.Params.homepage.cardViewScreenWidth | default false }}
{{ partial "recent-articles/cardview-fullwidth.html" . }}
{{ else }}
{{ partial "recent-articles/list.html" . }}
{{ end }}
{{ if .Site.Params.homepage.showMoreLink | default false }}
{{ if index .Site.Params.homepage "showRecentItems" }}
{{ $showMoreLinkDest = .Site.Params.homepage.showMoreLinkDest }}
{{ end }}
<div class="mt-10 flex justify-center">
<a href="{{ $showMoreLinkDest | relLangURL }}">
<button
class="bg-transparent hover:text-primary-500 prose dark:prose-invert font-semibold py-2 px-4 border border-primary-500 hover:border-transparent rounded">
{{ i18n "recent.show_more" | markdownify }}
</button>
</a>
</div>
{{ end }}
{{ end }}
更改為:
{{ $recentArticles := 5 }}
{{ $showMoreLinkDest := "/posts/" }}
{{ $showRecent := .Site.Params.homepage.showRecent | default false }}
{{ $isCardDefault := .Site.Params.homepage.cardView | default false }}
{{ $defaultView := cond $isCardDefault "card" "list" }}
{{ if $showRecent }}
{{ if index .Site.Params.homepage "showRecentItems" }}
{{ $recentArticles = .Site.Params.homepage.showRecentItems }}
{{ end }}
<div class="mt-8 flex flex-wrap items-center justify-between gap-3 mb-6">
<h2 class="m-0 text-2xl font-extrabold leading-tight">
{{ i18n "shortcode.recent_articles" | emojify }}
</h2>
<div
id="recent-articles-toggle"
class="flex items-center"
style="gap: 0.5rem;"
data-default-view="{{ $defaultView }}">
{{ $btnBase := "px-3 py-1 rounded-md border text-sm font-medium transition-colors" }}
<button
type="button"
class="{{ $btnBase }} recent-toggle-button {{ if eq $defaultView "card" }}bg-primary-500 border-primary-500 text-white{{ else }}bg-transparent border-neutral-300 text-neutral-700 dark:text-neutral-200 dark:border-neutral-600{{ end }}"
data-view="card"
aria-pressed="{{ if eq $defaultView "card" }}true{{ else }}false{{ end }}">
卡片
</button>
<button
type="button"
class="{{ $btnBase }} recent-toggle-button {{ if eq $defaultView "list" }}bg-primary-500 border-primary-500 text-white{{ else }}bg-transparent border-neutral-300 text-neutral-700 dark:text-neutral-200 dark:border-neutral-600{{ end }}"
data-view="list"
aria-pressed="{{ if eq $defaultView "list" }}true{{ else }}false{{ end }}">
列表
</button>
</div>
</div>
<div id="recent-articles-card" class="{{ if ne $defaultView "card" }}hidden{{ end }}">
{{ if and .Site.Params.homepage.cardView (not .Site.Params.homepage.cardViewScreenWidth) | default false }}
{{ partial "recent-articles/cardview.html" . }}
{{ else if and .Site.Params.homepage.cardView .Site.Params.homepage.cardViewScreenWidth | default false }}
{{ partial "recent-articles/cardview-fullwidth.html" . }}
{{ else }}
{{ partial "recent-articles/cardview.html" . }}
{{ end }}
</div>
<div id="recent-articles-list" class="{{ if ne $defaultView "list" }}hidden{{ end }}">
{{ partial "recent-articles/title-list.html" . }}
</div>
{{ if .Site.Params.homepage.showMoreLink | default false }}
{{ if index .Site.Params.homepage "showRecentItems" }}
{{ $showMoreLinkDest = .Site.Params.homepage.showMoreLinkDest }}
{{ end }}
<div class="mt-10 flex justify-center">
<a href="{{ $showMoreLinkDest | relLangURL }}">
<button
class="bg-transparent hover:text-primary-500 prose dark:prose-invert font-semibold py-2 px-4 border border-primary-500 hover:border-transparent rounded">
{{ i18n "recent.show_more" | markdownify }}
</button>
</a>
</div>
{{ end }}
{{ $recentToggle := resources.Get "js/switch-article-view.js" }}
{{ $recentToggle = $recentToggle | resources.Minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
<script
src="{{ $recentToggle.RelPermalink }}"
integrity="{{ $recentToggle.Data.Integrity }}"
defer></script>
{{ end }}
完成!
全部文章 #
接著要套用到全部文章 (/posts)的段落。
將/themes/blowfish/layouts/_default路徑下的list.html複製到
/layouts/_default。
將原本的程式碼:
{{ define "main" }}
{{ .Scratch.Set "scope" "list" }}
{{ $enableToc := .Params.showTableOfContents | default (site.Params.list.showTableOfContents | default false) }}
{{ $showToc := and $enableToc (in .TableOfContents "<ul") }}
{{/* Hero */}}
{{ if site.Params.list.showHero | default false }}
{{ $heroStyle := print "hero/" site.Params.list.heroStyle ".html" }}
{{ if templates.Exists ( printf "partials/%s" $heroStyle ) }}
{{ partial $heroStyle . }}
{{ else }}
{{ partial "hero/basic.html" . }}
{{ end }}
{{ end }}
{{/* Header */}}
<header>
{{ if .Params.showBreadcrumbs | default (site.Params.list.showBreadcrumbs | default false) }}
{{ partial "breadcrumbs.html" . }}
{{ end }}
<h1 class="mt-5 text-4xl font-extrabold text-neutral-900 dark:text-neutral">{{ .Title }}</h1>
<div class="mt-1 mb-2 text-base text-neutral-500 dark:text-neutral-400 print:hidden">
{{ partial "article-meta/list.html" (dict "context" . "scope" "single") }}
</div>
{{ $translations := .AllTranslations }}
{{ with .File }}
{{ $path := .Path }}
{{ range $translations }}
{{ $lang := print "." .Lang ".md" }}
{{ $path = replace $path $lang ".md" }}
{{ end }}
{{ $jsPage := resources.Get "js/page.js" }}
{{ $jsPage = $jsPage | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }}
<script
type="text/javascript"
src="{{ $jsPage.RelPermalink }}"
integrity="{{ $jsPage.Data.Integrity }}"
data-oid="views_{{ $path }}"
data-oid-likes="likes_{{ $path }}"></script>
{{ end }}
</header>
{{/* Description (markdown content) */}}
{{ $tocMargin := cond $showToc "mt-12" "mt-0" }}
{{ $topClass := cond (hasPrefix site.Params.header.layout "fixed") "lg:top-[140px]" "lg:top-10" }}
<section class="{{ $tocMargin }} prose flex max-w-full flex-col dark:prose-invert lg:flex-row">
{{ if $showToc }}
<div class="order-first px-0 lg:order-last lg:max-w-xs lg:ps-8">
<div class="toc ps-5 lg:sticky {{ $topClass }}">
{{ partial "toc.html" . }}
</div>
</div>
{{ end }}
<div class="min-w-0 min-h-0 max-w-prose">
{{ .Content }}
</div>
</section>
{{/* Article Grid */}}
{{ if gt .Pages 0 }}
{{ $cardView := .Params.cardView | default (site.Params.list.cardView | default false) }}
{{ $cardViewScreenWidth := .Params.cardViewScreenWidth | default (site.Params.list.cardViewScreenWidth | default false) }}
{{ $groupByYear := .Params.groupByYear | default (site.Params.list.groupByYear | default false) }}
{{ $orderByWeight := .Params.orderByWeight | default (site.Params.list.orderByWeight | default false) }}
{{ $groupByYear := and (not $orderByWeight) $groupByYear }}
{{ if not $cardView }}
<section class="space-y-10 w-full">
{{ if not $orderByWeight }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ if $groupByYear }}
<h2 class="mt-12 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
{{ end }}
{{ range .Pages }}
{{ partial "article-link/simple.html" . }}
{{ end }}
{{ end }}
{{ else }}
{{ range (.Paginate (.Pages.ByWeight)).Pages }}
{{ partial "article-link/simple.html" . }}
{{ end }}
{{ end }}
</section>
{{/* else: is cardView */}}
{{ else }}
{{ if $groupByYear }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ if $cardViewScreenWidth }}
<div class="relative w-screen max-w-[1600px] px-[30px] start-[calc(max(-50vw,-800px)+50%)]">
<h2 class="mt-12 mb-3 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
</section>
</div>
{{ else }}
<h2 class="mt-12 mb-3 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
</section>
{{ end }}
{{ end }}
{{/* else: not groupByYear */}}
{{ else }}
{{ if $cardViewScreenWidth }}
<div class="relative w-screen max-w-[1600px] px-[30px] start-[calc(max(-50vw,-800px)+50%)]">
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
{{ if not $orderByWeight }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
{{ else }}
{{ range (.Paginate (.Pages.ByWeight)).Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
</section>
</div>
{{ else }}
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
{{ if not $orderByWeight }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
{{ else }}
{{ range (.Paginate (.Pages.ByWeight)).Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
</section>
{{ end }}{{/* End of cardViewScreenWidth */}}
{{ end }}{{/* End of groupByYear */}}
{{ end }}{{/* End of cardView */}}
{{/* else: .Pages not greater to zero */}}
{{ else }}
<section class="mt-10 prose dark:prose-invert">
<p class="py-8 border-t">
<em>{{ i18n "list.no_articles" | emojify }}</em>
</p>
</section>
{{ end }}
{{ partial "pagination.html" . }}
{{ end }}
更改為:
{{ define "main" }}
{{ .Scratch.Set "scope" "list" }}
{{ $enableToc := .Params.showTableOfContents | default (site.Params.list.showTableOfContents | default false) }}
{{ $showToc := and $enableToc (in .TableOfContents "<ul") }}
{{/* Hero */}}
{{ if site.Params.list.showHero | default false }}
{{ $heroStyle := print "hero/" site.Params.list.heroStyle ".html" }}
{{ if templates.Exists ( printf "partials/%s" $heroStyle ) }}
{{ partial $heroStyle . }}
{{ else }}
{{ partial "hero/basic.html" . }}
{{ end }}
{{ end }}
{{/* Header */}}
<header>
{{ if .Params.showBreadcrumbs | default (site.Params.list.showBreadcrumbs | default false) }}
{{ partial "breadcrumbs.html" . }}
{{ end }}
<h1 class="mt-5 text-4xl font-extrabold text-neutral-900 dark:text-neutral">{{ .Title }}</h1>
<div class="mt-1 mb-2 text-base text-neutral-500 dark:text-neutral-400 print:hidden">
{{ partial "article-meta/list.html" (dict "context" . "scope" "single") }}
</div>
{{ $translations := .AllTranslations }}
{{ with .File }}
{{ $path := .Path }}
{{ range $translations }}
{{ $lang := print "." .Lang ".md" }}
{{ $path = replace $path $lang ".md" }}
{{ end }}
{{ $jsPage := resources.Get "js/page.js" }}
{{ $jsPage = $jsPage | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }}
<script
type="text/javascript"
src="{{ $jsPage.RelPermalink }}"
integrity="{{ $jsPage.Data.Integrity }}"
data-oid="views_{{ $path }}"
data-oid-likes="likes_{{ $path }}"></script>
{{ end }}
</header>
{{/* Description (markdown content) */}}
{{ $tocMargin := cond $showToc "mt-12" "mt-0" }}
{{ $topClass := cond (hasPrefix site.Params.header.layout "fixed") "lg:top-[140px]" "lg:top-10" }}
<section class="{{ $tocMargin }} prose flex max-w-full flex-col dark:prose-invert lg:flex-row">
{{ if $showToc }}
<div class="order-first px-0 lg:order-last lg:max-w-xs lg:ps-8">
<div class="toc ps-5 lg:sticky {{ $topClass }}">
{{ partial "toc.html" . }}
</div>
</div>
{{ end }}
<div class="min-w-0 min-h-0 max-w-prose">
{{ .Content }}
</div>
</section>
{{/* Article Grid + Toggle */}}
{{ if gt .Pages 0 }}
{{ $cardView := .Params.cardView | default (site.Params.list.cardView | default false) }}
{{ $cardViewScreenWidth := .Params.cardViewScreenWidth | default (site.Params.list.cardViewScreenWidth | default false) }}
{{ $groupByYear := .Params.groupByYear | default (site.Params.list.groupByYear | default false) }}
{{ $orderByWeight := .Params.orderByWeight | default (site.Params.list.orderByWeight | default false) }}
{{ $groupByYear := and (not $orderByWeight) $groupByYear }}
{{ $defaultView := cond $cardView "card" "list" }}
<div class="mt-8 mb-2 flex justify-end">
<div
id="posts-view-toggle"
class="flex items-center"
style="gap: 0.5rem;"
data-default-view="{{ $defaultView }}">
{{ $btnBase := "px-3 py-1 rounded-md border text-sm font-medium transition-colors" }}
<button
type="button"
class="{{ $btnBase }} recent-toggle-button {{ if eq $defaultView "card" }}bg-primary-500 border-primary-500 text-white{{ else }}bg-transparent border-neutral-300 text-neutral-700 dark:text-neutral-200 dark:border-neutral-600{{ end }}"
data-view="card"
aria-pressed="{{ if eq $defaultView "card" }}true{{ else }}false{{ end }}">
卡片
</button>
<button
type="button"
class="{{ $btnBase }} recent-toggle-button {{ if eq $defaultView "list" }}bg-primary-500 border-primary-500 text-white{{ else }}bg-transparent border-neutral-300 text-neutral-700 dark:text-neutral-200 dark:border-neutral-600{{ end }}"
data-view="list"
aria-pressed="{{ if eq $defaultView "list" }}true{{ else }}false{{ end }}">
列表
</button>
</div>
</div>
<div id="posts-card-view" class="{{ if ne $defaultView "card" }}hidden{{ end }}">
{{ if $groupByYear }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ if $cardViewScreenWidth }}
<div class="relative w-screen max-w-[1600px] px-[30px] start-[calc(max(-50vw,-800px)+50%)]">
<h2 class="mt-12 mb-3 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
</section>
</div>
{{ else }}
<h2 class="mt-12 mb-3 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
</section>
{{ end }}
{{ end }}
{{ else }}
{{ if $cardViewScreenWidth }}
<div class="relative w-screen max-w-[1600px] px-[30px] start-[calc(max(-50vw,-800px)+50%)]">
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
{{ if not $orderByWeight }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
{{ else }}
{{ range (.Paginate (.Pages.ByWeight)).Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
</section>
</div>
{{ else }}
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
{{ if not $orderByWeight }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
{{ else }}
{{ range (.Paginate (.Pages.ByWeight)).Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
</section>
{{ end }}{{/* End of cardViewScreenWidth */}}
{{ end }}{{/* End of groupByYear */}}
</div>
<div id="posts-list-view" class="{{ if ne $defaultView "list" }}hidden{{ end }}">
{{ if $groupByYear }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
<h2 class="mt-12 mb-3 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
<ul class="divide-y divide-neutral-200 dark:divide-neutral-800">
{{ range .Pages }}
<li class="py-2">
<div class="flex items-center">
<span class="text-sm text-neutral-500 dark:text-neutral-400 whitespace-nowrap mr-3">
{{ .Date.Format "2006-01-02" }}
</span>
<a
href="{{ .RelPermalink }}"
class="font-semibold text-neutral-800 dark:text-neutral-100 hover:underline hover:underline-offset-2">
{{ .Title | emojify }}
</a>
</div>
</li>
{{ end }}
</ul>
{{ end }}
{{ else }}
<ul class="divide-y divide-neutral-200 dark:divide-neutral-800">
{{ if not $orderByWeight }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ range .Pages }}
<li class="py-2">
<div class="flex items-center">
<span class="text-sm text-neutral-500 dark:text-neutral-400 whitespace-nowrap mr-3">
{{ .Date.Format "2006-01-02" }}
</span>
<a
href="{{ .RelPermalink }}"
class="font-semibold text-neutral-800 dark:text-neutral-100 hover:underline hover:underline-offset-2">
{{ .Title | emojify }}
</a>
</div>
</li>
{{ end }}
{{ end }}
{{ else }}
{{ range (.Paginate (.Pages.ByWeight)).Pages }}
<li class="py-2">
<div class="flex items-center">
<span class="text-sm text-neutral-500 dark:text-neutral-400 whitespace-nowrap mr-3">
{{ .Date.Format "2006-01-02" }}
</span>
<a
href="{{ .RelPermalink }}"
class="font-semibold text-neutral-800 dark:text-neutral-100 hover:underline hover:underline-offset-2">
{{ .Title | emojify }}
</a>
</div>
</li>
{{ end }}
{{ end }}
</ul>
{{ end }}
</div>
{{/* else: .Pages not greater to zero */}}
{{ else }}
<section class="mt-10 prose dark:prose-invert">
<p class="py-8 border-t">
<em>{{ i18n "list.no_articles" | emojify }}</em>
</p>
</section>
{{ end }}
{{ partial "pagination.html" . }}
{{ $switchView := resources.Get "js/switch-article-view.js" }}
{{ $switchView = $switchView | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }}
<script
src="{{ $switchView.RelPermalink }}"
integrity="{{ $switchView.Data.Integrity }}"
defer></script>
{{ end }}
完成!
Taxonomy #
接著要套用到自訂的 Taxonomy 頁面,像是各個分類 或標籤 。
將/themes/blowfish/layouts/_default路徑下的term.html複製到/layouts/_default/term.html。
將原本的程式碼:
{{ define "main" }}
{{ .Scratch.Set "scope" "term" }}
{{ $showHero := .Params.showHero | default site.Params.term.showHero | default false }}
{{ if $showHero }}
{{ $heroStyle := print "hero/" site.Params.term.heroStyle ".html" }}
{{ if templates.Exists ( printf "partials/%s" $heroStyle ) }}
{{ partial $heroStyle . }}
{{ else }}
{{ partial "hero/basic.html" . }}
{{ end }}
{{- end -}}
<header class="mt-5">
{{ if .Params.showBreadcrumbs | default (site.Params.term.showBreadcrumbs | default false) }}
{{ partial "breadcrumbs.html" . }}
{{ end }}
<h1 class="mt-5 text-4xl font-extrabold text-neutral-900 dark:text-neutral">{{ .Title }}</h1>
<div class="mt-1 mb-2 text-base text-neutral-500 dark:text-neutral-400 print:hidden">
{{ partial "article-meta/term.html" (dict "context" . "scope" "single") }}
</div>
</header>
<section class="flex flex-col max-w-full mt-0 mb-5 prose dark:prose-invert lg:flex-row">
{{ if .Content }}
<div class="min-w-0 min-h-0 max-w-prose">
{{ .Content }}
</div>
{{ $jsPage := resources.Get "js/page.js" }}
{{ $jsPage = $jsPage | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }}
<script
type="text/javascript"
src="{{ $jsPage.RelPermalink }}"
integrity="{{ $jsPage.Data.Integrity }}"
data-oid="views_term_{{ .Data.Term }}"
data-oid-likes="likes_term_{{ .Data.Term }}"></script>
{{ end }}
</section>
{{ if gt .Pages 0 }}
{{ $cardView := .Params.cardView | default (site.Params.term.cardView | default false) }}
{{ $cardViewScreenWidth := site.Params.term.cardViewScreenWidth | default false }}
{{ $groupByYear := .Params.groupByYear | default (site.Params.term.groupByYear | default false) }}
{{ if not $cardView }}
<section class="space-y-10 w-full">
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ if $groupByYear }}
<h2 class="mt-12 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
{{ end }}
{{ range .Pages }}
{{ partial "article-link/simple.html" . }}
{{ end }}
{{ end }}
</section>
{{ else if and $cardView (not $cardViewScreenWidth) }}
{{ if $groupByYear }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
<h2 class="mt-12 mb-3 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
</section>
{{ end }}
{{ else }}
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
</section>
{{ end }}
{{ else if and $cardView $cardViewScreenWidth }}
{{ if $groupByYear }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
<div class="relative w-screen max-w-[1600px] px-[30px] start-[calc(max(-50vw,-800px)+50%)]">
<h2 class="mt-12 mb-3 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
</section>
</div>
{{ end }}
{{ else }}
<div class="relative w-screen max-w-[1600px] px-[30px] start-[calc(max(-50vw,-800px)+50%)]">
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
</section>
</div>
{{ end }}
{{ end }}
{{ else }}
<section class="mt-10 prose dark:prose-invert">
<p class="py-8 border-t">
<em>{{ i18n "term.no_articles" | emojify }}</em>
</p>
</section>
{{ end }}
{{ partial "pagination.html" . }}
{{ end }}
更改為:
{{ define "main" }}
{{ .Scratch.Set "scope" "term" }}
{{ $showHero := .Params.showHero | default site.Params.term.showHero | default false }}
{{ if $showHero }}
{{ $heroStyle := print "hero/" site.Params.term.heroStyle ".html" }}
{{ if templates.Exists ( printf "partials/%s" $heroStyle ) }}
{{ partial $heroStyle . }}
{{ else }}
{{ partial "hero/basic.html" . }}
{{ end }}
{{- end -}}
<header class="mt-5">
{{ if .Params.showBreadcrumbs | default (site.Params.term.showBreadcrumbs | default false) }}
{{ partial "breadcrumbs.html" . }}
{{ end }}
<h1 class="mt-5 text-4xl font-extrabold text-neutral-900 dark:text-neutral">{{ .Title }}</h1>
<div class="mt-1 mb-2 text-base text-neutral-500 dark:text-neutral-400 print:hidden">
{{ partial "article-meta/term.html" (dict "context" . "scope" "single") }}
</div>
</header>
<section class="flex flex-col max-w-full mt-0 mb-5 prose dark:prose-invert lg:flex-row">
{{ if .Content }}
<div class="min-w-0 min-h-0 max-w-prose">
{{ .Content }}
</div>
{{ $jsPage := resources.Get "js/page.js" }}
{{ $jsPage = $jsPage | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }}
<script
type="text/javascript"
src="{{ $jsPage.RelPermalink }}"
integrity="{{ $jsPage.Data.Integrity }}"
data-oid="views_term_{{ .Data.Term }}"
data-oid-likes="likes_term_{{ .Data.Term }}"></script>
{{ end }}
</section>
{{ if gt .Pages 0 }}
{{ $cardView := .Params.cardView | default (site.Params.term.cardView | default false) }}
{{ $cardViewScreenWidth := site.Params.term.cardViewScreenWidth | default false }}
{{ $groupByYear := .Params.groupByYear | default (site.Params.term.groupByYear | default false) }}
{{ $defaultView := cond $cardView "card" "list" }}
<div class="mt-6 mb-2 flex justify-end">
<div
id="term-view-toggle"
class="flex items-center"
style="gap: 0.5rem;"
data-default-view="{{ $defaultView }}">
{{ $btnBase := "px-3 py-1 rounded-md border text-sm font-medium transition-colors" }}
<button
type="button"
class="{{ $btnBase }} recent-toggle-button {{ if eq $defaultView "card" }}bg-primary-500 border-primary-500 text-white{{ else }}bg-transparent border-neutral-300 text-neutral-700 dark:text-neutral-200 dark:border-neutral-600{{ end }}"
data-view="card"
aria-pressed="{{ if eq $defaultView "card" }}true{{ else }}false{{ end }}">
卡片
</button>
<button
type="button"
class="{{ $btnBase }} recent-toggle-button {{ if eq $defaultView "list" }}bg-primary-500 border-primary-500 text-white{{ else }}bg-transparent border-neutral-300 text-neutral-700 dark:text-neutral-200 dark:border-neutral-600{{ end }}"
data-view="list"
aria-pressed="{{ if eq $defaultView "list" }}true{{ else }}false{{ end }}">
列表
</button>
</div>
</div>
<div id="term-card-view" class="{{ if ne $defaultView "card" }}hidden{{ end }}">
{{ if not $cardView }}
<section class="space-y-10 w-full">
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ if $groupByYear }}
<h2 class="mt-12 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
{{ end }}
{{ range .Pages }}
{{ partial "article-link/simple.html" . }}
{{ end }}
{{ end }}
</section>
{{ else if and $cardView (not $cardViewScreenWidth) }}
{{ if $groupByYear }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
<h2 class="mt-12 mb-3 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
</section>
{{ end }}
{{ else }}
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
</section>
{{ end }}
{{ else if and $cardView $cardViewScreenWidth }}
{{ if $groupByYear }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
<div class="relative w-screen max-w-[1600px] px-[30px] start-[calc(max(-50vw,-800px)+50%)]">
<h2 class="mt-12 mb-3 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
</section>
</div>
{{ end }}
{{ else }}
<div class="relative w-screen max-w-[1600px] px-[30px] start-[calc(max(-50vw,-800px)+50%)]">
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ range .Pages }}
{{ partial "article-link/card.html" . }}
{{ end }}
{{ end }}
</section>
</div>
{{ end }}
{{ end }}
</div>
<div id="term-list-view" class="{{ if ne $defaultView "list" }}hidden{{ end }}">
{{ if $groupByYear }}
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
<h2 class="mt-12 mb-3 text-2xl font-bold text-neutral-700 first:mt-8 dark:text-neutral-300">
{{ .Key }}
</h2>
<ul class="divide-y divide-neutral-200 dark:divide-neutral-800">
{{ range .Pages }}
<li class="py-2">
<div class="flex items-center">
<span class="text-sm text-neutral-500 dark:text-neutral-400 whitespace-nowrap mr-3">
{{ .Date.Format "2006-01-02" }}
</span>
<a
href="{{ .RelPermalink }}"
class="font-semibold text-neutral-800 dark:text-neutral-100 hover:underline hover:underline-offset-2">
{{ .Title | emojify }}
</a>
</div>
</li>
{{ end }}
</ul>
{{ end }}
{{ else }}
<ul class="divide-y divide-neutral-200 dark:divide-neutral-800">
{{ range (.Paginate (.Pages.GroupByDate "2006")).PageGroups }}
{{ range .Pages }}
<li class="py-2">
<div class="flex items-center">
<span class="text-sm text-neutral-500 dark:text-neutral-400 whitespace-nowrap mr-3">
{{ .Date.Format "2006-01-02" }}
</span>
<a
href="{{ .RelPermalink }}"
class="font-semibold text-neutral-800 dark:text-neutral-100 hover:underline hover:underline-offset-2">
{{ .Title | emojify }}
</a>
</div>
</li>
{{ end }}
{{ end }}
</ul>
{{ end }}
</div>
{{ else }}
<section class="mt-10 prose dark:prose-invert">
<p class="py-8 border-t">
<em>{{ i18n "term.no_articles" | emojify }}</em>
</p>
</section>
{{ end }}
{{ partial "pagination.html" . }}
{{ $switchView := resources.Get "js/switch-article-view.js" }}
{{ $switchView = $switchView | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }}
<script
src="{{ $switchView.RelPermalink }}"
integrity="{{ $switchView.Data.Integrity }}"
defer></script>
{{ end }}
完成!
透過郵件回覆