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主题,不难发现,初始化后的主题目录结构为

 1.
 2├── archetypes
 3├── assets
 4├── config.yaml
 5├── content
 6├── data
 7├── deploy.sh
 8├── i18n
 9├── img
10├── layouts
11├── public
12├── resources
13├── static
14└── themes

而themes/hugo-theme-stack目录下的主题为

 1.
 2├── LICENSE
 3├── README.md
 4├── archetypes
 5├── assets
 6├── config.yaml
 7├── data
 8├── debug.sh
 9├── exampleSite
10├── go.mod
11├── i18n
12├── images
13├── layouts
14├── netlify.toml
15└── theme.toml

二者有很多相似之处(比如都有assets、layouts等目录),通过前端定位等测试发现,主目录下如果和hugo-theme-stack目录有相同的配置文件,则优先生效主目录下的文件(但似乎也有特殊情况,不过通常是这样的)。所以这里建议在assets创建一个名为scss的文件夹,然后在scss文件夹里创建一个名为custom.scss的文件,用于存放魔改代码。引用下面是页面概览:

页面概览

整体自定义样式表文件

这里贴出我的整体样式表文件,需要可自取:

  1//  ~\blog\assets\scss\custom.scss
  2
  3// 页面基本配色
  4:root {
  5    // 全局顶部边距
  6    --main-top-padding: 30px;
  7    // 全局卡片圆角
  8    --card-border-radius: 25px;
  9    // 标签云卡片圆角
 10    --tag-border-radius: 8px;
 11    // 卡片间距
 12    --section-separation: 40px;
 13    // 全局字体大小
 14    --article-font-size: 1.8rem;
 15    // 行内代码背景色
 16    --code-background-color: #f8f8f8;
 17    // 行内代码前景色
 18    --code-text-color: #e96900;
 19    // 暗色模式下样式
 20    &[data-scheme="dark"] {
 21      // 行内代码背景色
 22      --code-background-color: #ff6d1b17;
 23      // 行内代码前景色
 24      --code-text-color: #e96900;
 25    }
 26  }
 27  
 28  //------------------------------------------------------
 29  // 修复引用块内容窄页面显示问题
 30  a {
 31    word-break: break-all;
 32  }
 33  
 34  code {
 35    word-break: break-all;
 36  }
 37  
 38  //--------------------------------------------------
 39  // 文章封面高度
 40  .article-list article .article-image img {
 41    width: 100%;
 42    height: 200px !important;
 43    object-fit: cover;
 44  
 45    @include respond(md) {
 46        height: 250px !important;
 47    }
 48  
 49    @include respond(xl) {
 50        height: 285px !important;
 51    }
 52  }
 53  
 54  //---------------------------------------------------
 55  // 文章内容图片圆角阴影
 56  .article-page .main-article .article-content {
 57    img {
 58      max-width: 96% !important;
 59      height: auto !important;
 60      border-radius: 8px;
 61    }
 62  }
 63  
 64  //------------------------------------------------
 65  // 文章内容引用块样式
 66  .article-content {
 67    blockquote {
 68      border-left: 6px solid #358b9a1f !important;
 69      background: #3a97431f;
 70    }
 71  }
 72  // ---------------------------------------
 73  // 代码块基础样式修改
 74  .highlight {
 75    max-width: 102% !important;
 76    background-color: var(--pre-background-color);
 77    padding: var(--card-padding);
 78    position: relative;
 79    border-radius: 20px;
 80    margin-left: -7px !important;
 81    margin-right: -12px;
 82    box-shadow: var(--shadow-l1) !important;
 83  
 84    &:hover {
 85      .copyCodeButton {
 86        opacity: 1;
 87      }
 88    }
 89  
 90    // keep Codeblocks LTR
 91    [dir="rtl"] & {
 92      direction: ltr;
 93    }
 94  
 95    pre {
 96      margin: initial;
 97      padding: 0;
 98      margin: 0;
 99      width: auto;
100    }
101  }
102  
103  // light模式下的代码块样式调整
104  [data-scheme="light"] .article-content .highlight {
105    background-color: #fff9f3;
106  }
107  
108  [data-scheme="light"] .chroma {
109    color: #ff6f00;
110    background-color: #fff9f3cc;
111  }
112  
113  //-------------------------------------------
114  // 设置选中字体的区域背景颜色
115  //修改选中颜色
116  ::selection {
117    color: #fff;
118    background: #34495e;
119  }
120  
121  a {
122    text-decoration: none;
123    color: var(--accent-color);
124  
125    &:hover {
126      color: var(--accent-color-darker);
127    }
128  
129    &.link {
130      color: #4288b9ad;
131      font-weight: 600;
132      padding: 0 2px;
133      text-decoration: none;
134      cursor: pointer;
135  
136      &:hover {
137        text-decoration: underline;
138      }
139    }
140  }
141  
142  //-------------------------------------------------
143  //文章封面高度更改
144  .article-list article .article-image img {
145    width: 100%;
146    height: 150px;
147    object-fit: cover;
148  
149    @include respond(md) {
150      height: 200px;
151    }
152  
153    @include respond(xl) {
154      height: 305px;
155    }
156  }
157  
158  //---------------------------------------------------
159  // 全局页面布局间距调整
160  .main-container {
161    min-height: 100vh;
162    align-items: flex-start;
163    padding: 0 15px;
164    gap: var(--section-separation);
165    padding-top: var(--main-top-padding);
166  
167    @include respond(md) {
168      padding: 0 37px;
169    }
170  }
171  
172  //--------------------------------------------------
173  //页面三栏宽度调整
174  .container {
175    margin-left: auto;
176    margin-right: auto;
177  
178    .left-sidebar {
179      order: -3;
180      max-width: var(--left-sidebar-max-width);
181    }
182  
183    .right-sidebar {
184      order: -1;
185      max-width: var(--right-sidebar-max-width);
186  
187      /// Display right sidebar when min-width: lg
188      @include respond(lg) {
189        display: flex;
190      }
191    }
192  
193    &.extended {
194      @include respond(md) {
195        max-width: 1024px;
196        --left-sidebar-max-width: 25%;
197        --right-sidebar-max-width: 22% !important;
198      }
199  
200      @include respond(lg) {
201        max-width: 1280px;
202        --left-sidebar-max-width: 20%;
203        --right-sidebar-max-width: 30%;
204      }
205  
206      @include respond(xl) {
207        max-width: 1453px; //1536px;
208        --left-sidebar-max-width: 15%;
209        --right-sidebar-max-width: 25%;
210      }
211    }
212  
213    &.compact {
214      @include respond(md) {
215        --left-sidebar-max-width: 25%;
216        max-width: 768px;
217      }
218  
219      @include respond(lg) {
220        max-width: 1024px;
221        --left-sidebar-max-width: 20%;
222      }
223  
224      @include respond(xl) {
225        max-width: 1280px;
226      }
227    }
228  }
229  
230  //-------------------------------------------------------
231  //全局页面小图片样式微调
232  .article-list--compact article .article-image img {
233    width: var(--image-size);
234    height: var(--image-size);
235    object-fit: cover;
236    border-radius: 17%;
237  }
238  
239  //----------------------------------------------------
240  //固定代码块的高度
241  .article-content {
242    .highlight {
243        padding: var(--card-padding);
244        pre {
245            width: auto;
246            max-height: 20em;
247        }
248    }
249  }
250
251// --------------------------------
252// 菜单栏样式
253// 下拉菜单改圆角样式
254.menu {
255    padding-left: 0;
256    list-style: none;
257    flex-direction: column;
258    overflow-x: hidden;
259    overflow-y: scroll;
260    flex-grow: 1;
261    font-size: 1.6rem;
262    background-color: var(--card-background);
263  
264    box-shadow: var(--shadow-l2); //改个阴影
265    display: none;
266    margin: 0; //改为0
267    border-radius: 10px; //加个圆角
268    padding: 30px 30px;
269  
270    @include respond(xl) {
271      padding: 15px 0;
272    }
273  
274    &,
275    .menu-bottom-section {
276      gap: 30px;
277  
278      @include respond(xl) {
279        gap: 25px;
280      }
281    }
282  
283    &.show {
284      display: flex;
285    }
286  
287    @include respond(md) {
288      align-items: flex-end;
289      display: flex;
290      background-color: transparent;
291      padding: 0;
292      box-shadow: none;
293      margin: 0;
294    }
295  
296    li {
297      position: relative;
298      vertical-align: middle;
299      padding: 0;
300  
301      @include respond(md) {
302        width: 100%;
303      }
304  
305      svg {
306        stroke-width: 1.33;
307  
308        width: 20px;
309        height: 20px;
310      }
311  
312      a {
313        height: 100%;
314        display: inline-flex;
315        align-items: center;
316        color: var(--body-text-color);
317        gap: var(--menu-icon-separation);
318      }
319  
320      span {
321        flex: 1;
322      }
323  
324      &.current {
325        a {
326          color: var(--accent-color);
327          font-weight: bold;
328        }
329      }
330    }
331  }
332
333  //  ~\blog\assets\scss\custom.scss
334
335//------------------------------------------------
336//将滚动条修改为圆角样式
337//菜单滚动条美化
338.menu::-webkit-scrollbar {
339    display: none;
340  }
341  
342  // 全局滚动条美化
343  html {
344    ::-webkit-scrollbar {
345      width: 20px;
346    }
347  
348    ::-webkit-scrollbar-track {
349      background-color: transparent;
350    }
351  
352    ::-webkit-scrollbar-thumb {
353      background-color: #d6dee1;
354      border-radius: 20px;
355      border: 6px solid transparent;
356      background-clip: content-box;
357    }
358  
359    ::-webkit-scrollbar-thumb:hover {
360      background-color: #a8bbbf;
361    }
362  }
363
364//--------------------------------------------------
365//归档页面双栏
366/* 归档页面两栏 */
367@media (min-width: 1024px) {
368    .article-list--compact {
369      display: grid;
370      grid-template-columns: 1fr 1fr;
371      background: none;
372      box-shadow: none;
373      gap: 1rem;
374  
375      article {
376        background: var(--card-background);
377        border: none;
378        box-shadow: var(--shadow-l2);
379        margin-bottom: 8px;
380        border-radius: 16px;
381      }
382    }
383  }
384
385//--------------------------------------------------
386//链接三栏
387@media (min-width: 1024px) {
388    .article-list--compact.links {
389      display: grid;
390      grid-template-columns: 1fr 1fr 1fr; //三个1fr即为三栏,两个1fr则为双栏,以此类推即可.
391      background: none;
392      box-shadow: none;
393      gap: 1rem;
394  
395      article {
396        background: var(--card-background);
397        border: none;
398        box-shadow: var(--shadow-l2);
399        margin-bottom: 8px;
400        border-radius: var(--card-border-radius);
401  
402        &:nth-child(odd) {
403          margin-right: 8px;
404        }
405      }
406    }
407  }
408
409
410//---------------------------------------------------------
411//首页欢迎板块样式
412.welcome {
413    color: var(--card-text-color-main);
414    background: var(--card-background);
415    box-shadow: var(--shadow-l2);
416    border-radius: 30px;
417    display: inline-block;
418  }
419  
420  // 👋emoji实现摆动效果
421  .shake {
422    display: inline-block;
423    animation: shake 1s;
424    animation-duration: 1s;
425    animation-timing-function: ease;
426    animation-delay: 0s;
427    animation-iteration-count: 1;
428    animation-direction: normal;
429    animation-fill-mode: none;
430    animation-play-state: running;
431    animation-name: shake;
432    animation-timeline: auto;
433    animation-range-start: normal;
434    animation-range-end: normal;
435    animation-delay: 2s;
436    @keyframes shake {
437      0% {
438        transform: rotate(0);
439      }
440      25% {
441        transform: rotate(45deg) scale(1.2);
442      }
443      50% {
444        transform: rotate(0) scale(1.2);
445      }
446      75% {
447        transform: rotate(45deg) scale(1.2);
448      }
449      100% {
450        transform: rotate(0);
451      }
452    }
453  }
454  // 实现字符跳动动画
455  .jump-text1 {
456    display: inline-block;
457    animation: jump 0.5s 1;
458  }
459  
460  .jump-text2 {
461    display: inline-block;
462    animation: jump 0.5s 1;
463    animation-delay: 0.1s;
464  }
465  
466  .jump-text3 {
467    display: inline-block;
468    animation: jump 0.5s 1;
469    animation-delay: 0.2s;
470  }
471  
472  .jump-text4 {
473    display: inline-block;
474    animation: jump 0.5s 1;
475    animation-delay: 0.3s;
476  }
477  
478  .jump-text5 {
479    display: inline-block;
480    animation: jump 0.5s 1;
481    animation-delay: 0.4s;
482  }
483  
484  .jump-text6 {
485    display: inline-block;
486    animation: jump 0.5s 1;
487    animation-delay: 0.5s;
488  }
489  
490  .jump-text7 {
491    display: inline-block;
492    animation: jump 0.5s 1;
493    animation-delay: 0.6s;
494  }
495  
496  .jump-text8 {
497    display: inline-block;
498    animation: jump 0.5s 1;
499    animation-delay: 0.7s;
500  }
501  
502  .jump-text9 {
503    display: inline-block;
504    animation: jump 0.5s 1;
505    animation-delay: 0.9s;
506  }
507  
508  @keyframes jump {
509    0% {
510      transform: translateY(0);
511    }
512    50% {
513      transform: translateY(-20px);
514    }
515    100% {
516      transform: translateY(0);
517    }
518  }
519
520//--------------------------------------------------
521//引入左上角返回按钮
522.back-home {
523    background: var(--card-background);
524    border-radius: var(--tag-border-radius);
525    color: var(--card-text-color-tertiary);
526    margin-right: 0.1rem;
527    margin-top: 24px;
528    display: inline-flex;
529    align-items: center;
530    font-size: 1.4rem;
531    text-transform: uppercase;
532    padding: 10px 20px 10px 15px;
533    transition: box-shadow 0.3s ease;
534    box-shadow: var(--shadow-l3);
535  
536    &:hover {
537      box-shadow: var(--shadow-l2);
538    }
539  
540    svg {
541      margin-right: 5px;
542      width: 20px;
543      height: 20px;
544    }
545  
546    span {
547      font-weight: 500;
548      white-space: nowrap;
549    }
550  }
551  
552  .main-container .right-sidebar {
553    order: 2;
554    max-width: var(--right-sidebar-max-width);
555  
556    /// Display right sidebar when min-width: lg
557    @include respond(lg) {
558      display: flex;
559    }
560  }
561  
562  main.main {
563    order: 1;
564    min-width: 0;
565    max-width: 100%;
566    flex-grow: 1;
567    display: flex;
568    flex-direction: column;
569    gap: var(--section-separation);
570  
571    @include respond(md) {
572      padding-top: var(--main-top-padding);
573    }
574  }
575
576//----------------------------------------------------------
577//为代码块顶部添加macos样式
578.article-content {
579    .highlight:before {
580      content: "";
581      display: block;
582      background: url(/img/code-header.svg);
583      height: 32px;
584      width: 100%;
585      background-size: 57px;
586      background-repeat: no-repeat;
587      margin-bottom: 5px;
588      background-position: -1px 2px;
589    }
590  }
591
592.tagCloud {
593    .tagCloud-count {
594        color: var(--body-text-color);
595    }
596}
597
598.copyCodeButton {
599    border-radius: var(--category-border-radius);
600}
601
602code {
603    border-radius: var(--category-border-radius);
604}
605
606.article-category {
607  display: flex;
608  flex-wrap: wrap;
609  gap: 10px;
610
611  a {
612      background: var(--card-background);
613      box-shadow: var(--shadow-l1);
614      border-radius: var(--category-border-radius);
615      padding: 8px 20px;
616      color: var(--card-text-color-main);
617      font-size: 1.4rem;
618      transition: box-shadow 0.3s ease;
619
620      &:hover {
621          box-shadow: var(--shadow-l2);
622      }
623  }
624}
625
626/* Category widget */
627.category {
628  .category-label {
629      display: flex;
630      flex-wrap: wrap;
631      gap: 10px;
632
633      a {
634          border-left: 6px solid;
635          background: var(--card-background);
636          box-shadow: var(--shadow-l1);
637          border-radius: var(--category-border-radius);
638          padding: 12px 20px;
639          color: var(--card-text-color-main);
640          font-size: 1.5rem;
641          transition: box-shadow 0.3s ease;
642
643          &:hover {
644              box-shadow: var(--shadow-l2);
645          }
646      }
647  }
648  .category-count {
649      color: var(--body-text-color);
650  }
651}
652
653.running-time {
654  color: var(--card-text-color-secondary);
655  font-weight: normal;
656
657  .running-days {
658      font-weight:bold;
659      color: var(--emphasize-text-color);
660  }   
661}
662
663.totalcount {
664  color: var(--card-text-color-secondary);
665  font-weight: normal;
666  margin-bottom: 5px;
667  }
668
669code {
670  border-radius: var(--tag-border-radius);
671  font-size: 14px; // Add font size setting for code block
672  font-family: var(--code-font-family);
673}
674
675.article-subtitle {
676    margin-top: -5px;
677    font-size: 1.5rem;
678
679    @include respond(md) {
680        font-size: 1.6rem;
681    }
682}
683
684/*头像旋转动画*/
685.sidebar header .site-avatar .site-logo {
686  transition: transform 1.65s ease-in-out; //旋转时间
687
688}
689
690.sidebar header .site-avatar .site-logo:hover {
691  transform: rotate(360deg); //旋转角度为360度
692}
693
694/*社交菜单居中*/
695.social-menu svg {
696  gap: 15px;
697  justify-content: center;
698  width: 30px;
699  height: 25px; //社交菜单大小
700  stroke: var(--body-text-color);
701  stroke-width: 1.33;
702}
703
704/*页面加载动画部分*/
705#loading-box .loading-left-bg,
706#loading-box .loading-right-bg {
707    position: fixed;
708    z-index: 1000;
709    width: 50%;
710    height: 100%;
711    // 我在这里小改了一下颜色,
712    background-color: #b1c0c7;
713    transition: all 0.5s;
714}
715
716#loading-box .loading-right-bg {
717    right: 0;
718}
719
720#loading-box>.spinner-box {
721    position: fixed;
722    z-index: 1001;
723    display: flex;
724    justify-content: center;
725    align-items: center;
726    width: 100%;
727    height: 100vh;
728}
729
730#loading-box .spinner-box .configure-border-1 {
731    position: absolute;
732    padding: 3px;
733    width: 115px;
734    height: 115px;
735    background: #ffab91;
736    animation: configure-clockwise 3s ease-in-out 0s infinite alternate;
737}
738
739#loading-box .spinner-box .configure-border-2 {
740    left: -115px;
741    padding: 3px;
742    width: 115px;
743    height: 115px;
744    background: rgb(63, 249, 220);
745    transform: rotate(45deg);
746    animation: configure-xclockwise 3s ease-in-out 0s infinite alternate;
747}
748
749#loading-box .spinner-box .loading-word {
750    position: absolute;
751    color: #ffffff;
752    // 我在这里小改了一下文字大小和字体,注意!
753    font-size: 1.8rem;
754    font-family: 'Zhi Mang Xing', cursive;
755}
756
757#loading-box .spinner-box .configure-core {
758    width: 100%;
759    height: 100%;
760    background-color: #37474f;
761}
762
763div.loaded div.loading-left-bg {
764    transform: translate(-100%, 0);
765}
766
767div.loaded div.loading-right-bg {
768    transform: translate(100%, 0);
769}
770
771div.loaded div.spinner-box {
772    // 你可以把这个注释掉,这样就能一直看那个动画的效果了!
773    display: none !important;
774}
775
776@keyframes configure-clockwise {
777    0% {
778        transform: rotate(0);
779    }
780
781    25% {
782        transform: rotate(90deg);
783    }
784
785    50% {
786        transform: rotate(180deg);
787    }
788
789    75% {
790        transform: rotate(270deg);
791    }
792
793    100% {
794        transform: rotate(360deg);
795    }
796}
797
798@keyframes configure-xclockwise {
799    0% {
800        transform: rotate(45deg);
801    }
802
803    25% {
804        transform: rotate(-45deg);
805    }
806
807    50% {
808        transform: rotate(-135deg);
809    }
810
811    75% {
812        transform: rotate(-225deg);
813    }
814
815    100% {
816        transform: rotate(-315deg);
817    }
818}

