Efu asked me to repost his previous Solitude configuration tutorial, so I’ve compiled and organized it for everyone’s convenience.

Historical Events Card

  1. In the source folder, locate the _data folder (create one if it doesn’t exist) and find the aside.yml file (create one if it doesn’t exist). Add the following code to the aside.yml file:
    - name: history
      title: Historical Events
      class: card-history
      id:
      icon: solitude st-clock-fill
      content_class:
      content_id: history-baidu
      content_css: 'height:80px;overflow:hidden'
      content_html: '<div class="history_swiper-container" id="history-container" style="width: 100%;height: 100%;margin-top: 6px">
            <div id="history_container_wrapper" class="swiper-wrapper"></div>
          </div>'
  2. In the source folder, locate the css folder (create one if it doesn’t exist), and find the custom.css file (create one if it doesn’t exist). Add the following code to custom.css:
/**
Historical Events
*/

#aside-content .card-history .swiper-wrapper {
    flex-direction: column
}

#aside-content .card-history .history_slide {
    text-align: left;
    display: flex!important;
    flex-direction: column;
    align-items: flex-start
}

#aside-content .card-history #history-baidu>.blog-slider__pagination {
    display: none
}

#aside-content .card-history .history_slide_time {
    color: var(--ba-secondtext);
    font-size: 14px;
    font-style: italic;
    font-weight: lighter
}

#aside-content .card-history .history_slide_link {
    line-height: 1.5;
    -webkit-line-clamp: 2;
    display: -webkit-box;
    overflow: hidden;
    -webkit-box-orient: vertical
}

#aside-content .card-history .history_slide_link a {
    color: var(--ba-main);
    padding: 0 4px;
    border-radius: 4px
}

#aside-content .card-history .history_slide_link a:hover {
    color: var(--ba-white);
    background: var(--ba-main)
}
/**
Historical Events
*/

#aside-content .card-history .swiper-wrapper {
    flex-direction: column
}

#aside-content .card-history .item-headline {
    margin-left: 0;
}

#aside-content .card-history .history_slide {
    text-align: left;
    display: flex !important;
    flex-direction: column;
    align-items: flex-start
}

#aside-content .card-history .history_slide_time {
    color: var(--ba-secondtext);
    font-size: 14px;
    font-style: italic;
    font-weight: lighter
}

#aside-content .card-history .history_slide_link {
    line-height: 1.5;
    -webkit-line-clamp: 2;
    display: -webkit-box;
    overflow: hidden;
    -webkit-box-orient: vertical
}

#aside-content .card-history .history_slide_link a {
    color: var(--ba-main);
    padding: 0 4px;
    border-radius: 4px
}

#aside-content .card-history .history_slide_link a:hover {
    color: var(--ba-white);
    background: var(--ba-main)
}
  1. In the source folder, find or create the custom.js file in the js folder. Add the following code:
