*08.13更新:实装DLC内容。*

DlC更新公告

8.9
装修博客。

8.10
装修博客。

8.11
爱海啊爱海,你怎么能如此堕落!先前订下的学习计划和摸鱼计划你都忘了吗?子曰:“吾日三省吾身。”不能再这样下去了!

8.12
装修博客。

声明:小狗不会写代码,小狗只是代码的搬运工

一道代码盲的真理

遇事不决,问ChatGPT!

此次博客装修,ChatGPT稳坐首席顾问之位,我让它帮我解释代码含义,拼合新代码和旧代码,提出修改方案,检查代码错误。可以说,没有ChatGPT,就没有这次博客装修。ChatGPT,笨蛋小狗最好的陪伴式代码输出傻瓜机,值得拥有!

还要感谢塔老师的博客,我的大部分装修代码都是在塔老师的装修记录里直接copy现成的经验。塔老师,永远的神!!!!!

layouts\partials\header.html中加入logo元素和div遮罩层。

 <div class="logo-container">
    <img src="url" alt="Logo" class="logo-image"> <!-- url替换为logo图片的绝对路径 -->
    <div class="logo-overlay"></div>
</div>

为了控制图片的大小和位置,需要在自定义css中找个地方贴这段代码定义logo-container

.logo-container {
    float: left; /* 将logo图片浮动到最左边 */
    margin-right: 20px; /* 添加一些右边距,用于与标题分隔开 */
}

.logo-container img {
    width: 100px; /* 设置logo图片的宽度 */
    height: auto; /* 保持图片高度自适应 */
    transition: transform 0.3s;
}

logo小动画

顺便就找了一个简单的logo小动画代码套了上去,也是在css里定义之前在header.html里写的logo-overlay

.logo-container:hover .logo-image {
    animation: shake 1s alternate infinite; /* 无限循环播放 shake 动画,交替执行 */
}

@keyframes shake {
    from {
        transform: rotate(-10deg); /* 左晃动效果 */
    }
    to {
        transform: rotate(10deg); /* 右晃动效果 */
    }
}

鼠标悬停在logo动画上时小狗会持续晃动,非常可爱!

页尾注释修改

layouts\partials\header.html内修改,经由ChatGPT的一番指点,很不厚道地把主题默认的信息全删了。

博客运行时间统计

这个问了ChatGPT,一开始它给出的方案需要在toml配置里定义,我觉得对我来说太复杂了,就问有没有直接内嵌到里面的方法,于是得到了这样一串代码。

<span>| <span id="days">0</span> Days</span>
<script>
    var s1 = '2022-08-15'; // 设置为建站时间
    s1 = new Date(s1.replace(/-/g, "/"));
    s2 = new Date();
    var days = Math.floor((s2 - s1) / (1000 * 60 * 60 * 24));
    document.getElementById('days').innerHTML = days;
</script>

设置一下建站时间就可以直接显示出天数,很方便。

博客总字数统计

抄了塔老师的神仙代码,改了一下显示方式,并让其只统计post 分类下的文字。

{{$scratch := newScratch}}
{{ range where .Site.Pages "Kind" "page" }} 
  {{ if eq .Type "post" }} <!-- 仅统计博文页面 -->
    {{$scratch.Add "total" .WordCount}}
  {{ end }}
{{ end }} 
                            
口袋里共有{{ div ($scratch.Get "total") 1000.0 | lang.FormatNumber 1 }}k字

修改博客背景

原来博客主题的日间模式下背景是白色的,看着总觉得像Wordpress里没装修好的半成品。修改方法主题说明手册就有写,在自定义css里随便找个地方加一条:

$light-color-bg: #ECEFF4; 

总感觉是在加护眼模式呢ww

给博客下点糖果雨

用的是塔老师修改过后的Mengru老师的代码,首先在static/js里新建一个js文件,把下面的代码贴进去。

