Solitude主题魔改内容

记录一下魔改的主题的过程,有一些是在其他博主的魔改的方法。

评论链接安全转跳

{% link ‘❖星港◎Star☆’ ‘关于本站|Solitude主题魔改内容’ ‘https://blog.starsharbor.com/posts/solitude-changefiles/' %}

路径:solitude/layout/includes/widgets/third-party/comments/twikoo.pug

为实现评论区链接安全跳转提醒,将该文件onCommentLoaded之后一行进行修改,为保证缩进一致,此处贴出全部文件(使用前请先安装hexo安全跳转插件)

YAML
- const { envId, region, option ,accessToken } = theme.twikoo
- const { lazyload, count, use,commentBarrage } = theme.comment

script().
    (() => {
        const getCount = () => {
            const ele = document.querySelectorAll('.twikoo-count')
            if (!ele) return
            twikoo.getCommentsCount({
                envId: '!{envId}',
                region: '!{region}',
                urls: [window.location.pathname],
                includeReply: false
            }).then(res => {
                ele.forEach(item => item.textContent = res[0].count)
            }).catch(err => {
                console.error(err)
            })
        }
        const init = () => {
            twikoo.init(Object.assign({
                el: '#twikoo-wrap',
                envId: '!{envId}',
                region: '!{region}',
                path: window.location.pathname,
                onCommentLoaded: () => {
                    GLOBAL_CONFIG.lightbox && utils.lightbox(document.querySelectorAll('#twikoo .tk-content img:not(.tk-owo-emotion)'))
                    const processLinks = () => {
                        const container = document.querySelector('#twikoo .tk-comments-container');
                        if (!container) return;

                        const links = container.querySelectorAll('a');
                        links.forEach((link) => {
                            const href = link.getAttribute('href');
                            if (!href) return;

                            if (!href.startsWith(window.location.origin) && !link.hasAttribute('data-fancybox')) {
                                const encodedHref = btoa(href);
                                const newHref = `/go.html?i=${encodedHref}`;
                                link.setAttribute('href', newHref);
                                link.setAttribute('rel', 'external nofollow noopener noreferrer');
                                link.setAttribute('target', '_blank');
                            }
                        });
                    };
                    processLinks();
                }
            }, !{JSON.stringify(option)}))

            !{count ? ' && getCount()' : ''}
            sco.owoBig({
                body: '.OwO-body',
                item: '.OwO-items li'
            })

            !{commentBarrage} && barrageTwikoo()
        }

        const loadTwikoo = () => {
            if (typeof twikoo === 'object') setTimeout(init,0)
            else utils.getScript('!{url_for(theme.cdn.twikoo)}').then(init)
        }

        if ('!{use[0]}' === 'Twikoo' || !{lazyload}) {
            if (!{lazyload}) utils.loadComment(document.getElementById('twikoo-wrap'), loadTwikoo)
            else loadTwikoo()
        } else {
            window.loadTwoComment = loadTwikoo
        }
    })()

if commentBarrage
    script.
        async function barrageTwikoo() {
            await fetch("!{envId}", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json"
                },
                body: JSON.stringify({
                    event: "COMMENT_GET",
                    accessToken: "!{accessToken}",
                    url: window.location.pathname
                })
            }).then(async res => {
                if (!res.ok) throw new Error("HTTP error! status: " + res.status)
                const data = await res.json();
                const init = () => {
                    initializeCommentBarrage((data.data).map(item => Object.assign({
                        content: item.comment,
                        nick: item.nick,
                        mailMd5: item.mailMd5,
                        id: item.id
                    })))
                }
                if (typeof initializeCommentBarrage === "undefined") await utils.getScript('!{url_for(theme.cdn.commentBarrage)}').then(init)
                else init()
            }).catch(error => console.error("An error occurred while fetching comments: ", error))
        }
点击展开查看更多

文章统计

{% link ‘Eukon’ ‘Hexo 博客文章统计图’ ‘https://blog.eurkon.com/post/1213ef82.html' %}

  1. 创建页面
BASH
hexo new page charts
点击展开查看更多
  1. 配置文件引入部分引入
YAML
inject:
  head:
    - <script src="https://lib.baomitu.com/echarts/4.9.0-rc.1/echarts.min.js"></script>
点击展开查看更多

Solitude的作者在允许全局调用该模块,在主题的 _config.yml 搜索chart: false改成true

  1. 新建文件路径:solitude/scripts/helper/charts.js
JAVASCRIPT
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(category.attr('data-parent')))
    }

    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();
    });
    postsChart.on('click', 'series', (event) => {
      if (event.componentType === 'series') window.location.href = '/archives/' + event.name.replace('-', '/');
    });
  </script>`
}

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

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

  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,
          interval: 0
        },
        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: ${tagArrJson},
        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) => {
      if(event.data.path) window.location.href = '/' + event.data.path;
    });
  </script>`
}