// Historical Events
(function() {
    async function fetchHistoryData() {
        const myDate = new Date();
        const myMonth = myDate.getMonth() + 1;
        const getDate = myDate.getDate();
        const getMonth = myMonth < 10 ? "0" + myMonth : "" + myMonth;
        const getDay = getDate < 10 ? "0" + getDate : "" + getDate;
        const getMonthDate = "S" + getMonth + getDay;
        const history_data_url = `https://fastly.jsdelivr.net/gh/Zfour/Butterfly-card-history@2.08/baiduhistory/json/${getMonth}.json`;

        const response = await fetch(history_data_url);
        const data = await response.json();
        return data[getMonthDate];
    }

    function append(parent, text) {
        const temp = document.createElement('div');
        temp.innerHTML = text;
        const frag = document.createDocumentFragment();
        while (temp.firstChild) {
            frag.appendChild(temp.firstChild);
        }
        parent.appendChild(frag);
    }

    function card_history() {
        if (document.getElementById('history-container')) {
            fetchHistoryData().then(data => {
                const html_item = data.map(item => `
        <div class="swiper-slide history_slide">
            <span class="history_slide_time">A.D.${item.year}</span>
            <span class="history_slide_link">${item.title}</span>
        </div>
        `).join('');
                const history_container_wrapper = document.getElementById('history_container_wrapper');
                append(history_container_wrapper, html_item);
                const swiper_history = new Swiper('.history_swiper-container', {
                    passiveListeners: true,
                    spaceBetween: 30,
                    effect: 'coverflow',
                    coverflowEffect: {
                        rotate: 30,
                        slideShadows: false,
                    },
                    loop: true,
                    direction: 'vertical',
                    autoplay: {
                        disableOnInteraction: true,
                        delay: 5000
                    },
                    mousewheel: false,
                });
                const history_container = document.getElementById('history-container');
                history_container.onmouseenter = function () {
                    swiper_history.autoplay.stop();
                };
                history_container.onmouseleave = function () {
                    swiper_history.autoplay.start();
                }
            });
        }
    }

    card_history();

    document.addEventListener('pjax:complete', card_history);
})();
// Historical Events
document.addEventListener('DOMContentLoaded', function () {
    async function cardHistory() {
        const historyContainer = document.getElementById('history-container');
        if (!historyContainer) return;
        const data = await fetchHistoryData();
        const html = data.map(item => `<div class="swiper-slide history_slide"><span class="history_slide_time">A.D.${item.year}</span><span class="history_slide_link">${item.title}</span></div>`).join('');
        const swiperContainer = document.querySelector('.history_swiper-container');
        document.getElementById('history_container_wrapper').innerHTML = html
        const swiperHistory = new Swiper(swiperContainer, {
            loop: true,
            direction: 'vertical',
            autoplay: {disableOnInteraction: true, delay: 5000},
            mousewheel: false,
        });
        historyContainer.onmouseenter = () => swiperHistory.autoplay.stop();
        historyContainer.onmouseleave = () => swiperHistory.autoplay.start();

        async function fetchHistoryData() {
            const myDate = new Date();
            const formattedDate = 'S' + `${myDate.getMonth() + 1}`.padStart(2, '0') + `${myDate.getDate()}`.padStart(2, '0');
            const historyDataUrl = `https://fastly.jsdelivr.net/gh/Zfour/Butterfly-card-history@2.08/baiduhistory/json/${myDate.getMonth() < 10 ? '0' + (myDate.getMonth() + 1) : myDate.getMonth() + 1}.json`;
            const response = await fetch(historyDataUrl);
            const data = await response.json();
            return data[formattedDate];
        }
    }
    cardHistory()
    document.addEventListener('pjax:complete', cardHistory);
})
  1. Add the following in the extends section of the head in the theme configuration file _config.solitude.yml:
    - <link rel="stylesheet" href="/css/custom.css">
  2. Add the following in the extends section of the body in the theme configuration file _config.solitude.yml:
    - <script src="/js/custom.js"></script>

If you are not using Short Essays, you also need to add the following to extends:

extends:
   head:
     - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/11.0.5/swiper-bundle.min.css" />
   body:
     - <script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/11.0.5/swiper-bundle.min.js"></script>

New Year Countdown Card

The New Year Countdown Card has been invalid since version 1.9.0

  1. Find the _data folder in the source folder (do not create it first), and find the aside.yml file (do not create it first). Add the following code to the aside.yml file:
    home:
     noSticky:
        - class_name:
          id_name: newYear
          name:
          icon:
          html: '<div id="newYear-main">
             <p class="title"></p>
             <div class="newYear-time"></div>
             <p class="today" style="text-align: right;"></p>
             </div>'
     Sticky:
  2. Create a new custom.css file in the [root]/source/css directory (if there is no css folder, please create one) and add the following content:
    /* 新年侧边栏 */
    #newYear {
     color: var(--ba-card-bg);
     padding: 0 !important;
    }
    
    #newYear p,
    #newYear h3 {
     font-weight: normal;
     color: inherit;
     margin: 0;
    }
    
    #newYear .item-headline {
     display: none;
    }
    
    #newYear-main {
     min-height: 160px;
     padding: 1rem;
     position: relative;
     border-radius: 12px;
     background-color: var(--ba-theme);
    }
    
    #newYear-main * {
     position: relative;
     line-height: 1.3;
    }
    
    #newYear-main .newYear-time {
     font-weight: bold;
     text-align: center;
    }
    
    #newYear-main .time,
    #newYear-main .happyNewYear {
     font-size: 2rem;
     text-shadow: 2px 2px 2px red;
     margin: 1rem 0;
     display: block;
    }
    
    #newYear-main .day {
     font-size: 5rem;
    }
    
    #newYear-main .day .unit {
     font-size: 1rem;
    }
  3. Find the js folder in the source folder (do not create it first), and find the custom.js file (do not create it first). Add the following code to the custom.js file:
    let newYearTimer = null;
    var newYear = () => {
    clearTimeout(newYearTimer);
    if (!document.querySelector('#newYear')) return;
    // 新年时间戳 and 星期对象
    let newYear = new Date('2024-02-10 00:00:00').getTime() / 1000,
    week = { 0: '周日', 1: '周一', 2: '周二', 3: '周三', 4: '周四', 5: '周五', 6: '周六' }
    
        time();
    
        // 补零函数
        function nol(h) { return h > 9 ? h : '0' + h; };
    
        function time() {
            // 现在 时间对象
            let now = new Date();
    
            // 右下角 今天
            document.querySelector('#newYear .today').innerHTML = now.getFullYear() + '年' + (now.getMonth() + 1) + '月' + now.getDate() + '日 ' + week[now.getDay()]
    
            // 现在与新年相差秒数
            let second = newYear - Math.round(now.getTime() / 1000);
    
            // 小于0则表示已经过年
            if (second < 0) {
                document.querySelector('#newYear .title').innerHTML = '喜迎新年';
                document.querySelector('#newYear .newYear-time').innerHTML = '<span class="happyNewYear">新年快乐!</span>';
            } else {
                // 大于0则还未过年
                document.querySelector('#newYear .title').innerHTML = '距离2024年春节:'
    
                // 大于一天则直接渲染天数
                if (second > 86400) {
                    document.querySelector('#newYear .newYear-time').innerHTML = `<span class="day">${Math.ceil(second / 86400)}<span class="unit">天</span></span>`
                } else {
                    // 小于一天则使用时分秒计时。
                    let h = nol(parseInt(second / 3600));
                    second %= 3600;
                    let m = nol(parseInt(second / 60));
                    second %= 60;
                    let s = nol(second);
                    document.querySelector('#newYear .newYear-time').innerHTML = `<span class="time">${h}:${m}:${s}</span></span>`;
                    // 计时
                    newYearTimer = setTimeout(time, 1000);
                }
            }
        }
    }
    newYear();
    
    document.addEventListener('pjax:complete', newYear);
  4. Add the following content to the head of extends in the theme configuration file:
