Hugo Stack 主题美化
全局配置
页面基本配色
- 在
/assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| :root { --main-top-padding: 30px; --card-border-radius: 25px; --tag-border-radius: 8px; --section-separation: 40px; --article-font-size: 1.8rem; --code-background-color: #f8f8f8; --code-text-color: #e96900; &[data-scheme="dark"] { --code-background-color: #ff6d1b17; --code-text-color: #e96900; } }
|
全局布局调整
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
.main-container { min-height: 100vh; align-items: flex-start; padding: 0 15px; gap: var(--section-separation); padding-top: var(--main-top-padding);
@include respond(md) { padding: 0 37px; } }
.container { margin-left: auto; margin-right: auto;
.left-sidebar { order: -3; max-width: var(--left-sidebar-max-width); }
.right-sidebar { order: -1; max-width: var(--right-sidebar-max-width);
@include respond(lg) { display: flex; } }
&.extended { @include respond(md) { max-width: 1024px; --left-sidebar-max-width: 25%; --right-sidebar-max-width: 22% !important; }
@include respond(lg) { max-width: 1280px; --left-sidebar-max-width: 20%; --right-sidebar-max-width: 30%; }
@include respond(xl) { max-width: 1453px; --left-sidebar-max-width: 15%; --right-sidebar-max-width: 25%; } }
&.compact { @include respond(md) { --left-sidebar-max-width: 25%; max-width: 768px; }
@include respond(lg) { max-width: 1024px; --left-sidebar-max-width: 20%; }
@include respond(xl) { max-width: 1280px; } } }
.article-list--compact article .article-image img { width: var(--image-size); height: var(--image-size); object-fit: cover; border-radius: 17%; }
.menu { padding-left: 0; list-style: none; flex-direction: column; overflow-x: hidden; flex-grow: 1; font-size: 1.6rem; background-color: var(--card-background);
box-shadow: none; display: none; margin: 0; border-radius: 10px; padding: 30px 30px;
@include respond(xl) { padding: 15px 0; }
&, .menu-bottom-section { gap: 30px;
@include respond(xl) { gap: 25px; } }
&.show { display: flex; }
@include respond(md) { align-items: flex-end; display: flex; background-color: transparent; padding: 0; box-shadow: none; margin: 0; }
li { position: relative; vertical-align: middle; padding: 0;
@include respond(md) { width: 100%; }
svg { stroke-width: 1.33;
width: 20px; height: 20px; }
a { height: 100%; display: inline-flex; align-items: center; color: var(--body-text-color); gap: var(--menu-icon-separation); }
span { flex: 1; }
&.current { a { color: var(--accent-color); font-weight: bold; } } } }
.menu::-webkit-scrollbar { display: none; }
.sidebar header .site-name { margin: 8px; font-size: 2rem; }
|
文章内容美化
文章内容基本美化
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
.article-content { blockquote { border-left: 6px solid #358b9a1f !important; background: #3a97431f; } }
.highlight { max-width: 102% !important; background-color: var(--pre-background-color); padding: var(--card-padding); position: relative; border-radius: 20px; margin-left: -7px !important; margin-right: -12px; box-shadow: var(--shadow-l1) !important;
&:hover { .copyCodeButton { opacity: 1; } }
[dir="rtl"] & { direction: ltr; }
pre { margin: initial; padding: 0; margin: 0; width: auto; } }
[data-scheme="light"] .article-content .highlight { background-color: #fff9f3; }
[data-scheme="light"] .chroma { color: #ff6f00; background-color: #fff9f3cc; }
.article-page .main-article .article-content { img { max-width: 96% !important; height: auto !important; border-radius: 8px; } }
::selection { color: #fff; background: #001572; }
a { text-decoration: none; color: var(--accent-color);
&:hover { color: var(--accent-color-darker); }
.link { font-weight: 800; padding: 0 2px; text-decoration: none; cursor: pointer;
color: #000000;
&:hover { text-decoration: underline; } }
@media (prefers-color-scheme: dark) { .link { color: #FFFFFF; } } }
.article-list article .article-image img { width: 100%; height: 150px; object-fit: cover; @include respond(md) { height: 200px; }
@include respond(xl) { height: 305px; } }
a { word-break: break-all; }
code { word-break: break-all; }
|
MD 引用块样式
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| .article-content { blockquote { border-left: 6px solid #004b28 !important; background: #366e33; } } ```
### 使图床链接的图片居中 * 目前 Stack 默认只支持本地引用的图片居中,而在使用 url 图片链接时没有居中格式。在 `./assets/scss/partials/layout/article.scss` Line 256 处(同级任意位置)增加以下代码:
```scss
p > img { display: block; margin: 0 auto; max-width: 100%; height: auto; }
|
统计站点文章数量和字数
- 在
./layout/partials/footer/footer.html
的 <section class="powerby">
里边,加入代码:
1 2 3 4 5 6 7
| {{ $articleCount := len .Site.RegularPages }} {{ $totalWordCount := 0 }} {{ range .Site.Pages }} {{ $totalWordCount = add $totalWordCount .WordCount }} {{ end }}
<p>发布了 {{ $articleCount }} 篇文章 | 共 {{$totalWordCount}} 字</p>
|
首页文章样式
- 在
./assets/scss/custom.scss
加入代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| $image-scale: 1.2; .article-list article .article-image img { width: 100%; height: 150px; object-fit: cover; @include respond(sm) { height: 305px; }
@include respond(md) { height: 305px; } @include respond(xl) { height: 325px; } }
.article-list article { --card-border-radius: 24px; }
.article-category a, .article-tags a { border-radius: 11px; }
.article-list article .article-image { position: relative; overflow: hidden; }
.article-list article .article-image img:hover { transform: scale($image-scale); }
.article-list article .article-image img { transition: transform 0.85s ease-in-out; }
|
文章内部图片样式
- 在
./assets/scss/custom.scss
加入代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| .article-list--compact article .article-image img { border-radius: 17%; }
.article-list--compact article > a { transition: .6s ease; }
.article-list--compact article > a:hover { transform: scale(1.03, 1.03); overflow: visible; }
|
MacOS 风格代码块
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| .article-content { .highlight:before { content: ''; display: block; background: url(/code-header.svg); height: 32px; width: 100%; background-size: 57px; background-repeat: no-repeat; margin-bottom: 5px; background-position: -1px 2px; } }
[data-scheme="light"] .article-content .highlight { background-color: #fdf4eb; }
[data-scheme="light"] .chroma { color: #ff6f00; background-color: #fcf0e4cc; }
|
- 在
./static
文件夹下新建 code-header.svg
写入以下代码:
1 2 3 4 5 6
| <svg xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" width="470px" height="130px"> <ellipse cx="65" cy="65" rx="50" ry="52" stroke="rgb(220,60,54)" stroke-width="2" fill="rgb(237,108,96)"/> <ellipse cx="225" cy="65" rx="50" ry="52" stroke="rgb(218,151,33)" stroke-width="2" fill="rgb(247,193,81)"/> <ellipse cx="385" cy="65" rx="50" ry="52" stroke="rgb(27,161,37)" stroke-width="2" fill="rgb(100,200,86)"/> </svg>
|
修改代码块样式
- 修改
.\assets\scss\partials\layout\article.scss,
在文件尾添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
.highlight { margin-left: 0; margin-right: 0; width: calc(100%); border-radius: var(--card-border-radius); }
.copyCodeButton { top: 6px; right: 6px; }
|
代码块高亮
- 在
hugo.yaml
中,添加 highlight
参数,我文章里的代码块配置是这样子的:
1 2 3 4 5 6 7 8 9 10
| markup: highlight: noClasses: false codeFences: true guessSyntax: true lineNoStart: 1 lineNos: true lineNumbersInTable: true tabWidth: 4 style: github-dark
|
关闭代码块语言显示
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4
| .languageCodeButton { display: none; }
|
外部链接后面显示图标
- 创建
./layouts/_default/_markup/render-link.html
文件之后增加如下代码:
1 2 3 4 5 6 7 8 9 10 11
| <a class="link" href="{{ .Destination | safeURL }}" {{ with .Title }} title="{{ . }}" {{ end }} {{ if strings.HasPrefix .Destination "http" }} target="_blank" rel="noopener" {{ end }}> <span style="display: inline-flex; align-items: center; gap: 0.5em;"> {{ .Text | safeHTML }} {{ if strings.HasPrefix .Destination "http" }} <svg width=".7em" height=".7em" viewBox="0 0 21 21" xmlns="http://www.w3.org/2000/svg"> <path d="m13 3l3.293 3.293l-7 7l1.414 1.414l7-7L21 11V3z" fill="currentColor" /> <path d="M19 19H5V5h7l-2-2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2h14c1.103 0 2-.897 2-2v-5l-2-2v7z" fill="currentColor" /> </svg> {{ end }} </span> </a>
|
- 或者,创建
./layouts/_default/_markup/render-link.html
文件之后增加如下代码:
1 2 3 4 5 6 7 8 9 10 11
| <a class="link" href="{{ .Destination | safeURL }}" {{ with .Title }} title="{{ . }}" {{ end }} {{ if strings.HasPrefix .Destination "http" }} target="_blank" rel="noopener" {{ end }}> <span style="display: inline-flex; align-items: center; gap: 0.5em;"> <span>{{ .Text | safeHTML }}</span> {{ if strings.HasPrefix .Destination "http" }} <svg width=".7em" height=".7em" viewBox="0 0 21 21" xmlns="http://www.w3.org/2000/svg"> <path d="m13 3l3.293 3.293l-7 7l1.414 1.414l7-7L21 11V3z" fill="currentColor" /> <path d="M19 19H5V5h7l-2-2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2h14c1.103 0 2-.897 2-2v-5l-2-2v7z" fill="currentColor" /> </svg> {{ end }} </span> </a>
|
语言和复制按钮
- 原本的复制按钮要指针移动到代码块上才出现的,把它固定在右上角,并显示代码的语言种类。
- 在
./assets/ts/main.ts
中,第 66 行开始,改成以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| const highlights = document.querySelectorAll(".article-content div.highlight"); const copyText = `📄拷贝`, copiedText = `已拷贝!`;
highlights.forEach((highlight) => { const copyButton = document.createElement("button"); copyButton.innerHTML = copyText; copyButton.classList.add("copyCodeButton"); highlight.appendChild(copyButton);
const codeBlock = highlight.querySelector("code[data-lang]"); const lang = codeBlock.getAttribute("data-lang"); if (!codeBlock) return;
copyButton.addEventListener("click", () => { navigator.clipboard .writeText(codeBlock.textContent) .then(() => { copyButton.textContent = copiedText;
setTimeout(() => { copyButton.textContent = copyText; }, 1000); }) .catch((err) => { alert(err); console.log("Something went wrong", err); }); });
const languageButton = document.createElement("button"); languageButton.innerHTML = lang.toUpperCase() + " "; languageButton.classList.add("languageCodeButton");
highlight.appendChild(languageButton); });
new StackColorScheme(document.getElementById("dark-mode-toggle"));
|
- 在
./assets/scss/custom.scss
中加入以下代码调整按钮位置(需要自己调整以下距离,因为每个人的大小不一样)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| .article-content .copyCodeButton { position: absolute; top: 10px; right: 18px; border-radius: 12px; color: #ffffff; background: #3d3c3c; border: 1px solid #333; padding: 5px 10px; font-weight: 500; text-shadow: 0 0 1px rgba(255, 255, 255, 0.5); }
.article-content .copyCodeButton:hover { background: #ffa500; border-color: #000; }
|
侧边栏美化
页面左右边栏宽度
- 在
/themes/hugo-theme-stack/assets/scss/grid.scss
的第 29、30 行,修改为:
1 2
| --left-sidebar-max-width: 14%; --right-sidebar-max-width: 22%;
|
右侧导航栏动画
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
.widget.archives .widget-archive--list { transition: transform .3s ease; }
.widget.archives .widget-archive--list:hover { transform: scale(1.05, 1.05); }
.tagCloud .tagCloud-tags a { border-radius: 10px; font-size: 1.4rem; transition: transform .3s ease; }
.tagCloud .tagCloud-tags a:hover { transform: scale(1.1, 1.1); }
|
左侧导航栏美化
- 在
./assets/scss/custom.scss
加入代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| .left-sidebar { --sidebar-avatar-size: 115px; --sidebar-element-separation: 15px; --emoji-size: 40px; --emoji-font-size: 25px; }
.social-menu svg { gap: 15px; justify-content: center; width: 30px; height: 30px; stroke: var(--body-text-color); stroke-width: 1.33; }
|
左侧导航栏动画
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
#main-menu { overflow: visible; li { a { -webkit-font-smoothing: antialiased; will-change: transform; transition: transform 0.6s ease; &:hover { transform: scale(1.1, 1.1); will-change: transform; } } } }
.article-list--compact { overflow: visible; }
.article-list--compact article { transition: transform 0.6s ease; -webkit-font-smoothing: antialiased; will-change: transform; &:hover { transform: scale(1.05,1.05); z-index: 4; } }
.article-list--tile article { transition: 0.6s ease; }
.article-list--tile article:hover { transform: scale(1.05, 1.05); will-change: transform; }
|
社交 social
- 自定义图标,iconfont 下载,颜色 #2c3e50,大小 24,格式 svg。下载后放到
.\assets\icons
- 本主题自带了一些来自【Tabler Icons】的 SVG 图标。您可以在主题文件夹下找到它们
.\assets\icons
- 注意:将下载的 img 中的 svg 的所有 #2c3e50 改成
currentColor
,否则切换为黑色模式,图标颜色不能自动切换,因为优先使用内部定义的 color
- 修改 hugo 主配置文件,修改下面的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| menu: main: []
social: - identifier: bilibili name: Bilibili url: https://space.bilibili.com/35158479 weight: 100 params: icon: brand-bilibili newTab: true
- identifier: github name: GitHub url: https://github.com/meimolihan weight: 200 params: icon: brand-github newTab: true
- identifier: rss name: RSS url: https://meimolihan.github.io/index.xml weight: 300 params: icon: brand-rss newTab: true
|
- 图标360度旋转动画
.\assets\scss\custom.scss
追加以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| .icon-tabler-brand-bilibili { transition: transform 1s ease-in-out; }
.icon-tabler-brand-bilibili:hover { transform: rotate(360deg); }
.icon-tabler-brand-github { transition: transform 1s ease-in-out; }
.icon-tabler-brand-github:hover { transform: rotate(360deg);
.icon-tabler-rss { transition: transform 1s ease-in-out; }
.icon-tabler-rss:hover { transform: rotate(360deg); }
|
明亮模式,调整位置
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6
| #dark-mode-toggle { margin-bottom: 100px; gap: 30px; }
|
手动修改左右侧边栏设置样式
- 在
/assets/scss/grid.scss
中修改 left-sidebar
和 right-sidebar
的描述:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| .left-sidebar { order: -3; max-width: 10%; }
.right-sidebar { order: -1; max-width: 20%;
@include respond(lg) { display: flex; } }
|
把正文的占比改到了 70%, 原来的只有 50% 左右
头像旋转
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8
| .sidebar header .site-avatar .site-logo { transition: transform 1.65s ease-in-out; }
.sidebar header .site-avatar .site-logo:hover { transform: rotate(360deg); }
|
友情链接+分类+标签+归档【三栏显示】
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
@media (min-width: 1024px) { .article-list--compact { display: grid; grid-template-columns: 1fr 1fr 1fr; background: none; box-shadow: none; gap: 1rem;
article { background: var(--card-background); border: none; box-shadow: var(--shadow-l2); margin-bottom: 8px; margin-right: 8px; border-radius: 16px; } } }
|
缩小归档页的分类卡片尺寸
- 默认的卡片有些太大了,
./assets/scss/partials/layout/list.scss
中加入以下代码:(并修改)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| .subsection-list { overflow-x: auto;
.article-list--tile { display: flex; padding-bottom: 0px;
article { width: 230px; height: 120px; margin-right: 5px; flex-shrink: 0;
.article-title { margin: 0; font-size: 1.8rem; }
.article-details { padding: 20px; } } } }
|
调整 TOC 目录间距
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
.widget--toc { background-color: var(--card-background); border-radius: var(--card-border-radius); box-shadow: var(--shadow-l2); display: flex; flex-direction: column; color: var(--card-text-color-main); overflow: hidden; display:inline-block;
#TableOfContents { max-height: 65vh;
ol, ul { list-style-type: none; }
li { margin: 10px 10px;
& > ol, & > ul { margin-top: 10px; padding-left: 10px; margin-bottom: -5px;
& > li:last-child { margin-bottom: 0; } } }
& > ul { padding: 0 1em; }
li { margin: 5px 20px; padding: 6px;
& > ol, & > ul { margin-top: 10px; padding-left: 10px; margin-bottom: -5px;
& > li:last-child { margin-bottom: 0; } } } } }
|
鼠标悬停,超链接的显示
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| a { text-decoration: none; color: var(--accent-color);
&:hover { color: var(--accent-color-darker); }
&.link { box-shadow: 0px -2px 0px rgba(var(--link-background-color), var(--link-background-opacity-hover)) inset; transition: all 0.3s ease;
&:hover { box-shadow: 0px -18px 0px rgba(var(--link-background-color), var(--link-background-opacity-hover)) inset; } } }
|
其它小部件
添加站点统计信息与 i18n
展示格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <section class="count_info"> <div> {{ T "footer.runtime1" }} <span id="ds" class="running-days"></span> {{ T "footer.runtime2" }} <span id="hs" class="running-days"></span> {{ T "footer.runtime3" }} <span id="ms" class="running-days"></span> {{ T "footer.runtime4" }} </div> <div> {{$scratch := newScratch}} {{ range (where .Site.Pages "Kind" "page" )}} {{$scratch.Add "total" .WordCount}} {{ end }} {{ T "footer.count1" }} {{ len (where .Site.RegularPages "Section" "post") }} {{ T "footer.count2" }} {{ div ($scratch.Get "total") 1000.0 | lang.FormatNumber 2 }} k {{ T "footer.count3" }} </div> <div> <span id="busuanzi_container_site_pv">{{ T "footer.pv1" }}<span id="busuanzi_value_site_pv"></span>{{ T "footer.pv2" }}</span> </div> </section>
<script> let s1 = '2023-6-18'; s1 = new Date(s1.replace(/-/g, "/")); let s2 = new Date(); let timeDifference = s2.getTime() - s1.getTime();
let days = Math.floor(timeDifference / (1000 * 60 * 60 * 24)); let hours = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); let minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60)); document.getElementById('ds').innerHTML = days; document.getElementById('hs').innerHTML = hours; document.getElementById('ms').innerHTML = minutes;
</script>
|
- 在主题目录
/i18n/zh-cn.yaml
下找到对应语言的文件,在属性 footer 下添加相应字段,结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| footer: # 本博客已稳定运行1天2小时3分钟 runtime1: other: 本博客已稳定运行 runtime2: other: 天 runtime3: other: 小时 runtime4: other: 分钟
# 共发表x篇文章,总计y k字 count1: other: 共发表 count2: other: 篇文章 · 总计 count3: other: 字
# 本站总访问量X次 pv1: other: 本站总访问量 pv2: other: 次
|
添加访客地图
- 在根目录
./layouts/partials/sidebar/right.html
添加后完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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) }} {{ partial (printf "widget/%s" .type) (dict "Context" $context "Params" .params) }} {{ else }} {{ warnf "Widget %s not found" .type }} {{ end }} {{ end }} <div style="height: 30%;width: 30%"> <script type="text/javascript" id="clstr_globe" src="//clustrmaps.com/globe.js?d=xxxxx"></script> </div> </aside> {{ end }}
|
鼠标样式
- 准备好鼠标样式图片(默认,指针,文本…),图片大小建议控制在 32px 左右,将.png图片放入
static/mouse
文件夹下(文件夹自己创建)
修改对应的图片名即可
- 修改
./assets/scss/custom.scss
(文件不存在则自己创建),将以下代码复制进去,根据主题按实际情况填写对应的css选择器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
body, html, .article-content img { cursor: url(../mouse/default.png), auto !important; }
a:hover, button:hover, .copyCodeButton:hover, #dark-mode-toggle { cursor: url(../mouse/pointer.png), auto; }
input:hover, .site-description, .article-subtitle, .article-content span, .article-content li, .article-content p { cursor: url(../mouse/text.png), auto; }
.main-container { gap: 50px;
@include respond(md) { padding: 0 30px; gap: 40px; } }
.related-contents { overflow-x: visible; padding-bottom: 15px; }
|
首页欢迎横幅
- 在
./layouts/index.html
的 <section class="article-list">
前添加以下代码:
1 2 3 4 5 6 7 8 9 10 11
| <!-- 首页欢迎字幅 --> <div class="welcome"> <p style="font-size: 2rem; text-align: center; font-weight: bold"> <span class="shake">👋</span> <span class="jump-text1" > Welcome</span> <span class="jump-text2"> To </span> <span class="jump-text3" style="color:#e99312">Xa</span><span class="jump-text4" style="color:#e99312">l</span><span class="jump-text5" style="color:#e99312">a</span><span class="jump-text6" style="color:#e99312">o</span><span class="jump-text7" style="color:#e99312">k</span><span class="jump-text8" style="color:#e99312">'s</span> <span class="jump-text9" style="color:#e99312">Blog</span> </p> </div> <!-- 首页欢迎字幅 -->
|
- 在
./assets/scss/custom.scss
中加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| .welcome { color: var(--card-text-color-main); background: var(--card-background); box-shadow: var(--shadow-l2); border-radius: 30px; display: inline-block; }
.shake { display: inline-block; animation: shake 1s; animation-duration: 1s; animation-timing-function: ease; animation-delay: 0s; animation-iteration-count: 1; animation-direction: normal; animation-fill-mode: none; animation-play-state: running; animation-name: shake; animation-timeline: auto; animation-range-start: normal; animation-range-end: normal; animation-delay: 2s; @keyframes shake { 0% { transform: rotate(0); } 25% { transform: rotate(45deg) scale(1.2); } 50% { transform: rotate(0) scale(1.2); } 75% { transform: rotate(45deg) scale(1.2); } 100% { transform: rotate(0); } } }
.jump-text1 { display: inline-block; animation: jump 0.5s 1; }
.jump-text2 { display: inline-block; animation: jump 0.5s 1; animation-delay: 0.1s; }
.jump-text3 { display: inline-block; animation: jump 0.5s 1; animation-delay: 0.2s; }
.jump-text4 { display: inline-block; animation: jump 0.5s 1; animation-delay: 0.3s; }
.jump-text5 { display: inline-block; animation: jump 0.5s 1; animation-delay: 0.4s; }
.jump-text6 { display: inline-block; animation: jump 0.5s 1; animation-delay: 0.5s; }
.jump-text7 { display: inline-block; animation: jump 0.5s 1; animation-delay: 0.6s; }
.jump-text8 { display: inline-block; animation: jump 0.5s 1; animation-delay: 0.7s; }
.jump-text9 { display: inline-block; animation: jump 0.5s 1; animation-delay: 0.9s; }
@keyframes jump { 0% { transform: translateY(0); } 50% { transform: translateY(-20px); } 100% { transform: translateY(0); } }
|
删除“使用 Hugo 构建 主题Stack由Jimmy设计”等字样
- 删除掉
./layout/partials/footer/footer.html
原先的代码,注意是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| {{- $ThemeVersion := "3.29.0" -}} <footer class="site-footer"> <section class="copyright"> © {{ 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 }}
{{ $articleCount := len .Site.RegularPages }} {{ $totalWordCount := 0 }} {{ range .Site.Pages }} {{ $totalWordCount = add $totalWordCount .WordCount }} {{ end }}
<p>发布了 {{ $articleCount }} 篇文章 | 共 {{$totalWordCount}} 字</p> </section> <!------------- 以上的删除掉 -------------> </footer>
|
添加【返回顶部】按钮
-
- 返回顶部图片,复制以下代码保存为
.svg
文件,放到./assets/icons
文件夹下(不存在则自行创建)
1 2 3 4 5 6 7 8
| <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="#707070" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-square-rounded-arrow-up"> <path stroke="none" d="M0 0h24v24H0z" fill="none"/> <path d="M16 12l-4 -4l-4 4"/> <path d="M12 16v-8"/> <path d="M12 3c7.2 0 9 1.8 9 9s-1.8 9 -9 9s-9 -1.8 -9 -9s1.8 -9 9 -9z"/> </svg>
|
-
- 将以下代码复制到
layouts/partials/footer/custom.html
文件中(不存在则自行创建)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
<style> #backTopBtn { display: none; position: fixed; bottom: 30px; z-index: 99; cursor: pointer; width: 30px; height: 30px; background-image: url({{ (resources.Get "icons/backTop.svg").RelPermalink }}); transition: transform 1s ease-in-out; } #backTopBtn:hover { transform: rotate(360deg); }
</style>
<script>
function initScrollTop() { let rightSideBar = document.querySelector(".right-sidebar"); if (!rightSideBar) { return; } let btn = document.createElement("div"); btn.id = "backTopBtn"; btn.onclick = backToTop rightSideBar.appendChild(btn) window.onscroll = function() { if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) { btn.style.display = "block"; } else { btn.style.display = "none"; } }; }
function backToTop(){ window.scrollTo({ top: 0, behavior: "smooth" }) }
initScrollTop(); </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| <style> #backTopBtn { display: none; position: fixed; bottom: 100px; z-index: 99; cursor: pointer; width: 40px; height: 40px; background-image: url({{ (resources.Get "icons/backTop.svg").RelPermalink }}); will-change: transform; transition: transform 1s ease-in-out; }
#backTopBtn:hover { transform: rotate(360deg); } </style>
<script>
function initScrollTop() { let rightSideBar = document.querySelector(".right-sidebar"); if (!rightSideBar) { return; } let btn = document.createElement("div"); btn.id = "backTopBtn"; btn.onclick = backToTop rightSideBar.appendChild(btn) window.onscroll = function () { let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; if (scrollTop > 20) { btn.style.display = "block"; } else { btn.style.display = "none"; } }; }
function backToTop() { window.scrollTo({ top: 0, behavior: "smooth" }) }
initScrollTop(); </script>
|
-
- 解决 PJAX 刷新问题
- 编辑
.\layouts\partials\footer\pjax.html
文件 。pjax:complete
事件下,添加以下内容:
1 2 3
| topbar.hide(); initScrollTop();
|
hugo 接入评论
1、GitHub 打开评论
- 首先进入【GitHub】,hugo 博客项目主页–>>项目设置–>>找到Discussions Loading

2、giscus 配置

3、GitHub 博客项目接入 giscus

- 随着官网的说明一步步配置下去。配置完成后便可在 启用 giscus 下找到需要的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <script src="https://giscus.app/client.js" data-repo="meimolihan/meimolihan.github.io" data-repo-id="R_kgDONpRkKg" data-category="Announcements" data-category-id="DIC_kwDONpRkKs4CmwSa" data-mapping="pathname" data-strict="0" data-reactions-enabled="1" data-emit-metadata="0" data-input-position="bottom" data-theme="dark" data-lang="zh-CN" crossorigin="anonymous" async> </script>
|
4、修改 hugo 主配置文件
- 我使用的是Hugo的stack主题,需要在 config.yaml 中设置
1 2 3
| comments: enabled: true provider: giscus
|
5、引入 giscus-js文件
- 将stack主题
./themes/hugo-theme-stack/layouts/partials/comments/provider/giscus.html
文件拷贝至./layouts/partials/comments/provider/
目录下 (需新建)
- 然后将giscus-js代码放到下面的位置:

- 配置完成,
hugo server -D
启动hugo,在本地就可以看到效果。
Hugo Stack 预加载动画

1、新增组件
小组件放在layouts/partials/widget/preload.html
文件里,注意,这个文件是自己创建的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| {{ if .Site.Params.enablePreloadingAnim }} <div id="loading-box"> <div class="loading-left-bg"></div> <div class="loading-right-bg"></div> <div class="spinner-box"> <div class="configure-border-1"> <div class="configure-core"></div> </div> <div class="configure-border-2"> <div class="configure-core"></div> </div> <div class="loading-word">加载中...</div> </div> </div>
<script> if (typeof $ !== 'function') { console.error("jQuery is not loaded. Please ensure jQuery is included in your project."); }
window.addEventListener("load", function () { const loadingBox = document.getElementById('loading-box'); if (loadingBox) { setTimeout(function () { loadingBox.classList.add("loaded"); console.log("Preloader hidden after all resources are loaded."); }, 500); } else { console.error("Preloader element not found!"); } });
let loadedResources = 0; const totalResources = document.images.length + document.styleSheets.length;
function checkResourceLoad() { loadedResources++; const progress = Math.round((loadedResources / totalResources) * 100); const loadingWord = document.querySelector('.loading-word'); if (loadingWord) { loadingWord.textContent = `加载中... ${progress}%`; } if (loadedResources >= totalResources) { window.dispatchEvent(new Event('load')); } }
document.images.forEach(img => { img.addEventListener('load', checkResourceLoad); img.addEventListener('error', checkResourceLoad); });
document.styleSheets.forEach(sheet => { checkResourceLoad(); }); </script> {{ end }}
|
2、组件样式
- 找到
./assets/scss/custom.scss
在文件里面追加 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| #loading-box .loading-left-bg, #loading-box .loading-right-bg { position: fixed; z-index: 1000; width: 50%; height: 100%; background-color: #b1c0c7; transition: all 0.5s; }
#loading-box .loading-right-bg { right: 0; }
#loading-box>.spinner-box { position: fixed; z-index: 1001; display: flex; justify-content: center; align-items: center; width: 100%; height: 100vh; }
#loading-box .spinner-box .configure-border-1 { position: absolute; padding: 3px; width: 115px; height: 115px; background: #ffab91; animation: configure-clockwise 3s ease-in-out 0s infinite alternate; }
#loading-box .spinner-box .configure-border-2 { left: -115px; padding: 3px; width: 115px; height: 115px; background: rgb(63, 249, 220); transform: rotate(45deg); animation: configure-xclockwise 3s ease-in-out 0s infinite alternate; }
#loading-box .spinner-box .loading-word { position: absolute; color: #ffffff; font-size: 1.8rem; font-family: 'Zhi Mang Xing', cursive; }
#loading-box .spinner-box .configure-core { width: 100%; height: 100%; background-color: #37474f; }
div.loaded div.loading-left-bg { transform: translate(-100%, 0); }
div.loaded div.loading-right-bg { transform: translate(100%, 0); }
div.loaded div.spinner-box { display: none !important; }
@keyframes configure-clockwise { 0% { transform: rotate(0); }
25% { transform: rotate(90deg); }
50% { transform: rotate(180deg); }
75% { transform: rotate(270deg); }
100% { transform: rotate(360deg); } }
@keyframes configure-xclockwise { 0% { transform: rotate(45deg); }
25% { transform: rotate(-45deg); }
50% { transform: rotate(-135deg); }
75% { transform: rotate(-225deg); }
100% { transform: rotate(-315deg); } }
|
3、配置文件
- hugo配置文件
params
栏目底下,加上 enablePreloadingAnim: true
1 2
| params: enablePreloadingAnim: true
|
Hugo 图片灯箱

- 使用 Fancybox 实现图片灯箱/放大功能
- Hugo 自带的图片渲染是没有灯箱效果的,所以我们需要自己添加。灯箱效果就是点击图片后,图片会放大显示。
修改 Hugo 配置文件
修改网站根目录下的 config.toml 或者 config.yaml 文件,我的配置文件为 yaml 格式,toml 需要自行调整格式,在 params参数下添加以下内容:
1 2
| params fancybox: true # 图片灯箱,false为关闭,true为开启
|
创建 render-image.html 文件
- 在你的 Hugo 根目录下创建以下路径和文件:
./layouts/_default/_markup/render-image.html
- 编辑
render-image.html
添加以下内容:
1 2 3 4 5 6 7
| {{if .Page.Site.Params.fancybox }} <div class="post-img-view"> <a data-fancybox="gallery" href="{{ .Destination | safeURL }}"> <img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" {{ with .Title}} title="{{ . }}"{{ end }} /> </a> </div> {{ end }}
|
复制 custom.html 文件
- 从你主题目录
./themes/stack/layouts/partials/footer/custom.html
复制到 Hugo在你根目录 layouts/partials/footer/custom.html
,添加以下内容:
1 2 3 4 5
| {{if .Page.Site.Params.fancybox }} <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" /> <script src="https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js"></script> {{ end }}
|
接下来就可以直接 hugo server -D看看效果了。
引入动态背景(点线漂浮(particles.js))
1. 前往【配置页面】配置参数,参数按自己喜好即可,唯一注意要修改的参数是 detect_on,要改成 window

2. 下载配置文件,以及 particles.js 所需要的js文件
【particlesjs-config.json】(Ctrl + S 保存),本博客的动态背景json配置,有需求的可直接下载

3. 把下载好的文件,解压并将以下两个文件放到assets/background文件夹下
- particlesjs-config.json
- particles.min.js

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <div id="particles-js"></div>
<script src={{ (resources.Get "background/particles.min.js").Permalink }}></script> <script> particlesJS.load('particles-js', {{ (resources.Get "background/particlesjs-config.json").Permalink }}, function() { console.log('particles.js loaded - callback'); }); </script>
<style> #particles-js { position: fixed; top: 0; left: 0; width: 100%; z-index: -1; } </style>
|
【Hugo】博客文章浏览数统计
引入第三方组件,来给博客文章统计浏览数
教程
Hugo
前言:
- 博客文章统计组件个人找到了两个,分别是不蒜子,以及vercount
- 不蒜子比较老,但很稳定,到现在仍然可以使用,没有停服
- vercount则比较新,并做了一些代码优化
- 两种使用都基本一样,差别不大,看自己喜好,下面的教程是以vercount来举例,用不蒜子的话,就把对应的脚本和元素标签替换一下就好
1 基本引入
- (1)修改
layouts/partials/footer/custom.html
(不存在则自行创建),引入脚本
1
| <script defer src="https://cn.vercount.one/js"></script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div class="article-details"> ... <footer class="article-time"> ... <div id="viewCount"> {{ partial "helper/icon" "eye" }} <time class="article-time--reading"> <span id="vercount_value_page_pv">loading... </span>次 </time> </div> </footer> ... </div>
|

2 问题修复
- 问题描述:
- 博客首页的文章列表显示了浏览数,且只有第一篇文章才有浏览数,并且浏览数的数字不正确

-
产生原因:
layouts/partials/article/components/details.html
此html文件也被用在了博客首页的文章列表,所以也触发了vercount读取当前页面的浏览数
- 因为读取的数据是当前页面的浏览数,也就是首页的浏览数,并非文章的浏览数,所以数据只加载一次,且不准确
-
解决思路:
- 由于vercount并未提供
只查询文章浏览数
的接口,只有一个文章浏览数+1,并且返回浏览数
的接口,所以无法实现首页对每篇文章的浏览数的单独查询
- 既然无法实现首页展示每篇文章的单独浏览数,那就直接隐藏就好了,等点入文章才看到具体的浏览数
-
具体操作:
- (1)修改
layouts/partials/footer/custom.html
,引入以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <script> function showHideView() { let viewCounts = document.querySelectorAll("#viewCount"); if (viewCounts) { let article = document.querySelector(".article-page"); if (!article) { viewCounts.forEach(ele => { ele.style.display = 'none'; }); } } } showHideView(); </script>
|
- 如果嫌麻烦,浏览数统计可以和更新时间一样,放到文章末尾就好,就不会显示到首页上了
- 具体修改
layouts/partials/article/footer.html
就好,看个人喜好吧