Featured image of post 小白hugo博客装修笔记(1)

小白hugo博客装修笔记(1)

买不起房子就自己做一个互联网小屋了

写在前面:

本篇教程由于作者很懒,部分内容可能是从别处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文件

修改关于|about

头像旋转😵‍💫

在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") -}} 

添加相册功能

  1. 日常更新把图片(需按格式:日期 + 空格 + 图片名)丢到/static/photos/中即可。

  2. /content/page/photos/index.md创建一个 md,好让 Hugo 生成页面

    title: 相册 | photos
    layout: "photos"
    slug: "photos"
    menu:
        main: 
            weight: -50
            params:
                icon: photos
    comments: false
    
  3. 创建/layouts/_default/photos.html

    {{ define "main" }}
    <div class="button-group">
        <button class="filter-button" data-category="-">&nbsp;All&nbsp;</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)

私信联系气泡 山茶花舍

参考文章

Stack主题的自定义

Hugo Stack主题装修笔记

Hugo Stack 主题配置与使用

Hugo Stack主题更新小记

Hugo|自定义 hugo-theme-Stack

创建单页相册

Hugo 的 LoveIt 主题修改及增强(三)

shortcode使用

本博客已稳定运行
发表了13篇文章 · 总计29.11k字
森 ICP备2024001234
Built with Hugo
主题 StackJimmy 设计