动态纹理:蛛网、花瓣

蛛网特效在 /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,不然头像修改不成功)

1sidebar:
2  compact: false
3  emoji: 🍥
4  subtitle: 行者不必言深,孤独本是常态。
5  avatar:
6    enabled: true
7    local: true
8    src: /img/avatar.jpg

修改社交栏

依然是在主目录下的config.yaml文件进行修改,搜索social,需要添加一个社交按钮则仿照原来的添加如下代码:

1- identifier: github
2  name: GitHub
3  url: https://github.com/Bla1n
4  params:
5    newTab: true
6    icon: brand-github

icon图标存储目录为~/blog/themes/hugo-theme-stack/assets/icons

修改栏目

icon存储目录同上,但要修改栏目名称则需要前往/content/page目录

打开对应栏目文件夹,修改index.md文件

修改关于|about

头像旋转😵‍💫

在assets\scss\custom.scss路径下添加如下代码

 1/* 头像旋转 */
 2.home .home-profile .home-avatar img {
 3    width: 5rem;
 4
 5  /* 设置循环动画
 6  [animation: 
 7	(play)动画名称
 8	(2s)动画播放时长单位秒或微秒
 9	(ease-out)动画播放的速度曲线为以低速结束 
10	(1s)等待1秒然后开始动画
11	(1)动画播放次数(infinite为循环播放) ]*/
12 
13  /* 鼠标经过头像旋转360度 */
14  -webkit-transition: -webkit-transform 1.0s ease-out;
15  -moz-transition: -moz-transform 1.0s ease-out;
16  transition: transform 1.0s ease-out;
17    &:hover {
18      /* 鼠标经过停止头像旋转 
19      -webkit-animation-play-state:paused;
20      animation-play-state:paused;*/
21
22      /* 鼠标经过头像旋转360度 */
23      -webkit-transform: rotateZ(360deg);
24      -moz-transform: rotateZ(360deg);
25      transform: rotateZ(360deg);
26    }
27}

