Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。

准备工作

基本环境

  1. NodeJS
  2. Git
  3. Hexo 框架

创建Github仓库

  1. 格式必须为:<用户名>.github.io,然后点击 Create repository
  2. 生成 SSHKeys
    1. 检查SSH keys是否存在
      1
      2
      ls -al ~/.ssh
      # Lists the files in your .ssh directory, if they exist
    2. 生成新的ssh key
      1
      2
      ssh-keygen -t rsa -C "your_email@example.com"
      #生成完成后在 C:\Users\用户名\.ssh 目录下
    3. 将ssh key添加到GitHub中
      1. 文本编辑器打开id_rsa.pub文件复制内容
      2. Github —> Settings —> SH and GPG keys —> New SSH key (Title 随意取,将内容粘贴到 Key文本框) —> Add SSH key
    4. 测试ssh是否绑定成功:
      1
      ssh -T git@github.com

      Hexo 初始化

  3. 安装Hexo(如已安装可跳过此步骤)
    1
    2
    3
    4
    5
    npm install -g hexo-cli
    ``2. 初始化

    ```shell
    hexo init
  4. 初始化完成之后,打开 _config.yml 文件,添加以下配置信息
    1
    2
    3
    4
    5
    deploy:
    type: git
    repository: https://github.com/HaloBoys/HaloBoys.github.io.git
    # github 更新之后仓库默认分支为 main
    branch: main
  5. 打开本地博客目录安装hexo-deployer-git自动部署发布工具
    1
    npm install hexo-deployer-git --save
  6. 本地编写完博客之后输入命令:hexo g 将md 文件转换为html文件
    然后输入命令:hexo d 部署页面到远程仓库,会弹出提示框要求填写用户名和 token 令牌
    Token 令牌获取路径:Settings —> Developer settings —> Personal access tokens —> Generate new token

Hexo 主题 (Butterfly)

https://github.com/jerryc127/hexo-theme-butterfly [butterfly官方文档]

功能配置

评论功能:

Gitalk

Gitalk 是一个基于 GitHub Issue 和 Preact 开发的评论插件。

  1. 在github上创建一个仓库,Gitalk会把评论放在这个仓库的issues里面。
    20220510184112
  2. 在github上申请一个GitHub OAuth application,来让Gitalk有权限操作github上的仓库。详情GitHub 应用文档
  • 打开github网站登陆后,点击右上角Settings —> Developer settings —> OAuth Apps —> New OAuth App
    20220510184615
参数 描述
Application name 【必填】OAuth的名字
Homepage URL 【必填】应用的网址,哪个网站用了Gitalk组件,就填写这个网址
Application description 【选填】该OAuth的说明
Authorization callback URL 【必填】授权成功后回调网址,跟Homepage URL参数保持一致就好
  • 注册成功后会自动跳转到这个OAuth应用的页面,或在Developer settings —> OAuth Apps后就能看见你创建的OAuth应用名字,新创建的OAuth应用里面的Client IDClient Secret就是我们需要的参数。
    20220510185258
  • 进入主题Hexo 主题配置文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # gitalk
    # https://github.com/gitalk/gitalk
    gitalk:
    client_id:
    client_secret:
    repo:
    # 仓库的创建者
    owner:
    # 如果仓库有多个人可以操作,那么在这里以数组形式写出
    admin:
    option:

    Twikoo

    Twikoo 是一个简洁、安全、无后端的静态网站评论系统,基于腾讯云开发。

在线聊天

Chatra

  1. https://chatra.com/cn/ [chatra] 直接注册账号,然后在这里将key 复制到主题_config配置文件中
    image-20220427162100013
  2. 修改主题_config配置文件
    1
    2
    3
    4
    5
    # chatra
    # https://chatra.io/
    chatra:
    enable: true
    id: xxxxxxx // Public key
  3. Chatra 手机/电脑 App 下载
    image-20220427162608710

分享功能

  1. https://github.com/overtrue/share.js/ [Share.js]
  2. https://www.addtoany.com/ [一个第三方分享服务]
  3. https://www.addthis.com/ [一个第三方分享服务]

网站搜索系统

  1. https://github.com/thom4parisot/hexo-algolia
  2. localsearch
  3. 安装 hexo-generator-search,根据官方文档去做相应配置
  4. 修改主题配置文件
    1
    2
    3
    4
    local_search:
    enable: false
    preload: false
    CDN:
参数 功能
enable 是否开启本地搜索
preload 预加载,开启后,进入网页后会自动加载搜索文件。关闭时,只有点击搜索按钮后,才会加载搜索文件
CDN 搜索文件的 CDN 地址(默认使用的本地链接)

文章加密

开源地址 https://github.com/D0n9X1n/hexo-blog-encrypt

  1. 安装
    1
    npm install --save hexo-blog-encrypt
  2. 快速使用:将 "password" 字段添加到您文章信息头就像这样
    1
    2
    3
    4
    5
    ---
    title: Hello World
    date: 2016-03-30 21:18:02
    password: hello
    ---
    再使用 hexo clean && hexo g && hexo s 在本地预览加密的文章.

对博文禁用 Tag 加密

只需要将博文头部的 password 设置为 “” 即可取消 Tag 加密.

1
2
3
4
5
6
7
8
9
---
title: Callback Test
date: 2019-12-21 11:54:07
tags:
- A Tag should be encrypted
password: ""
---

Use a "" to diable tag encryption.

swiper 置顶文章

参考:https://akilar.top/posts/8e1264d1/

  1. 安装插件,在博客根目录 [Blogroot] 下打开终端,运行以下指令:
    1
    npm install hexo-butterfly-swiper --save
  2. 在站点配置文件_config.yml 或者主题配置文件_config.butterfly.yml 中添加
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # hexo-butterfly-swiper
    # see https://akilar.top/posts/8e1264d1/
    swiper:
    enable: true # 开关
    priority: 5 #过滤器优先权
    enable_page: all # 应用页面
    timemode: date #date/updated
    layout: # 挂载容器类型
    type: id
    name: recent-posts
    index: 0
    default_descr: 再怎么看我也不知道怎么描述它的啦!
    swiper_css: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.css #swiper css依赖
    swiper_js: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.js #swiper js依赖
    custom_css: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiperstyle.css # 适配主题样式补丁
    custom_js: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper_init.js # swiper初始化方法
  3. 在文章的 front_matter 中添加 swiper_index 配置项即可。
    1
    2
    3
    4
    5
    6
    7
    8
    ---
    title: 文章标题
    date: 创建日期
    updated: 更新日期
    cover: 文章封面
    description: 文章描述
    swiper_index: 1 #置顶轮播图顺序,非负整数,数字越大越靠前
    ---

Math 数学

參考: https://butterfly.js.org/posts/ceeb73f/#Math-%E6%95%B8%E5%AD%B8 并采用 katex 数学公式方案

https://katex.org/docs/options.html

效果设置

滚动条

  1. 在 themes\Butterfly\source\css 文件夹新建 scrollbar.css 文件,文件内容如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    /* 滚动条 */
    ::-webkit-scrollbar {
    width: 8px;
    height: 8px;
    }

    ::-webkit-scrollbar-track {
    background-color: rgba(73, 177, 245, 0.2);
    border-radius: 2em;
    }

    ::-webkit-scrollbar-thumb {
    background-color: #49b1f5 !important;
    background-image: -webkit-linear-gradient(
    45deg,
    rgba(255, 255, 255, 0.4) 25%,
    transparent 25%,
    transparent 50%,
    rgba(255, 255, 255, 0.4) 50%,
    rgba(255, 255, 255, 0.4) 75%,
    transparent 75%,
    transparent
    ) !important;
    border-radius: 2em;
    }

    ::-webkit-scrollbar-corner {
    background-color: transparent;
    }

    ::-moz-selection {
    color: #fff;
    background-color: #49b1f5;
    }

    [data-theme="dark"] ::-webkit-scrollbar-thumb {
    background-color: #1f1f1f !important;
    }
  2. 编辑 _config.butterfly.yml 文件,在 inject->head 下面添加如下内容:
    1
    2
    3
    inject:
    head:
    - <link rel="stylesheet" href="/css/scrollbar.css">

公告canvas小人

在 Butterfly/layout/includes/widget/card_announcement.pug 下添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   .xpand(style='height:200px;')
canvas.illo(width='800' height='800' style='max-width: 200px; max-height: 200px; touch-action: none; width: 640px; height: 640px;')
script(src='https://cdn.jsdelivr.net/gh/xiaopengand/blogCdn@latest/xzxr/twopeople1.js')
script(src='https://cdn.jsdelivr.net/gh/xiaopengand/blogCdn@latest/xzxr/zdog.dist.js')
script#rendered-js(src='https://cdn.jsdelivr.net/gh/xiaopengand/blogCdn@latest/xzxr/twopeople.js')
style.
.card-widget.card-announcement {
margin: 0;
align-items: center;
justify-content: center;
text-align: center;
}
canvas {
display: block;
margin: 0 auto;
cursor: move;
}

星空背景和流星特效

  1. 在 [Blogroot]\themes\source\js\ 目录下新建 universe.js 输入:
    1
    2
    function dark() {window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame;var n,e,i,h,t=.05,s=document.getElementById("universe"),o=!0,a="180,184,240",r="226,225,142",d="226,225,224",c=[];function f(){n=window.innerWidth,e=window.innerHeight,i=.216*n,s.setAttribute("width",n),s.setAttribute("height",e)}function u(){h.clearRect(0,0,n,e);for(var t=c.length,i=0;i<t;i++){var s=c[i];s.move(),s.fadeIn(),s.fadeOut(),s.draw()}}function y(){this.reset=function(){this.giant=m(3),this.comet=!this.giant&&!o&&m(10),this.x=l(0,n-10),this.y=l(0,e),this.r=l(1.1,2.6),this.dx=l(t,6*t)+(this.comet+1-1)*t*l(50,120)+2*t,this.dy=-l(t,6*t)-(this.comet+1-1)*t*l(50,120),this.fadingOut=null,this.fadingIn=!0,this.opacity=0,this.opacityTresh=l(.2,1-.4*(this.comet+1-1)),this.do=l(5e-4,.002)+.001*(this.comet+1-1)},this.fadeIn=function(){this.fadingIn&&(this.fadingIn=!(this.opacity>this.opacityTresh),this.opacity+=this.do)},this.fadeOut=function(){this.fadingOut&&(this.fadingOut=!(this.opacity<0),this.opacity-=this.do/2,(this.x>n||this.y<0)&&(this.fadingOut=!1,this.reset()))},this.draw=function(){if(h.beginPath(),this.giant)h.fillStyle="rgba("+a+","+this.opacity+")",h.arc(this.x,this.y,2,0,2*Math.PI,!1);else if(this.comet){h.fillStyle="rgba("+d+","+this.opacity+")",h.arc(this.x,this.y,1.5,0,2*Math.PI,!1);for(var t=0;t<30;t++)h.fillStyle="rgba("+d+","+(this.opacity-this.opacity/20*t)+")",h.rect(this.x-this.dx/4*t,this.y-this.dy/4*t-2,2,2),h.fill()}else h.fillStyle="rgba("+r+","+this.opacity+")",h.rect(this.x,this.y,this.r,this.r);h.closePath(),h.fill()},this.move=function(){this.x+=this.dx,this.y+=this.dy,!1===this.fadingOut&&this.reset(),(this.x>n-n/4||this.y<0)&&(this.fadingOut=!0)},setTimeout(function(){o=!1},50)}function m(t){return Math.floor(1e3*Math.random())+1<10*t}function l(t,i){return Math.random()*(i-t)+t}f(),window.addEventListener("resize",f,!1),function(){h=s.getContext("2d");for(var t=0;t<i;t++)c[t]=new y,c[t].reset();u()}(),function t(){document.getElementsByTagName('html')[0].getAttribute('data-theme')=='dark'&&u(),window.requestAnimationFrame(t)}()};
    dark()
  2. 在 [Blogroot]\themes\source\css\ 目录下新建 universe.css 输入:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /* 背景宇宙星光  */
    #universe{
    display: block;
    position: fixed;
    margin: 0;
    padding: 0;
    border: 0;
    outline: 0;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: -1;
    }
  3. 在 [Blogroot]_config.butterfly.yml 的 inject 配置项中 bottom 下填入:
    1
    2
    3
    4
    5
    inject:
    bottom:
    + # 星空背景
    + - <canvas id="universe"></canvas>
    + - <script defer src="[root]/js/universe.js"></script>
  4. 在 [Blogroot]_config.butterfly.yml 的 inject 配置项中 head 下填入:
    1
    2
    3
    4
    5
    inject:
    head:
    + # 星空背景
    + - <link rel="stylesheet" href="/css/universe.css">
    ---

SAO UI 风格侧栏卡片

实现效果:
20220518204655

  1. 在 [Blogroot]\themes\butterfly\source\css\custom.css 中添加如下内容。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    /* SAOUI字体精简包,仅73KB */
    @font-face{
    font-family: 'SAOUI';
    src: url('https://npm.elemecdn.com/akilar-candyassets/fonts/SAOUI.ttf');
    font-display: swap;
    }
    /* 应用于除了作者卡片以为的所有侧栏卡片 */
    .card-widget:not(.card-info) {
    overflow: visible !important;
    margin-top: 45px !important;
    border-bottom-left-radius: 10px;
    border-bottom-right-radius: 10px;
    border-top-right-radius: 10px;
    border-top-left-radius: 0px !important;
    font-family: 'SAOUI';
    color: rgba(60,60,61,0.7);
    font-weight: bold;
    }
    /* 修复一下对侧栏电子钟的覆盖 */
    .card-widget.card-clock {
    overflow: hidden !important;
    border-radius: 8px !important;
    margin-top: 0px !important;
    }
    /* 定义标题栏的定位方式为绝对定位 */
    .item-headline {
    font-family: 'SAOUI';
    color: rgba(60,60,61,0.7);
    font-weight: bold;
    position: absolute;
    z-index: 4;
    height: 27px;
    width: 65%;
    top: -27px;
    left: 7px;
    }
    /* 标题栏下各元素的层级,保证它们能显示在伪类之上 */
    .item-headline i {
    position: relative;
    top: 0px;
    margin-left: 5%;
    z-index: 2;
    }
    .item-headline span {
    position: relative;
    top: 0px;
    z-index: 2;
    }
    .item-headline a {
    position: relative;
    top: 0px;
    z-index: 2;
    }
    /* 梯形伪类 */
    .item-headline:after {
    content: '';
    position: absolute;
    top: -3px; /*卡片顶部突起上下偏移量*/
    right: 0;
    bottom: 0;
    left: -3px; /*卡片顶部突起左右偏移量*/
    z-index: 1;
    background: rgba(255,255,255,0.9);
    border: 1px solid rgba(255,255,255,0.9);
    border-bottom: 0 solid #fff;
    /* 关键形变 */
    transform: perspective(20px) rotateX(3deg);
    border-top-right-radius: 5px !important;
    border-top-left-radius: 5px !important;
    }
    /* 下划线伪类 */
    .item-headline:before {
    display: block;
    width: 140%;
    margin-top: 2px;
    height: 2px;
    content: '';
    background: rgba(160,159,160,0.9);
    border-radius: 5px;
    top: 40px;
    left: 0;
    position: relative;
    }
    /* 针对手机样式的偏移量调整 */
    @media screen and (max-width: 800px) {
    .item-headline {
    left: 8px;
    }
    }
    /* 夜间模式色彩适配,此处仅代表糖果屋夜间模式配色 */
    [data-theme="dark"] .card-widget:not(.card-info) {
    color: rgba(255,255,255,0.7) !important;
    }
    [data-theme="dark"] .item-headline {
    color: rgba(255,255,255,0.7) !important;
    }
    [data-theme="dark"] .item-headline:after {
    background: rgba(0,0,0,0.5);
    border: 1px solid rgba(0,0,0,0.5);
    border-bottom: 0 solid rgba(0,0,0,0.5);
    }
    [data-theme="dark"] .item-headline:before {
    background: rgba(255,255,255,0.9);
    }
  2. 在 [Blogroot]_config.butterfly.yml 中引入
    1
    2
    3
    inject:
    head:
    - <link rel="stylesheet" href="/css/custom.css" media="defer" onload="this.media='all'">

昼夜转换动画

  1. 新建 [Blogroot]\themes\butterfly\layout\includes\custom\sun_moon.pug, 这部分其实实质上就是一个 svg 文件,通过 js 操作它的旋转显隐,淡入淡出实现动画效果。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    svg(aria-hidden='true', style='position:absolute; overflow:hidden; width:0; height:0')
    symbol#icon-sun(viewBox='0 0 1024 1024')
    path(d='M960 512l-128 128v192h-192l-128 128-128-128H192v-192l-128-128 128-128V192h192l128-128 128 128h192v192z', fill='#FFD878', p-id='8420')
    path(d='M736 512a224 224 0 1 0-448 0 224 224 0 1 0 448 0z', fill='#FFE4A9', p-id='8421')
    path(d='M512 109.248L626.752 224H800v173.248L914.752 512 800 626.752V800h-173.248L512 914.752 397.248 800H224v-173.248L109.248 512 224 397.248V224h173.248L512 109.248M512 64l-128 128H192v192l-128 128 128 128v192h192l128 128 128-128h192v-192l128-128-128-128V192h-192l-128-128z', fill='#4D5152', p-id='8422')
    path(d='M512 320c105.888 0 192 86.112 192 192s-86.112 192-192 192-192-86.112-192-192 86.112-192 192-192m0-32a224 224 0 1 0 0 448 224 224 0 0 0 0-448z', fill='#4D5152', p-id='8423')
    symbol#icon-moon(viewBox='0 0 1024 1024')
    path(d='M611.370667 167.082667a445.013333 445.013333 0 0 1-38.4 161.834666 477.824 477.824 0 0 1-244.736 244.394667 445.141333 445.141333 0 0 1-161.109334 38.058667 85.077333 85.077333 0 0 0-65.066666 135.722666A462.08 462.08 0 1 0 747.093333 102.058667a85.077333 85.077333 0 0 0-135.722666 65.024z', fill='#FFB531', p-id='11345')
    path(d='M329.728 274.133333l35.157333-35.157333a21.333333 21.333333 0 1 0-30.165333-30.165333l-35.157333 35.157333-35.114667-35.157333a21.333333 21.333333 0 0 0-30.165333 30.165333l35.114666 35.157333-35.114666 35.157334a21.333333 21.333333 0 1 0 30.165333 30.165333l35.114667-35.157333 35.157333 35.157333a21.333333 21.333333 0 1 0 30.165333-30.165333z', fill='#030835', p-id='11346')
  2. 新建 [Blogroot]\themes\butterfly\source\_layout\sun_moon.styl:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    .Cuteen_DarkSky,
    .Cuteen_DarkSky:before
    content ''
    position fixed
    left 0
    right 0
    top 0
    bottom 0
    z-index 88888888

    .Cuteen_DarkSky
    background linear-gradient(#feb8b0, #fef9db)
    &:before
    transition 2s ease all
    opacity 0
    background linear-gradient(#4c3f6d, #6c62bb, #93b1ed)

    .DarkMode
    .Cuteen_DarkSky
    &:before
    opacity 1

    .Cuteen_DarkPlanet
    z-index 99999999
    position fixed
    left -50%
    top -50%
    width 200%
    height 200%
    -webkit-animation CuteenPlanetMove 2s cubic-bezier(0.7, 0, 0, 1)
    animation CuteenPlanetMove 2s cubic-bezier(0.7, 0, 0, 1)
    transform-origin center bottom


    @-webkit-keyframes CuteenPlanetMove {
    0% {
    transform: rotate(0);
    }
    to {
    transform: rotate(360deg);
    }
    }
    @keyframes CuteenPlanetMove {
    0% {
    transform: rotate(0);
    }
    to {
    transform: rotate(360deg);
    }
    }
    .Cuteen_DarkPlanet
    &:after
    position absolute
    left 35%
    top 40%
    width 9.375rem
    height 9.375rem
    border-radius 50%
    content ''
    background linear-gradient(#fefefe, #fffbe8)

    .search
    span
    display none

    .menus_item
    a
    text-decoration none!important
    //按钮相关,对侧栏按钮做过魔改的可以调整这里的数值
    .icon-V
    padding 5px
  3. 新建 [Blogroot]\themes\butterfly\source\js\sun_moon.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    function switchNightMode() {
    document.querySelector('body').insertAdjacentHTML('beforeend', '<div class="Cuteen_DarkSky"><div class="Cuteen_DarkPlanet"></div></div>'),
    setTimeout(function() {
    document.querySelector('body').classList.contains('DarkMode') ? (document.querySelector('body').classList.remove('DarkMode'), localStorage.setItem('isDark', '0'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-moon')) : (document.querySelector('body').classList.add('DarkMode'), localStorage.setItem('isDark', '1'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-sun')),
    setTimeout(function() {
    document.getElementsByClassName('Cuteen_DarkSky')[0].style.transition = 'opacity 3s';
    document.getElementsByClassName('Cuteen_DarkSky')[0].style.opacity = '0';
    setTimeout(function() {
    document.getElementsByClassName('Cuteen_DarkSky')[0].remove();
    }, 1e3);
    }, 2e3)
    })
    const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
    if (nowMode === 'light') {
    activateDarkMode()
    saveToLocal.set('theme', 'dark', 2)
    GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
    document.getElementById('modeicon').setAttribute('xlink:href', '#icon-sun')
    } else {
    activateLightMode()
    saveToLocal.set('theme', 'light', 2)
    document.querySelector('body').classList.add('DarkMode'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-moon')
    }
    // handle some cases
    typeof utterancesTheme === 'function' && utterancesTheme()
    typeof FB === 'object' && window.loadFBComment()
    window.DISQUS && document.getElementById('disqus_thread').children.length && setTimeout(() => window.disqusReset(), 200)
    }
  4. 修改 [Blogroot]\themes\butterfly\layout\includes\head.pug, 在文件末位加上一行:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //- global config
    !=partial('includes/head/config', {}, {cache: true})

    include ./head/config_site.pug
    include ./head/noscript.pug

    !=fragment_cache('injectHeadJs', function(){return inject_head_js()})

    !=fragment_cache('injectHead', function(){return injectHtml(theme.inject.head)})

    + include ./custom/sun_moon.pug
  5. 修改 [Blogroot]\themes\butterfly\layout\includes\rightside.pug, 把原本的昼夜切换按钮替换掉:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    when 'translate'
    if translate.enable
    button#translateLink(type="button" title=_p('rightside.translate_title'))= translate.default
    when 'darkmode'
    if darkmode.enable && darkmode.button
    - button#darkmode(type="button" title=_p('rightside.night_mode_title'))
    - i.fas.fa-adjust
    + a.icon-V.hidden(onclick='switchNightMode()', title=_p('rightside.night_mode_title'))
    + svg(width='25', height='25', viewBox='0 0 1024 1024')
    + use#modeicon(xlink:href='#icon-moon')
  6. 修改 [Blogroot]_config.butterfly.yml, 引入一下 js:
    1
    2
    3
    4
    inject:
    head:
    bottome:
    - <script src="[root]/js/sun_moon.js" async></script>

Butterfly 标签文章数上下标

在 Butterfly 主题中,文章标签页和标签侧边栏都有文章标签的词云图,但仅仅用字体大小表示某个标签下的文章数量是不明显的,可以在这个基础上加上表示某个标签下文章数的上下标,其中 表示上标, 表示下标。

  • 在 \themes\butterfly\scripts\helpers\page.js 找到 cloudTags 函数增加 ${tag.length}${tag.length} 可绘制表示标签文章数的上下标。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    hexo.extend.helper.register('cloudTags', function (options = {}) {
    const theme = hexo.theme.config
    const env = this
    let source = options.source
    const minfontsize = options.minfontsize
    const maxfontsize = options.maxfontsize
    const limit = options.limit
    const unit = options.unit || 'px'

    let result = ''
    if (limit > 0) {
    source = source.limit(limit)
    }

    const sizes = []
    source.sort('length').forEach(tag => {
    const { length } = tag
    if (sizes.includes(length)) return
    sizes.push(length)
    })

    const length = sizes.length - 1
    source.forEach(tag => {
    const ratio = length ? sizes.indexOf(tag.length) / length : 0
    const size = minfontsize + ((maxfontsize - minfontsize) * ratio)
    let style = `font-size: ${parseFloat(size.toFixed(2))}${unit};`
    const color = 'rgb(' + Math.floor(Math.random() * 201) + ', ' + Math.floor(Math.random() * 201) + ', ' + Math.floor(Math.random() * 201) + ')' // 0,0,0 -> 200,200,200
    style += ` color: ${color}`
    - result += `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}</a>`
    + result += `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}<sup>${tag.length}</sup></a>`
    })
    return result
    })

Hexo 博客文章统计图

使用的是 ECharts 开源可视化库对博客的文章发布时间、文章分类、文章标签的维度绘制统计图。

  1. 新建 charts 页面:
    在 [Blogroot]\source\ 目录下新建 charts 文件夹,并在新建的 charts 文件夹下新建 index.md 文件,添加以下内容:
    1
    2
    3
    4
    ---
    title: 统计图表
    date: 2022-05-01 08:00:00
    ---
  2. 引入 ECharts.js(echarts.js 必须在渲染 echarts 实例的 JavaScript 前引入)
    在 [Blogroot]_config.butterfly.yml 的 inject 配置项中引入 echart.js 文件。
    1
    2
    3
    inject:
    head:
    - <script src="https://cdn.jsdelivr.net/npm/echarts@4.9.0/dist/echarts.min.js"></script>
  3. 新建文章统计代码
    在 [Blogroot]\themes\butterfly\scripts\helpers\ 目录下新建 charts.js 文件,然后添加以下内容:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    const cheerio = require('cheerio')
    const moment = require('moment')

    hexo.extend.filter.register('after_render:html', function (locals) {
    const $ = cheerio.load(locals)
    const post = $('#posts-chart')
    const tag = $('#tags-chart')
    const category = $('#categories-chart')
    const htmlEncode = false

    if (post.length > 0 || tag.length > 0 || category.length > 0) {
    if (post.length > 0 && $('#postsChart').length === 0) {
    if (post.attr('data-encode') === 'true') htmlEncode = true
    post.after(postsChart(post.attr('data-start')))
    }
    if (tag.length > 0 && $('#tagsChart').length === 0) {
    if (tag.attr('data-encode') === 'true') htmlEncode = true
    tag.after(tagsChart(tag.attr('data-length')))
    }
    if (category.length > 0 && $('#categoriesChart').length === 0) {
    if (category.attr('data-encode') === 'true') htmlEncode = true
    category.after(categoriesChart())
    }

    if (htmlEncode) {
    return $.root().html().replace(/&amp;#/g, '&#')
    } else {
    return $.root().html()
    }
    } else {
    return locals
    }
    }, 15)

    function postsChart (startMonth) {
    const startDate = moment(startMonth || '2020-01')
    const endDate = moment()

    const monthMap = new Map()
    const dayTime = 3600 * 24 * 1000
    for (let time = startDate; time <= endDate; time += dayTime) {
    const month = moment(time).format('YYYY-MM')
    if (!monthMap.has(month)) {
    monthMap.set(month, 0)
    }
    }
    hexo.locals.get('posts').forEach(function (post) {
    const month = post.date.format('YYYY-MM')
    if (monthMap.has(month)) {
    monthMap.set(month, monthMap.get(month) + 1)
    }
    })
    const monthArr = JSON.stringify([...monthMap.keys()])
    const monthValueArr = JSON.stringify([...monthMap.values()])

    return `
    <script id="postsChart">
    var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
    var postsChart = echarts.init(document.getElementById('posts-chart'), 'light');
    var postsOption = {
    title: {
    text: '文章发布统计图',
    x: 'center',
    textStyle: {
    color: color
    }
    },
    tooltip: {
    trigger: 'axis'
    },
    xAxis: {
    name: '日期',
    type: 'category',
    boundaryGap: false,
    nameTextStyle: {
    color: color
    },
    axisTick: {
    show: false
    },
    axisLabel: {
    show: true,
    color: color
    },
    axisLine: {
    show: true,
    lineStyle: {
    color: color
    }
    },
    data: ${monthArr}
    },
    yAxis: {
    name: '文章篇数',
    type: 'value',
    nameTextStyle: {
    color: color
    },
    splitLine: {
    show: false
    },
    axisTick: {
    show: false
    },
    axisLabel: {
    show: true,
    color: color
    },
    axisLine: {
    show: true,
    lineStyle: {
    color: color
    }
    }
    },
    series: [{
    name: '文章篇数',
    type: 'line',
    smooth: true,
    lineStyle: {
    width: 0
    },
    showSymbol: false,
    itemStyle: {
    opacity: 1,
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(128, 255, 165)'
    },
    {
    offset: 1,
    color: 'rgba(1, 191, 236)'
    }])
    },
    areaStyle: {
    opacity: 1,
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(128, 255, 165)'
    }, {
    offset: 1,
    color: 'rgba(1, 191, 236)'
    }])
    },
    data: ${monthValueArr},
    markLine: {
    data: [{
    name: '平均值',
    type: 'average',
    label: {
    color: color
    }
    }]
    }
    }]
    };
    postsChart.setOption(postsOption);
    window.addEventListener('resize', () => {
    postsChart.resize();
    });
    </script>`
    }

    function tagsChart (len) {
    const tagArr = []
    hexo.locals.get('tags').map(function (tag) {
    tagArr.push({ name: tag.name, value: tag.length })
    })
    tagArr.sort((a, b) => { return b.value - a.value })

    const dataLength = Math.min(tagArr.length, len) || tagArr.length
    const tagNameArr = []
    const tagCountArr = []
    for (let i = 0; i < dataLength; i++) {
    tagNameArr.push(tagArr[i].name)
    tagCountArr.push(tagArr[i].value)
    }
    const tagNameArrJson = JSON.stringify(tagNameArr)
    const tagCountArrJson = JSON.stringify(tagCountArr)

    return `
    <script id="tagsChart">
    var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
    var tagsChart = echarts.init(document.getElementById('tags-chart'), 'light');
    var tagsOption = {
    title: {
    text: 'Top ${dataLength} 标签统计图',
    x: 'center',
    textStyle: {
    color: color
    }
    },
    tooltip: {},
    xAxis: {
    name: '标签',
    type: 'category',
    nameTextStyle: {
    color: color
    },
    axisTick: {
    show: false
    },
    axisLabel: {
    show: true,
    color: color
    },
    axisLine: {
    show: true,
    lineStyle: {
    color: color
    }
    },
    data: ${tagNameArrJson}
    },
    yAxis: {
    name: '文章篇数',
    type: 'value',
    splitLine: {
    show: false
    },
    nameTextStyle: {
    color: color
    },
    axisTick: {
    show: false
    },
    axisLabel: {
    show: true,
    color: color
    },
    axisLine: {
    show: true,
    lineStyle: {
    color: color
    }
    }
    },
    series: [{
    name: '文章篇数',
    type: 'bar',
    data: ${tagCountArrJson},
    itemStyle: {
    borderRadius: [5, 5, 0, 0],
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(128, 255, 165)'
    },
    {
    offset: 1,
    color: 'rgba(1, 191, 236)'
    }])
    },
    emphasis: {
    itemStyle: {
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(128, 255, 195)'
    },
    {
    offset: 1,
    color: 'rgba(1, 211, 255)'
    }])
    }
    },
    markLine: {
    data: [{
    name: '平均值',
    type: 'average',
    label: {
    color: color
    }
    }]
    }
    }]
    };
    tagsChart.setOption(tagsOption);
    window.addEventListener('resize', () => {
    tagsChart.resize();
    });
    tagsChart.on('click', 'series', (event) => {
    let href = '/tags/' + event.name + '/';
    window.location.href = href;
    });
    </script>`
    }

    function categoriesChart () {
    const categoryArr = []
    hexo.locals.get('categories').map(function (category) {
    categoryArr.push({ name: category.name, value: category.length })
    })
    categoryArr.sort((a, b) => { return b.value - a.value });
    const categoryArrJson = JSON.stringify(categoryArr)

    return `
    <script id="categoriesChart">
    var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
    var categoriesChart = echarts.init(document.getElementById('categories-chart'), 'light');
    var categoriesOption = {
    title: {
    text: '文章分类统计图',
    x: 'center',
    textStyle: {
    color: color
    }
    },
    legend: {
    top: 'bottom',
    textStyle: {
    color: color
    }
    },
    tooltip: {
    trigger: 'item',
    formatter: '{a} <br/>{b} : {c} ({d}%)'
    },
    series: [{
    name: '文章篇数',
    type: 'pie',
    radius: [30, 80],
    center: ['50%', '50%'],
    roseType: 'area',
    label: {
    color: color,
    formatter: '{b} : {c} ({d}%)'
    },
    data: ${categoryArrJson},
    itemStyle: {
    emphasis: {
    shadowBlur: 10,
    shadowOffsetX: 0,
    shadowColor: 'rgba(255, 255, 255, 0.5)'
    }
    }
    }]
    };
    categoriesChart.setOption(categoriesOption);
    window.addEventListener('resize', () => {
    categoriesChart.resize();
    });
    categoriesChart.on('click', 'series', (event) => {
    let href = '/categories/' + event.name + '/';
    window.location.href = href;
    });
    </script>`
    }
  4. 使用统计图
    在 [Blogroot]\source\charts\index.md 文件中添加以下内容:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // posts-chart 的 data-start="2021-01" 属性表示文章发布时间统计图仅显示 2021-01 及以后的文章数据。
    // tags-chart 的 data-length="10" 属性表示仅显示排名前 10 的标签。

    <!-- 文章发布时间统计图 -->
    <div id="posts-chart" data-start="2021-01" style="border-radius: 8px; height: 300px; padding: 10px;"></div>
    <!-- 文章标签统计图 -->
    <div id="tags-chart" data-length="10" style="border-radius: 8px; height: 300px; padding: 10px;"></div>
    <!-- 文章分类统计图 -->
    <div id="categories-chart" style="border-radius: 8px; height: 300px; padding: 10px;"></div>
  5. 安装 cheerio 插件:在根目录执行:
    1
    npm i cheerio --save

GitHub 贡献度

  1. 安装插件 hexo-github-calendar
    1
    npm i hexo-githubcalendar --save
  2. 打开 Hexo 的站点配置文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    githubcalendar:
    enable: true
    enable_page: / # 表示只在根目录(首页)显示
    user: xxx # 替换成你 GitHub 的用户名
    layout_id: recent-posts
    githubcalendar_html: '<div class="recent-post-item" style="width:100%;height:auto;padding:10px;"><div id="github_loading" style="width:10%;height:100%;margin:0 auto;display: block"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50" xml:space="preserve"><path fill="#d0d0d0" d="M25.251,6.461c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615V6.461z" transform="rotate(275.098 25 25)"><animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="0.6s" repeatCount="indefinite"></animateTransform></path></svg></div><div id="github_container"></div></div>'
    pc_minheight: 280px
    mobile_minheight: 0px
    # 粉色调
    color: "['#ebedf0', '#fdcdec', '#fc9bd9', '#fa6ac5', '#f838b2', '#f5089f', '#c4067e', '#92055e', '#540336', '#48022f', '#30021f']"
    # 橘黄色调
    # color: "['#e4dfd7', '#f9f4dc', '#f7e8aa', '#f7e8aa', '#f8df72', '#fcd217', '#fcc515', '#f28e16', '#fb8b05', '#d85916', '#f43e06']"
    # 翠绿色调
    # color: "['#ebedf0', '#f0fff4', '#dcffe4', '#bef5cb', '#85e89d', '#34d058', '#28a745', '#22863a', '#176f2c', '#165c26', '#144620']"
    # 天青色调
    # color: "['#ebedf0', '#f1f8ff', '#dbedff', '#c8e1ff', '#79b8ff', '#2188ff', '#0366d6', '#005cc5', '#044289', '#032f62', '#05264c']"
    api: https://python-github-calendar-api.vercel.app/api
    # api: https://python-gitee-calendar-api.vercel.app/api
    calendar_js: https://cdn.jsdelivr.net/gh/Zfour/hexo-github-calendar@1.16/hexo_githubcalendar.js

博客透明度设置

  1. 在 [Blogroot]\themes\source\css\ 目录下新建 alpha.css 输入:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    /* 文章页背景 */
    .layout_post>#post {
    /* 以下代表透明度为0.5 可以自行修改*/
    opacity: .9;
    }

    /* 所有页面背景 */
    #aside_content .card-widget,
    #recent-posts>.recent-post-item,
    .layout_page>div:first-child:not(.recent-posts),
    .layout_post>#page,
    .layout_post>#post,
    .read-mode .layout_post>#post {
    /* 以下代表透明度为0.5 */
    opacity: .9;
    }

    /*侧边栏背景*/
    .aside-content>.card-widget {
    opacity: .9;
    }
    .sticky_layout {
    opacity: .9;
    }

    /*文章页面*/
    .layout>#post {
    opacity: .9;
    }

    /*分类页面*/
    .layout>#page {
    opacity: .9;
    }

    /*时间轴页面*/
    .layout>#archive {
    opacity: .9;
    }
  2. 在主题配置文件 inject>head 中引入
    1
    2
    3
    inject:
    head:
    - <link rel="stylesheet" href="[root]/css/alpha.css">

首页页码样式调整

修改 [Blogroot]\themes\butterfly\source\css_layout\pagination.styl, 将整个文件替换成以下内容,不保证魔改普适性,请务必记得做好文件备份方便回退!开头为效果配色,可以自行调整成适合自己的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
:root
--pagenumber-color: #ffffff
--pagenumber-current-color: #1E7EE2
--pagenumber-current-shadow-color: #104477
--pagenumber-hover-color: #1E7EE2
--pagenumber-background-color: rgba(0, 0, 0, 0.85)
[data-theme="dark"]
--pagenumber-color: #ffffff
--pagenumber-current-color: #1E7EE2
--pagenumber-current-shadow-color: #104477
--pagenumber-hover-color: #1E7EE2
--pagenumber-background-color: rgba(120, 120, 120, 0.85)
#pagination
.pagination
margin-top: 20px
text-align: center
position: relative;
a
color: var(--pagenumber-color)
&::after
content ''
position absolute
width 100%
height 35px
left 0
bottom 0
z-index -1
background-image -moz-linear-gradient(left, rgba(0, 0, 0, 0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0, 0, 0, 0) 100%)
background-image -webkit-linear-gradient(left, rgba(0, 0, 0, 0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0, 0, 0, 0) 100%)
background-image linear-gradient(to right, rgba(0, 0, 0, 0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0, 0, 0, 0) 100%)
.page-number
&.current
background var(--pagenumber-current-color)
color var(--pagenumber-color)
padding: 9px 3px 0px 3px;
height: 40px;
&:before
content: '';
position: absolute;
top: -10px;
transform: translateX(-20px);
width: 30px;
border: 10px solid transparent;
border-bottom: 7px solid var(--pagenumber-current-shadow-color);
z-index: -1;
&:hover
&::after
display none


.layout
& > .recent-posts
.pagination
& > *
display: inline-block
margin: 0 6px
min-width: 30px
width: auto
height: 35px
line-height: 30px
padding: 4px 3px 0px 3px;

& > *:not(.space)
&:hover
background: var(--pagenumber-hover-color)
color: var(--pagenumber-color)

& > div:not(.recent-posts)
.pagination
.page-number
color: var(--pagenumber-color);
padding: 13px 5px 5px;
margin: 0 10px;
position: relative;
&:hover
color: var(--pagenumber-color)
&::after
content ''
position absolute
width 24px
height 24px
background var(--pagenumber-hover-color)
-moz-border-radius 100%
-webkit-border-radius 100%
border-radius 100%
z-index -1
left -3px
bottom 4px
margin auto







.pagination-info
position: absolute
top: 50%
padding: 20px 40px
width: 100%
transform: translate(0, -50%)

.prev_info,
.next_info
@extend .limit-one-line
color: var(--white)
font-weight: 500

.next-post
.pagination-info
text-align: right

.pull-full
width: 100% !important

.prev-post .label,
.next-post .label
color: var(--light-grey)
text-transform: uppercase
font-size: 90%

.prev-post,
.next-post
@extend .postImgHover
width: 50%

+maxWidth768()
width: 100%

a
position: relative
display: block
overflow: hidden
height: 150px

&.pagination-post
overflow: hidden
margin-top: 40px
width: 100%
background: $dark-black

原文件备份:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#pagination
.pagination
margin-top: 20px
text-align: center

.page-number
&.current
background: $theme-paginator-color
color: var(--white)

.pagination-info
position: absolute
top: 50%
padding: 20px 40px
width: 100%
transform: translate(0, -50%)

.prev_info,
.next_info
@extend .limit-one-line
color: var(--white)
font-weight: 500

.next-post
.pagination-info
text-align: right

.pull-full
width: 100% !important

.prev-post .label,
.next-post .label
color: var(--light-grey)
text-transform: uppercase
font-size: 90%

.prev-post,
.next-post
@extend .postImgHover
width: 50%

+maxWidth768()
width: 100%

a
position: relative
display: block
overflow: hidden
height: 150px

&.pagination-post
overflow: hidden
margin-top: 40px
width: 100%
background: $dark-black

.layout
& > .recent-posts
.pagination
& > *
display: inline-block
margin: 0 6px
width: w = 2.5em
height: w
line-height: w

& > *:not(.space)
@extend .cardHover

&:hover
background: var(--btn-hover-color)
color: var(--btn-color)

& > div:not(.recent-posts)
.pagination
.page-number
display: inline-block
margin: 0 4px
min-width: w = 24px
height: w
text-align: center
line-height: w
cursor: pointer

首页文章卡片修改

  1. 修改 [Blogroot]\themes\butterfly\layout\includes\mixins\post-ui.pug,将整个文件的内容替换为以下代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    mixin postUI(posts)
    each article , index in page.posts.data
    .recent-post-item
    -
    let link = article.link || article.path
    let title = article.title || _p('no_title')
    const position = theme.cover.position
    let leftOrRight = position === 'both'
    ? index%2 == 0 ? 'left' : 'right'
    : position === 'left' ? 'left' : 'right'
    let post_cover = article.cover
    let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : ''
    -
    .recent-post-content(class=leftOrRight)
    a.article-content(href=url_for(link) title=subtitle)
    //- Display the article introduction on homepage
    case theme.index_post_content.method
    when false
    - break
    when 1
    .article-content-text!= article.description
    when 2
    if article.description
    .article-content-text!= article.description
    else
    - const content = strip_html(article.content)
    - let expert = content.substring(0, theme.index_post_content.length)
    - content.length > theme.index_post_content.length ? expert += ' ...' : ''
    .article-content-text!= expert
    default
    - const content = strip_html(article.content)
    - let expert = content.substring(0, theme.index_post_content.length)
    - content.length > theme.index_post_content.length ? expert += ' ...' : ''
    .article-content-text!= expert
    .recent-post-info
    a.article-title(href=url_for(link) title=subtitle)
    .article-title-link= title
    .recent-post-meta
    .article-meta-wrap
    if (is_home() && (article.top || article.sticky > 0))
    span.article-meta
    i.fas.fa-thumbtack.sticky
    span.sticky= _p('sticky')
    span.article-meta-separator |
    if (theme.post_meta.page.date_type)
    span.post-meta-date
    if (theme.post_meta.page.date_type === 'both')
    i.far.fa-calendar-alt
    span.article-meta-label=_p('post.created')
    time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format)
    span.article-meta-separator |
    i.fas.fa-history
    span.article-meta-label=_p('post.updated')
    time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format)
    else
    - let data_type_updated = theme.post_meta.page.date_type === 'updated'
    - let date_type = data_type_updated ? 'updated' : 'date'
    - let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt'
    - let date_title = data_type_updated ? _p('post.updated') : _p('post.created')
    i(class=date_icon)
    span.article-meta-label=date_title
    time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format)
    if (theme.post_meta.page.categories && article.categories.data.length > 0)
    span.article-meta
    span.article-meta-separator |
    i.fas.fa-inbox
    each item, index in article.categories.data
    a(href=url_for(item.path)).article-meta__categories #[=item.name]
    if (index < article.categories.data.length - 1)
    i.fas.fa-angle-right.article-meta-link
    if (theme.post_meta.page.tags && article.tags.data.length > 0)
    span.article-meta.tags
    span.article-meta-separator |
    i.fas.fa-tag
    each item, index in article.tags.data
    a(href=url_for(item.path)).article-meta__tags #[=item.name]
    if (index < article.tags.data.length - 1)
    span.article-meta-link #[='•']

    mixin countBlockInIndex
    - needLoadCountJs = true
    span.article-meta
    span.article-meta-separator |
    i.fas.fa-comments
    if block
    block
    span.article-meta-label= ' ' + _p('card_post_count')

    if theme.comments.card_post_count
    case theme.comments.use[0]
    when 'Disqus'
    when 'Disqusjs'
    +countBlockInIndex
    a(href=full_url_for(link) + '#disqus_thread')
    when 'Valine'
    +countBlockInIndex
    a(href=url_for(link) + '#post-comment' itemprop="discussionUrl")
    span.valine-comment-count(data-xid=url_for(link) itemprop="commentCount")
    when 'Waline'
    +countBlockInIndex
    a(href=url_for(link) + '#post-comment')
    span.waline-comment-count(id=url_for(link))
    when 'Twikoo'
    +countBlockInIndex
    a.twikoo-count(href=url_for(link) + '#post-comment')
    when 'Facebook Comments'
    +countBlockInIndex
    a(href=url_for(link) + '#post-comment')
    span.fb-comments-count(data-href=urlNoIndex(article.permalink))
    .recent-post-cover
    img.article-cover(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=subtitle)

    if theme.ad && theme.ad.index
    if (index + 1) % 3 == 0
    .recent-post-item.ads-wrap!=theme.ad.index

备份:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
mixin postUI(posts)
each article , index in page.posts.data
.recent-post-item
-
let link = article.link || article.path
let title = article.title || _p('no_title')
const position = theme.cover.position
let leftOrRight = position === 'both'
? index%2 == 0 ? 'left' : 'right'
: position === 'left' ? 'left' : 'right'
let post_cover = article.cover
let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : ''
-
if post_cover && theme.cover.index_enable
.post_cover(class=leftOrRight)
a(href=url_for(link) title=title)
img.post_bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=title)
.recent-post-info(class=no_cover)
a.article-title(href=url_for(link) title=title)= title
.article-meta-wrap
if (is_home() && (article.top || article.sticky > 0))
span.article-meta
i.fas.fa-thumbtack.sticky
span.sticky= _p('sticky')
span.article-meta-separator |
if (theme.post_meta.page.date_type)
span.post-meta-date
if (theme.post_meta.page.date_type === 'both')
i.far.fa-calendar-alt
span.article-meta-label=_p('post.created')
time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format)
span.article-meta-separator |
i.fas.fa-history
span.article-meta-label=_p('post.updated')
time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format)
else
- let data_type_updated = theme.post_meta.page.date_type === 'updated'
- let date_type = data_type_updated ? 'updated' : 'date'
- let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt'
- let date_title = data_type_updated ? _p('post.updated') : _p('post.created')
i(class=date_icon)
span.article-meta-label=date_title
time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format)
if (theme.post_meta.page.categories && article.categories.data.length > 0)
span.article-meta
span.article-meta-separator |
i.fas.fa-inbox
each item, index in article.categories.data
a(href=url_for(item.path)).article-meta__categories #[=item.name]
if (index < article.categories.data.length - 1)
i.fas.fa-angle-right.article-meta-link
if (theme.post_meta.page.tags && article.tags.data.length > 0)
span.article-meta.tags
span.article-meta-separator |
i.fas.fa-tag
each item, index in article.tags.data
a(href=url_for(item.path)).article-meta__tags #[=item.name]
if (index < article.tags.data.length - 1)
span.article-meta-link #[='•']

mixin countBlockInIndex
- needLoadCountJs = true
span.article-meta
span.article-meta-separator |
i.fas.fa-comments
if block
block
span.article-meta-label= ' ' + _p('card_post_count')

if theme.comments.card_post_count
case theme.comments.use[0]
when 'Disqus'
when 'Disqusjs'
+countBlockInIndex
a(href=full_url_for(link) + '#disqus_thread')
when 'Valine'
+countBlockInIndex
a(href=url_for(link) + '#post-comment' itemprop="discussionUrl")
span.valine-comment-count(data-xid=url_for(link) itemprop="commentCount")
when 'Waline'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.waline-comment-count(id=url_for(link))
when 'Twikoo'
+countBlockInIndex
a.twikoo-count(href=url_for(link) + '#post-comment')
when 'Facebook Comments'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.fb-comments-count(data-href=urlNoIndex(article.permalink))

//- Display the article introduction on homepage
case theme.index_post_content.method
when false
- break
when 1
.content!= article.description
when 2
if article.description
.content!= article.description
else
- const content = strip_html(article.content)
- let expert = content.substring(0, theme.index_post_content.length)
- content.length > theme.index_post_content.length ? expert += ' ...' : ''
.content!= expert
default
- const content = strip_html(article.content)
- let expert = content.substring(0, theme.index_post_content.length)
- content.length > theme.index_post_content.length ? expert += ' ...' : ''
.content!= expert

if theme.ad && theme.ad.index
if (index + 1) % 3 == 0
.recent-post-item.ads-wrap!=theme.ad.index

  1. 修改 [Blogroot]\themes\butterfly\source\css_page\homepage.styl,将整个文件的内容替换为以下代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    //default color:
    :root
    --recent-post-bgcolor: rgba(255, 255, 255, 0.9)
    --article-content-bgcolor: #49b1f5
    --recent-post-triangle: #fff
    --recent-post-cover-shadow: #ffffff
    [data-theme="dark"]
    --recent-post-bgcolor: rgba(35,35,35,0.5)
    --article-content-bgcolor: #99999a
    --recent-post-triangle: #37e2dd
    --recent-post-cover-shadow: #232323
    .recent-posts
    padding 0 15px 0 15px

    .recent-post-item
    margin-bottom 15px
    width 100%
    background var(--recent-post-bgcolor)
    overflow hidden
    border-radius 15px
    .recent-post-info
    .article-title-link
    display -webkit-box
    -webkit-box-orient vertical
    -webkit-line-clamp 2
    overflow hidden
    .article-content
    background var(--article-content-bgcolor)
    position relative
    display flex
    align-items: center;
    justify-content: center;
    .article-content-text
    transition: all .8s cubic-bezier(0.59, 0.01, 0.48, 1.17)
    display -webkit-box
    -webkit-box-orient vertical
    -webkit-line-clamp 4
    text-overflow: ellipsis
    overflow hidden
    color #fff
    text-shadow: 1px 2px 3px #000;
    .recent-post-cover
    position relative
    background transparent
    img
    &.article-cover
    height 100%
    width 100%
    object-fit cover

    .recent-post-info
    align-items center
    flex-direction column
    position relative
    background var(--recent-post-bgcolor)
    display flex
    color #000000
    .article-title
    height 50%
    font-size 24px
    display: flex
    align-items: center
    justify-content: flex-end
    flex-direction: column
    .article-title-link
    color: var(--text-highlight-color)
    transition: all .2s ease-in-out
    &:hover
    color: $text-hover
    .recent-post-meta
    height 50%
    display: flex
    align-items: center
    justify-content: flex-start
    flex-direction: column
    .article-meta-wrap
    font-size 12px
    color #969797
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
    a
    color: var(--text-highlight-color)
    transition: all .2s ease-in-out
    color #969797
    &:hover
    color: $text-hover
    &.ads-wrap
    display: block !important
    height: auto !important
    @media screen and (min-width:600px)
    .recent-post-item
    &:hover
    .recent-post-content
    &.both,
    &.right
    transform translateX(21%)
    transition: all .8s cubic-bezier(0.59, 0.01, 0.48, 1.17)
    &::before
    transition: all .8s cubic-bezier(0.59, 0.01, 0.48, 1.17)
    left: 50px;
    .article-content-text
    margin 20px 20px 20px 60px
    &.left
    transform translateX(-21%)
    transition: all .8s cubic-bezier(0.59, 0.01, 0.48, 1.17)
    &::before
    transition: all .8s cubic-bezier(0.59, 0.01, 0.48, 1.17)
    right: 50px;
    .article-content-text
    margin 20px 60px 20px 20px


    .recent-post-content
    background var(--recent-post-bgcolor)
    position relative
    height 200px
    width 130%
    z-index 0
    display flex
    overflow hidden
    border 0px solid
    &::before
    content: "";
    width: 0;
    height: 0;
    background: transparent;
    position: absolute;
    z-index: 3;
    top: calc(50% - 10px);
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent;
    transition: all .5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
    &.both,
    &.right
    flex-direction: row;
    left calc(-23.07% - 41px)
    transition: all .5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
    &::before
    left: calc(23.07% + 40px);
    border-left: 6px solid var(--recent-post-triangle);
    .recent-post-info
    &::before
    background linear-gradient(to right, var(--recent-post-cover-shadow), transparent)
    left calc(100% - 1px)
    .article-content
    &::before
    right -59px
    border-left 60px solid var(--article-content-bgcolor)
    .article-content-text
    margin 20px 20px 20px 0px
    .article-title
    padding 0px 30px 0px 70px
    .recent-post-meta
    padding 0px 20px 0px 70px
    &.left
    flex-direction: row-reverse;
    right 9px
    transition: all .5s cubic-bezier(0.59, 0.01, 0.48, 1.17)
    &::before
    right: calc(23.07% + 40px);
    border-right: 6px solid var(--recent-post-triangle);
    .recent-post-info
    &::before
    background linear-gradient(to left, var(--recent-post-cover-shadow), transparent)
    right calc(100% - 1px)
    .article-content
    &::before
    left -59px
    border-right 60px solid var(--article-content-bgcolor)
    .article-content-text
    margin 20px 0px 20px 20px
    .article-title
    padding 0px 70px 0px 30px
    .recent-post-meta
    padding 0px 70px 0px 20px

    .article-content
    width 30%
    height 200px
    left 0
    align-items center
    &::before
    content ""
    width 0
    height 0
    background transparent
    position absolute
    z-index 2
    top 0
    border-top 100px solid transparent
    border-bottom 100px solid transparent
    .recent-post-info
    width 60%
    height 200px
    &::before
    content ""
    width 200px
    height 200px
    position absolute
    z-index 1
    top 0
    .recent-post-meta
    & > .article-meta-wrap
    margin: 6px 0
    color: $theme-meta-color
    font-size: 90%

    & > .post-meta-date
    cursor: default

    .sticky
    color: $sticky-color

    i
    margin: 0 4px 0 0

    .article-meta-label
    if hexo-config('post_meta.page.label')
    padding-right: 4px
    else
    display: none

    .article-meta-separator
    margin: 0 6px

    .article-meta-link
    margin: 0 4px

    if hexo-config('post_meta.page.date_format') == 'relative'
    time
    display: none

    a
    color: $theme-meta-color

    &:hover
    color: $text-hover
    text-decoration: underline
    .recent-post-cover
    width 40%
    height 200px
    @media screen and (max-width:600px)
    .recent-post-item
    height 400px
    .recent-post-content
    display flex
    flex-direction: column
    height 400px
    .article-content
    pointer-events none
    order: 1;
    height: 200px;
    position: absolute;
    width: calc(100% - 40px);
    z-index: 3;
    background: rgba(22,22,22,0.5);
    border-top-left-radius: 15px;
    border-top-right-radius: 15px;
    display: none
    opacity: 0
    .article-content-text
    height 120px
    color: white;
    width: 80%

    .recent-post-cover
    order: 2
    height 200px
    transition: all .5s
    .recent-post-info
    order: 3
    height 200px
    &::before
    content: '';
    width: 0;
    height: 0;
    position: absolute;
    z-index: 3;
    bottom: calc(100% - 4px);
    left: 0;
    border-bottom: 50px solid var(--recent-post-bgcolor);
    border-right: 300px solid transparent;
    &::after
    content: '';
    width: 0;
    height: 0;
    position: absolute;
    z-index: 3;
    bottom: calc(100% + 150px);
    right: 0;
    border-top: 50px solid var(--recent-post-bgcolor);
    border-left: 300px solid transparent;
    .article-title
    padding: 0px 35px 0px 35px
    .recent-post-meta
    padding: 0px 30px 0px 30px
    &:hover
    .article-content
    display: flex !important;
    animation: shutter-effect-content 0.5s 2 forwards linear
    .recent-post-info
    &::before
    animation: shutter-effect-left 0.5s 1 ease-in-out
    &::after
    animation: shutter-effect-right 0.5s 1 ease-in-out
    .recent-post-cover
    filter blur(2px)
    @keyframes shutter-effect-right {
    0%{
    bottom: calc(100% + 150px);
    border-top: 50px solid var(--recent-post-bgcolor);
    border-left: 300px solid transparent;
    }
    50%{
    bottom: 100%;
    border-top: 200px solid var(--recent-post-bgcolor);
    border-left: 600px solid transparent;
    }
    100%{
    bottom: calc(100% + 150px);
    border-top: 50px solid var(--recent-post-bgcolor);
    border-left: 300px solid transparent;
    }
    }
    @keyframes shutter-effect-left {
    0%{
    bottom: calc(100% - 4px);
    border-bottom: 50px solid var(--recent-post-bgcolor);
    border-right: 300px solid transparent;
    }
    50%{
    bottom: calc(100% - 4px);
    border-bottom: 200px solid var(--recent-post-bgcolor);
    border-right: 600px solid transparent;
    }
    100%{
    bottom: calc(100% - 4px);
    border-bottom: 50px solid var(--recent-post-bgcolor);
    border-right: 300px solid transparent;
    }
    }
    @keyframes shutter-effect-content {
    from {
    opacity: 0
    }
    to {
    opacity: 1
    }
    }
    备份:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    #recent-posts
    & > .recent-post-item:not(:first-child)
    margin-top: 20px

    & > .recent-post-item
    @extend .cardHover
    display: flex
    flex-direction: row
    align-items: center
    overflow: hidden
    height: 18em

    +maxWidth768()
    flex-direction: column
    height: auto

    &:hover
    img.post_bg
    transform: scale(1.1)

    &.ads-wrap
    display: block !important
    height: auto !important

    .post_cover
    overflow: hidden
    width: 44%
    height: 100%

    +maxWidth768()
    width: 100%
    height: 230px

    img.post_bg
    @extend .imgHover

    &.right
    order: 1

    +maxWidth768()
    order: 0

    & >.recent-post-info
    padding: 0 40px
    width: 57%

    +maxWidth768()
    padding: 20px 20px 30px
    width: 100%

    &.no-cover
    width: 100%

    +maxWidth768()
    padding: 30px 20px

    & > .article-title
    @extend .limit-more-line
    color: var(--text-highlight-color)
    font-size: 1.72em
    line-height: 1.4
    transition: all .2s ease-in-out
    -webkit-line-clamp: 2

    +maxWidth768()
    font-size: 1.43em

    &:hover
    color: $text-hover

    & > .article-meta-wrap
    margin: 6px 0
    color: $theme-meta-color
    font-size: 90%

    & > .post-meta-date
    cursor: default

    .sticky
    color: $sticky-color

    i
    margin: 0 4px 0 0

    .article-meta-label
    if hexo-config('post_meta.page.label')
    padding-right: 4px
    else
    display: none

    .article-meta-separator
    margin: 0 6px

    .article-meta-link
    margin: 0 4px

    if hexo-config('post_meta.page.date_format') == 'relative'
    time
    display: none

    a
    color: $theme-meta-color

    &:hover
    color: $text-hover
    text-decoration: underline

    & > .content
    @extend .limit-more-line
    -webkit-line-clamp: 2

时钟插件

  1. 安装插件,在博客根目录 [Blogroot] 下打开终端,运行以下指令:
    1
    npm install hexo-butterfly-clock --save
  2. 在站点配置文件_config.yml 或者主题配置文件_config.butterfly.yml 中添加
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # electric_clock
    # see https://akilar.top/posts/4e39cf4a/
    electric_clock:
    enable: true # 开关
    priority: 5 #过滤器优先权
    enable_page: all # 应用页面
    exclude:
    # - /posts/
    # - /about/
    layout: # 挂载容器类型
    type: class
    name: sticky_layout
    index: 0
    loading: https://npm.elemecdn.com/hexo-butterfly-clock/lib/loading.gif #加载动画自定义
    clock_css: https://npm.elemecdn.com/hexo-butterfly-clock/lib/clock.min.css
    clock_js: https://npm.elemecdn.com/hexo-butterfly-clock/lib/clock.min.js
    ip_api: https://pv.sohu.com/cityjson?ie=utf-8

字体样式修改

不一定是 ttf 后缀,其他后缀也是完全正常的,例如 eot、otf、fon、font、ttc、woff、woff2 等.

  1. 首先需要下载心仪的字体。第一字体网:https://www.diyiziti.com/List/all/2 选择心仪的字体下载得到相应的字体文件,将其重命名为英文 xxx.ttf。
  2. 将下载好的字体包放到本地文件夹下,这里推荐新建一个 fonts 文件夹: [Blogroot]\themes\butterfly\source\fonts\ 目录下。
  3. 在自定义样式 custom.css 中引入字体包:
    1
    2
    3
    4
    5
    @font-face{
    font-family:'UniverseFont' ; /* 字体名自定义即可 */
    src:url('/fonts/Font.ttf'); /* 字体文件路径 */
    font-display : swap;
    }
  4. 在页面按F12,然后在控制台中进行调试。获取想应用字体元素的 id/class 然后把 font-family 写进 custom.css 就可以了
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @font-face{
    font-family:'UniverseFont' ; /* 字体名自定义即可 */
    src:url('/fonts/Font.ttf'); /* 字体文件路径 */
    font-display : swap;
    }

    /* 例如 */
    h1#site-title {
    font-family: 'UniverseFont', sans-serif;
    }

更改文章 h1~6 级标题前 icon 图标

单靠肉眼识别字体大小来判断标题等级不是件容易的事情,若 h1~6 标题使用不同图标的话,那么识别会容易许多。

1
2
3
4
5
6

/* 在<Custom>.css里添加以下代码: */
#article-container h1:before {
content: "<Custom>";
}
/* h2~6以此类推 */

其中部分可以填写一下内容:

  • H¹、H²、H³、H⁴、H⁵、H⁶
  • H₁、H₂、H₃、H₄、H₅、H₆
  • H1、H2、H3、H4、H5、H6
  • icon 图标
  • 阿里图标 …
    1
    2
    3
    4
    #article-container h1:before {
    font-family: "iconfont";
    content: "<Custom>"; /*阿里图标的 Unicode*/
    }

补充插件

hexo-renderer-pug

pug 以及 stylus 的渲染器

1
npm install hexo-renderer-pug hexo-renderer-stylus --save

hexo-next文章链接默认的生成规则是::year/:month/:day/:title,是按照年、月、日、标题来生成的,如果文章标题是中文的话,URL链接是也会是中文,复制后的链接是一长串,非常不利于阅读,也不简洁。用此插件可以生成唯一不变的URl链接。

  1. 安装
    1
    npm install hexo-abbrlink --save
  2. 修改根目录站点配置文件config.yml
    1
    2
    3
    4
    permalink: posts/:abbrlink.html  # post 参数为自己的自定义设置。比如::year/:month/:day:title/:abbrlink.html
    abbrlink:
    alg: crc32 #算法: crc16(default) and crc32
    rep: hex #进制: dec(default) and hex
  3. 生成完后,原md文件的Front-matter 内会增加abbrlink 字段,值为生成的ID 。这个字段确保了在我们修改了Front-matter 内的博客标题title或创建日期date字段之后而不会改变链接地址。

进阶操作

图床

PicGo + Gitee + Typora

PicGo + Github + Typora

特点:绑定 Typora 后支持直接在软件内插入图片自动上传图床。
缺点:国内访问速度慢(用的是github 作为存储仓库)

Typora 配置:
20220521224229

PicGo + SMMS

永久存储,图片链接支持https,可以删除上传的图片,提供多种图片链接格式。
每个图片最大5M,单次最多上传10张 。

Chrome 图床插件(不保证其稳定性)

方法:Chrome 插件市场 搜索插件名称安装即可

  1. 微博图床
    20220510154000
  2. Bilibili图床
    20220510154056

自定义域名

Github 自定义

之前绑定过了,现在好像忘了,看来不做笔记还是不行啊。有时间再重新操作下。

Gitee 自定义

要Pro版本才可以自定义,找了下开通Pro的入口没找到暂时被取消了

Hexo 写作命令

  • 分类与子分类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    并列分类:
    categories:
    - [Linux]
    - [Tools]

    并列+子分类:
    categories:
    - [Linux, Hexo]
    - [Tools, PHP]
  • 创建页面
    1
    2
    3
    4
    5
    6
    7
    hexo new [layout] <title>
    // hexo new post 'test'

    Layout:Hexo 有三种默认布局:post、page 和 draft,创建这三种不同类型的文件时,它们将会被保存到不同的路径:
    post source/_posts
    page source
    draft source/_drafts
  • 模版(Scaffold):在新建文章时,Hexo 会根据 scaffolds 文件夹内相对应的文件来建立文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Blog\scaffolds 文件夹下新建模板编辑模板取好模板名称,然后可以执行如下命令根据模板内容建立文章
    hexo new [模板名称] "文件名"


    模板参数 描述 默认值
    layout 布局 config.default_layout
    title 标题 文章的文件名
    date 建立日期 文件建立日期
    updated 更新日期 文件更新日期
    comments 开启文章的评论功能 true
    tags 标签(不适用于分页)
    categories 分类(不适用于分页)
    permalink 覆盖文章网址
    excerpt 纯文本的页面摘录。使用这个插件来格式化文本
    disableNunjucks 启用时禁用 Nunjucks 标签 {{ }}/{% %} 和标签插件的呈现
    lang 设置语言 Inherited from _config.yml
  • 分类和标签
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 需要为文章添加多个分类,可以使用以下 list 中的方法

    categories:
    - [Diary, PlayStation]
    - [Diary, Games]
    - [Life]

    此时这篇文章同时包括三个分类:
    PlayStation 和 Games 分别都是父分类 Diary 的子分类
    Life 是一个没有子分类的分类
  • 监视文件变动
    1
    hexo generate --watch
  • 一键三连
    1
    hexo clean & hexo g & hexo d
  • 部署
    1
    2
    3
    4
    5
    6
    7
    # 执行下列的其中一个命令,让 Hexo 在生成完毕后自动部署网站,两个命令的作用是相同的
    hexo generate --deploy
    hexo deploy --generate

    # 简写:上面两个命令可以简写为
    hexo g -d
    hexo d -g