- <link rel="stylesheet" href="/css/custom.css">
  1. Add the following content to the body of extends in the theme configuration file:
    - <script src="/js/custom.js"></script>

Intuitively display the friend link application conditions to ensure that others can apply after seeing and agreeing, effectively saving time for both parties.

  • Twikoo
<style>
.tk-comments > .tk-submit {
  opacity: 0;
  height: 0;
  transition: opacity 0.5s, height 0.5s;
  overflow: inherit !important;
}
</style>

<p  style="padding: 0px 0px 0px 0px;">
Please <strong>check</strong> the conditions that apply:
</p>

<div id="friendlink_checkboxs" style="padding: 0px 1rem 0px 0px;">
  <p>
    <label class="checkbox"><input type="checkbox" id="checkbox1" onclick="checkForm()">I have added btwoa's blog friend link</label>
  </p>
  <p>
    <label class="checkbox"><input type="checkbox" id="checkbox2" onclick="checkForm()">My site is personal, and the type is blog</label>
  </p>
  <p>
    <label class="checkbox"><input type="checkbox" id="checkbox3" onclick="checkForm()">My site is accessible from mainland China</label>
  </p>
  <p>
    <label class="checkbox"><input type="checkbox" id="checkbox4" onclick="checkForm()">The content of my site complies with Chinese laws</label>
  </p>
</div>

<script>
var twikooSubmit = document.getElementsByClassName("tk-submit")[0];
if(twikooSubmit) {
    twikooSubmit.style.opacity = "0";
}
function checkForm() {
    let comment = document.querySelector('.tk-submit');
    if(comment===null) return;
    let checkboxes = document.querySelectorAll('#friends_checkbox input[type="checkbox"]');
    let content = document.querySelector('.el-textarea__inner');
    let allChecked = Array.from(checkboxes).every(checkbox => checkbox.checked);
    if (allChecked) {
        comment.style.display = 'block';
        content.value = "```yaml \n- name: \n  link: \n  avatar: \n  descr: \n```";
        content.style.height = '205px';
        content.focus();
    } else {
        comment.style.display = 'none';
        content.value = '';
    }
}
window.onload = checkForm;
document.addEventListener('pjax:complete', checkForm);
</script>

Accessibility shortcut menu

  1. The theme has built-in configuration items, just enable and configure them.
    keyboard:
      enable: false # 是否开启键盘控制 / Whether to enable keyboard control
      # 键盘控制配置
      # Keyboard control configuration
      list:
      # name: 按键名称
      # name: Key name
      # key: 按键
      # key: Key
      # func: 方法
      # func: Function
      # sco: sco内置方法
      # sco: sco built-in method
      # url: 跳转链接
      # url: Jump link
      #    - name: 关闭快捷键功能
      #      key: K
      #      func: keyboard
      #    - name: 打开中控台
      #      key: A
      #      sco: showConsole
      #    - name: 播放/暂停音乐
      #      key: M
      #      sco: musicToggle
      #    - name: 打开友情链接
      #      key: L
      #      url: '/links/'
  2. List The methods that can be added include
    func: self-defined methods, non-Sco methods in the theme
    sco: Sco built-in methods
    link: can directly write links