文章添加音乐

单首音乐效果如下

音乐列表效果如下

直接在文章中插入如下代码:

1单曲:(autoplay参数为是否自动播放音乐)
2{{< music server="netease" type="song" id="1372188635" autoplay="false" >}}
3列表:
4{{< music auto="https://music.163.com/playlist?id=6843891038">}}

修改底栏

博客运行时长

layouts/partials/footer/custom.html里添加以下JS代码,其中s1是网站创建日期。代码参考自这里 ,加上了小时和分钟的计算。

 1<!-- Add blog running time -->
 2<script>
 3    let s1 = '2023-3-18'; //website start date
 4    s1 = new Date(s1.replace(/-/g, "/"));
 5    let s2 = new Date();
 6    let timeDifference = s2.getTime() - s1.getTime();
 7
 8    let days = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
 9    let hours = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
10    let minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
11
12    let result = days + "天" + hours + "小时" + minutes + "分钟";
13    document.getElementById('runningdays').innerHTML = result;
14</script>

再在layouts/partials/footer/footer.html里添加以下代码:

1<!-- Add blog running time -->
2<section class="running-time">
3本博客已稳定运行
4<span id="runningdays" class="running-days"></span>
5</section>

assets/scss/partials/footer.scss里添加风格样式,这里单独把计时的部分加粗,并改了颜色。

