aboutsummaryrefslogtreecommitdiff
path: root/themes/hugo-theme-stack/layouts
diff options
context:
space:
mode:
authorAlexander Neonxp Kiryukhin <i@neonxp.ru>2024-11-03 20:08:36 +0300
committerAlexander Neonxp Kiryukhin <i@neonxp.ru>2024-11-03 20:08:36 +0300
commit59c7d4567380d1a9c80e96eb958fdbdd512ce006 (patch)
tree65410cfc10dbc7d060ec23be110662d9b7f6b0e9 /themes/hugo-theme-stack/layouts
новая жизнь блога
Diffstat (limited to 'themes/hugo-theme-stack/layouts')
-rw-r--r--themes/hugo-theme-stack/layouts/404.html45
-rw-r--r--themes/hugo-theme-stack/layouts/_default/_markup/render-heading.html6
-rw-r--r--themes/hugo-theme-stack/layouts/_default/_markup/render-image.html41
-rw-r--r--themes/hugo-theme-stack/layouts/_default/_markup/render-link.html3
-rw-r--r--themes/hugo-theme-stack/layouts/_default/archives.html35
-rw-r--r--themes/hugo-theme-stack/layouts/_default/baseof.html28
-rw-r--r--themes/hugo-theme-stack/layouts/_default/list.html85
-rw-r--r--themes/hugo-theme-stack/layouts/_default/rss.xml48
-rw-r--r--themes/hugo-theme-stack/layouts/_default/single.html46
-rw-r--r--themes/hugo-theme-stack/layouts/index.html19
-rw-r--r--themes/hugo-theme-stack/layouts/page/search.html33
-rw-r--r--themes/hugo-theme-stack/layouts/page/search.json26
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article-list/compact.html40
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article-list/default.html4
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article-list/tile.html39
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article/article.html11
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article/components/content.html5
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article/components/details.html61
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article/components/footer.html19
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article/components/header.html35
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article/components/links.html30
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article/components/math.html13
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article/components/photoswipe.html68
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article/components/related-content.html13
-rw-r--r--themes/hugo-theme-stack/layouts/partials/article/components/tags.html7
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/include.html3
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/beaudar.html46
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/cactus.html29
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/cusdis.html21
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/disqus.html22
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/disqusjs.html61
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/giscus.html52
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/gitalk.html31
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/remark42.html29
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/twikoo.html58
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/utterances.html46
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/vssue.html27
-rw-r--r--themes/hugo-theme-stack/layouts/partials/comments/provider/waline.html34
-rw-r--r--themes/hugo-theme-stack/layouts/partials/data/description.html17
-rw-r--r--themes/hugo-theme-stack/layouts/partials/data/title.html38
-rw-r--r--themes/hugo-theme-stack/layouts/partials/footer/components/custom-font.html11
-rw-r--r--themes/hugo-theme-stack/layouts/partials/footer/components/script.html12
-rw-r--r--themes/hugo-theme-stack/layouts/partials/footer/custom.html0
-rw-r--r--themes/hugo-theme-stack/layouts/partials/footer/footer.html23
-rw-r--r--themes/hugo-theme-stack/layouts/partials/footer/include.html3
-rw-r--r--themes/hugo-theme-stack/layouts/partials/head/colorScheme.html39
-rw-r--r--themes/hugo-theme-stack/layouts/partials/head/custom.html0
-rw-r--r--themes/hugo-theme-stack/layouts/partials/head/head.html26
-rw-r--r--themes/hugo-theme-stack/layouts/partials/head/opengraph/include.html2
-rw-r--r--themes/hugo-theme-stack/layouts/partials/head/opengraph/provider/base.html43
-rw-r--r--themes/hugo-theme-stack/layouts/partials/head/opengraph/provider/twitter.html16
-rw-r--r--themes/hugo-theme-stack/layouts/partials/head/script.html0
-rw-r--r--themes/hugo-theme-stack/layouts/partials/head/style.html3
-rw-r--r--themes/hugo-theme-stack/layouts/partials/helper/external.html29
-rw-r--r--themes/hugo-theme-stack/layouts/partials/helper/icon.html6
-rw-r--r--themes/hugo-theme-stack/layouts/partials/helper/image.html61
-rw-r--r--themes/hugo-theme-stack/layouts/partials/pagination.html26
-rw-r--r--themes/hugo-theme-stack/layouts/partials/sidebar/left.html103
-rw-r--r--themes/hugo-theme-stack/layouts/partials/sidebar/right.html16
-rw-r--r--themes/hugo-theme-stack/layouts/partials/widget/archives.html35
-rw-r--r--themes/hugo-theme-stack/layouts/partials/widget/categories.html16
-rw-r--r--themes/hugo-theme-stack/layouts/partials/widget/search.html16
-rw-r--r--themes/hugo-theme-stack/layouts/partials/widget/tag-cloud.html16
-rw-r--r--themes/hugo-theme-stack/layouts/partials/widget/toc.html12
-rw-r--r--themes/hugo-theme-stack/layouts/shortcodes/bilibili.html23
-rw-r--r--themes/hugo-theme-stack/layouts/shortcodes/gitlab.html4
-rw-r--r--themes/hugo-theme-stack/layouts/shortcodes/quote.html15
-rw-r--r--themes/hugo-theme-stack/layouts/shortcodes/tencent.html10
-rw-r--r--themes/hugo-theme-stack/layouts/shortcodes/video.html14
-rw-r--r--themes/hugo-theme-stack/layouts/shortcodes/youtube.html13
70 files changed, 1867 insertions, 0 deletions
diff --git a/themes/hugo-theme-stack/layouts/404.html b/themes/hugo-theme-stack/layouts/404.html
new file mode 100644
index 0000000..98f4a67
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/404.html
@@ -0,0 +1,45 @@
+{{ define "main" }}
+ <div class="not-found-card">
+ <h1 class="article-title">{{ T "notFound.title" }}</h1>
+ <h2 class="article-subtitle">{{ T "notFound.subtitle" }}</h2>
+ </div>
+
+ {{- $query := first 1 (where .Site.Pages "Layout" "==" "search") -}}
+ {{- $searchPage := index $query 0 -}}
+
+ {{- with $searchPage -}}
+ <form action="{{ $searchPage.RelPermalink }}" class="search-form widget" {{ with .OutputFormats.Get "json" -}}data-json="{{ .Permalink }}" {{- end }}>
+ <p>
+ <label>{{ T "search.title" }}</label>
+ <input id="searchInput" name="keyword" required placeholder="{{ T `search.placeholder` }}" />
+
+ <button title="{{ T `search.title` }}">
+ {{ partial "helper/icon" "search" }}
+ </button>
+ </p>
+ </form>
+
+ <div class="search-result">
+ <h3 class="search-result--title section-title"></h3>
+ <div class="search-result--list article-list--compact"></div>
+ </div>
+
+ <script>
+ window.searchResultTitleTemplate = "{{ T `search.resultTitle` }}"
+ </script>
+
+ {{- $opts := dict "minify" hugo.IsProduction "JSXFactory" "createElement" -}}
+ {{- $searchScript := resources.Get "ts/search.tsx" | js.Build $opts -}}
+ <script type="text/javascript" src="{{ $searchScript.RelPermalink }}" defer></script>
+
+ <script>
+ const wrongUrl = new URL(window.location.href);
+
+ /// Get the search keyword from the wrong URL by removing all slashes and dashes
+ const searchKeyword = wrongUrl.pathname.split(/[/|-]/).join(' ').trim();
+
+ document.getElementById('searchInput').setAttribute('value', searchKeyword);
+ </script>
+ {{- end -}}
+ {{ partialCached "footer/footer" . }}
+{{ end }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/_default/_markup/render-heading.html b/themes/hugo-theme-stack/layouts/_default/_markup/render-heading.html
new file mode 100644
index 0000000..f79308a
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/_default/_markup/render-heading.html
@@ -0,0 +1,6 @@
+<h{{ .Level }} id="{{ .Anchor }}">
+ {{- if site.Params.Article.HeadingAnchor -}}
+ <a href="#{{ .Anchor }}" class="header-anchor"></a>
+ {{- end -}}
+ {{ .Text | safeHTML }}
+</h{{ .Level }}> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/_default/_markup/render-image.html b/themes/hugo-theme-stack/layouts/_default/_markup/render-image.html
new file mode 100644
index 0000000..0ed5584
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/_default/_markup/render-image.html
@@ -0,0 +1,41 @@
+{{- $image := .Page.Resources.GetMatch (printf "%s" (.Destination | safeURL)) -}}
+{{- $Permalink := .Destination | relURL | safeURL -}}
+{{- $alt := .PlainText | safeHTML -}}
+{{- $Width := 0 -}}
+{{- $Height := 0 -}}
+{{- $Srcset := "" -}}
+
+{{/* SVG and external images won't work with gallery layout, because their width and height attributes are unknown */}}
+{{- $galleryImage := false -}}
+
+{{- if $image -}}
+ {{- $notSVG := ne (path.Ext .Destination) ".svg" -}}
+ {{- $Permalink = $image.RelPermalink -}}
+
+ {{- if $notSVG -}}
+ {{- $Width = $image.Width -}}
+ {{- $Height = $image.Height -}}
+ {{- $galleryImage = true -}}
+
+ {{- if (default true .Page.Site.Params.imageProcessing.content.enabled) -}}
+ {{- $small := $image.Resize `480x` -}}
+ {{- $big := $image.Resize `1024x` -}}
+ {{- $Srcset = printf `%s 480w, %s 1024w` $small.RelPermalink $big.RelPermalink -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+<img src="{{ $Permalink }}"
+ {{ with $Width }}width="{{ . }}"{{ end }}
+ {{ with $Height }}height="{{ . }}"{{ end }}
+ {{ with $Srcset }}srcset="{{ . }}"{{ end }}
+ loading="lazy"
+ {{ with $alt }}
+ alt="{{ . }}"
+ {{ end }}
+ {{ if $galleryImage }}
+ class="gallery-image"
+ data-flex-grow="{{ div (mul $image.Width 100) $image.Height }}"
+ data-flex-basis="{{ div (mul $image.Width 240) $image.Height }}px"
+ {{ end }}
+> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/_default/_markup/render-link.html b/themes/hugo-theme-stack/layouts/_default/_markup/render-link.html
new file mode 100644
index 0000000..843854d
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/_default/_markup/render-link.html
@@ -0,0 +1,3 @@
+<a class="link" href="{{ .Destination | safeURL }}" {{ with .Title}} title="{{ . }}"
+ {{ end }}{{ if strings.HasPrefix .Destination "http" }} target="_blank" rel="noopener"
+ {{ end }}>{{ .Text | safeHTML }}</a> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/_default/archives.html b/themes/hugo-theme-stack/layouts/_default/archives.html
new file mode 100644
index 0000000..5d5243c
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/_default/archives.html
@@ -0,0 +1,35 @@
+{{ define "body-class" }}template-archives{{ end }}
+{{ define "main" }}
+ <header>
+ {{- $taxonomy := $.Site.GetPage "taxonomyTerm" "categories" -}}
+ {{- $terms := $taxonomy.Pages -}}
+ {{ if $terms }}
+ <h2 class="section-title">{{ $taxonomy.Title }}</h2>
+ <div class="subsection-list">
+ <div class="article-list--tile">
+ {{ range $terms }}
+ {{ partial "article-list/tile" (dict "context" . "size" "250x150" "Type" "taxonomy") }}
+ {{ end }}
+ </div>
+ </div>
+ {{ end }}
+ </header>
+
+ {{ $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections }}
+ {{ $notHidden := where .Site.RegularPages "Params.hidden" "!=" true }}
+ {{ $filtered := ($pages | intersect $notHidden) }}
+
+ {{ range $filtered.GroupByDate "2006" }}
+ {{ $id := lower (replace .Key " " "-") }}
+ <div class="archives-group" id="{{ $id }}">
+ <h2 class="archives-date section-title"><a href="{{ $.RelPermalink }}#{{ $id }}">{{ .Key }}</a></h2>
+ <div class="article-list--compact">
+ {{ range .Pages }}
+ {{ partial "article-list/compact" . }}
+ {{ end }}
+ </div>
+ </div>
+ {{ end }}
+
+ {{ partialCached "footer/footer" . }}
+{{ end }}
diff --git a/themes/hugo-theme-stack/layouts/_default/baseof.html b/themes/hugo-theme-stack/layouts/_default/baseof.html
new file mode 100644
index 0000000..83fdaa3
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/_default/baseof.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="{{ .Site.LanguageCode }}" dir="{{ default `ltr` .Language.LanguageDirection }}">
+ <head>
+ {{- partial "head/head.html" . -}}
+ {{- block "head" . -}}{{ end }}
+ </head>
+ <body class="{{ block `body-class` . }}{{ end }}">
+ {{- partial "head/colorScheme" . -}}
+
+ {{/* The container is wider when there's any activated widget */}}
+ {{- $hasWidget := false -}}
+ {{- range .Site.Params.widgets -}}
+ {{- if gt (len .) 0 -}}
+ {{- $hasWidget = true -}}
+ {{- end -}}
+ {{- end -}}
+ <div class="container main-container flex on-phone--column {{ if $hasWidget }}extended{{ else }}compact{{ end }}">
+ {{- block "left-sidebar" . -}}
+ {{ partial "sidebar/left.html" . }}
+ {{- end -}}
+ {{- block "right-sidebar" . -}}{{ end }}
+ <main class="main full-width">
+ {{- block "main" . }}{{- end }}
+ </main>
+ </div>
+ {{ partial "footer/include.html" . }}
+ </body>
+</html>
diff --git a/themes/hugo-theme-stack/layouts/_default/list.html b/themes/hugo-theme-stack/layouts/_default/list.html
new file mode 100644
index 0000000..9bc618d
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/_default/list.html
@@ -0,0 +1,85 @@
+{{ define "main" }}
+ <header>
+ <h3 class="section-title">
+ {{ if eq .Parent (.GetPage "/") }}
+ {{ T "list.section" }}
+ {{ else }}
+ {{ .Parent.Title }}
+ {{ end }}
+ </h3>
+
+ <div class="section-card">
+ <div class="section-details">
+ <h3 class="section-count">{{ T "list.page" (len .Pages) }}</h3>
+ <h1 class="section-term">{{ .Title }}</h1>
+ {{ with .Params.description }}
+ <h2 class="section-description">{{ . }}</h2>
+ {{ end }}
+ </div>
+
+ {{- $image := partialCached "helper/image" (dict "Context" . "Type" "section") .RelPermalink "section" -}}
+ {{ if $image.exists }}
+ <div class="section-image">
+ {{ if $image.resource }}
+ {{- $Permalink := $image.resource.RelPermalink -}}
+ {{- $Width := $image.resource.Width -}}
+ {{- $Height := $image.resource.Height -}}
+
+ {{- if (default true .Page.Site.Params.imageProcessing.cover.enabled) -}}
+ {{- $thumbnail := $image.resource.Fill "120x120" -}}
+ {{- $Permalink = $thumbnail.RelPermalink -}}
+ {{- $Width = $thumbnail.Width -}}
+ {{- $Height = $thumbnail.Height -}}
+ {{- end -}}
+
+ <img src="{{ $Permalink }}"
+ width="{{ $Width }}"
+ height="{{ $Height }}"
+ loading="lazy">
+ {{ else }}
+ <img src="{{ $image.permalink }}" loading="lazy" />
+ {{ end }}
+ </div>
+ {{ end }}
+ </div>
+ </header>
+
+ {{- $subsections := .Sections -}}
+ {{- $pages := .Pages | complement $subsections -}}
+
+ {{- if eq (len $pages) 0 -}}
+ {{/* If there are no normal pages, display subsections in list style, with pagination */}}
+ {{/* This happens with taxonomies like categories or tags */}}
+ {{- $pages = $subsections -}}
+ {{- $subsections = slice -}}
+ {{- end -}}
+
+ {{- with $subsections -}}
+ <aside>
+ <h2 class="section-title">{{ T "list.subsection" (len $subsections) }}</h2>
+ <div class="subsection-list">
+ <div class="article-list--tile">
+ {{ range . }}
+ {{ partial "article-list/tile" (dict "context" . "size" "250x150" "Type" "section") }}
+ {{ end }}
+ </div>
+ </div>
+ </aside>
+ {{- end -}}
+
+ {{/* List only pages that are not a subsection */}}
+ {{ $paginator := .Paginate $pages }}
+ <section class="article-list--compact">
+ {{ range $paginator.Pages }}
+ {{ partial "article-list/compact" . }}
+ {{ end }}
+ </section>
+
+ {{- partial "pagination.html" . -}}
+
+ {{ partialCached "footer/footer" . }}
+{{ end }}
+
+{{ define "right-sidebar" }}
+ {{ partial "sidebar/right.html" (dict "Context" . "Scope" "homepage") }}
+{{ end }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/_default/rss.xml b/themes/hugo-theme-stack/layouts/_default/rss.xml
new file mode 100644
index 0000000..3d2e592
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/_default/rss.xml
@@ -0,0 +1,48 @@
+{{- $pctx := . -}}
+{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
+{{- $pages := slice -}}
+{{- if or $.IsHome $.IsSection -}}
+{{- $pages = $pctx.RegularPages -}}
+{{- else -}}
+{{- $pages = $pctx.Pages -}}
+{{- end -}}
+{{- $pages := where $pages "Params.hidden" "!=" true -}}
+{{- $limit := .Site.Config.Services.RSS.Limit -}}
+{{- if ge $limit 1 -}}
+{{- $pages = $pages | first $limit -}}
+{{- end -}}
+{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
+<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
+ <channel>
+ <title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }}</title>
+ <link>{{ .Permalink }}</link>
+ <description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description>
+ <generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }}
+ <language>{{.}}</language>{{end}}{{ with .Site.Params.Author.email }}
+ <managingEditor>{{.}}{{ with $.Site.Params.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Params.Author.email }}
+ <webMaster>{{.}}{{ with $.Site.Params.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
+ <copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}
+ <lastBuildDate>{{ (index $pages.ByLastmod.Reverse 0).Lastmod.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
+ {{- with .OutputFormats.Get "RSS" -}}
+ {{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
+ {{- end -}}
+ {{ range $pages }}
+ {{- $content := safeHTML (.Summary | html) -}}
+ {{- if .Site.Params.rssFullContent -}}
+ {{- $content = safeHTML (.Content | html) -}}
+ {{- end -}}
+ <item>
+ <title>{{ .Title }}</title>
+ <link>{{ .Permalink }}</link>
+ <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
+ {{ with .Site.Params.Author.email }}<author>{{.}}{{ with $.Site.Params.Author.name }} ({{.}}){{end}}</author>{{end}}
+ <guid>{{ .Permalink }}</guid>
+ <description>
+ {{- $image := partial "helper/image" (dict "Context" . "Type" "rss") -}}
+ {{- if $image.exists -}}
+ {{ "<" | html }}img src="{{ $image.permalink | absURL }}" alt="Featured image of post {{ .Title }}" {{ "/>" | html}}
+ {{- end -}}{{ $content }}</description>
+ </item>
+ {{ end }}
+ </channel>
+</rss>
diff --git a/themes/hugo-theme-stack/layouts/_default/single.html b/themes/hugo-theme-stack/layouts/_default/single.html
new file mode 100644
index 0000000..5f300bf
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/_default/single.html
@@ -0,0 +1,46 @@
+{{ define "body-class" }}
+ article-page
+ {{/*
+ Enable the right sidebar if
+ - Widget different from 'TOC' is enabled
+ - TOC is enabled and not empty
+ */}}
+ {{- $HasWidgetNotTOC := false -}}
+ {{- $TOCWidgetEnabled := false -}}
+ {{- range .Site.Params.widgets.page -}}
+ {{- if ne .type "toc" -}}
+ {{ $HasWidgetNotTOC = true -}}
+ {{- else -}}
+ {{ $TOCWidgetEnabled = true -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- $TOCManuallyDisabled := eq .Params.toc false -}}
+ {{- $TOCEnabled := and (not $TOCManuallyDisabled) $TOCWidgetEnabled -}}
+ {{- $hasTOC := ge (len .TableOfContents) 100 -}}
+ {{- .Scratch.Set "TOCEnabled" (and $TOCEnabled $hasTOC) -}}
+
+ {{- .Scratch.Set "hasWidget" (or $HasWidgetNotTOC (and $TOCEnabled $hasTOC)) -}}
+{{ end }}
+
+{{ define "main" }}
+ {{ partial "article/article.html" . }}
+
+ {{ if .Params.links }}
+ {{ partial "article/components/links" . }}
+ {{ end }}
+
+ {{ partial "article/components/related-content" . }}
+
+ {{ if not (eq .Params.comments false) }}
+ {{ partial "comments/include" . }}
+ {{ end }}
+
+ {{ partialCached "footer/footer" . }}
+
+ {{ partialCached "article/components/photoswipe" . }}
+{{ end }}
+
+{{ define "right-sidebar" }}
+ {{ if .Scratch.Get "hasWidget" }}{{ partial "sidebar/right.html" (dict "Context" . "Scope" "page") }}{{ end}}
+{{ end }}
diff --git a/themes/hugo-theme-stack/layouts/index.html b/themes/hugo-theme-stack/layouts/index.html
new file mode 100644
index 0000000..0cd0b88
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/index.html
@@ -0,0 +1,19 @@
+{{ define "main" }}
+ {{ $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections }}
+ {{ $notHidden := where .Site.RegularPages "Params.hidden" "!=" true }}
+ {{ $filtered := ($pages | intersect $notHidden) }}
+ {{ $pag := .Paginate ($filtered) }}
+
+ <section class="article-list">
+ {{ range $index, $element := $pag.Pages }}
+ {{ partial "article-list/default" . }}
+ {{ end }}
+ </section>
+
+ {{- partial "pagination.html" . -}}
+ {{- partial "footer/footer" . -}}
+{{ end }}
+
+{{ define "right-sidebar" }}
+ {{ partial "sidebar/right.html" (dict "Context" . "Scope" "homepage") }}
+{{ end }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/page/search.html b/themes/hugo-theme-stack/layouts/page/search.html
new file mode 100644
index 0000000..fbfb74d
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/page/search.html
@@ -0,0 +1,33 @@
+{{ define "body-class" }}template-search{{ end }}
+{{ define "head" }}
+ {{- with .OutputFormats.Get "json" -}}
+ <link rel="preload" href="{{ .RelPermalink }}" as="fetch" crossorigin="anonymous">
+ {{- end -}}
+{{ end }}
+{{ define "main" }}
+<form action="{{ .RelPermalink }}" class="search-form"{{ with .OutputFormats.Get "json" -}} data-json="{{ .RelPermalink }}"{{- end }}>
+ <p>
+ <label>{{ T "search.title" }}</label>
+ <input name="keyword" placeholder="{{ T `search.placeholder` }}" />
+ </p>
+
+ <button title="{{ T `search.title` }}">
+ {{ partial "helper/icon" "search" }}
+ </button>
+</form>
+
+<div class="search-result">
+ <h3 class="search-result--title section-title"></h3>
+ <div class="search-result--list article-list--compact"></div>
+</div>
+
+<script>
+ window.searchResultTitleTemplate = "{{ T `search.resultTitle` }}"
+</script>
+
+{{- $opts := dict "minify" hugo.IsProduction "JSXFactory" "createElement" -}}
+{{- $searchScript := resources.Get "ts/search.tsx" | js.Build $opts -}}
+<script type="text/javascript" src="{{ $searchScript.RelPermalink }}" defer></script>
+
+{{ partialCached "footer/footer" . }}
+{{ end }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/page/search.json b/themes/hugo-theme-stack/layouts/page/search.json
new file mode 100644
index 0000000..5d4e627
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/page/search.json
@@ -0,0 +1,26 @@
+{{- $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections -}}
+{{- $notHidden := where .Site.RegularPages "Params.hidden" "!=" true -}}
+{{- $filtered := ($pages | intersect $notHidden) -}}
+
+{{- $result := slice -}}
+
+{{- range $filtered -}}
+ {{- $data := dict "title" .Title "date" .Date "permalink" .Permalink "content" (.Plain) -}}
+
+ {{- $image := partialCached "helper/image" (dict "Context" . "Type" "articleList") .RelPermalink "articleList" -}}
+ {{- if $image.exists -}}
+ {{- $imagePermalink := "" -}}
+ {{- if and $image.resource (default true .Page.Site.Params.imageProcessing.cover.enabled) -}}
+ {{- $thumbnail := $image.resource.Fill "120x120" -}}
+ {{- $imagePermalink = (absURL $thumbnail.Permalink) -}}
+ {{- else -}}
+ {{- $imagePermalink = $image.permalink -}}
+ {{- end -}}
+
+ {{- $data = merge $data (dict "image" (absURL $imagePermalink)) -}}
+ {{- end -}}
+
+ {{- $result = $result | append $data -}}
+{{- end -}}
+
+{{ jsonify $result }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/article-list/compact.html b/themes/hugo-theme-stack/layouts/partials/article-list/compact.html
new file mode 100644
index 0000000..376512a
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article-list/compact.html
@@ -0,0 +1,40 @@
+<article>
+ <a href="{{ .RelPermalink }}">
+ <div class="article-details">
+ <h2 class="article-title">
+ {{- .Title -}}
+ </h2>
+ <footer class="article-time">
+ <time datetime='{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}'>
+ {{- .Date.Format (or .Site.Params.dateFormat.published "Jan 02, 2006") -}}
+ </time>
+ </footer>
+ </div>
+
+ {{- $image := partialCached "helper/image" (dict "Context" . "Type" "articleList") .RelPermalink "articleList" -}}
+ {{ if $image.exists }}
+ <div class="article-image">
+ {{ if $image.resource }}
+ {{- $Permalink := $image.resource.RelPermalink -}}
+ {{- $Width := $image.resource.Width -}}
+ {{- $Height := $image.resource.Height -}}
+
+ {{- if (default true .Page.Site.Params.imageProcessing.cover.enabled) -}}
+ {{- $thumbnail := $image.resource.Fill "120x120" -}}
+ {{- $Permalink = $thumbnail.RelPermalink -}}
+ {{- $Width = $thumbnail.Width -}}
+ {{- $Height = $thumbnail.Height -}}
+ {{- end -}}
+
+ <img src="{{ $Permalink }}"
+ width="{{ $Width }}"
+ height="{{ $Height }}"
+ alt="{{ .Title }}"
+ loading="lazy">
+ {{ else }}
+ <img src="{{ $image.permalink }}" loading="lazy" alt="Featured image of post {{ .Title }}" />
+ {{ end }}
+ </div>
+ {{ end }}
+ </a>
+</article> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/article-list/default.html b/themes/hugo-theme-stack/layouts/partials/article-list/default.html
new file mode 100644
index 0000000..02e0b30
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article-list/default.html
@@ -0,0 +1,4 @@
+{{ $image := partialCached "helper/image" (dict "Context" . "Type" "articleList") .RelPermalink "articleList" }}
+<article class="{{ if $image.exists }}has-image{{ end }}">
+ {{ partial "article/components/header" . }}
+</article> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/article-list/tile.html b/themes/hugo-theme-stack/layouts/partials/article-list/tile.html
new file mode 100644
index 0000000..be5744b
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article-list/tile.html
@@ -0,0 +1,39 @@
+{{ $image := partialCached "helper/image" (dict "Context" .context "Type" .Type) .context.RelPermalink .Type }}
+<article class="{{ if $image.exists }}has-image{{ end }}">
+ <a href="{{ .context.RelPermalink }}">
+
+ {{ if $image.exists }}
+ <div class="article-image">
+ {{ if $image.resource }}
+ {{- $imageRaw := $image.resource | resources.Fingerprint "md5" -}}
+ {{- $Permalink := $imageRaw.RelPermalink -}}
+ {{- $Width := $imageRaw.Width -}}
+ {{- $Height := $imageRaw.Height -}}
+
+ {{- if .context.Site.Params.imageProcessing.cover.enabled -}}
+ {{- $thumbnail := $imageRaw.Fill .size -}}
+ {{- $Permalink = $thumbnail.RelPermalink -}}
+ {{- $Width = $thumbnail.Width -}}
+ {{- $Height = $thumbnail.Height -}}
+ {{- end -}}
+
+ <img src="{{ $Permalink }}"
+ width="{{ $Width }}"
+ height="{{ $Height }}"
+ loading="lazy"
+ alt="Featured image of post {{ .context.Title }}"
+ {{ with .context.Slug }}data-key="{{ . }}" {{ end }}
+ data-hash="{{ $imageRaw.Data.Integrity }}">
+ {{ else }}
+ <img src="{{ $image.permalink }}" loading="lazy" data-key="{{ .context.Slug }}" data-hash="{{ $image.permalink }}"/>
+ {{ end }}
+ </div>
+ {{ end }}
+
+ <div class="article-details">
+ <h2 class="article-title">
+ {{- .context.Title -}}
+ </h2>
+ </div>
+ </a>
+</article>
diff --git a/themes/hugo-theme-stack/layouts/partials/article/article.html b/themes/hugo-theme-stack/layouts/partials/article/article.html
new file mode 100644
index 0000000..f3f7e90
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article/article.html
@@ -0,0 +1,11 @@
+<article class="{{ if .Params.image }}has-image {{ end }}main-article">
+ {{ partial "article/components/header" . }}
+
+ {{ partial "article/components/content" . }}
+
+ {{ partial "article/components/footer" . }}
+
+ {{ if or .Params.math .Site.Params.article.math }}
+ {{ partialCached "article/components/math.html" . }}
+ {{ end }}
+</article> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/article/components/content.html b/themes/hugo-theme-stack/layouts/partials/article/components/content.html
new file mode 100644
index 0000000..61e536c
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article/components/content.html
@@ -0,0 +1,5 @@
+<section class="article-content">
+ <!-- Refer to https://discourse.gohugo.io/t/responsive-tables-in-markdown/10639/5 -->
+ {{ $wrappedTable := printf "<div class=\"table-wrapper\">${1}</div>" }}
+ {{ .Content | replaceRE "(<table>(?:.|\n)+?</table>)" $wrappedTable | safeHTML }}
+</section>
diff --git a/themes/hugo-theme-stack/layouts/partials/article/components/details.html b/themes/hugo-theme-stack/layouts/partials/article/components/details.html
new file mode 100644
index 0000000..7c27302
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article/components/details.html
@@ -0,0 +1,61 @@
+<div class="article-details">
+ {{ if .Params.categories }}
+ <header class="article-category">
+ {{ range (.GetTerms "categories") }}
+ <a href="{{ .RelPermalink }}" {{ with .Params.style }}style="background-color: {{ .background }}; color: {{ .color }};"{{ end }}>
+ {{ .LinkTitle }}
+ </a>
+ {{ end }}
+ </header>
+ {{ end }}
+
+ <div class="article-title-wrapper">
+ <h2 class="article-title">
+ <a href="{{ .RelPermalink }}">
+ {{- .Title -}}
+ </a>
+ </h2>
+
+ {{ with .Params.description }}
+ <h3 class="article-subtitle">
+ {{ . }}
+ </h3>
+ {{ end }}
+ </div>
+
+ {{ $showReadingTime := .Params.readingTime | default (.Site.Params.article.readingTime) }}
+ {{ $showDate := not .Date.IsZero }}
+ {{ $showFooter := or $showDate $showReadingTime }}
+ {{ if $showFooter }}
+ <footer class="article-time">
+ {{ if $showDate }}
+ <div>
+ {{ partial "helper/icon" "date" }}
+ <time class="article-time--published">
+ {{- .Date | time.Format (or .Site.Params.dateFormat.published "Jan 02, 2006") -}}
+ </time>
+ </div>
+ {{ end }}
+
+ {{ if $showReadingTime }}
+ <div>
+ {{ partial "helper/icon" "clock" }}
+ <time class="article-time--reading">
+ {{ T "article.readingTime" .ReadingTime }}
+ </time>
+ </div>
+ {{ end }}
+ </footer>
+ {{ end }}
+
+ {{ if .IsTranslated }}
+ <footer class="article-translations">
+ {{ partial "helper/icon" "language" }}
+ <div>
+ {{ range .Translations }}
+ <a href="{{ .Permalink }}" class="link">{{ .Language.LanguageName }}</a>
+ {{ end }}
+ </div>
+ </footer>
+ {{ end }}
+</div>
diff --git a/themes/hugo-theme-stack/layouts/partials/article/components/footer.html b/themes/hugo-theme-stack/layouts/partials/article/components/footer.html
new file mode 100644
index 0000000..9795880
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article/components/footer.html
@@ -0,0 +1,19 @@
+<footer class="article-footer">
+ {{ partial "article/components/tags" . }}
+
+ {{ if and (.Site.Params.article.license.enabled) (not (eq .Params.license false)) }}
+ <section class="article-copyright">
+ {{ partial "helper/icon" "copyright" }}
+ <span>{{ default .Site.Params.article.license.default .Params.license | markdownify }}</span>
+ </section>
+ {{ end }}
+
+ {{- if ne .Lastmod .Date -}}
+ <section class="article-lastmod">
+ {{ partial "helper/icon" "clock" }}
+ <span>
+ {{ T "article.lastUpdatedOn" }} {{ .Lastmod | time.Format ( or .Site.Params.dateFormat.lastUpdated "Jan 02, 2006 15:04 MST" ) }}
+ </span>
+ </section>
+ {{- end -}}
+</footer>
diff --git a/themes/hugo-theme-stack/layouts/partials/article/components/header.html b/themes/hugo-theme-stack/layouts/partials/article/components/header.html
new file mode 100644
index 0000000..7582ec2
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article/components/header.html
@@ -0,0 +1,35 @@
+<header class="article-header">
+ {{- $image := partialCached "helper/image" (dict "Context" . "Type" "article") .RelPermalink "article" -}}
+ {{ if $image.exists }}
+ <div class="article-image">
+ <a href="{{ .RelPermalink }}">
+ {{ if $image.resource }}
+ {{- $Permalink := $image.resource.RelPermalink -}}
+ {{- $Width := $image.resource.Width -}}
+ {{- $Height := $image.resource.Height -}}
+ {{- $Srcset := "" -}}
+
+ {{- if (default true .Page.Site.Params.imageProcessing.cover.enabled) -}}
+ {{- $thumbnail := $image.resource.Resize "800x" -}}
+ {{- $thumbnailRetina := $image.resource.Resize "1600x" -}}
+ {{- $Srcset = printf "%s 800w, %s 1600w" $thumbnail.RelPermalink $thumbnailRetina.RelPermalink -}}
+ {{- $Permalink = $thumbnail.RelPermalink -}}
+ {{- $Width = $thumbnail.Width -}}
+ {{- $Height = $thumbnail.Height -}}
+ {{- end -}}
+
+ <img src="{{ $Permalink }}"
+ {{ with $Srcset }}srcset="{{ . }}"{{ end }}
+ width="{{ $Width }}"
+ height="{{ $Height }}"
+ loading="lazy"
+ alt="Featured image of post {{ .Title }}" />
+ {{ else }}
+ <img src="{{ $image.permalink }}" loading="lazy" alt="Featured image of post {{ .Title }}" />
+ {{ end }}
+ </a>
+ </div>
+ {{ end }}
+
+ {{ partialCached "article/components/details" . .RelPermalink }}
+</header> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/article/components/links.html b/themes/hugo-theme-stack/layouts/partials/article/components/links.html
new file mode 100644
index 0000000..a2ac26c
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article/components/links.html
@@ -0,0 +1,30 @@
+<div class="article-list--compact links">
+ {{ range $i, $link := .Params.links }}
+ <article>
+ <a href="{{ $link.website }}" target="_blank" rel="noopener">
+ <div class="article-details">
+ <h2 class="article-title">
+ {{- $link.title -}}
+ </h2>
+ <footer class="article-time">
+ {{ with $link.description }}
+ {{ . }}
+ {{ else }}
+ {{ $link.website }}
+ {{ end }}
+ </footer>
+ </div>
+
+ {{ with $link.image }}
+ {{ $permalink := . }}
+ {{ with ($.Resources.GetMatch (printf "%s" (. | safeURL))) }}
+ {{ $permalink = .RelPermalink }}
+ {{ end }}
+ <div class="article-image">
+ <img src="{{ $permalink }}" loading="lazy">
+ </div>
+ {{ end }}
+ </a>
+ </article>
+ {{ end }}
+</div> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/article/components/math.html b/themes/hugo-theme-stack/layouts/partials/article/components/math.html
new file mode 100644
index 0000000..bd1a7f8
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article/components/math.html
@@ -0,0 +1,13 @@
+{{- partial "helper/external" (dict "Context" . "Namespace" "KaTeX") -}}
+<script>
+ window.addEventListener("DOMContentLoaded", () => {
+ renderMathInElement(document.body, {
+ delimiters: [
+ { left: "$$", right: "$$", display: true },
+ { left: "$", right: "$", display: false },
+ { left: "\\(", right: "\\)", display: false },
+ { left: "\\[", right: "\\]", display: true }
+ ],
+ ignoredClasses: ["gist"]
+ });})
+</script> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/article/components/photoswipe.html b/themes/hugo-theme-stack/layouts/partials/article/components/photoswipe.html
new file mode 100644
index 0000000..c33ff49
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article/components/photoswipe.html
@@ -0,0 +1,68 @@
+<!-- Root element of PhotoSwipe. Must have class pswp. -->
+<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
+
+ <!-- Background of PhotoSwipe.
+ It's a separate element as animating opacity is faster than rgba(). -->
+ <div class="pswp__bg"></div>
+
+ <!-- Slides wrapper with overflow:hidden. -->
+ <div class="pswp__scroll-wrap">
+
+ <!-- Container that holds slides.
+ PhotoSwipe keeps only 3 of them in the DOM to save memory.
+ Don't modify these 3 pswp__item elements, data is added later on. -->
+ <div class="pswp__container">
+ <div class="pswp__item"></div>
+ <div class="pswp__item"></div>
+ <div class="pswp__item"></div>
+ </div>
+
+ <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
+ <div class="pswp__ui pswp__ui--hidden">
+
+ <div class="pswp__top-bar">
+
+ <!-- Controls are self-explanatory. Order can be changed. -->
+
+ <div class="pswp__counter"></div>
+
+ <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
+
+ <button class="pswp__button pswp__button--share" title="Share"></button>
+
+ <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
+
+ <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
+
+ <!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->
+ <!-- element will get class pswp__preloader--active when preloader is running -->
+ <div class="pswp__preloader">
+ <div class="pswp__preloader__icn">
+ <div class="pswp__preloader__cut">
+ <div class="pswp__preloader__donut"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
+ <div class="pswp__share-tooltip"></div>
+ </div>
+
+ <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
+ </button>
+
+ <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
+ </button>
+
+ <div class="pswp__caption">
+ <div class="pswp__caption__center"></div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
+
+{{- partial "helper/external" (dict "Context" . "Namespace" "PhotoSwipe") -}} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/article/components/related-content.html b/themes/hugo-theme-stack/layouts/partials/article/components/related-content.html
new file mode 100644
index 0000000..aba88e3
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article/components/related-content.html
@@ -0,0 +1,13 @@
+{{ $related := (where (.Site.RegularPages.Related .) "Params.hidden" "!=" true) | first 5 }}
+{{ with $related }}
+<aside class="related-content--wrapper">
+ <h2 class="section-title">{{ T "article.relatedContent" }}</h2>
+ <div class="related-content">
+ <div class="flex article-list--tile">
+ {{ range . }}
+ {{ partial "article-list/tile" (dict "context" . "size" "250x150" "Type" "articleList") }}
+ {{ end }}
+ </div>
+ </div>
+</aside>
+{{ end }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/article/components/tags.html b/themes/hugo-theme-stack/layouts/partials/article/components/tags.html
new file mode 100644
index 0000000..aae38b4
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/article/components/tags.html
@@ -0,0 +1,7 @@
+{{ if .Params.Tags }}
+ <section class="article-tags">
+ {{ range (.GetTerms "tags") }}
+ <a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
+ {{ end }}
+ </section>
+{{ end }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/include.html b/themes/hugo-theme-stack/layouts/partials/comments/include.html
new file mode 100644
index 0000000..a3d0618
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/include.html
@@ -0,0 +1,3 @@
+{{ if .Site.Params.comments.enabled }}
+ {{ partial (printf "comments/provider/%s" .Site.Params.comments.provider) . }}
+{{ end }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/beaudar.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/beaudar.html
new file mode 100644
index 0000000..761801f
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/beaudar.html
@@ -0,0 +1,46 @@
+<script
+ src="https://beaudar.lipk.org/client.js"
+ repo="{{ .Site.Params.comments.beaudar.repo }}"
+ issue-term="{{ .Site.Params.comments.beaudar.issueTerm }}"
+ {{ with .Site.Params.comments.beaudar.label }}
+ label="{{ . }}"
+ {{ end }}
+ theme="{{ .Site.Params.comments.beaudar.theme }}"
+ crossorigin="anonymous"
+ async
+></script>
+
+<style>
+ .beaudar {
+ max-width: unset;
+ }
+</style>
+
+<script>
+ let beaudarLoaded = false;
+
+ function setBeaudarTheme(theme) {
+ let beaudar = document.querySelector(".beaudar iframe");
+ if (beaudar) {
+ beaudar.contentWindow.postMessage(
+ {
+ type: "set-theme",
+ theme: `github-${theme}`,
+ },
+ "https://beaudar.lipk.org"
+ );
+ }
+ }
+
+ addEventListener("message", (event) => {
+ if (event.origin !== "https://beaudar.lipk.org") return;
+ /// Called when Beaudar is ready
+ beaudarLoaded = true;
+ setBeaudarTheme(document.documentElement.dataset.scheme);
+ });
+
+ window.addEventListener("onColorSchemeChange", (e) => {
+ if (!beaudarLoaded) return;
+ setBeaudarTheme(e.detail);
+ });
+</script>
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/cactus.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/cactus.html
new file mode 100644
index 0000000..ae172d3
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/cactus.html
@@ -0,0 +1,29 @@
+{{- with .Site.Params.comments.cactus -}}
+{{- partial "helper/external" (dict "Context" $ "Namespace" "Cactus") -}}
+
+<style>
+ .cactus-editor-textarea {
+ color: var(--body-text-color);
+ }
+
+ .cactus-comment-header {
+ color: var(--card-text-color-main);
+ }
+
+ .cactus-message-text > p {
+ color: var(--body-text-color);
+ }
+</style>
+
+<div id="comment-section"></div>
+
+<script>
+ initComments({
+ node: document.getElementById("comment-section"),
+ defaultHomeserverUrl: "{{ .defaultHomeserverUrl | safeJS }}",
+ serverName: "{{ .serverName }}",
+ siteName: "{{ .siteName }}",
+ commentSectionId: "{{ $.File.UniqueID }}"
+ })
+</script>
+{{- end -}}
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/cusdis.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/cusdis.html
new file mode 100644
index 0000000..a89746c
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/cusdis.html
@@ -0,0 +1,21 @@
+{{- $host := default "https://cusdis.com" .Site.Params.comments.cusdis.host -}}
+<div id="cusdis_thread"
+ data-host="{{ $host }}"
+ data-app-id="{{ .Site.Params.comments.cusdis.id }}"
+ data-page-id="{{ .File.UniqueID }}"
+ data-page-url="{{ .Permalink }}"
+ data-page-title="{{ .Title }}"></div>
+<script async defer src="{{ $host }}/js/cusdis.es.js"></script>
+
+<script>
+ function setCusdisTheme(theme) {
+ let cusdis = document.querySelector('#cusdis_thread iframe');
+ if (cusdis) {
+ window.CUSDIS.setTheme(theme)
+ }
+ }
+
+ window.addEventListener('onColorSchemeChange', (e) => {
+ setCusdisTheme(e.detail)
+ })
+</script>
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/disqus.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/disqus.html
new file mode 100644
index 0000000..fb17b77
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/disqus.html
@@ -0,0 +1,22 @@
+<div class="disqus-container">
+ {{ template "_internal/disqus.html" . }}
+</div>
+
+<style>
+ .disqus-container {
+ background-color: var(--card-background);
+ border-radius: var(--card-border-radius);
+ box-shadow: var(--shadow-l1);
+ padding: var(--card-padding);
+ }
+</style>
+
+<script>
+ window.addEventListener('onColorSchemeChange', (e) => {
+ if (typeof DISQUS == 'object') {
+ DISQUS.reset({
+ reload: true
+ });
+ }
+ })
+</script> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/disqusjs.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/disqusjs.html
new file mode 100644
index 0000000..967c38c
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/disqusjs.html
@@ -0,0 +1,61 @@
+{{- $pc := .Site.Config.Privacy.Disqus -}}
+{{- $disqusjs := .Site.Params.Comments.disqusjs -}}
+{{- if and (not $pc.Disable) (and $disqusjs.Shortname $disqusjs.ApiKey) -}}
+
+{{- $style := resources.Get "scss/partials/comments/disqusjs.scss" | toCSS | minify -}}
+<link rel="stylesheet" href="{{ $style.RelPermalink }}">
+
+<div class="disqus-container">
+ <div id="disqus_thread"></div>
+ <script type="application/javascript">
+ let disqusjs;
+ function loadDisqusJS() {
+ disqusjs = new DisqusJS({
+ shortname: {{ $disqusjs.Shortname }},
+ siteName: {{ .Site.Title }},
+ apikey: {{ $disqusjs.ApiKey }},
+ {{ with $disqusjs.ApiUrl }}api: {{ . }},{{ end }}
+ {{ with $disqusjs.Admin }}admin: {{ . }},{{ end }}
+ {{ with $disqusjs.AdminLabel }}adminLabel: {{ . }}{{ end }}
+ });
+ }
+
+ function lazyLoadDisqusJS() {
+ if (["localhost", "127.0.0.1"].indexOf(window.location.hostname) != -1) {
+ document.getElementById('disqus_thread').innerHTML = 'Disqus comments not available by default when the website is previewed locally.';
+ return;
+ }
+
+ let d = document.createElement('script');
+ d.src = 'https://cdn.jsdelivr.net/npm/disqusjs@1.3/dist/disqus.js';
+ d.async = false;
+ document.body.appendChild(d);
+ d.onload = () => {
+ loadDisqusJS();
+ window.addEventListener('onColorSchemeChange', (e) => {
+ if (disqusjs) {
+ loadDisqusJS();
+ }
+ })
+ }
+ }
+
+ let runningOnBrowser = typeof window !== "undefined";
+ let isBot = runningOnBrowser && !("onscroll" in window) || typeof navigator !== "undefined" && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent);
+ let supportsIntersectionObserver = runningOnBrowser && "IntersectionObserver" in window;
+
+ if (!isBot && supportsIntersectionObserver) {
+ let disqus_observer = new IntersectionObserver(function(entries) {
+ if (entries[0].isIntersecting) {
+ lazyLoadDisqusJS();
+ disqus_observer.disconnect();
+ }
+ });
+ disqus_observer.observe(document.getElementById('disqus_thread'));
+ } else {
+ lazyLoadDisqusJS();
+ }
+ </script>
+ <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
+</div>
+{{- end -}} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/giscus.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/giscus.html
new file mode 100644
index 0000000..97fbb77
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/giscus.html
@@ -0,0 +1,52 @@
+{{- with .Site.Params.comments.giscus -}}
+<script
+ src="https://giscus.app/client.js"
+ data-repo="{{- .repo -}}"
+ data-repo-id="{{- .repoID -}}"
+ data-category="{{- .category -}}"
+ data-category-id="{{- .categoryID -}}"
+ data-mapping="{{- default `title` .mapping -}}"
+ data-strict="{{- default 0 .strict -}}"
+ data-reactions-enabled="{{- default 1 .reactionsEnabled -}}"
+ data-emit-metadata="{{- default 0 .emitMetadata -}}"
+ data-input-position="{{- default `top` .inputPosition -}}"
+ data-theme="{{- default `light` .lightTheme -}}"
+ data-lang="{{- default (default `en` $.Language.LanguageCode) .lang -}}"
+ data-loading="{{- .loading -}}"
+ crossorigin="anonymous"
+ async
+></script>
+<script>
+ function setGiscusTheme(theme) {
+ let giscus = document.querySelector("iframe.giscus-frame");
+ if (giscus) {
+ giscus.contentWindow.postMessage(
+ {
+ giscus: {
+ setConfig: {
+ theme: theme,
+ },
+ },
+ },
+ "https://giscus.app"
+ );
+ }
+ }
+
+ (function () {
+ addEventListener("message", (e) => {
+ if (event.origin !== "https://giscus.app") return;
+ handler();
+ });
+ window.addEventListener("onColorSchemeChange", handler);
+
+ function handler() {
+ if (document.documentElement.dataset.scheme === "light") {
+ setGiscusTheme('{{- default "light" .lightTheme -}}');
+ } else {
+ setGiscusTheme('{{- default "dark_dimmed" .darkTheme -}}');
+ }
+ }
+ })();
+</script>
+{{- end -}}
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/gitalk.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/gitalk.html
new file mode 100644
index 0000000..54bfcba
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/gitalk.html
@@ -0,0 +1,31 @@
+{{- with .Site.Params.comments.gitalk -}}
+<div id="gitalk-container"></div>
+<link
+ rel="stylesheet"
+ href="https://cdn.jsdelivr.net/npm/gitalk@1.7.2/dist/gitalk.css"
+/>
+<script src="https://cdn.jsdelivr.net/npm/gitalk@1.7.2/dist/gitalk.min.js"></script>
+<script src="https://cdn.jsdelivr.net/npm/blueimp-md5@2.18.0/js/md5.min.js"></script>
+<script>
+ const gitalk = new Gitalk({
+ clientID: "{{- .clientID -}}",
+ clientSecret: "{{- .clientSecret -}}",
+ repo: "{{- .repo -}}",
+ owner: "{{- .owner -}}",
+ admin: ["{{- .admin -}}"],
+ distractionFreeMode: false, // Facebook-like distraction free mode
+ id: md5(location.pathname), // Max Location.pathname Legth:75 https://github.com/gitalk/gitalk/issues/102
+ proxy: {{- .proxy -}},
+ });
+ (function () {
+ if (
+ ["localhost", "127.0.0.1"].indexOf(window.location.hostname) != -1
+ ) {
+ document.getElementById("gitalk-container").innerHTML =
+ "Gitalk comments not available by default when the website is previewed locally.";
+ return;
+ }
+ gitalk.render("gitalk-container");
+ })();
+</script>
+{{ end }}
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/remark42.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/remark42.html
new file mode 100644
index 0000000..18acf1b
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/remark42.html
@@ -0,0 +1,29 @@
+{{- with .Site.Params.comments.remark42 -}}
+<div id="remark42"></div>
+<script>
+ var remark_config = {
+ host: '{{ .host }}',
+ site_id: '{{ .site }}',
+ components: ['embed'],
+ url: '{{ $.Permalink }}',
+ max_shown_comments: {{ default 15 .max_shown_comments }},
+ theme: document.documentElement.dataset.scheme,
+ page_title: '{{ $.Title }}',
+ locale: '{{ default "en" .locale }}',
+ show_email_subscription: {{ default true .show_email_subscription }}
+ };
+
+ !function(e, n) {
+ for (var o = 0; o < e.length; o++) {
+ var r = n.createElement('script'),
+ c = '.js',
+ d = n.head || n.body;
+ 'noModule' in r ? (r.type = 'module', c = '.mjs') : r.async = !0, r.defer = !0, r.src = remark_config.host + '/web/' + e[o] + c, d.appendChild(r)
+ }
+ }(remark_config.components || ['embed'], document);
+
+ window.addEventListener('onColorSchemeChange', (e) => {
+ window.REMARK42.changeTheme(e.detail);
+ })
+</script>
+{{- end -}}
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/twikoo.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/twikoo.html
new file mode 100644
index 0000000..8c22507
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/twikoo.html
@@ -0,0 +1,58 @@
+<script src="//cdn.jsdelivr.net/npm/twikoo@1.6.39/dist/twikoo.all.min.js"></script>
+<div id="tcomment"></div>
+<style>
+ .twikoo {
+ background-color: var(--card-background);
+ border-radius: var(--card-border-radius);
+ box-shadow: var(--shadow-l1);
+ padding: var(--card-padding);
+ }
+ :root[data-scheme="dark"] {
+ --twikoo-body-text-color-main: rgba(255, 255, 255, 0.9);
+ --twikoo-body-text-color: rgba(255, 255, 255, 0.7);
+ }
+ .twikoo .el-input-group__prepend,
+ .twikoo .tk-action-icon,
+ .twikoo .tk-submit-action-icon,
+ .twikoo .tk-time,
+ .twikoo .tk-comments-no,
+ .twikoo .tk-comments-count {
+ color: var(--twikoo-body-text-color);
+ }
+ .twikoo .el-input__inner,
+ .twikoo .el-textarea__inner,
+ .twikoo .tk-preview-container,
+ .twikoo .tk-content,
+ .twikoo .tk-nick,
+ .twikoo .tk-send {
+ color: var(--twikoo-body-text-color-main);
+ }
+ .twikoo .el-button{
+ color: var(--twikoo-body-text-color)!important;
+ }
+ .twikoo .el-input__count {
+ color: var(--twikoo-body-text-color) !important;
+ }
+ .OwO .OwO-body {
+ background-color: var(--body-background) !important;
+ color: var(--body-text-color) !important;
+ }
+</style>
+
+{{- with .Site.Params.comments.twikoo -}}
+<script>
+ twikoo.init({
+ envId: '{{- .envId -}}',
+ el: '#tcomment',
+ {{- with .region -}}
+ region: '{{- . -}}',
+ {{- end -}}
+ {{- with .path -}}
+ path: '{{- . -}}',
+ {{- end -}}
+ {{- with .lang -}}
+ lang: '{{- . -}}',
+ {{- end -}}
+ })
+</script>
+{{- end -}}
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/utterances.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/utterances.html
new file mode 100644
index 0000000..b1e370b
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/utterances.html
@@ -0,0 +1,46 @@
+<script src="https://utteranc.es/client.js"
+ repo="{{ .Site.Params.comments.utterances.repo }}"
+ issue-term="{{ .Site.Params.comments.utterances.issueTerm }}"
+ {{ with .Site.Params.comments.utterances.label }}
+ label="{{ . }}"
+ {{ end }}
+ crossorigin="anonymous"
+ async
+ >
+</script>
+
+<style>
+ .utterances {
+ max-width: unset;
+ }
+</style>
+
+<script>
+ let utterancesLoaded = false;
+
+ function setUtterancesTheme(theme) {
+ let utterances = document.querySelector('.utterances iframe');
+ if (utterances) {
+ utterances.contentWindow.postMessage(
+ {
+ type: 'set-theme',
+ theme: `github-${theme}`
+ },
+ 'https://utteranc.es'
+ );
+ }
+ }
+
+ addEventListener('message', event => {
+ if (event.origin !== 'https://utteranc.es') return;
+
+ /// Called when Utterances is ready
+ utterancesLoaded = true;
+ setUtterancesTheme(document.documentElement.dataset.scheme)
+ });
+
+ window.addEventListener('onColorSchemeChange', (e) => {
+ if (!utterancesLoaded) return;
+ setUtterancesTheme(e.detail)
+ })
+</script>
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/vssue.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/vssue.html
new file mode 100644
index 0000000..79ac381
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/vssue.html
@@ -0,0 +1,27 @@
+{{- with .Site.Params.comments.vssue -}}
+<link rel="stylesheet" href="https://unpkg.com/vssue/dist/vssue.min.css" />
+
+<div id="vssue"></div>
+
+<script src="https://unpkg.com/vue@2/dist/vue.runtime.min.js"></script>
+<script src="https://unpkg.com/vssue/dist/vssue.{{ .platform }}.min.js"></script>
+
+<script>
+ new Vue({
+ el: "#vssue",
+ render: (h) =>
+ h("Vssue", {
+ props: {
+ title: "{{ $.Title }}",
+ options: {
+ autoCreateIssue: {{ default false .autoCreateIssue }},
+ owner: "{{ .owner }}",
+ repo: "{{ .repo }}",
+ clientId: "{{ .clientId }}",
+ clientSecret: "{{ .clientSecret }}",
+ },
+ },
+ }),
+ });
+</script>
+{{- end -}}
diff --git a/themes/hugo-theme-stack/layouts/partials/comments/provider/waline.html b/themes/hugo-theme-stack/layouts/partials/comments/provider/waline.html
new file mode 100644
index 0000000..9d1a2a0
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/comments/provider/waline.html
@@ -0,0 +1,34 @@
+<script src='//unpkg.com/@waline/client@v2/dist/waline.js'></script>
+<link href='//unpkg.com/@waline/client@v2/dist/waline.css' rel='stylesheet'/>
+<div id="waline" class="waline-container"></div>
+<style>
+ .waline-container {
+ background-color: var(--card-background);
+ border-radius: var(--card-border-radius);
+ box-shadow: var(--shadow-l1);
+ padding: var(--card-padding);
+ --waline-font-size: var(--article-font-size);
+ }
+ .waline-container .wl-count {
+ color: var(--card-text-color-main);
+ }
+</style>
+
+{{- with .Site.Params.comments.waline -}}
+{{- $config := dict "el" "#waline" "dark" `html[data-scheme="dark"]` -}}
+{{- $replaceKeys := dict "serverurl" "serverURL" "requiredmeta" "requiredMeta" "wordlimit" "wordLimit" "pagesize" "pageSize" "imageuploader" "imageUploader" "texrenderer" "texRenderer" -}}
+
+{{- range $key, $val := . -}}
+ {{- if ne $val nil -}}
+ {{- $replaceKey := index $replaceKeys $key -}}
+ {{- $k := default $key $replaceKey -}}
+
+ {{- $config = merge $config (dict $k $val) -}}
+ {{- end -}}
+{{- end -}}
+
+<script>
+ /// Waline client configuration see: https://waline.js.org/en/reference/client.html
+ Waline.init({{ $config | jsonify | safeJS }});
+</script>
+{{- end -}}
diff --git a/themes/hugo-theme-stack/layouts/partials/data/description.html b/themes/hugo-theme-stack/layouts/partials/data/description.html
new file mode 100644
index 0000000..7f6cc32
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/data/description.html
@@ -0,0 +1,17 @@
+<!-- Use site subtitle by default -->
+{{ $description := .Site.Params.sidebar.subtitle }}
+
+<!-- Seprate description exists -->
+{{ if .Site.Params.description }}
+ {{ $description = .Site.Params.description }}
+{{ end }}
+
+{{ if .Description }}
+ <!-- Page description exists -->
+ {{ $description = .Description }}
+{{ else if .IsPage }}
+ <!-- Use page summary -->
+ {{ $description = .Summary }}
+{{ end }}
+
+{{ return (replaceRE "\n" " " $description | plainify) }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/data/title.html b/themes/hugo-theme-stack/layouts/partials/data/title.html
new file mode 100644
index 0000000..85a7bc7
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/data/title.html
@@ -0,0 +1,38 @@
+{{- $title := .Title -}}
+{{- $siteTitle := .Site.Title -}}
+
+{{- if .IsHome -}}
+ <!-- Homepage, and it's pagination -->
+
+ <!-- Build paginator -->
+ {{ $pages := where .Site.RegularPages "Section" "in" .Site.Params.mainSections }}
+ {{ $notHidden := where .Site.RegularPages "Params.hidden" "!=" true }}
+ {{ $filtered := ($pages | intersect $notHidden) }}
+ {{ $pag := .Paginate ($filtered) }}
+
+ {{ if .Paginator.HasPrev }}
+ <!-- Paginated. Append page number to title -->
+ {{ $title = printf "%s - %s" .Paginator $siteTitle }}
+ {{ else }}
+ {{ $title = $siteTitle}}
+ {{ end }}
+{{- else if eq .Kind "term" -}}
+ <!-- Taxonomy page -->
+
+ <!-- Build paginator -->
+ {{ $notHidden := where .Pages "Params.hidden" "!=" true }}
+ {{ $pag := .Paginate ($notHidden) }}
+
+ <!-- {TAXONOMY_TYPE}: {TAXONOMY_TERM} -->
+ {{ $title = slice (title .Data.Singular) ": " $title }}
+
+ {{ if .Paginator.HasPrev }}
+ <!-- Add page number-->
+ {{ $title = $title | append " - " .Paginator }}
+ {{ end }}
+
+ {{ $title = $title | append " - " $siteTitle }}
+ {{ $title = delimit $title "" }}
+{{- end -}}
+
+{{ return $title }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/footer/components/custom-font.html b/themes/hugo-theme-stack/layouts/partials/footer/components/custom-font.html
new file mode 100644
index 0000000..8e2ff37
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/footer/components/custom-font.html
@@ -0,0 +1,11 @@
+<script>
+ (function () {
+ const customFont = document.createElement('link');
+ customFont.href = "https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&display=swap";
+
+ customFont.type = "text/css";
+ customFont.rel = "stylesheet";
+
+ document.head.appendChild(customFont);
+ }());
+</script> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/footer/components/script.html b/themes/hugo-theme-stack/layouts/partials/footer/components/script.html
new file mode 100644
index 0000000..3dc96cb
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/footer/components/script.html
@@ -0,0 +1,12 @@
+{{- partial "helper/external" (dict "Context" . "Namespace" "Vibrant") -}}
+
+{{- $opts := dict "minify" hugo.IsProduction -}}
+{{- $script := resources.Get "ts/main.ts" | js.Build $opts | fingerprint -}}
+
+<script type="text/javascript" src="{{ $script.RelPermalink }}" defer></script>
+
+{{- with resources.Get "ts/custom.ts" -}}
+ {{/* Place your custom script in HUGO_SITE_FOLDER/assets/ts/custom.ts */}}
+ {{- $customScript := . | js.Build $opts | fingerprint -}}
+ <script type="text/javascript" src="{{ $customScript.RelPermalink }}" defer></script>
+{{- end -}} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/footer/custom.html b/themes/hugo-theme-stack/layouts/partials/footer/custom.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/footer/custom.html
diff --git a/themes/hugo-theme-stack/layouts/partials/footer/footer.html b/themes/hugo-theme-stack/layouts/partials/footer/footer.html
new file mode 100644
index 0000000..9c28779
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/footer/footer.html
@@ -0,0 +1,23 @@
+{{- $ThemeVersion := "3.29.0" -}}
+<footer class="site-footer">
+ <section class="copyright">
+ &copy;
+ {{ if and (.Site.Params.footer.since) (ne .Site.Params.footer.since (int (now.Format "2006"))) }}
+ {{ .Site.Params.footer.since }} -
+ {{ end }}
+ {{ now.Format "2006" }} {{ default .Site.Title .Site.Copyright }}
+ </section>
+
+ <section class="powerby">
+ {{ with .Site.Params.footer.customText }}
+ {{ . | safeHTML }} <br/>
+ {{ end }}
+
+ {{- $Generator := `<a href="https://gohugo.io/" target="_blank" rel="noopener">Hugo</a>` -}}
+ {{- $Theme := printf `<b><a href="https://github.com/CaiJimmy/hugo-theme-stack" target="_blank" rel="noopener" data-version="%s">Stack</a></b>` $ThemeVersion -}}
+ {{- $DesignedBy := `<a href="https://jimmycai.com" target="_blank" rel="noopener">Jimmy</a>` -}}
+
+ {{ T "footer.builtWith" (dict "Generator" $Generator) | safeHTML }} <br />
+ {{ T "footer.designedBy" (dict "Theme" $Theme "DesignedBy" $DesignedBy) | safeHTML }}
+ </section>
+</footer>
diff --git a/themes/hugo-theme-stack/layouts/partials/footer/include.html b/themes/hugo-theme-stack/layouts/partials/footer/include.html
new file mode 100644
index 0000000..4b50a88
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/footer/include.html
@@ -0,0 +1,3 @@
+{{ partialCached "footer/components/script.html" . }}
+{{ partialCached "footer/components/custom-font.html" . }}
+{{ partial "footer/custom.html" . }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/head/colorScheme.html b/themes/hugo-theme-stack/layouts/partials/head/colorScheme.html
new file mode 100644
index 0000000..42f4dd8
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/head/colorScheme.html
@@ -0,0 +1,39 @@
+{{- $defaultColorScheme := default "auto" .Site.Params.colorScheme.default -}}
+{{- if not (default false .Site.Params.colorScheme.toggle) -}}
+ {{/* If toggle is disabled, force default scheme */}}
+ <script>
+ (function() {
+ const colorSchemeKey = 'StackColorScheme';
+ localStorage.setItem(colorSchemeKey, "{{ $defaultColorScheme }}");
+ })();
+ </script>
+{{- else -}}
+ {{/* Otherwise set to default scheme only if no preference is set by user */}}
+ <script>
+ (function() {
+ const colorSchemeKey = 'StackColorScheme';
+ if(!localStorage.getItem(colorSchemeKey)){
+ localStorage.setItem(colorSchemeKey, "{{ $defaultColorScheme }}");
+ }
+ })();
+ </script>
+{{- end -}}
+
+<script>
+ (function() {
+ const colorSchemeKey = 'StackColorScheme';
+ const colorSchemeItem = localStorage.getItem(colorSchemeKey);
+ const supportDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches === true;
+
+ if (colorSchemeItem == 'dark' || colorSchemeItem === 'auto' && supportDarkMode) {
+ /**
+ * Enable dark mode if:
+ * 1. If dark mode is set already (in local storage)
+ * 2. Auto mode & prefere color scheme is dark
+ */
+ document.documentElement.dataset.scheme = 'dark';
+ } else {
+ document.documentElement.dataset.scheme = 'light';
+ }
+ })();
+</script>
diff --git a/themes/hugo-theme-stack/layouts/partials/head/custom.html b/themes/hugo-theme-stack/layouts/partials/head/custom.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/head/custom.html
diff --git a/themes/hugo-theme-stack/layouts/partials/head/head.html b/themes/hugo-theme-stack/layouts/partials/head/head.html
new file mode 100644
index 0000000..a7991c1
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/head/head.html
@@ -0,0 +1,26 @@
+<meta charset='utf-8'>
+<meta name='viewport' content='width=device-width, initial-scale=1'>
+
+{{- $description := partialCached "data/description" . .RelPermalink -}}
+<meta name='description' {{ printf "content=%q" $description | safeHTMLAttr }}>
+{{ with .Params.Keywords }}<meta name="keywords" content="{{ delimit . ", " }}">{{ end }}
+
+{{- $title := partial "data/title" . -}}
+<title>{{ $title }}</title>
+
+<link rel='canonical' href='{{ .Permalink }}'>
+
+{{- partial "head/style.html" . -}}
+{{- partial "head/script.html" . -}}
+{{- partial "head/opengraph/include.html" . -}}
+
+{{- range .AlternativeOutputFormats -}}
+ <link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
+{{- end -}}
+
+{{ with .Site.Params.favicon }}
+ <link rel="shortcut icon" href="{{ . | relURL }}" />
+{{ end }}
+
+{{- template "_internal/google_analytics.html" . -}}
+{{- partial "head/custom.html" . -}}
diff --git a/themes/hugo-theme-stack/layouts/partials/head/opengraph/include.html b/themes/hugo-theme-stack/layouts/partials/head/opengraph/include.html
new file mode 100644
index 0000000..3a43f48
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/head/opengraph/include.html
@@ -0,0 +1,2 @@
+{{ partial "head/opengraph/provider/base" . }}
+{{ partial "head/opengraph/provider/twitter" . }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/head/opengraph/provider/base.html b/themes/hugo-theme-stack/layouts/partials/head/opengraph/provider/base.html
new file mode 100644
index 0000000..055745d
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/head/opengraph/provider/base.html
@@ -0,0 +1,43 @@
+{{- $title := partialCached "data/title" . .RelPermalink -}}
+{{- $description := partialCached "data/description" . .RelPermalink -}}
+
+<meta property='og:title' {{ printf "content=%q" $title | safeHTMLAttr }}>
+<meta property='og:description' {{ printf "content=%q" $description | safeHTMLAttr }}>
+<meta property='og:url' content='{{ .Permalink }}'>
+<meta property='og:site_name' content='{{ .Site.Title }}'>
+<meta property='og:type' content='
+ {{- if .IsPage -}}
+ article
+ {{- else -}}
+ website
+ {{- end -}}
+'>
+
+{{- with .Params.locale -}}
+ <meta property='og:locale' content='{{ . }}'>
+{{- end -}}
+
+{{- if .IsPage -}}
+ <meta property='article:section' content='{{ .Section | title }}' />
+ {{- range .Params.tags -}}
+ <meta property='article:tag' content='{{ . }}' />
+ {{- end -}}
+{{- end -}}
+
+{{- if .IsPage -}}
+ {{- if not .Date.IsZero -}}
+ <meta property='article:published_time' content='{{ .Date.Format "2006-01-02T15:04:05-07:00" | safeHTML }}'/>
+ {{- end -}}
+ {{- if not .Lastmod.IsZero -}}
+ <meta property='article:modified_time' content='{{ .Lastmod.Format "2006-01-02T15:04:05-07:00" | safeHTML }}'/>
+ {{- end -}}
+{{- else -}}
+ {{- if not .Site.Lastmod.IsZero -}}
+ <meta property='og:updated_time' content='{{ .Site.Lastmod.Format " 2006-01-02T15:04:05-07:00 " | safeHTML }}'/>
+ {{- end -}}
+{{- end -}}
+
+{{ $image := partialCached "helper/image" (dict "Context" . "Type" "opengraph") .RelPermalink "opengraph" }}
+{{- if $image.exists -}}
+ <meta property='og:image' content='{{ absURL $image.permalink }}' />
+{{- end -}} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/head/opengraph/provider/twitter.html b/themes/hugo-theme-stack/layouts/partials/head/opengraph/provider/twitter.html
new file mode 100644
index 0000000..c39eba3
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/head/opengraph/provider/twitter.html
@@ -0,0 +1,16 @@
+{{- with .Site.Params.opengraph.twitter.site -}}
+ <meta name="twitter:site" content="@{{ . }}">
+ <meta name="twitter:creator" content="@{{ . }}">
+{{- end -}}
+
+{{- $title := partialCached "data/title" . .RelPermalink -}}
+{{- $description := partialCached "data/description" . .RelPermalink -}}
+
+<meta name="twitter:title" {{ printf "content=%q" $title | safeHTMLAttr }}>
+<meta name="twitter:description" {{ printf "content=%q" $description | safeHTMLAttr }}>
+
+{{- $image := partialCached "helper/image" (dict "Context" . "Type" "opengraph") .RelPermalink "opengraph" -}}
+{{- if $image.exists -}}
+ <meta name="twitter:card" content="{{ default `summary_large_image` .Site.Params.opengraph.twitter.card }}">
+ <meta name="twitter:image" content='{{ absURL $image.permalink }}' />
+{{- end -}} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/head/script.html b/themes/hugo-theme-stack/layouts/partials/head/script.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/head/script.html
diff --git a/themes/hugo-theme-stack/layouts/partials/head/style.html b/themes/hugo-theme-stack/layouts/partials/head/style.html
new file mode 100644
index 0000000..30ca26e
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/head/style.html
@@ -0,0 +1,3 @@
+{{ $sass := resources.Get "scss/style.scss" }}
+{{ $style := $sass | toCSS | minify | resources.Fingerprint "sha256" }}
+<link rel="stylesheet" href="{{ $style.RelPermalink }}"> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/helper/external.html b/themes/hugo-theme-stack/layouts/partials/helper/external.html
new file mode 100644
index 0000000..88d9525
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/helper/external.html
@@ -0,0 +1,29 @@
+{{- $List := index .Context.Site.Data.external .Namespace -}}
+{{- with $List -}}
+ {{- range . -}}
+ {{- if eq .type "script" -}}
+ <script
+ src="{{ .src }}"
+ {{- with .integrity -}}
+ integrity="{{ . }}"
+ {{- end -}}
+ crossorigin="anonymous"
+ {{ if .defer }}defer{{ end }}
+ >
+ </script>
+ {{- else if eq .type "style" -}}
+ <link
+ rel="stylesheet"
+ href="{{ .src }}"
+ {{- with .integrity -}}
+ integrity="{{ . }}"
+ {{- end -}}
+ crossorigin="anonymous"
+ >
+ {{- else -}}
+ {{- errorf "Error: unknown external resource type: %s" .type -}}
+ {{- end -}}
+ {{- end -}}
+{{- else -}}
+ {{- errorf "Error: external resource '%s' is not found" .Namespace -}}
+{{- end -}} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/helper/icon.html b/themes/hugo-theme-stack/layouts/partials/helper/icon.html
new file mode 100644
index 0000000..72162e8
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/helper/icon.html
@@ -0,0 +1,6 @@
+{{- $iconFile := resources.GetMatch (printf "icons/%s.svg" .) -}}
+{{- if $iconFile -}}
+ {{- $iconFile.Content | safeHTML -}}
+{{- else -}}
+ {{- errorf "Error: icon '%s.svg' is not found under 'assets/icons' folder" . -}}
+{{- end -}} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/helper/image.html b/themes/hugo-theme-stack/layouts/partials/helper/image.html
new file mode 100644
index 0000000..11fc3b6
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/helper/image.html
@@ -0,0 +1,61 @@
+{{ $result := dict "exists" false "permalink" nil "resource" nil "isDefault" false }}
+{{ $imageField := default "image" .Context.Site.Params.featuredImageField }}
+{{ $imageValue := index .Context.Params $imageField }}
+
+{{ if $imageValue }}
+ <!-- If page has `image` field set -->
+ {{ $result = merge $result (dict "exists" true) }}
+ {{ $url := urls.Parse $imageValue }}
+
+ {{ if or (eq $url.Scheme "http") (eq $url.Scheme "https") }}
+ <!-- Is an external image -->
+ {{ $result = merge $result (dict "permalink" $imageValue) }}
+ {{ else }}
+ {{ $pageResourceImage := .Context.Resources.GetMatch (printf "%s" ($imageValue | safeURL)) }}
+
+ {{ if $pageResourceImage }}
+ <!-- If image is found under page bundle -->
+ {{ $result = merge $result (dict "permalink" $pageResourceImage.RelPermalink) }}
+
+ <!-- Disable SVG image processing, not supported by Hugo -->
+ {{ if ne (path.Ext $imageValue) ".svg" }}
+ {{ $result = merge $result (dict "resource" $pageResourceImage) }}
+ {{ end }}
+ {{ else }}
+ <!-- Can not find the image under page bundle. Could be a relative linked image -->
+ {{ $result = merge $result (dict "permalink" (relURL $imageValue)) }}
+ {{ end }}
+
+ {{ end }}
+
+{{ else if and (ne .Type nil) (index .Context.Site.Params.defaultImage .Type) }}
+ <!-- Type arg is set, check for defaultImage setting -->
+ {{ $defaultImageSetting := index .Context.Site.Params.defaultImage .Type }}
+
+ {{ if $defaultImageSetting.enabled }}
+ {{ $result = merge $result (dict "isDefault" true) }}
+ {{ $result = merge $result (dict "exists" true) }}
+
+ {{ if $defaultImageSetting.local }}
+ {{ $siteResourceImage := resources.GetMatch (printf "%s" ($defaultImageSetting.src | safeURL)) }}
+
+ {{ if $siteResourceImage }}
+ <!-- Try search image under site's assets folder -->
+ {{ $result = merge $result (dict "permalink" $siteResourceImage.RelPermalink) }}
+ {{ $result = merge $result (dict "resource" $siteResourceImage) }}
+ {{ else }}
+ <!-- Can not find the image -->
+ {{ errorf "Failed loading image: %q" $defaultImageSetting.src }}
+ {{ $result = merge $result (dict "exists" false) }}
+ {{ end }}
+
+ {{ else }}
+ <!-- External image -->
+ {{ $result = merge $result (dict "permalink" (relURL $defaultImageSetting.src)) }}
+ {{ end }}
+
+ {{ end }}
+
+{{ end }}
+
+{{ return $result }}
diff --git a/themes/hugo-theme-stack/layouts/partials/pagination.html b/themes/hugo-theme-stack/layouts/partials/pagination.html
new file mode 100644
index 0000000..7756050
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/pagination.html
@@ -0,0 +1,26 @@
+{{ if gt .Paginator.TotalPages 1 }}
+ <nav class='pagination'>
+ {{ $.Scratch.Set "hasPrevDots" false }}
+ {{ $.Scratch.Set "hasNextDots" false }}
+
+ {{ range .Paginator.Pagers }}
+ {{ if eq . $.Paginator }}
+ <span class='page-link current'>
+ {{- .PageNumber -}}
+ </span>
+ {{ else if or (or (eq . $.Paginator.First) (eq . $.Paginator.Prev)) (or (eq . $.Paginator.Next) (eq . $.Paginator.Last )) }}
+ <a class='page-link' href='{{ .URL }}'>
+ {{- .PageNumber -}}
+ </a>
+ {{ else }}
+ {{ if and (not ($.Scratch.Get "hasPrevDots")) (lt .PageNumber $.Paginator.PageNumber) }}
+ {{ $.Scratch.Set "hasPrevDots" true }}
+ <span class='page-link dots'>&hellip;</span>
+ {{ else if and (not ($.Scratch.Get "hasNextDots")) (gt .PageNumber $.Paginator.PageNumber) }}
+ {{ $.Scratch.Set "hasNextDots" true }}
+ <span class='page-link dots'>&hellip;</span>
+ {{ end }}
+ {{ end }}
+ {{ end }}
+ </nav>
+{{ end }}
diff --git a/themes/hugo-theme-stack/layouts/partials/sidebar/left.html b/themes/hugo-theme-stack/layouts/partials/sidebar/left.html
new file mode 100644
index 0000000..21e7d3e
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/sidebar/left.html
@@ -0,0 +1,103 @@
+<aside class="sidebar left-sidebar sticky {{ if .Site.Params.sidebar.compact }}compact{{ end }}">
+ <button class="hamburger hamburger--spin" type="button" id="toggle-menu" aria-label="{{ T `toggleMenu` }}">
+ <span class="hamburger-box">
+ <span class="hamburger-inner"></span>
+ </span>
+ </button>
+
+ <header>
+ {{ with .Site.Params.sidebar.avatar }}
+ {{ if (default true .enabled) }}
+ <figure class="site-avatar">
+ <a href="{{ .Site.BaseURL | relLangURL }}">
+ {{ if not .local }}
+ <img src="{{ .src }}" width="300" height="300" class="site-logo" loading="lazy" alt="Avatar">
+ {{ else }}
+ {{ $avatar := resources.Get (.src) }}
+
+ {{ if $avatar }}
+ {{ $avatarResized := $avatar.Resize "300x" }}
+ <img src="{{ $avatarResized.RelPermalink }}" width="{{ $avatarResized.Width }}"
+ height="{{ $avatarResized.Height }}" class="site-logo" loading="lazy" alt="Avatar">
+ {{ else }}
+ {{ errorf "Failed loading avatar from %q" . }}
+ {{ end }}
+ {{ end }}
+ </a>
+ {{ with $.Site.Params.sidebar.emoji }}
+ <span class="emoji">{{ . }}</span>
+ {{ end }}
+ </figure>
+ {{ end }}
+ {{ end }}
+
+ <div class="site-meta">
+ <h1 class="site-name"><a href="{{ .Site.BaseURL | relLangURL }}">{{ .Site.Title }}</a></h1>
+ <h2 class="site-description">{{ .Site.Params.sidebar.subtitle }}</h2>
+ </div>
+ </header>
+
+ {{- with .Site.Menus.social -}}
+ <ol class="menu-social">
+ {{ range . }}
+ <li>
+ <a
+ href='{{ .URL }}'
+ {{ if eq (default true .Params.newTab) true }}target="_blank"{{ end }}
+ {{ with .Name }}title="{{ . }}"{{ end }}
+ rel="me"
+ >
+ {{ $icon := default "link" .Params.Icon }}
+ {{ with $icon }}
+ {{ partial "helper/icon" . }}
+ {{ end }}
+ </a>
+ </li>
+ {{ end }}
+ </ol>
+ {{- end -}}
+
+ <ol class="menu" id="main-menu">
+ {{ $currentPage := . }}
+ {{ range .Site.Menus.main }}
+ {{ $active := or (eq $currentPage.Title .Name) (or ($currentPage.HasMenuCurrent "main" .) ($currentPage.IsMenuCurrent "main" .)) }}
+ <li {{ if $active }} class='current' {{ end }}>
+ <a href='{{ .URL }}' {{ if eq .Params.newTab true }}target="_blank"{{ end }}>
+ {{ $icon := default .Pre .Params.Icon }}
+ {{ if .Pre }}
+ {{ warnf "Menu item [%s] is using [pre] field to set icon, please use [params.icon] instead.\nMore information: https://stack.jimmycai.com/config/menu" .URL }}
+ {{ end }}
+ {{ with $icon }}
+ {{ partial "helper/icon" . }}
+ {{ end }}
+ <span>{{- .Name -}}</span>
+ </a>
+ </li>
+ {{ end }}
+ <li class="menu-bottom-section">
+ <ol class="menu">
+ {{- $currentLanguageCode := .Language.Lang -}}
+ {{ if ( compare.Gt .Site.Home.AllTranslations.Len 1 ) }}
+ {{ with .Site.Home.AllTranslations }}
+ <li id="i18n-switch">
+ {{ partial "helper/icon" "language" }}
+ <select name="language" title="language" onchange="window.location.href = this.selectedOptions[0].value">
+ {{ range . }}
+ <option value="{{ .Permalink }}" {{ if eq .Language.Lang $currentLanguageCode }}selected{{ end }}>{{ .Language.LanguageName }}</option>
+ {{ end }}
+ </select>
+ </li>
+ {{ end }}
+ {{ end }}
+
+ {{ if (default false .Site.Params.colorScheme.toggle) }}
+ <li id="dark-mode-toggle">
+ {{ partial "helper/icon" "toggle-left" }}
+ {{ partial "helper/icon" "toggle-right" }}
+ <span>{{ T "darkMode" }}</span>
+ </li>
+ {{ end }}
+ </ol>
+ </li>
+ </ol>
+</aside>
diff --git a/themes/hugo-theme-stack/layouts/partials/sidebar/right.html b/themes/hugo-theme-stack/layouts/partials/sidebar/right.html
new file mode 100644
index 0000000..6333f10
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/sidebar/right.html
@@ -0,0 +1,16 @@
+{{- $scope := default "homepage" .Scope -}}
+{{- $context := .Context -}}
+{{- with (index .Context.Site.Params.widgets $scope) -}}
+ <aside class="sidebar right-sidebar sticky">
+ {{ range $widget := . }}
+ {{ if templates.Exists (printf "partials/widget/%s.html" .type) }}
+ <!-- Ensure that the `params` is not nil -->
+ {{- $params := default dict .params -}}
+
+ {{ partial (printf "widget/%s" .type) (dict "Context" $context "Params" $params) }}
+ {{ else }}
+ {{ warnf "Widget %s not found" .type }}
+ {{ end }}
+ {{ end }}
+ </aside>
+{{ end }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/widget/archives.html b/themes/hugo-theme-stack/layouts/partials/widget/archives.html
new file mode 100644
index 0000000..1f2abc5
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/widget/archives.html
@@ -0,0 +1,35 @@
+{{- $query := first 1 (where .Context.Site.Pages "Layout" "==" "archives") -}}
+{{- $context := .Context -}}
+{{- $limit := default 5 .Params.limit -}}
+{{- if $query -}}
+ {{- $archivesPage := index $query 0 -}}
+ <section class="widget archives">
+ <div class="widget-icon">
+ {{ partial "helper/icon" "infinity" }}
+ </div>
+ <h2 class="widget-title section-title">{{ T "widget.archives.title" }}</h2>
+
+ {{ $pages := where $context.Site.RegularPages "Type" "in" $context.Site.Params.mainSections }}
+ {{ $notHidden := where $context.Site.RegularPages "Params.hidden" "!=" true }}
+ {{ $filtered := ($pages | intersect $notHidden) }}
+ {{ $archives := $filtered.GroupByDate "2006" }}
+
+ <div class="widget-archive--list">
+ {{ range $index, $item := first (add $limit 1) ($archives) }}
+ {{- $id := lower (replace $item.Key " " "-") -}}
+ <div class="archives-year">
+ <a href="{{ $archivesPage.RelPermalink }}#{{ $id }}">
+ {{ if eq $index $limit }}
+ <span class="year">{{ T "widget.archives.more" }}</span>
+ {{ else }}
+ <span class="year">{{ .Key }}</span>
+ <span class="count">{{ len $item.Pages }}</span>
+ {{ end }}
+ </a>
+ </div>
+ {{ end }}
+ </div>
+ </section>
+{{- else -}}
+ {{- warnf "Archives page not found. Create a page with layout: archives." -}}
+{{- end -}} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/widget/categories.html b/themes/hugo-theme-stack/layouts/partials/widget/categories.html
new file mode 100644
index 0000000..10c8a35
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/widget/categories.html
@@ -0,0 +1,16 @@
+{{- $context := .Context -}}
+{{- $limit := default 10 .Params.limit -}}
+<section class="widget tagCloud">
+ <div class="widget-icon">
+ {{ partial "helper/icon" "categories" }}
+ </div>
+ <h2 class="widget-title section-title">{{ T "widget.categoriesCloud.title" }}</h2>
+
+ <div class="tagCloud-tags">
+ {{ range first $limit $context.Site.Taxonomies.categories.ByCount }}
+ <a href="{{ .Page.RelPermalink }}" class="font_size_{{ .Count }}">
+ {{ .Page.Title }}
+ </a>
+ {{ end }}
+ </div>
+</section>
diff --git a/themes/hugo-theme-stack/layouts/partials/widget/search.html b/themes/hugo-theme-stack/layouts/partials/widget/search.html
new file mode 100644
index 0000000..7b0fc73
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/widget/search.html
@@ -0,0 +1,16 @@
+{{- $query := first 1 (where .Context.Site.Pages "Layout" "==" "search") -}}
+{{- if $query -}}
+ {{- $searchPage := index $query 0 -}}
+ <form action="{{ $searchPage.RelPermalink }}" class="search-form widget" {{ with .OutputFormats.Get "json" -}}data-json="{{ .Permalink }}" {{- end }}>
+ <p>
+ <label>{{ T "search.title" }}</label>
+ <input name="keyword" required placeholder="{{ T `search.placeholder` }}" />
+
+ <button title="{{ T `search.title` }}">
+ {{ partial "helper/icon" "search" }}
+ </button>
+ </p>
+ </form>
+{{- else -}}
+ {{- warnf "Search page not found. Create a page with layout: search." -}}
+{{- end -}} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/widget/tag-cloud.html b/themes/hugo-theme-stack/layouts/partials/widget/tag-cloud.html
new file mode 100644
index 0000000..e64e5e2
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/widget/tag-cloud.html
@@ -0,0 +1,16 @@
+{{- $context := .Context -}}
+{{- $limit := default 10 .Params.limit -}}
+<section class="widget tagCloud">
+ <div class="widget-icon">
+ {{ partial "helper/icon" "tag" }}
+ </div>
+ <h2 class="widget-title section-title">{{ T "widget.tagCloud.title" }}</h2>
+
+ <div class="tagCloud-tags">
+ {{ range first $limit $context.Site.Taxonomies.tags.ByCount }}
+ <a href="{{ .Page.RelPermalink }}" class="font_size_{{ .Count }}">
+ {{ .Page.Title }}
+ </a>
+ {{ end }}
+ </div>
+</section> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/partials/widget/toc.html b/themes/hugo-theme-stack/layouts/partials/widget/toc.html
new file mode 100644
index 0000000..e311de3
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/partials/widget/toc.html
@@ -0,0 +1,12 @@
+{{ if (.Context.Scratch.Get "TOCEnabled") }}
+ <section class="widget archives">
+ <div class="widget-icon">
+ {{ partial "helper/icon" "hash" }}
+ </div>
+ <h2 class="widget-title section-title">{{ T "article.tableOfContents" }}</h2>
+
+ <div class="widget--toc">
+ {{ .Context.TableOfContents }}
+ </div>
+ </section>
+{{ end }} \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/shortcodes/bilibili.html b/themes/hugo-theme-stack/layouts/shortcodes/bilibili.html
new file mode 100644
index 0000000..cb72e43
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/shortcodes/bilibili.html
@@ -0,0 +1,23 @@
+{{ $vid := (.Get 0) }}
+{{ $videopage := default 1 (.Get 1) }}
+{{ $basicQuery := querify "page" $videopage "high_quality" 1 "as_wide" 1 }}
+{{ $videoQuery := "" }}
+
+{{ if strings.HasPrefix (lower $vid) "av" }}
+ {{ $videoQuery = querify "aid" (strings.TrimPrefix "av" (lower $vid)) }}
+{{ else if strings.HasPrefix (lower $vid) "bv" }}
+ {{ $videoQuery = querify "bvid" $vid }}
+{{ else }}
+ <p>Bilibili 视频av号或BV号错误!请检查视频av号或BV号是否正确</p>
+ <p>当前视频av或BV号:{{ $vid }},视频分P:{{ $videopage }}</p>
+{{ end }}
+
+<div class="video-wrapper">
+ <iframe src="https://player.bilibili.com/player.html?{{ $basicQuery | safeURL }}&{{ $videoQuery | safeURL }}"
+ scrolling="no"
+ frameborder="no"
+ framespacing="0"
+ allowfullscreen="true"
+ >
+ </iframe>
+</div>
diff --git a/themes/hugo-theme-stack/layouts/shortcodes/gitlab.html b/themes/hugo-theme-stack/layouts/shortcodes/gitlab.html
new file mode 100644
index 0000000..b5a16cf
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/shortcodes/gitlab.html
@@ -0,0 +1,4 @@
+<script
+ type="application/javascript"
+ src="https://gitlab.com/-/snippets/{{ index .Params 0 }}.js"
+></script> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/shortcodes/quote.html b/themes/hugo-theme-stack/layouts/shortcodes/quote.html
new file mode 100644
index 0000000..09bb07c
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/shortcodes/quote.html
@@ -0,0 +1,15 @@
+<blockquote>
+ <p>{{ .Inner | markdownify }}</p>
+ {{- if or (.Get "author") (.Get "source") -}}
+ <span class="cite"><span>― </span>
+ {{- if .Get "author" -}}
+ <span>
+ {{- .Get "author" -}}{{- if .Get "source" -}}, {{ end -}}
+ </span>
+ {{- end -}}
+ {{- with .Get "url" -}}<a href="{{ . }}">{{- end -}}
+ <cite>{{ .Get "source" }}</cite>
+ {{- if .Get "url" -}}</a>{{- end -}}
+ </span>
+ {{- end -}}
+</blockquote> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/shortcodes/tencent.html b/themes/hugo-theme-stack/layouts/shortcodes/tencent.html
new file mode 100644
index 0000000..463dec5
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/shortcodes/tencent.html
@@ -0,0 +1,10 @@
+{{ $vid := .Get 0 }}
+<div class="video-wrapper">
+ <iframe src="https://v.qq.com/txp/iframe/player.html?vid={{ $vid }}&auto=0"
+ scrolling="no"
+ frameborder="no"
+ framespacing="0"
+ allowfullscreen="true"
+ >
+ </iframe>
+</div> \ No newline at end of file
diff --git a/themes/hugo-theme-stack/layouts/shortcodes/video.html b/themes/hugo-theme-stack/layouts/shortcodes/video.html
new file mode 100644
index 0000000..5324754
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/shortcodes/video.html
@@ -0,0 +1,14 @@
+{{- $src := .Get "src" | default (.Get 0) -}}
+<div class="video-wrapper">
+ <video
+ controls
+ src="{{- $src -}}"
+ {{ with .Get "poster" }}poster="{{- . -}}"{{ end }}
+ {{ with .Get "autoplay" }}autoplay{{ end }}
+ >
+ <p>
+ Your browser doesn't support HTML5 video. Here is a
+ <a href="{{- $src -}}">link to the video</a> instead.
+ </p>
+ </video>
+</div>
diff --git a/themes/hugo-theme-stack/layouts/shortcodes/youtube.html b/themes/hugo-theme-stack/layouts/shortcodes/youtube.html
new file mode 100644
index 0000000..2f85931
--- /dev/null
+++ b/themes/hugo-theme-stack/layouts/shortcodes/youtube.html
@@ -0,0 +1,13 @@
+{{- $pc := .Page.Site.Config.Privacy.YouTube -}}
+{{- if not $pc.Disable -}}
+{{- $ytHost := cond $pc.PrivacyEnhanced "www.youtube-nocookie.com" "www.youtube.com" -}}
+{{- $id := .Get "id" | default (.Get 0) -}}
+<div class="video-wrapper">
+ <iframe loading="lazy"
+ src="https://{{ $ytHost }}/embed/{{ $id }}{{ with .Get "autoplay" }}{{ if eq . "true" }}?autoplay=1{{ end }}{{ end }}"
+ allowfullscreen
+ title="YouTube Video"
+ >
+ </iframe>
+</div>
+{{ end -}} \ No newline at end of file