Only one method can be added. If multiple methods are added, only the last method will be executed

  1. My configuration
    keyboard:
     enable: true
     list:
       - name: 关闭快捷键功能
         key: K
         func: keyboard
       - name: 打开中控台
         key: A
         sco: showConsole
       - name: 播放/暂停音乐
         key: M
         sco: musicToggle
       - name: 深色/浅色显示切换
         key: N 
         sco: switchDarkMode
       - name: 站内搜索
         key: S
         func: openSearch
       - name: 随机访问
         key: R
         func: toRandomPost
       - name: 返回首页
         key: H
         url: /
       - name: 友链鱼塘
         key: F
         url: '/moments/'
       - name: 友情链接
         key: L
         url: '/links/'
       - name: 关于本站
         key: P
         url: '/about/' 
  2. After saving, redeploy.
  3. Reference
Type Method Description
func openSearch Open site search
func toRandomPost Random access
sco switchDarkMode Switch dark/light mode
sco switchKeyboard Switch shortcut key switch
sco showConsole Open the console
sco musicToggle Play/pause music
sco switchCommentBarrage Switch barrage switch
sco toTop Back to the top
link Write the address to jump to

Expandable func, custom method, method name cannot be repeated.

Compress code

  1. Install the plugin
npm install gulp compress gulp-clean-css gulp-html-minifier-terser gulp-htmlclean gulp-terser gulp-uglify --save
  1. Create a new gulpfile.js file
var gulp = require('gulp');
var cleanCSS = require('gulp-clean-css');
var htmlmin = require('gulp-html-minifier-terser');
var htmlclean = require('gulp-htmlclean');
var terser = require('gulp-terser');
var uglify = require('gulp-uglify');
// 压缩js
gulp.task('compress', () =>
gulp.src(['./public/**/*.js', '!./public/**/*.min.js'])
.pipe(terser())
.pipe(uglify())
.pipe(gulp.dest('./public'))
)
//压缩css
gulp.task('minify-css', () => {
return gulp.src(['./public/**/*.css'])
.pipe(cleanCSS({
compatibility: 'ie11'
}))
.pipe(gulp.dest('./public'));
});
//压缩html
gulp.task('minify-html', () => {
return gulp.src('./public/**/*.html')
.pipe(htmlclean())
.pipe(htmlmin({
removeComments: true, //清除html注释
collapseWhitespace: true, //压缩html
collapseBooleanAttributes: true,
//省略布尔属性的值,例如:<input checked="true"/> ==> <input />
removeEmptyAttributes: true,
//删除所有空格作属性值,例如:<input id="" /> ==> <input />
removeScriptTypeAttributes: true,
//删除<script>的type="text/javascript"
removeStyleLinkTypeAttributes: true,
//删除<style>和<link>的 type="text/css"
minifyJS: true, //压缩页面 JS
minifyCSS: true, //压缩页面 CSS
minifyURLs: true  //压缩页面URL
}))
.pipe(gulp.dest('./public'))
});

// 运行gulp命令时依次执行以下任务
gulp.task('default', gulp.parallel(
'compress', 'minify-css', 'minify-html'
))

Mouse cursor

To ensure the accuracy of following and feedback, it will follow the mouse position in real time and listen to mouse events. There are a lot of DOM operations, which may occasionally cause lag. It is not recommended for those who are sensitive to resource usage

  1. Add the following code to the custom.css file
@media (max-width: 1000px) {
    html, body {
        cursor: default;
  }

  .circle {
      display: none;
  }

  .small-circle, .large-circle, body.hovered .small-circle::before, .pulse {
      display: none !important;
  }
}

@media (min-width: 1000px) {
    html, body {
        cursor: none;
  }

    html, body, img, div, a, span, path, svg, button, p, h1, h2, h3, h4, h5, h6, 
    b, strong, i, em, blockquote, ul, ol, li, pre, code, label, textarea, input, 
    select, option, audio, video, canvas, iframe, table, tr, td, th, thead, tbody, 
    tfoot, col, colgroup, form, fieldset, legend, nav, header, footer, article, 
    section, aside, figure, figcaption, details, summary, main {
        cursor: none !important;
    }
}

.circle {
    position: fixed;
    border-radius: 50%;
    pointer-events: none;
    display: none;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}

.small-circle {
    width: 12px;
    height: 12px;
    background-color: #fff;
    mix-blend-mode: exclusion;
    z-index: 99999999;
    transition: transform 0.2s ease-out;
    transform-origin: center;
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}

.large-circle {
    width: 32px;
    height: 32px;
    background: radial-gradient(circle, rgba(34, 34, 34, 0.2) 0%, rgba(34, 34, 34, 0.3) 100%);
    transition: transform 0.2s ease-out, left 0.2s ease-out, top 0.2s ease-out;
    z-index: 99999998;
    transform-origin: center;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
}

.small-circle::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    width: 1px;
    height: 100%;
    background-color: #000;
    transform: translateX(-50%);
    visibility: hidden;
}

body.hovered .small-circle::before {
    visibility: visible;
}