1.running-time {
2    color: var(--card-text-color-secondary);
3    font-weight: normal;
4
5    .running-days {
6        font-weight:bold;
7        color: var(--emphasize-text-color);
8    }   
9}

上面的计时部分设置成var(--emphasize-text-color),这样能比较方便地在assets/scss/variables.scss里设置暗色模式的颜色

1    --accent-color-text: #fff;
2    --body-text-color: #b0b0b0;
3    --emphasize-text-color: #9e8f9f; // Add emphasize font color
4
5    &[data-scheme="dark"] {
6        --emphasize-text-color: #d5cfc4; // Add emphasize font color for dark scheme
7    }

文字统计

layouts/partials/footer/footer.html里增加以下代码,其中文章篇数统计参考了这篇 ,字数统计的展示方式参考了小球飞鱼的博客

1<!-- Add total page and word count time -->
2<section class="totalcount">
3    {{$scratch := newScratch}}
4    {{ range (where .Site.Pages "Kind" "page" )}}
5        {{$scratch.Add "total" .WordCount}}
6    {{ end }}
7    发表了{{ len (where .Site.RegularPages "Section" "post") }}篇文章 · 
8    总计{{ div ($scratch.Get "total") 1000.0 | lang.FormatNumber 2 }}k字
9</section>