function categoriesChart (dataParent) {
  const categoryArr = []
  let categoryParentFlag = false
  hexo.locals.get('categories').map(function (category) {
    if (category.parent) categoryParentFlag = true
    categoryArr.push({
      name: category.name,
      value: category.length,
      path: category.path,
      id: category._id,
      parentId: category.parent || '0'
    })
  })
  categoryParentFlag = categoryParentFlag && dataParent === 'true'
  categoryArr.sort((a, b) => { return b.value - a.value })
  function translateListToTree (data, parent) {
    let tree = []
    let temp
    data.forEach((item, index) => {
      if (data[index].parentId == parent) {
        let obj = data[index];
        temp = translateListToTree(data, data[index].id);
        if (temp.length > 0) {
          obj.children = temp
        }
        if (tree.indexOf())
          tree.push(obj)
      }
    })
    return tree
  }
  const categoryNameJson = JSON.stringify(categoryArr.map(function (category) { return category.name }))
  const categoryArrJson = JSON.stringify(categoryArr)
  const categoryArrParentJson = JSON.stringify(translateListToTree(categoryArr, '0'))

  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 categoryParentFlag = ${categoryParentFlag}
    var categoriesOption = {
      title: {
        text: '文章分类统计图',
        x: 'center',
        textStyle: {
          color: color
        }
      },
      legend: {
        top: 'bottom',
        data: ${categoryNameJson},
        textStyle: {
          color: color
        }
      },
      tooltip: {
        trigger: 'item'
      },
      series: []
    };
    categoriesOption.series.push(
      categoryParentFlag ? 
      {
        nodeClick :false,
        name: '文章篇数',
        type: 'sunburst',
        radius: ['15%', '90%'],
        center: ['50%', '55%'],
        sort: 'desc',
        data: ${categoryArrParentJson},
        itemStyle: {
          borderColor: '#fff',
          borderWidth: 2,
          emphasis: {
            focus: 'ancestor',
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: 'rgba(255, 255, 255, 0.5)'
          }
        }
      }
      :
      {
        name: '文章篇数',
        type: 'pie',
        radius: [30, 80],
        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) => {
      if(event.data.path) window.location.href = '/' + event.data.path;
    });
  </script>`
}
点击展开查看更多
  1. 在页面使用
HTML
<!-- 文章发布时间统计图 -->
<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" data-parent="true" style="border-radius: 8px; height: 300px; padding: 10px;"></div>
点击展开查看更多

导航栏nav模糊效果

这个样式也是仿别人的,忘记作者的地址了。

CSS
[data-theme=light] #nav .menus_items .menus_item .menus_item_child {
    background-color: #ffffff4f!important;
    backdrop-filter: blur(7px)!important;
    -webkit-backdrop-filter: blur(7px)!important
}

[data-theme=dark] #nav .menus_items .menus_item .menus_item_child {
    background-color: #1d1e224f!important;
    backdrop-filter: blur(7px)!important;
    -webkit-backdrop-filter: blur(7px)!important
}

[data-theme=dark] #page-header.nav-fixed #nav {
    background: #0000006f!important
}

[data-theme=light] #page-header.nav-fixed #nav {
    background: #ffffff4f!important;
}

#page-header.nav-fixed #nav {
    outline: 1px #7c7c7c43 solid!important;
    backdrop-filter: blur(7px)!important;
    -webkit-backdrop-filter: blur(7px)!important
}

@media screen and (max-width: 768px) {
    #nav {
        background:#fff0!important
    }
}

@media screen and (max-width: 768px) {
    body[data-type=post] #page-header #nav {
        --font-color:#fff
    }
}

@media screen and (max-width: 768px) {
    #page-header.nav-fixed #nav {
    --font-color: var(--efu-fontcolor)!important;
    }
}

[data-theme=dark] #page-header.nav-fixed #nav {
    background: #1d1e224f!important;
    backdrop-filter: blur(7px)!important;
    -webkit-backdrop-filter: blur(7px)!important
}
点击展开查看更多

footer优化

调整页脚的上下的间隙,看起来更美观!个人认为

CSS
#footer-bar {
    padding: .3rem 1rem .3rem 1rem !important;
}
点击展开查看更多

首页卡片放大效果

CSS
#recent-posts>.recent-post-item:not(a):hover {
    box-shadow: 0 5px 15px rgba(0,0,0,.4);
    transform: scale(1.015);
}
点击展开查看更多

隐藏侧边滚动条

CSS
::-webkit-scrollbar {
    width: 0;
    border: none;
    background: #9b9b9b;
}
::-webkit-scrollbar-thumb {
    border: none;
    background: none;
    -webkit-transition: all 1.7s;
    transition: all 1.7s;
}
  
::-webkit-scrollbar-track {
    background: #f1f1f1;
}
点击展开查看更多

tags标签

仿Heo的tags样式

CSS
#page .category-lists .tag-cloud-list a {
    display: flex;
    width: fit-content;
    color: var(--efu-fontcolor) !important;
    font-size: 1.4em !important;
    padding: .2em .5em;
    background: var(--efu-card-bg);
    margin: .5em .5em  !important;
    border-radius: 12px;
    -webkit-backface-visibility: hidden;
    -webkit-transform-style: preserve-3d;
    border: var(--style-border-always);
    box-shadow: var(--efu-shadow-border);
    align-items: center;
}
点击展开查看更多

版权声明

作者: JunYan`Blog

链接: https://www.jinjun.top/posts/87/

许可证: CC BY-NC-SA 4.0

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Please attribute the source, use non-commercially, and maintain the same license.

评论

开始搜索

输入关键词搜索文章内容

↑↓
ESC
⌘K 快捷键