;(function () {
    const Config = {
       snow: ['🧊', '🍭', '🍧', '🍮', '🍸', '💊', ], // 雪花的样式,可以放不同的雪花,或者任何 emoji,每次生成新雪花时会随机挑选其中一个
        speed: 10, // 雪花从生成到落到最底端所经历的时间,单位是秒。数字越小落得越快
        dom: document.getElementsByTagName('body')[0], // 下雪的区域,可以保持不变,这样就是全屏下雪
        interval: 800 // 生成一片雪花的时间间隔,单位是毫秒
    }
    if (!Config.dom) {
        throw Error('错误提示')
    }
    const $canvas = document.createElement('div')

    useStyle($canvas, {
        width: '100%',
        height: '100%',
        position: 'fixed',
        top: 0,
        left: 0,
        pointerEvents: 'none',
        zIndex: 100
    })

    setInterval(() => {
        const $snow = document.createElement('div')
        $snow.innerText = Config.snow[rand(0, Config.snow.length - 1)]
        useStyle($snow, {
            display: 'inline-block',
            color: Config.color,
            fontSize: rand(20, 30) + 'px',
            position: 'absolute',
            top: 0,
            left: rand(0, 100) + '%',
            transition: 'transform ' + Config.speed + 's linear' + ',opacity ' + Config.speed + 's linear',
            transform: 'translateY(-100%)',
            opacity: Math.random() + 0.3
        })
        setTimeout(() => {
            useStyle($snow, {
                transform: 'translate(0, ' + getComputedStyle($canvas).height + ') rotate(480deg)',
                opacity: 0
            })
            $snow.addEventListener('transitionend', () => {
                $snow.remove()
            })
        }, 100)
        $canvas.appendChild($snow)
    }, Config.interval)

    function rand (from, to) {
        return from + Math.floor(Math.random() * (to - from + 1))
    }
    function useStyle (dom, style) {
        for (let sKey in style) {
            dom.style[sKey] = style[sKey]
        }
    }

    Config.dom.appendChild($canvas)
})()

随后在layouts\partials\header.html里的……呃……前面一点的部分(啊?)……嗯……引用?

<script src="/js/xxx.js"></script>

嗯嗯,实现博客甜点和药物自由!不过我在火狐浏览器上测试时发现如果把页面最小化并放置一会,再回来点开时这些emoji会堆成一条直线齐齐掉下来,像小时候玩的游戏机,还挺有趣的!

鼠标样式修改

一直很想修改鼠标样式,起先找到的代码放进去跑没有反应,后来经过无数次找新代码,问ChatGPT,复制黏贴测试的繁琐笨办法,我终于在博客上安装好了小豆泥鼠标指针,鼠标移动到图片或者链接上,可以看到超绝可爱的两眼放光小豆泥

首先下载一个自己喜欢的鼠标样式包,然后用网站把cur格式转换成png或者ico,扔到你喜欢的地方,图床或者本地文件都可以,然后到自定义css里加入代码。

body {
    cursor: url(指针文件路径), default; /* 默认鼠标指针样式 */
}

a:hover{
    cursor:url(指针文件路径), pointer; /* 链接鼠标指针样式 */
}

简单来说,第一个是修改默认状态下的指针,第二个是修改手型光标指针,这是最基础的,也是大部分教程都会给出的两个鼠标指针样式的修改。推到vercel上跑一下,博客就会显示出新的鼠标样式。但很快我就发现了新的问题,鼠标悬停在博客的搜索块、代码复制键和图片上时,依旧是系统默认的光标。我研究了好一会解决方案,最后姑且是成功了,只不过这个方法有点迂回,类似解一道有多种解法的数学题,我选择的是最没有因果逻辑,但依旧能得出正确答案的方法。

我的思路是在你需要修改样式的地方右键,选择检查,然后就会出现这个区块的网页源码。

检查

可以看出这个区块的属性是button,接下来我们只要在自定义css里写入:

button{
    cursor:url(指针文件路径), pointer; /* 按钮鼠标指针样式 */
}

这样,博客按钮就成功被小豆泥占领啦!按照这种方法,我先后修改了divimgsummaryspanpreinput的等鼠标样式,大体上做到了博客表面的小豆泥指针全覆盖,剩下一些细枝末节的有心情再研究吧。

鼠标选择文字颜色修改

在自定义css文件里添加:

::selection {
    color: #fff;
    background: #34495e;
}