assets/scss/partials/footer.scss里修改风格:

1.totalcount {
2    color: var(--card-text-color-secondary);
3    font-weight: normal;
4    margin-bottom: 5px;
5    }

返回顶部按钮

在阅读长文章时,如果想返回顶部没有快捷按钮则是很不方便的,所以添加此按钮

/layouts/partials/footer/custom.html里面添加如下代码

  1<!--返回顶部按钮 -->
  2<a href="#" id="back-to-top" title="返回顶部"></a>
  3
  4<!--返回顶部CSS -->
  5<style>
  6  #back-to-top {
  7    display: none;
  8    position: fixed;
  9    bottom: 20px;
 10    right: 55px;
 11    width: 55px;
 12    height: 55px;
 13    border-radius: 7px;
 14    background-color: rgba(64, 158, 255, 0.5);
 15    box-shadow: var(--shadow-l2);
 16    font-size: 30px;
 17    text-align: center;
 18    line-height: 50px;
 19    cursor: pointer;
 20  }
 21
 22  #back-to-top:before {
 23    content: ' ';
 24    display: inline-block;
 25    position: relative;
 26    top: 0;
 27    transform: rotate(135deg);
 28    height: 10px;
 29    width: 10px;
 30    border-width: 0 0 2px 2px;
 31    border-color: var(--back-to-top-color);
 32    border-style: solid;
 33  }
 34
 35  #back-to-top:hover:before {
 36    border-color: #2674e0;
 37  }
 38
 39  /* 在屏幕宽度小于 768 像素时,钮位置调整 */
 40  @media screen and (max-width: 768px) {
 41    #back-to-top {
 42      bottom: 20px;
 43      right: 20px;
 44      width: 40px;
 45      height: 40px;
 46      font-size: 10px;
 47    }
 48  }
 49
 50  /* 在屏幕宽度大于等于 1024 像素时,按钮位置调整 */
 51  @media screen and (min-width: 1024px) {
 52    #back-to-top {
 53      bottom: 20px;
 54      right: 40px;
 55    }
 56  }
 57
 58  /* 在屏幕宽度大于等于 1280 像素时,按钮位置调整 */
 59  @media screen and (min-width: 1280px) {
 60    #back-to-top {
 61      bottom: 20px;
 62      right: 55px;
 63    }
 64  }
 65
 66  /* 目录显示时,隐藏按钮 */
 67  @media screen and (min-width: 1536px) {
 68    #back-to-top {
 69      visibility: hidden;
 70    }
 71  }
 72</style>
 73
 74<!--返回顶部JS -->
 75<script>
 76  function backToTop() {
 77    document.documentElement.scrollIntoView({
 78      behavior: 'smooth',
 79    })
 80  }
 81
 82  window.onload = function () {
 83    let scrollTop =
 84      this.document.documentElement.scrollTop || this.document.body.scrollTop
 85    let totopBtn = this.document.getElementById('back-to-top')
 86    if (scrollTop > 0) {
 87      totopBtn.style.display = 'inline'
 88    } else {
 89      totopBtn.style.display = 'none'
 90    }
 91  }
 92
 93  window.onscroll = function () {
 94    let scrollTop =
 95      this.document.documentElement.scrollTop || this.document.body.scrollTop
 96    let totopBtn = this.document.getElementById('back-to-top')
 97    if (scrollTop < 200) {
 98      totopBtn.style.display = 'none'
 99    } else {
100      totopBtn.style.display = 'inline'
101      totopBtn.addEventListener('click', backToTop, false)
102    }
103  }
104</script>