@keyframes pulse {
    0% {
        transform: scale(0.5);
        opacity: 0.5;
    }
    50% {
        transform: scale(1);
        opacity: 0.8;
    }
    100% {
        transform: scale(0.5);
        opacity: 0.5;
    }
}

.pulse {
    animation: pulse 1.5s infinite;
}
  1. custom.js 文件中添加如下代码
const largeCircle = document.getElementById('largeCircle');
const smallCircle = document.getElementById('smallCircle');

let isMouseDown = false;
let isLargeCircleVisible = false;
let mouseX = 0;
let mouseY = 0;

function setPosition(x, y) {
    const halfLargeCircleWidth = largeCircle.offsetWidth / 2;
    const halfSmallCircleWidth = smallCircle.offsetWidth / 2;

    smallCircle.style.left = `${x - halfSmallCircleWidth}px`;
    smallCircle.style.top = `${y - halfSmallCircleWidth}px`;

    largeCircle.style.left = `${x - halfLargeCircleWidth}px`;
    largeCircle.style.top = `${y - halfLargeCircleWidth}px`;

    largeCircle.style.transform = isMouseDown ? 'scale(0.5)' : 'scale(1)';
    smallCircle.style.transform = isMouseDown ? 'scale(2)' : 'scale(1)';
}

function updateHoverStatus(x, y) {
    const textElements = document.querySelectorAll('p, h1, h2, h3, h4, h5, h6, span, a, div, pre, code, input, textarea');
    let isHoveringText = Array.from(textElements).some(el => {
        const textNodes = Array.from(el.childNodes).filter(node => node.nodeType === Node.TEXT_NODE);
        return textNodes.some(node => {
            const range = document.createRange();
            range.selectNodeContents(node);
            return Array.from(range.getClientRects()).some(rect =>
                x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom
            );
        });
    });

    const inputElements = document.querySelectorAll('input, textarea');
    isHoveringText = isHoveringText || Array.from(inputElements).some(el => {
        const rect = el.getBoundingClientRect();
        return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
    });

    document.body.classList.toggle('hovered', isHoveringText);
}

function animate() {
    setPosition(mouseX, mouseY);
    updateHoverStatus(mouseX, mouseY);

    if (!isLargeCircleVisible) {
        isLargeCircleVisible = true;
        largeCircle.style.display = 'block';
        smallCircle.style.display = 'block';
    }

    requestAnimationFrame(animate);
}

function handleMove(event) {
    mouseX = event.clientX;
    mouseY = event.clientY;

    if (!isLargeCircleVisible) {
        requestAnimationFrame(animate);
    }
}

document.addEventListener('mousemove', handleMove);

document.addEventListener('mousedown', (event) => {
    isMouseDown = true;
    mouseX = event.clientX;
    mouseY = event.clientY;
    setPosition(mouseX, mouseY);
    largeCircle.classList.add('pulse');
});

document.addEventListener('mouseup', () => {
    isMouseDown = false;
    setPosition(mouseX, mouseY);
    largeCircle.classList.remove('pulse');
});
  1. layout/includes/inject/body.pug 文件顶部添加如下代码
#smallCircle.circle.small-circle
#largeCircle.circle.large-circle

Theme Tags

The Solitude Theme Plugin Tags are partially migrated from Store Owner’s hexo-butterfly-tag-plugins-plus. Please credit the source when reposting.
Usage and configuration options are similar.

btn Button

{% btn [url],[text],[icon],[color] [style] [layout] [position] [size] %}

[url]: Link
[text]: Button text
[icon]: [Optional] Icon
[color]: [Optional] Button background color (default style)
Button text and border color (for outline style)
bg-default/bg-blue/bg-pink/bg-red/bg-purple/bg-orange/bg-green
[style]: [Optional] Button style, default is solid
outline/leave empty
[layout]: [Optional] Button layout, default is inline
block/leave empty
[position]: [Optional] Button position, applicable only if layout is block, default is left
center/right/leave empty
[size]: [Optional] Button size
larger/leave empty
Parameter Description
url Link
text Button text
icon [Optional] Icon
color [Optional] Button background color (default for solid style), text and border color (for outline style). Choices: default/blue/pink/red/purple/orange/green
layout [Optional] Button layout, default is inline. Choices: block/leave empty
position [Optional] Button position if layout is block, default is left. Choices: center/right/leave empty
size [Optional] Button size. Choices: larger/leave empty

A set of buttons

This is my website, click the btn

This is my website, click the btn

This is my website, click the btn

This is my website, click the btn

This is my website, click the btn

Adjust position or size

More than one btn in center

Centered buttons

> A set of buttons