电脑上文字反选就会变成黑色,正式告别时代window蓝(那是什么)

鼠标点击烟花特效

这个特效作者的原帖已经找不到了,从使用这个特效的博客的三年前的评论区里翻了出来,还是在static/js里新建一个js文件复制代码。

class Circle {
    constructor({ origin, speed, color, angle, context }) {
      this.origin = origin
      this.position = { ...this.origin }
      this.color = color
      this.speed = speed
      this.angle = angle
      this.context = context
      this.renderCount = 0
    }
  
    draw() {
      this.context.fillStyle = this.color
      this.context.beginPath()
      this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2)
      this.context.fill()
    }
  
    move() {
      this.position.x = (Math.sin(this.angle) * this.speed) + this.position.x
      this.position.y = (Math.cos(this.angle) * this.speed) + this.position.y + (this.renderCount * 0.3)
      this.renderCount++
    }
  }
  
  class Boom {
    constructor ({ origin, context, circleCount = 10, area }) {
      this.origin = origin
      this.context = context
      this.circleCount = circleCount
      this.area = area
      this.stop = false
      this.circles = []
    }
  
    randomArray(range) {
      const length = range.length
      const randomIndex = Math.floor(length * Math.random())
      return range[randomIndex]
    }
  
    randomColor() {
      const range = ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
      return '#' + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range)
    }
  
    randomRange(start, end) {
      return (end - start) * Math.random() + start
    }
  
    init() {
      for(let i = 0; i < this.circleCount; i++) {
        const circle = new Circle({
          context: this.context,
          origin: this.origin,
          color: this.randomColor(),
          angle: this.randomRange(Math.PI - 1, Math.PI + 1),
          speed: this.randomRange(1, 6)
        })
        this.circles.push(circle)
      }
    }
  
    move() {
      this.circles.forEach((circle, index) => {
        if (circle.position.x > this.area.width || circle.position.y > this.area.height) {
          return this.circles.splice(index, 1)
        }
        circle.move()
      })
      if (this.circles.length == 0) {
        this.stop = true
      }
    }
  
    draw() {
      this.circles.forEach(circle => circle.draw())
    }
  }
  
  class CursorSpecialEffects {
    constructor() {
      this.computerCanvas = document.createElement('canvas')
      this.renderCanvas = document.createElement('canvas')
  
      this.computerContext = this.computerCanvas.getContext('2d')
      this.renderContext = this.renderCanvas.getContext('2d')
  
      this.globalWidth = window.innerWidth
      this.globalHeight = window.innerHeight
  
      this.booms = []
      this.running = false
    }
  
    handleMouseDown(e) {
      const boom = new Boom({
        origin: { x: e.clientX, y: e.clientY },
        context: this.computerContext,
        area: {
          width: this.globalWidth,
          height: this.globalHeight
        }
      })
      boom.init()
      this.booms.push(boom)
      this.running || this.run()
    }
  
    handlePageHide() {
      this.booms = []
      this.running = false
    }
  
    init() {
      const style = this.renderCanvas.style
      style.position = 'fixed'
      style.top = style.left = 0
      style.zIndex = '999999999999999999999999999999999999999999'
      style.pointerEvents = 'none'
  
      style.width = this.renderCanvas.width = this.computerCanvas.width = this.globalWidth
      style.height = this.renderCanvas.height = this.computerCanvas.height = this.globalHeight
  
      document.body.append(this.renderCanvas)
  
      window.addEventListener('mousedown', this.handleMouseDown.bind(this))
      window.addEventListener('pagehide', this.handlePageHide.bind(this))
    }
  
    run() {
      this.running = true
      if (this.booms.length == 0) {
        return this.running = false
      }
  
      requestAnimationFrame(this.run.bind(this))
  
      this.computerContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
      this.renderContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
  
      this.booms.forEach((boom, index) => {
        if (boom.stop) {
          return this.booms.splice(index, 1)
        }
        boom.move()
        boom.draw()
      })
      this.renderContext.drawImage(this.computerCanvas, 0, 0, this.globalWidth, this.globalHeight)
    }
  }
  
  const cursorSpecialEffects = new CursorSpecialEffects()
  cursorSpecialEffects.init()