layouts/partials/footer/components/script.html里可以修改按钮的颜色:

1#back-to-top {
2    background-color: var(--body-background);
3  }
4
5  #back-to-top:hover:before {
6    border-color: var(--accent-color);
7  }

去除归档页初始滤镜

具体可看此issue

/* */注释掉themes/hugo-theme-stack/assets/ts/main.ts中的

 1import { getColor } from 'ts/color'; 
 2
 3
 4
 5         const articleTile = document.querySelector('.article-list--tile'); 
 6         if (articleTile) { 
 7             let observer = new IntersectionObserver(async (entries, observer) => { 
 8                 entries.forEach(entry => { 
 9                     if (!entry.isIntersecting) return; 
10                     observer.unobserve(entry.target); 
11  
12                     const articles = entry.target.querySelectorAll('article.has-image'); 
13                     articles.forEach(async articles => { 
14                         const image = articles.querySelector('img'), 
15                             imageURL = image.src, 
16                             key = image.getAttribute('data-key'), 
17                             hash = image.getAttribute('data-hash'), 
18                             articleDetails: HTMLDivElement = articles.querySelector('.article-details'); 
19  
20                         const colors = await getColor(key, hash, imageURL); 
21  
22                         articleDetails.style.background = ` 
23                         linear-gradient(0deg,  
24                             rgba(${colors.DarkMuted.rgb[0]}, ${colors.DarkMuted.rgb[1]}, ${colors.DarkMuted.rgb[2]}, 0.5) 0%,  
25                             rgba(${colors.Vibrant.rgb[0]}, ${colors.Vibrant.rgb[1]}, ${colors.Vibrant.rgb[2]}, 0.75) 100%)`; 
26                     }) 
27                 }) 
28             }); 
29  
30             observer.observe(articleTile) 
31         } 

