写在前面:
本篇教程由于作者很懒,部分内容可能是从别处CV过来的,可能与作者实际配置的有细微差别,如果发现有错误的地方导致你无法实现该功能先深表歉意,并且欢迎通过右下角的channel联系我~ 在我看到消息后会第一时间给你我实际的配置内容。
本次装修的环境
操作系统: MacOS Sonoma 14.0
Markdown编辑器: Typora
博客配置编辑器: VS Code
命令行工具: Git、Terminal
Hugo版本: hugo_extended_0.121.2_darwin-universal
Hugo主题: hugo-theme-stack
hugo博客的结构
因为不会写前端,也是第一次搭建hugo博客,在此写下我浅显的理解,如有错误,欢迎批评指正
本文通过 git submodule 方式安装的stack主题,不难发现,初始化后的主题目录结构为
.
├── archetypes
├── assets
├── config.yaml
├── content
├── data
├── deploy.sh
├── i18n
├── img
├── layouts
├── public
├── resources
├── static
└── themes
而themes/hugo-theme-stack目录下的主题为
.
├── LICENSE
├── README.md
├── archetypes
├── assets
├── config.yaml
├── data
├── debug.sh
├── exampleSite
├── go.mod
├── i18n
├── images
├── layouts
├── netlify.toml
└── theme.toml
二者有很多相似之处(比如都有assets、layouts等目录),通过前端定位等测试发现,主目录下如果和hugo-theme-stack目录有相同的配置文件,则优先生效主目录下的文件(但似乎也有特殊情况,不过通常是这样的)。所以这里建议在assets创建一个名为scss的文件夹,然后在scss文件夹里创建一个名为custom.scss的文件,用于存放魔改代码。引用下面是页面概览:
整体自定义样式表文件
这里贴出我的整体样式表文件,需要可自取:
// ~\blog\assets\scss\custom.scss
// 页面基本配色
: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;
}
}
//------------------------------------------------------
// 修复引用块内容窄页面显示问题
a {
word-break: break-all;
}
code {
word-break: break-all;
}
//--------------------------------------------------
// 文章封面高度
.article-list article .article-image img {
width: 100%;
height: 200px !important;
object-fit: cover;
@include respond(md) {
height: 250px !important;
}
@include respond(xl) {
height: 285px !important;
}
}
//---------------------------------------------------
// 文章内容图片圆角阴影
.article-page .main-article .article-content {
img {
max-width: 96% !important;
height: auto !important;
border-radius: 8px;
}
}
//------------------------------------------------
// 文章内容引用块样式
.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;
}
}
// keep Codeblocks LTR
[dir="rtl"] & {
direction: ltr;
}
pre {
margin: initial;
padding: 0;
margin: 0;
width: auto;
}
}
// light模式下的代码块样式调整
[data-scheme="light"] .article-content .highlight {
background-color: #fff9f3;
}
[data-scheme="light"] .chroma {
color: #ff6f00;
background-color: #fff9f3cc;
}
//-------------------------------------------
// 设置选中字体的区域背景颜色
//修改选中颜色
::selection {
color: #fff;
background: #34495e;
}
a {
text-decoration: none;
color: var(--accent-color);
&:hover {
color: var(--accent-color-darker);
}
&.link {
color: #4288b9ad;
font-weight: 600;
padding: 0 2px;
text-decoration: none;
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}
//-------------------------------------------------
//文章封面高度更改
.article-list article .article-image img {
width: 100%;
height: 150px;
object-fit: cover;
@include respond(md) {
height: 200px;
}
@include respond(xl) {
height: 305px;
}
}
//---------------------------------------------------
// 全局页面布局间距调整
.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);
/// Display right sidebar when min-width: lg
@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; //1536px;
--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%;
}
//----------------------------------------------------
//固定代码块的高度
.article-content {
.highlight {
padding: var(--card-padding);
pre {
width: auto;
max-height: 20em;
}
}
}
// --------------------------------
// 菜单栏样式
// 下拉菜单改圆角样式
.menu {
padding-left: 0;
list-style: none;
flex-direction: column;
overflow-x: hidden;
overflow-y: scroll;
flex-grow: 1;
font-size: 1.6rem;
background-color: var(--card-background);
box-shadow: var(--shadow-l2); //改个阴影
display: none;
margin: 0; //改为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;
}
}
}
}
// ~\blog\assets\scss\custom.scss
//------------------------------------------------
//将滚动条修改为圆角样式
//菜单滚动条美化
.menu::-webkit-scrollbar {
display: none;
}
// 全局滚动条美化
html {
::-webkit-scrollbar {
width: 20px;
}
::-webkit-scrollbar-track {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: #d6dee1;
border-radius: 20px;
border: 6px solid transparent;
background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
background-color: #a8bbbf;
}
}
//--------------------------------------------------
//归档页面双栏
/* 归档页面两栏 */
@media (min-width: 1024px) {
.article-list--compact {
display: grid;
grid-template-columns: 1fr 1fr;
background: none;
box-shadow: none;
gap: 1rem;
article {
background: var(--card-background);
border: none;
box-shadow: var(--shadow-l2);
margin-bottom: 8px;
border-radius: 16px;
}
}
}
//--------------------------------------------------
//链接三栏
@media (min-width: 1024px) {
.article-list--compact.links {
display: grid;
grid-template-columns: 1fr 1fr 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;
border-radius: var(--card-border-radius);
&:nth-child(odd) {
margin-right: 8px;
}
}
}
}
//---------------------------------------------------------
//首页欢迎板块样式
.welcome {
color: var(--card-text-color-main);
background: var(--card-background);
box-shadow: var(--shadow-l2);
border-radius: 30px;
display: inline-block;
}
// 👋emoji实现摆动效果
.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);
}
}
//--------------------------------------------------
//引入左上角返回按钮
.back-home {
background: var(--card-background);
border-radius: var(--tag-border-radius);
color: var(--card-text-color-tertiary);
margin-right: 0.1rem;
margin-top: 24px;
display: inline-flex;
align-items: center;
font-size: 1.4rem;
text-transform: uppercase;
padding: 10px 20px 10px 15px;
transition: box-shadow 0.3s ease;
box-shadow: var(--shadow-l3);
&:hover {
box-shadow: var(--shadow-l2);
}
svg {
margin-right: 5px;
width: 20px;
height: 20px;
}
span {
font-weight: 500;
white-space: nowrap;
}
}
.main-container .right-sidebar {
order: 2;
max-width: var(--right-sidebar-max-width);
/// Display right sidebar when min-width: lg
@include respond(lg) {
display: flex;
}
}
main.main {
order: 1;
min-width: 0;
max-width: 100%;
flex-grow: 1;
display: flex;
flex-direction: column;
gap: var(--section-separation);
@include respond(md) {
padding-top: var(--main-top-padding);
}
}
//----------------------------------------------------------
//为代码块顶部添加macos样式
.article-content {
.highlight:before {
content: "";
display: block;
background: url(/img/code-header.svg);
height: 32px;
width: 100%;
background-size: 57px;
background-repeat: no-repeat;
margin-bottom: 5px;
background-position: -1px 2px;
}
}
.tagCloud {
.tagCloud-count {
color: var(--body-text-color);
}
}
.copyCodeButton {
border-radius: var(--category-border-radius);
}
code {
border-radius: var(--category-border-radius);
}
.article-category {
display: flex;
flex-wrap: wrap;
gap: 10px;
a {
background: var(--card-background);
box-shadow: var(--shadow-l1);
border-radius: var(--category-border-radius);
padding: 8px 20px;
color: var(--card-text-color-main);
font-size: 1.4rem;
transition: box-shadow 0.3s ease;
&:hover {
box-shadow: var(--shadow-l2);
}
}
}
/* Category widget */
.category {
.category-label {
display: flex;
flex-wrap: wrap;
gap: 10px;
a {
border-left: 6px solid;
background: var(--card-background);
box-shadow: var(--shadow-l1);
border-radius: var(--category-border-radius);
padding: 12px 20px;
color: var(--card-text-color-main);
font-size: 1.5rem;
transition: box-shadow 0.3s ease;
&:hover {
box-shadow: var(--shadow-l2);
}
}
}
.category-count {
color: var(--body-text-color);
}
}
.running-time {
color: var(--card-text-color-secondary);
font-weight: normal;
.running-days {
font-weight:bold;
color: var(--emphasize-text-color);
}
}
.totalcount {
color: var(--card-text-color-secondary);
font-weight: normal;
margin-bottom: 5px;
}
code {
border-radius: var(--tag-border-radius);
font-size: 14px; // Add font size setting for code block
font-family: var(--code-font-family);
}
.article-subtitle {
margin-top: -5px;
font-size: 1.5rem;
@include respond(md) {
font-size: 1.6rem;
}
}
/*头像旋转动画*/
.sidebar header .site-avatar .site-logo {
transition: transform 1.65s ease-in-out; //旋转时间
}
.sidebar header .site-avatar .site-logo:hover {
transform: rotate(360deg); //旋转角度为360度
}
/*社交菜单居中*/
.social-menu svg {
gap: 15px;
justify-content: center;
width: 30px;
height: 25px; //社交菜单大小
stroke: var(--body-text-color);
stroke-width: 1.33;
}
/*页面加载动画部分*/
#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);
}
}
动态纹理:蛛网、花瓣
蛛网特效在 /layouts/_default/baseof.html中间插入以下代码
<script type="text/javascript" src="https://demo.hellozwh.com/source/canvas-nest.min.js"></script>
花瓣特效只需要将src的地址换为https://cdn.jsdelivr.net/gh/Ukenn2112/UkennWeb@3.0/index/web.js
即可
修改主页侧边栏样式
修改头像及简介
将自己的头像存放在/assets/img/
目录下,之后打开主目录下的config.yaml文件,搜索sidebar,
subtitle代表简介
avatar的src路径为头像路径
改为如下代码
(local最好设置为true,不然头像修改不成功)
sidebar:
compact: false
emoji: 🍥
subtitle: 行者不必言深,孤独本是常态。
avatar:
enabled: true
local: true
src: /img/avatar.jpg
修改社交栏
依然是在主目录下的config.yaml文件进行修改,搜索social,需要添加一个社交按钮则仿照原来的添加如下代码:
- identifier: github
name: GitHub
url: https://github.com/Bla1n
params:
newTab: true
icon: brand-github
icon图标存储目录为~/blog/themes/hugo-theme-stack/assets/icons
修改栏目
icon存储目录同上,但要修改栏目名称则需要前往/content/page
目录
打开对应栏目文件夹,修改index.md文件
头像旋转😵💫
在assets\scss\custom.scss路径下添加如下代码
/* 头像旋转 */
.home .home-profile .home-avatar img {
width: 5rem;
/* 设置循环动画
[animation:
(play)动画名称
(2s)动画播放时长单位秒或微秒
(ease-out)动画播放的速度曲线为以低速结束
(1s)等待1秒然后开始动画
(1)动画播放次数(infinite为循环播放) ]*/
/* 鼠标经过头像旋转360度 */
-webkit-transition: -webkit-transform 1.0s ease-out;
-moz-transition: -moz-transform 1.0s ease-out;
transition: transform 1.0s ease-out;
&:hover {
/* 鼠标经过停止头像旋转
-webkit-animation-play-state:paused;
animation-play-state:paused;*/
/* 鼠标经过头像旋转360度 */
-webkit-transform: rotateZ(360deg);
-moz-transform: rotateZ(360deg);
transform: rotateZ(360deg);
}
}
文章添加音乐
单首音乐效果如下
音乐列表效果如下
直接在文章中插入如下代码:
单曲:(autoplay参数为是否自动播放音乐)
{{< music server="netease" type="song" id="1372188635" autoplay="false" >}}
列表:
{{< music auto="https://music.163.com/playlist?id=6843891038">}}
修改底栏
博客运行时长
在layouts/partials/footer/custom.html
里添加以下JS代码,其中s1
是网站创建日期。代码参考自这里
,加上了小时和分钟的计算。
<!-- Add blog running time -->
<script>
let s1 = '2023-3-18'; //website start date
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));
let result = days + "天" + hours + "小时" + minutes + "分钟";
document.getElementById('runningdays').innerHTML = result;
</script>
再在layouts/partials/footer/footer.html
里添加以下代码:
<!-- Add blog running time -->
<section class="running-time">
本博客已稳定运行
<span id="runningdays" class="running-days"></span>
</section>
在assets/scss/partials/footer.scss
里添加风格样式,这里单独把计时的部分加粗,并改了颜色。
.running-time {
color: var(--card-text-color-secondary);
font-weight: normal;
.running-days {
font-weight:bold;
color: var(--emphasize-text-color);
}
}
上面的计时部分设置成var(--emphasize-text-color)
,这样能比较方便地在assets/scss/variables.scss
里设置暗色模式的颜色
--accent-color-text: #fff;
--body-text-color: #b0b0b0;
--emphasize-text-color: #9e8f9f; // Add emphasize font color
&[data-scheme="dark"] {
--emphasize-text-color: #d5cfc4; // Add emphasize font color for dark scheme
}
文字统计
在layouts/partials/footer/footer.html
里增加以下代码,其中文章篇数统计参考了这篇
,字数统计的展示方式参考了小球飞鱼的博客
。
<!-- Add total page and word count time -->
<section class="totalcount">
{{$scratch := newScratch}}
{{ range (where .Site.Pages "Kind" "page" )}}
{{$scratch.Add "total" .WordCount}}
{{ end }}
发表了{{ len (where .Site.RegularPages "Section" "post") }}篇文章 ·
总计{{ div ($scratch.Get "total") 1000.0 | lang.FormatNumber 2 }}k字
</section>
在assets/scss/partials/footer.scss
里修改风格:
.totalcount {
color: var(--card-text-color-secondary);
font-weight: normal;
margin-bottom: 5px;
}
返回顶部按钮
在阅读长文章时,如果想返回顶部没有快捷按钮则是很不方便的,所以添加此按钮
在/layouts/partials/footer/custom.html
里面添加如下代码
<!--返回顶部按钮 -->
<a href="#" id="back-to-top" title="返回顶部"></a>
<!--返回顶部CSS -->
<style>
#back-to-top {
display: none;
position: fixed;
bottom: 20px;
right: 55px;
width: 55px;
height: 55px;
border-radius: 7px;
background-color: rgba(64, 158, 255, 0.5);
box-shadow: var(--shadow-l2);
font-size: 30px;
text-align: center;
line-height: 50px;
cursor: pointer;
}
#back-to-top:before {
content: ' ';
display: inline-block;
position: relative;
top: 0;
transform: rotate(135deg);
height: 10px;
width: 10px;
border-width: 0 0 2px 2px;
border-color: var(--back-to-top-color);
border-style: solid;
}
#back-to-top:hover:before {
border-color: #2674e0;
}
/* 在屏幕宽度小于 768 像素时,钮位置调整 */
@media screen and (max-width: 768px) {
#back-to-top {
bottom: 20px;
right: 20px;
width: 40px;
height: 40px;
font-size: 10px;
}
}
/* 在屏幕宽度大于等于 1024 像素时,按钮位置调整 */
@media screen and (min-width: 1024px) {
#back-to-top {
bottom: 20px;
right: 40px;
}
}
/* 在屏幕宽度大于等于 1280 像素时,按钮位置调整 */
@media screen and (min-width: 1280px) {
#back-to-top {
bottom: 20px;
right: 55px;
}
}
/* 目录显示时,隐藏按钮 */
@media screen and (min-width: 1536px) {
#back-to-top {
visibility: hidden;
}
}
</style>
<!--返回顶部JS -->
<script>
function backToTop() {
document.documentElement.scrollIntoView({
behavior: 'smooth',
})
}
window.onload = function () {
let scrollTop =
this.document.documentElement.scrollTop || this.document.body.scrollTop
let totopBtn = this.document.getElementById('back-to-top')
if (scrollTop > 0) {
totopBtn.style.display = 'inline'
} else {
totopBtn.style.display = 'none'
}
}
window.onscroll = function () {
let scrollTop =
this.document.documentElement.scrollTop || this.document.body.scrollTop
let totopBtn = this.document.getElementById('back-to-top')
if (scrollTop < 200) {
totopBtn.style.display = 'none'
} else {
totopBtn.style.display = 'inline'
totopBtn.addEventListener('click', backToTop, false)
}
}
</script>
在layouts/partials/footer/components/script.html
里可以修改按钮的颜色:
#back-to-top {
background-color: var(--body-background);
}
#back-to-top:hover:before {
border-color: var(--accent-color);
}
去除归档页初始滤镜
具体可看此issue
用/* */
注释掉themes/hugo-theme-stack/assets/ts/main.ts
中的
import { getColor } from 'ts/color';
和
const articleTile = document.querySelector('.article-list--tile');
if (articleTile) {
let observer = new IntersectionObserver(async (entries, observer) => {
entries.forEach(entry => {
if (!entry.isIntersecting) return;
observer.unobserve(entry.target);
const articles = entry.target.querySelectorAll('article.has-image');
articles.forEach(async articles => {
const image = articles.querySelector('img'),
imageURL = image.src,
key = image.getAttribute('data-key'),
hash = image.getAttribute('data-hash'),
articleDetails: HTMLDivElement = articles.querySelector('.article-details');
const colors = await getColor(key, hash, imageURL);
articleDetails.style.background = `
linear-gradient(0deg,
rgba(${colors.DarkMuted.rgb[0]}, ${colors.DarkMuted.rgb[1]}, ${colors.DarkMuted.rgb[2]}, 0.5) 0%,
rgba(${colors.Vibrant.rgb[0]}, ${colors.Vibrant.rgb[1]}, ${colors.Vibrant.rgb[2]}, 0.75) 100%)`;
})
})
});
observer.observe(articleTile)
}
以及themes/hugo-theme-stack/layouts/partials/footer/components/script.html
中的
{{- partial "helper/external" (dict "Context" . "Namespace" "Vibrant") -}}
添加相册功能
-
日常更新把图片(需按格式:日期 + 空格 + 图片名)丢到
/static/photos/
中即可。 -
/content/page/photos/index.md
创建一个 md,好让 Hugo 生成页面title: 相册 | photos layout: "photos" slug: "photos" menu: main: weight: -50 params: icon: photos comments: false
-
创建
/layouts/_default/photos.html
{{ define "main" }} <div class="button-group"> <button class="filter-button" data-category="-"> All </button> <button class="filter-button" data-category="日常">#日常</button> <button class="filter-button" data-category="风景">#风景</button> <button class="filter-button" data-category="狗哥">#狗哥</button> <button class="filter-button" data-category="赛">#赛</button> </div> <div class="gallery-photos page"> {{ range (sort (readDir "./static/photos") "Name" "desc")}} {{ if ( .Name | findRE "\\.(gif|jpg|jpeg|tiff|png|bmp|webp|avif|jxl)") }} <div class="gallery-photo"> <img class="photo-img" loading='lazy' decoding="async" src="/photos/{{ .Name }}" alt="{{ .Name }}" /> <span class="photo-title">{{ .Name | replaceRE "^[0-9 -]+(.*)[.].*" "$1"}}</span><span class="photo-time">{{ .Name | replaceRE "^([0-9-]+).*[.].*" "$1" }}</span> </div> {{ end }} {{ end }} </div> <style> .gallery-photos{width:100%;} .gallery-photo{width:24.9%;position: relative;visibility: hidden;overflow: hidden;} .gallery-photo.visible{visibility: visible;animation: fadeIn 2s;} .gallery-photo img{ display: block; width:100%; border-radius:20px; padding:4px; animation: fadeIn 1s; cursor: pointer; transition: all .4s ease-in-out; } .gallery-photo span.photo-title,.gallery-photo span.photo-time{ background: rgba(0, 0, 0, 0.3); padding:0px 8px; font-size:0.9rem; color: #fff; display:none; animation: fadeIn 1s; } .gallery-photo span.photo-title{ position:absolute; bottom:4px; left:4px; border-radius:10px; background-color: #a3dfff; color: #000000; font-size:1.2rem } .gallery-photo span.photo-time{position:absolute;top:4px;left:4px;font-size:0.8rem;} .gallery-photo:hover span.photo-title{display:block;} .gallery-photo:hover img{transform: scale(1.1);} .button-group { display: flex; flex-direction: row; gap: 18px; justify-content: center; } .filter-button { padding: 8px 8px; width: auto; background-color: var(--card-background); color: #57bd8f; border: none; border-radius: 5px; cursor: pointer; transition: background-color 0.3s ease; } .filter-button:hover { color: #5e88f7; } .selected-button { background-color: #CCE8CF; color: #000000; /* 选中项的颜色 */ } @media screen and (max-width: 1280px) { .gallery-photo{width:33.3%;} } @media screen and (max-width: 860px) { .gallery-photo{width:49.9%;} } @media (max-width: 683px){ .photo-time{display: none;} } @keyframes fadeIn{ 0% {opacity: 0;} 100% {opacity: 1;} } </style> <script src="https://immmmm.com/waterfall.min.js"></script> <script src="https://immmmm.com/imgStatus.min.js"></script> <script> document.addEventListener('DOMContentLoaded', () => { imgStatus.watch('.photo-img', function(imgs) { if(imgs.isDone()){ waterfall('.gallery-photos'); let pagePhoto = document.querySelectorAll('.gallery-photo'); for(var i=0;i < pagePhoto.length;i++){pagePhoto[i].className += " visible"}; } }); window.addEventListener('resize', function () { waterfall('.gallery-photos'); }); }); </script> <script src="https://immmmm.com/view-image.js"></script> <script src="https://immmmm.com/lately.min.js"></script> <script> window.Lately && Lately.init({ target: '.photo-time'}); window.ViewImage && ViewImage.init('.gallery-photo img') </script> <script> document.addEventListener('DOMContentLoaded', () => { const filterButtons = document.querySelectorAll('.filter-button'); const galleryPhotos = document.querySelectorAll('.gallery-photo'); filterButtons.forEach(button => { button.addEventListener('click', () => { const category = button.getAttribute('data-category'); // 隐藏所有照片 galleryPhotos.forEach(photo => { photo.style.visibility = 'hidden'; }); // 显示符合特定词语的照片 galleryPhotos.forEach(photo => { const imageName = photo.querySelector('.photo-img').getAttribute('alt'); if (imageName.includes(category)) { photo.style.visibility = 'visible'; } }); // 移除所有按钮的选中状态 filterButtons.forEach(btn => { btn.classList.remove('selected-button'); }); // 将当前点击的按钮标记为选中状态 button.classList.add('selected-button'); }); }); }); </script> {{ end }}
这段代码同时添加了分类功能,只需在图片文件名中含有相应关键字即可分类
添加右下角联系小气泡按钮
效果图为:
请参考这两篇文章,两位博主写的非常详细,不难配置,在此不在赘述(懒了,hhh)