This is my website, click the btn {% btn 'https://google.com/',G %}
This is my website, click the btn {% btn 'https://google.com/',G,st-lightbulb-line %}
This is my website, click the btn {% btn 'https://google.com/',G,outline %}
This is my website, click the btn {% btn 'https://google.com/',G,st-lightbulb-line,outline %}
This is my website, click the btn {% btn 'https://google.com/',G,st-lightbulb-line,larger %}

> Adjust position or size

{% btn 'https://google.com/',G,st-lightbulb-line,block %}
{% btn 'https://google.com/',G,st-lightbulb-line,block center larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,block right outline larger %}

> More than one btn in the center

<span>
{% btn 'https://google.com/',G,st-lightbulb-line,larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,blue larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,pink larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,red larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,purple larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,orange larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,green larger %}
</span>

> Centered buttons

<div class="btn-center">
{% btn 'https://google.com/',G,st-lightbulb-line,outline larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,outline blue larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,outline pink larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,outline red larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,outline purple larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,outline orange larger %}
{% btn 'https://google.com/',G,st-lightbulb-line,outline green larger %}
</div>

image 单张图片

{% image 链接, width=宽度(可选), height=高度(可选), alt=描述(可选), bg=占位颜色(可选) %}
  1. 图片宽度高度:width=300px, height=32px
  2. 图片描述:alt=图片描述
  3. 占位背景色:bg=#f2f2f2

添加描述

侵蚀之困
侵蚀之困

指定宽度

设置占位背景色

> 添加描述