以及themes/hugo-theme-stack/layouts/partials/footer/components/script.html中的

1{{- partial "helper/external" (dict "Context" . "Namespace" "Vibrant") -}} 

添加相册功能

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

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

    1title: 相册 | photos
    2layout: "photos"
    3slug: "photos"
    4menu:
    5    main: 
    6        weight: -50
    7        params:
    8            icon: photos
    9comments: false
    
  3. 创建/layouts/_default/photos.html

      1{{ define "main" }}
      2<div class="button-group">
      3    <button class="filter-button" data-category="-">&nbsp;All&nbsp;</button>
      4    <button class="filter-button" data-category="日常">#日常</button>
      5    <button class="filter-button" data-category="风景">#风景</button>
      6    <button class="filter-button" data-category="狗哥">#狗哥</button>
      7    <button class="filter-button" data-category="赛">#赛</button>
      8</div>
      9<div class="gallery-photos page">
     10  {{ range (sort (readDir "./static/photos") "Name" "desc")}}
     11    {{ if ( .Name | findRE "\\.(gif|jpg|jpeg|tiff|png|bmp|webp|avif|jxl)") }}
     12    <div class="gallery-photo">
     13      <img class="photo-img" loading='lazy' decoding="async" src="/photos/{{ .Name }}" alt="{{ .Name }}" />
     14      <span class="photo-title">{{ .Name | replaceRE "^[0-9 -]+(.*)[.].*" "$1"}}</span><span class="photo-time">{{ .Name | replaceRE "^([0-9-]+).*[.].*" "$1" }}</span>
     15    </div>
     16    {{ end }}
     17  {{ end }}
     18</div>
     19
     20<style>
     21.gallery-photos{width:100%;}
     22.gallery-photo{width:24.9%;position: relative;visibility: hidden;overflow: hidden;}
     23.gallery-photo.visible{visibility: visible;animation: fadeIn 2s;}
     24.gallery-photo img{
     25    display: block;
     26    width:100%;
     27    border-radius:20px;
     28    padding:4px;
     29    animation: fadeIn 1s;
     30    cursor: pointer;
     31    transition: all .4s ease-in-out;
     32}
     33.gallery-photo span.photo-title,.gallery-photo span.photo-time{
     34    background: rgba(0, 0, 0, 0.3);
     35    padding:0px 8px;
     36    font-size:0.9rem;
     37    color: #fff;
     38    display:none;
     39    animation: fadeIn 1s;
     40}
     41.gallery-photo span.photo-title{
     42    position:absolute;
     43    bottom:4px;
     44    left:4px;
     45    border-radius:10px;
     46    background-color: #a3dfff;
     47    color: #000000;
     48    font-size:1.2rem
     49}
     50.gallery-photo span.photo-time{position:absolute;top:4px;left:4px;font-size:0.8rem;}
     51.gallery-photo:hover span.photo-title{display:block;}
     52.gallery-photo:hover img{transform: scale(1.1);}
     53.button-group {
     54                display: flex;
     55                flex-direction: row;
     56                gap: 18px;
     57                justify-content: center;
     58            }
     59            .filter-button {
     60                padding: 8px 8px;
     61                width: auto;
     62                background-color: var(--card-background);
     63                color: #57bd8f;
     64                border: none;
     65                border-radius: 5px;
     66                cursor: pointer;
     67                transition: background-color 0.3s ease;
     68            }
     69            .filter-button:hover {
     70                color: #5e88f7;
     71            }
     72            .selected-button {
     73                background-color: #CCE8CF;
     74                color: #000000;
     75                /* 选中项的颜色 */
     76            }
     77@media screen and (max-width: 1280px) {
     78	.gallery-photo{width:33.3%;}
     79}
     80@media screen and (max-width: 860px) {
     81	.gallery-photo{width:49.9%;}
     82}
     83@media (max-width: 683px){
     84	.photo-time{display: none;}
     85}
     86@keyframes fadeIn{
     87	0% {opacity: 0;}
     88   100% {opacity: 1;}
     89}
     90</style>
     91<script src="https://immmmm.com/waterfall.min.js"></script>
     92<script src="https://immmmm.com/imgStatus.min.js"></script>
     93<script>
     94document.addEventListener('DOMContentLoaded', () => {
     95    imgStatus.watch('.photo-img', function(imgs) {
     96      if(imgs.isDone()){
     97        waterfall('.gallery-photos');
     98        let pagePhoto = document.querySelectorAll('.gallery-photo');
     99        for(var i=0;i < pagePhoto.length;i++){pagePhoto[i].className += " visible"};
    100      }
    101    });
    102    window.addEventListener('resize', function () {
    103      waterfall('.gallery-photos');
    104    });
    105});
    106</script>
    107<script src="https://immmmm.com/view-image.js"></script>
    108<script src="https://immmmm.com/lately.min.js"></script>
    109<script>
    110  window.Lately && Lately.init({ target: '.photo-time'});
    111  window.ViewImage && ViewImage.init('.gallery-photo img')
    112</script>
    113<script>
    114    document.addEventListener('DOMContentLoaded', () => {
    115    const filterButtons = document.querySelectorAll('.filter-button');
    116    const galleryPhotos = document.querySelectorAll('.gallery-photo');
    117    filterButtons.forEach(button => {
    118        button.addEventListener('click', () => {
    119            const category = button.getAttribute('data-category');
    120            // 隐藏所有照片
    121            galleryPhotos.forEach(photo => {
    122                photo.style.visibility = 'hidden';
    123            });
    124            // 显示符合特定词语的照片
    125            galleryPhotos.forEach(photo => {
    126                const imageName = photo.querySelector('.photo-img').getAttribute('alt');
    127                if (imageName.includes(category)) {
    128                    photo.style.visibility = 'visible';
    129                }
    130            });
    131            // 移除所有按钮的选中状态
    132            filterButtons.forEach(btn => {
    133                btn.classList.remove('selected-button');
    134            });
    135            // 将当前点击的按钮标记为选中状态
    136            button.classList.add('selected-button');
    137        });
    138    });
    139});
    140</script>
    141{{ end }}
    

    这段代码同时添加了分类功能,只需在图片文件名中含有相应关键字即可分类

添加右下角联系小气泡按钮

效果图为:

私信气泡

请参考这两篇文章,两位博主写的非常详细,不难配置,在此不在赘述(懒了,hhh)

私信联系气泡 山茶花舍

参考文章

Stack主题的自定义

Hugo Stack主题装修笔记

Hugo Stack 主题配置与使用

Hugo Stack主题更新小记

Hugo|自定义 hugo-theme-Stack

创建单页相册

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

shortcode使用

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