然后就是在footer.html里引入。

<script src="/js/xxx.js"></script>

我很喜欢这个烟花特效,像猫猫撒彩色糖粒。

代码块自定义

这个部分是因为想着要写这篇装修记录而修改的。

代码块高度限制

主题默认的代码块代码多长它就多长,不限制一下高度的话很影响文章阅读,我翻遍fuji的主题文件夹,最终在assets\scss\_fuji-theme\_style.scss里找到了设置代码块样式的代码,之后只要在里面添加:

pre[class*='language-'] {
  max-height: 300px; /* 设置最大高度 */
  overflow: auto; /* 添加滚动条,以处理溢出内容 */
}

不得不说,有滚轮的代码块真高级啊!(无端感慨

添加copy按钮

加了滚动条,代码复制就不方便了,copy按钮的需求迫在眉睫。一开始问ChatGPT,给出来的方案换了几番,但全要在文章里单独设置,学不会。只得google求助,最后找来了Typecho教程的代码,虽然不知道为什么是Typecho,不过能用就行。

嗯嗯,依旧是在static/js里新建一个js文件复制下面的代码。

var codeblocks = document.getElementsByTagName("pre")
//循环每个pre代码块,并添加 复制代码

for (var i = 0; i < codeblocks.length; i++) {
//显示 复制代码 按钮
currentCode = codeblocks[i]
currentCode.style = "position: relative;"
var copy = document.createElement("div")
copy.style = "position: absolute;right: 4px;\
top: 4px;background-color: white;padding: 2px 8px;\
margin: 8px;border-radius: 4px;cursor: pointer;\
z-index: 9999;\
box-shadow: 0 2px 4px rgba(0,0,0,0.05), 0 2px 4px rgba(0,0,0,0.05);"
copy.innerHTML = "Copy"
currentCode.appendChild(copy)
//让所有 "复制"按钮 全部隐藏
copy.style.visibility = "hidden"
}

for (var i = 0; i < codeblocks.length; i++) {

!function (i) {
    //鼠标移到代码块,就显示按钮
    codeblocks[i].onmouseover = function () {
        codeblocks[i].childNodes[1].style.visibility = "visible"
    }

    //执行 复制代码 功能
    function copyArticle(event) {
        const range = document.createRange();

        //范围是 code,不包括刚才创建的div
        range.selectNode(codeblocks[i].childNodes[0]);

        const selection = window.getSelection();
        if (selection.rangeCount > 0) selection.removeAllRanges();
        selection.addRange(range);
        document.execCommand('copy');

        codeblocks[i].childNodes[1].innerHTML = "Copied!"
        setTimeout(function () {
            codeblocks[i].childNodes[1].innerHTML = "ReCopy"
        }, 1000);
        //清除选择区
        if (selection.rangeCount > 0) selection.removeAllRanges(); 0
    }
    codeblocks[i].childNodes[1].addEventListener('click', copyArticle, false);

}(i);

!function (i) {
    //鼠标从代码块移开 则不显示复制代码按钮
    codeblocks[i].onmouseout = function () {
        codeblocks[i].childNodes[1].style.visibility = "hidden"
    }
}(i);
}

惯例footer.html引用!嗯,为什么都是footer.html呢?因为我的主题只有这个!(?

<script src="/js/xxx.js"></script>

图片轮播

手把手按照塔老师的教程做的,很成功,用几张我的宝贝母肥演示一下,鼠标滚轮就可以切换!

因为母肥太完美了所以又加了五张(草

盘古之白

参考这里,可以让中英文之间自动加空格。继续在footer.html里加代码。

<script>
(function(u, c) {
  var d = document, t = 'script', o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
  o.src = u;
  if (c) { o.addEventListener('load', function(e) { c(e); }); }
  s.parentNode.insertBefore(o, s);
})('//cdn.bootcss.com/pangu/3.3.0/pangu.min.js', function() {
  pangu.spacingPage();
});
</script>

邮箱订阅页面

2024.01.11更新:tinyletter已关闭服务

tinyletter做了一个邮箱订阅博客的页面,不过需要手动发送邮件,如果真的有人订阅的话,我会努力记得发送更新通知的!

订阅中转站

tinyletter还提供了内嵌订阅的代码,有小玩具箱的即视感。

powered by TinyLetter

DLC1-umami统计

2024.03.03更新:已停止使用

不喜欢在博客里放浏览量统计和访问量统计,毕竟目前我的博客绝大多数访问量都来源于我自己反复装修和调试,没有实际意义。看到很多友的博客都使用了umami统计,便也寻思着自己整一个。零成本搭建工具是vercelSupabase,整个过程参考了少数派的文章和塔老师博客里的一些Tips。或许是umami版本升级的原因,我搭建时已经可以跳过导入sql文件,直接在vercel上部署DATABASE_URLHASH_SALT这两个环境变量,等待vercel跑好后,修改自定义子域名,登录,添加网站,将追踪链接copy到/layouts\partials\head.html上,再刷新几下系统就会自动开始统计。UI可以调成中文,这个轻量简洁的界面真的非常完美!

unami

DLC2-Waline评论区实装

之前博客用的评论框架是主题支持的disqus,虽然配置起来很快,但这个评论系统需要梯子才能访问,使用起来也挺麻烦。寻寻觅觅,意识到目前似乎只有waline评论系统能兼具美观,安全与实用性,遂立即着手开始研究如何在自己的博客上配置,途中遇到了不少难以描述的问题,不过基本都用更不可描述(?)的方法解决了!

本dlc内容根据以下资料学习生成:

配置waline

我的博客使用的主题fuji没有配置waline,一切都得自己动手从头开始。首先按照官方文档,在vercel上配置好自己的waline服务端,然后在\layouts\partials目录下新建一个comment-waline.html,把官方文档提供的代码复制进去。

<head>
  <!-- ... -->
  <link
    rel="stylesheet"
    href="https://unpkg.com/@waline/client@v2/dist/waline.css"
  />
  <!-- ... -->
</head>
<body>
  <!-- ... -->
  <div id="waline"></div>
  <script type="module">
    import { init } from 'https://unpkg.com/@waline/client@v2/dist/waline.mjs';

    init({
      el: '#waline',
      serverURL: 'https://your-domain.vercel.app',
    });
  </script>
</body>    

之后我们需要在博客模板页面渲染这个html文件,打开layouts\_default\single.html,可以看到我的主题中关于评论渲染方面的短代码。

{{ if and (.Site.Params.disqusJSApi) (ne .Params.showComments false) }}
{{ partial "comment-disqusjs.html" . }}
{{ else if and (.Site.Params.disqusShortname) (ne .Params.showComments false) }}
{{ partial "comment-disqus.html" . }}
{{ else if and (ne .Params.showComments false) }}  /*条件状语(?)在文章未关闭评论下执行*/
{{ partial "comment-waline.html" . }}  /*渲染waline*/
{{ else }}{{ end }}

我图省事,只是将最后一个else前面的else if和它的变量改了一下,最后推送到vercel,部署完毕后刷新,就可以看到全新的waline的评论区了。

自定义waline

前端配置

参考waline文档的客户端条目前端配置部分,除了必填项elserverURL,其它挑选你想修改的填进去就行,我的前端配置代码是这样的:

<script type="module">
    import { init } from 'https://unpkg.com/@waline/client@v2/dist/waline.mjs';
init({
 el: '#waline',
 serverURL: '',
 dark: 'body[data-theme="dark"]',
 requiredMeta: ['nick', 'mail'],
 search: false,
 locale: {
   placeholder: '冒险者,请写下你想说的话吧!(填写邮箱的话可以收到我们的回复报告库啵)'
   },
  avatar: 'retro',
});
</script>

值得一提的是这个暗黑模式开启设置dark,一开始我输入的是auto,理所当然地没反应。然而官方文档第二种开启模式的说明我没怎么懂,折腾了一个多小时,最后还是靠万能的右键检查解决了。首先找到我的博客里切换黑夜模式的按钮,开查。

黑夜模式按钮

可以看到按钮切换相关代码对应开启暗黑模式的配色启动指令是body[data-theme="dark"],把这串字符填进去,评论区的主题颜色就会跟着主题模式切换了(整这玩意整到了凌晨一点半我大脑发光

分隔线

html文件最前面加上<hr />,以便划分正文和评论区的领地。

颜色样式修改

waline默认样式的主题色实在有点一言难尽,可以在html文件head部分添加style模块来修改颜色样式。

<style>

 :root {
 --waline-theme-color: #34495e; /*主题色,提交按钮*/
 --waline-active-color: #bababa; /*鼠标移到提交按钮上的颜色*/
 --waline-badge-color: #34495e; /*博主徽章色*/
 --waline-dark-grey: #34495e; /*ID颜色*/
 --waline-bgcolor: #f0f8ff;
 --waline-bgcolor-light: #e9f3fb;
 --waline-border-color: #3f4551;        
  }

/*夜间模式*/
  :root[data-scheme="dark"] {
  --waline-theme-color: #acc6e0;
  --waline-white: #34495e; /*按键字体颜色*/
  --waline-active-color: #8ab1d8;
  --waline-light-grey: #666;
  --waline-dark-grey: #acc6e0; /*ID颜色*/
  --waline-badge-color: #acc6e0;
  /* 布局颜色 */
  --waline-text-color: rgba(255, 255, 255, 0.7);
  --waline-bgcolor: #515151;
  --waline-bgcolor-light: #66696b; /*行内代码块颜色*/
  --waline-border-color: #9b9c9c;
  --waline-disable-bgcolor: #444;
  --waline-disable-color: #272727; 

  /* 特殊颜色 */
  --waline-bq-color: #9b9c9c; /*quote*/

  /* 其他颜色 */
  --waline-info-bgcolor: #acc6e0;
  --waline-info-color: #9b9c9c;
  }
</style>

自定义表情包

添加了小豆泥blobmenhera 酱表情包,特别好!感谢妈咪们的上传!

表情包

安装表情包只需在init里前端配置的地方加上:

 emoji: [
 '表情包链接',
],

表情包链接顺序会决定评论区表情包分类的显示顺序。

修改表情包尺寸

这么可爱的表情包当然要放大显示,在自定义css里添加。

body {
    .wl-content .vemoji, .wl-content .wl-emoji {
        display: inline-block;
        vertical-align: baseline;
        height: 2.35em; //表情包大小
        margin: -0.125em 0.25em;
    }
}

然后在html文件的head部分中引入自定义css路径。

<link
 rel="stylesheet"
 href="assets/scss/_custom_var.scss"
/>

评论邮件通知

参照官方文档,在vercel设置相关的环境变量,保存后重新部署。我注册了一个单独的163邮箱来发送邮件。这样,不管访客是否登录,只要在信息一栏写下邮箱,就可以及时收到回复通知了。忘了检查评论箱子错过回复时间的悲剧轮回,在此刻斩断!

一些碎碎念

waline唯一的遗憾是我研究半天也无法做到小豆泥鼠标指针在评论界面的全覆盖,没办法,美丽总是有代价的(?)。如果您想知道改完后我的博客的评论区是什么样的话,下拉到最底部就可以啦!

对了waline服务端后台还可以给登录的用户设置专属头衔,如果有的友需要的话可以找我!(揣手手

DLC3-首页文章卡预览由Summary改为Description

fuji主题卡片的预览默认是文章前面的部分,写新的摸鱼排版上不太方便(问就是被NotionNext惯坏了),遂杀到layouts\_default\list.html里修改了显示代码。

    <div class="post-item post-summary markdown-body">
        {{ .Description}}
    </div>

这样首页的文章卡就只会显示描述的文字,美观了不少。

收工!freetalk

这次装修成果可以说算是伏怒山猪突飞猛进,我的博客一下子坐拥小狗小猫小烟花和小甜点,变成了我都不太认识的模样。每次点进我的博客就像点进一个自己缝缝补补的玩具箱子,可以在里面摆弄那些自己涂色的小模型玩上好久的过家家。

如果还有第三次装修,大概会修改一些系统文字,美化一下侧栏,或许还会换一个字体吧。不过这都是后话了,我得先赶紧写完这个日志,免得我又手痒开始装修了(结果还是装了甚至装出了dlc