{% image https://assets.btwoa.com/measure.avif, alt=侵蚀之困 %}

> 指定宽度

{% image https://assets.btwoa.com/measure.avif, width=500px %}

> 设置占位背景色

{% image https://assets.btwoa.com/measure.avif, width=400px, bg=#000000 %}

inlineimage 行内图片

{% inlineimage 图片链接, height=高度(可选) %}
  1. 高度:height=20px

这是 一段话。

这又是 一段话。

这是 {% inlineimage https://assets.btwoa.com/measure.avif %} 一段话。

这又是 {% inlineimage https://assets.btwoa.com/measure.avif, height=100px %} 一段话。

label 标签

{% label text color %}
参数 释义
text 文字
color 【可选】背景颜色,默认为 default,default/blue/pink/red/purple/orange/green

臣亮言: 创业未半,而 。今天下三分, ,此诚 也!然侍衞之臣,不懈于内; ,忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气;不宜妄自菲薄,引喻失义,以塞忠谏之路也。
宫中、府中,俱为一体;陟罚臧否,不宜异同。若有 ,及为忠善者,宜付有司,论其刑赏,以昭陛下平明之治;不宜偏私,使内外异法也。

臣亮言:{% label 先帝 %}创业未半,而{% label 中道崩殂 blue %}。今天下三分,{% label 益州疲敝 pink %},此诚{% label 危急存亡之秋 red %}也!然侍衞之臣,不懈于内;{% label 忠志之士 purple %},忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气;不宜妄自菲薄,引喻失义,以塞忠谏之路也。
宫中、府中,俱为一体;陟罚臧否,不宜异同。若有{% label 作奸 orange %}、{% label 犯科 green %},及为忠善者,宜付有司,论其刑赏,以昭陛下平明之治;不宜偏私,使内外异法也。

audio 直链音频

{% audio 音频链接 %}
{% audio 音频链接 %}

video 直链视频

{% video 视频链接 %}
  1. 对其方向:left, center, right
  2. 列数:逗号后面直接写列数,支持 1 ~ 4 列。

默认

50% 宽度

25 %

> 默认

{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}

> 50% 宽度

{% videos, 2 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% endvideos %}

> 25 %

{% videos, 4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% video https://assets.btwoa.com/video/bueviocwmp.mp4 %}
{% endvideos %}

p 段落文本

{% p 样式参数(参数以空格划分), 文本内容 %}
  1. 字体: logo, code
  2. 颜色: red,yellow,green,cyan,blue,gray
  3. 大小: small, h4, h3, h2, h1, large, huge, ultra
  4. 对齐方向: left, center, right

red left

yellow center

green right

center h1

center ultra


{% p red left, red left %}

{% p yellow center, yellow center %}

{% p green right, green right %}

{% p center h1, center h1 %}

{% p center ultra, center ultra %}

Note (Bootstrap Callout)

{% note [class] %}
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam, libero.
{% endnote %}
参数 含义
class 显示值

显示值:(中间空格)

  • 配色
    • default / primary / success / info / warning / danger
  • 样式
    • simple / modern / flat / disabled
  • 图标
    • noicon

默认样式

Demo 1 - default

Simple 样式

Demo 1 - default

Demo 2 - primary

Demo 3 - success

Demo 4 - info

Demo 5 - warning

Demo 6 - danger

Modern 样式

Demo 1 - default

Demo 2 - primary

Demo 3 - success

Demo 4 - info

Demo 5 - warning

Demo 6 - danger

Flat 样式

Demo 1 - default

Demo 2 - primary

Demo 3 - success

Demo 4 - info

Demo 5 - warning

Demo 6 - danger

Disabled 样式

Demo 1 - default

Demo 2 - primary

Demo 3 - success

Demo 4 - info

Demo 5 - warning

Demo 6 - danger

默认样式:
{% note default %}
Demo 1 - default
{% endnote %}

1. Simple 样式
   {% note default simple %}
   Demo 1 - default
   {% endnote %}

{% note primary simple %}
Demo 2 - primary
{% endnote %}

{% note success simple %}
Demo 3 - success
{% endnote %}

{% note info simple %}
Demo 4 - info
{% endnote %}

{% note warning simple %}
Demo 5 - warning
{% endnote %}

{% note danger simple %}
Demo 6 - danger
{% endnote %}

2. Modern 样式
   {% note default modern %}
   Demo 1 - default
   {% endnote %}

{% note primary modern %}
Demo 2 - primary
{% endnote %}

{% note success modern %}
Demo 3 - success
{% endnote %}

{% note info modern %}
Demo 4 - info
{% endnote %}

{% note warning modern %}
Demo 5 - warning
{% endnote %}

{% note danger modern %}
Demo 6 - danger
{% endnote %}

3. Flat 样式
   {% note default flat %}
   Demo 1 - default
   {% endnote %}

{% note primary flat %}
Demo 2 - primary
{% endnote %}

{% note success flat %}
Demo 3 - success
{% endnote %}

{% note info flat %}
Demo 4 - info
{% endnote %}

{% note warning flat %}
Demo 5 - warning
{% endnote %}

{% note danger flat %}
Demo 6 - danger
{% endnote %}

3. Disabled 样式
   {% note default disabled %}
   Demo 1 - default
   {% endnote %}

{% note primary disabled %}
Demo 2 - primary
{% endnote %}

{% note success disabled %}
Demo 3 - success
{% endnote %}

{% note info disabled %}
Demo 4 - info
{% endnote %}

{% note warning disabled %}
Demo 5 - warning
{% endnote %}

{% note danger disabled %}
Demo 6 - danger
{% endnote %}

tabs 分栏

分栏支持内置codesign图标,如果开启了 customicon 则可以使用自定义的图标,否则只能使用默内置codesign图标

{% tabs Unique name, [index] %}

<!-- tab [Tab caption] [@icon] -->

Any content (support inline tags too).

<!-- endtab -->

{% endtabs %}
  1. Unique name:不带逗号的选项卡块标记的唯一名称。
    1. 将在 #id 中用作每个选项卡及其索引号的前缀。
    2. 如果名称中有空格,则对于生成 #id 所有空格都将替换为破折号。
    3. 仅帖子/页面的当前网址必须是唯一的!
  2. [index]:活动选项卡的索引号。
    1. 如果未指定,将选择第一个选项卡 (1)。
    2. 如果 index 为 -1,则不选择任何选项卡。这将是剧透。
    3. 可选参数。
  3. [Tab caption]:当前选项卡的标题。
    1. 如果未指定标题,则带有选项卡索引后缀的唯一名称将用作选项卡的标题。
    2. 如果未指定标题,但指定了图标,则标题将为空。
    3. 可选参数。
  4. [@icon]:图标名称(全名,例如“solitude st-logo”)
    1. 可以指定有或没有空格;例如,“Tab caption @icon”类似于“Tab caption@icon”。
    2. 可选参数。

Demo 1 - 预设选择第一个【默认】

This is Tab 1.

This is Tab 2.

This is Tab 3.

Demo 2 - 没有预设值

This is Tab 1.

This is Tab 2.

This is Tab 3.

Demo 3 - 自定义Tab名 + icon + Tab名和icon

This is Tab 1.

This is Tab 2.

This is Tab 3.

Demo 1 - 预设选择第一个【默认】


{% subtabs Demo1 %}
<!-- tab test1 -->
This is Tab 1.
<!-- endtab-->
<!-- tab test2 -->
This is Tab 2.
<!-- endtab-->
<!-- tab test3 -->
This is Tab 3.
<!-- endtab-->
{% endsubtabs %}

Demo 2 - 没有预设值

{% subtabs Demo2 %}
<!-- tab -->
This is Tab 1.
<!-- endtab-->
<!-- tab -->
This is Tab 2.
<!-- endtab-->
<!-- tab -->
This is Tab 3.
<!-- endtab-->
{% endsubtabs %}

Demo 3 - 自定义Tab名 + icon + Tab名和icon

{% subtabs Demo3 %}
<!-- tab test1  -->
This is Tab 1.
<!-- endtab-->
<!-- tab @st-mac -->
This is Tab 2.
<!-- endtab-->
<!-- tab Apple @st-mac -->
This is Tab 3.
<!-- endtab-->
{% endsubtabs %}

Timelne 时间轴

{% timeline title %}

{% timenode title %}

xxxx

{% endtimenode %}

{% timenode title %}

xxxx

{% endtimenode %}

{% endtimeline %}
参数 含义
title 节点名称
xxxx 内容区

1976.4

史蒂夫·乔布斯、斯蒂夫·沃兹尼亚克和罗纳德·韦恩创立了苹果公司

1996

苹果收购NeXT公司,乔布斯于隔年重返苹果公司

2007.1

苹果电脑公司正式推出其首款智能手机iPhone,并宣布更名为苹果公司

2020.6

库克宣布Mac将采用自研的ARM芯片

{% timeline %}

{% timenode 1976.4 %}

史蒂夫·乔布斯、斯蒂夫·沃兹尼亚克和罗纳德·韦恩创立了苹果公司

{% endtimenode %}

{% timenode 1996 %}
 
苹果收购NeXT公司,乔布斯于隔年重返苹果公司

{% endtimenode %}

{% timenode 2007.1 %}
 
苹果电脑公司正式推出其首款智能手机iPhone,并宣布更名为苹果公司

{% endtimenode %}

{% timenode 2020.6 %}
 
库克宣布Mac将采用自研的ARM芯片

{% endtimenode %}

{% endtimeline %}
{% link [title],[subtitle],[link] %}
参数 含义
title 标题
subtitle 简介
link 跳转链接
{% link Google,谷歌搜索,https://google.com/ %}

{% link AUR,archlinux user repository,https://aur.archlinux.org/ %}

fold 折叠块

{% fold title open %}

{% endfold %}
参数 含义
title 标题(可选)
oepn 是否打开(可选)不填默认不打开

Demo 1 - title

Demo1

Demo 2 - title + open

Demo2

Demo 1 - title

{% fold Demo1 %}

{% endfold %}

Demo 2 - title + open

{% fold Demo2 open %}

{% endfold %}

bvideo bilibili视频标签

{% bvideo [id] [time] %}
参数 含义
url bvid(例如视频链接后的:BV1k2421K7sQ)
{% bvideo BV1k2421K7sQ %}

checkbox 复选列表

{% checkbox 样式参数(可选), 文本内容 %}
  1. 样式: plus, minus, times
  2. 颜色: red,yellow,green,cyan,blue,gray
  3. 选中状态: checked

纯文本测试

支持简单的 markdown 语法

支持自定义颜色

绿色 + 默认选中

黄色 + 默认选中

青色 + 默认选中

蓝色 + 默认选中

增加

减少

{% checkbox 纯文本测试 %}
{% checkbox checked, 支持简单的 [markdown](https://guides.github.com/features/mastering-markdown/) 语法 %}
{% checkbox red, 支持自定义颜色 %}
{% checkbox green checked, 绿色 + 默认选中 %}
{% checkbox yellow checked, 黄色 + 默认选中 %}
{% checkbox cyan checked, 青色 + 默认选中 %}
{% checkbox blue checked, 蓝色 + 默认选中 %}
{% checkbox plus green checked, 增加 %}
{% checkbox minus yellow checked, 减少 %}
{% checkbox times red checked, 叉 %}

Katex

Replace the markdown-it renderer

npm un hexo-renderer-marked --save
npm un hexo-renderer-kramed --save
npm i hexo-renderer-markdown-it --save
npm install katex @renbaoshuo/markdown-it-katex

Add the following configuration to the root configuration file _config.yml:

# markdown-it
markdown:
    preset: 'default'
    render:
        html: true
        xhtmlOut: false
        langPrefix: 'language-'
        breaks: true
        linkify: true
        typographer: true
        quotes: '“”‘’'
    enable_rules:
    disable_rules:
    plugins:
        - '@renbaoshuo/markdown-it-katex'
    anchors:
        level: 2
        collisionSuffix: ''
        permalink: true
        permalinkClass: 'headerlink'
        permalinkSide: 'left'
        permalinkSymbol: ''
        case: 0
        separator: '-'
    images:
        lazyload: true
        prepend_root: false
        post_asset: false
    inline: false   

If you want to use Katex in your blog post, just add katex: true in the Front Matter of the post:

---
katex: true
---
$$
f(t)=\int_{-\infty}^\infty f(t) e^{-iwt}dt
$$

f(t)=f(t)eiwtdtf(t)=\int_{-\infty}^\infty f(t) e^{-iwt}dt

Typeit

{% typeit 'div' %}
options
{% endtypeit %}
Parameter Description
div Tag name
{% typeit 'div' %}
waitUntilVisible: true,
strings: "Hello World",
{% endtypeit %}