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

评论链接安全转跳

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

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

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

 1- const { envId, region, option ,accessToken } = theme.twikoo
 2- const { lazyload, count, use,commentBarrage } = theme.comment
 3
 4script().
 5    (() => {
 6        const getCount = () => {
 7            const ele = document.querySelectorAll('.twikoo-count')
 8            if (!ele) return
 9            twikoo.getCommentsCount({
10                envId: '!{envId}',
11                region: '!{region}',
12                urls: [window.location.pathname],
13                includeReply: false
14            }).then(res => {
15                ele.forEach(item => item.textContent = res[0].count)
16            }).catch(err => {
17                console.error(err)
18            })
19        }
20        const init = () => {
21            twikoo.init(Object.assign({
22                el: '#twikoo-wrap',
23                envId: '!{envId}',
24                region: '!{region}',
25                path: window.location.pathname,
26                onCommentLoaded: () => {
27                    GLOBAL_CONFIG.lightbox && utils.lightbox(document.querySelectorAll('#twikoo .tk-content img:not(.tk-owo-emotion)'))
28                    const processLinks = () => {
29                        const container = document.querySelector('#twikoo .tk-comments-container');
30                        if (!container) return;
31
32                        const links = container.querySelectorAll('a');
33                        links.forEach((link) => {
34                            const href = link.getAttribute('href');
35                            if (!href) return;
36
37                            if (!href.startsWith(window.location.origin) && !link.hasAttribute('data-fancybox')) {
38                                const encodedHref = btoa(href);
39                                const newHref = `/go.html?i=${encodedHref}`;
40                                link.setAttribute('href', newHref);
41                                link.setAttribute('rel', 'external nofollow noopener noreferrer');
42                                link.setAttribute('target', '_blank');
43                            }
44                        });
45                    };
46                    processLinks();
47                }
48            }, !{JSON.stringify(option)}))
49
50            !{count ? ' && getCount()' : ''}
51            sco.owoBig({
52                body: '.OwO-body',
53                item: '.OwO-items li'
54            })
55
56            !{commentBarrage} && barrageTwikoo()
57        }
58
59        const loadTwikoo = () => {
60            if (typeof twikoo === 'object') setTimeout(init,0)
61            else utils.getScript('!{url_for(theme.cdn.twikoo)}').then(init)
62        }
63
64        if ('!{use[0]}' === 'Twikoo' || !{lazyload}) {
65            if (!{lazyload}) utils.loadComment(document.getElementById('twikoo-wrap'), loadTwikoo)
66            else loadTwikoo()
67        } else {
68            window.loadTwoComment = loadTwikoo
69        }
70    })()
71
72if commentBarrage
73    script.
74        async function barrageTwikoo() {
75            await fetch("!{envId}", {
76                method: "POST",
77                headers: {
78                    "Content-Type": "application/json"
79                },
80                body: JSON.stringify({
81                    event: "COMMENT_GET",
82                    accessToken: "!{accessToken}",
83                    url: window.location.pathname
84                })
85            }).then(async res => {
86                if (!res.ok) throw new Error("HTTP error! status: " + res.status)
87                const data = await res.json();
88                const init = () => {
89                    initializeCommentBarrage((data.data).map(item => Object.assign({
90                        content: item.comment,
91                        nick: item.nick,
92                        mailMd5: item.mailMd5,
93                        id: item.id
94                    })))
95                }
96                if (typeof initializeCommentBarrage === "undefined") await utils.getScript('!{url_for(theme.cdn.commentBarrage)}').then(init)
97                else init()
98            }).catch(error => console.error("An error occurred while fetching comments: ", error))
99        }

文章统计

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

  1. 创建页面
1hexo new page charts
  1. 配置文件引入部分引入
1inject:
2  head:
3    - <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
  1const cheerio = require('cheerio')
  2const moment = require('moment')
  3
  4hexo.extend.filter.register('after_render:html', function (locals) {
  5  const $ = cheerio.load(locals)
  6  const post = $('#posts-chart')
  7  const tag = $('#tags-chart')
  8  const category = $('#categories-chart')
  9  const htmlEncode = false
 10
 11  if (post.length > 0 || tag.length > 0 || category.length > 0) {
 12    if (post.length > 0 && $('#postsChart').length === 0) {
 13      if (post.attr('data-encode') === 'true') htmlEncode = true
 14      post.after(postsChart(post.attr('data-start')))
 15    }
 16    if (tag.length > 0 && $('#tagsChart').length === 0) {
 17      if (tag.attr('data-encode') === 'true') htmlEncode = true
 18      tag.after(tagsChart(tag.attr('data-length')))
 19    }
 20    if (category.length > 0 && $('#categoriesChart').length === 0) {
 21      if (category.attr('data-encode') === 'true') htmlEncode = true
 22      category.after(categoriesChart(category.attr('data-parent')))
 23    }
 24
 25    if (htmlEncode) {
 26      return $.root().html().replace(/&amp;#/g, '&#')
 27    } else {
 28      return $.root().html()
 29    }
 30  } else {
 31    return locals
 32  }
 33}, 15)
 34
 35function postsChart (startMonth) {
 36  const startDate = moment(startMonth || '2020-01')
 37  const endDate = moment()
 38
 39  const monthMap = new Map()
 40  const dayTime = 3600 * 24 * 1000
 41  for (let time = startDate; time <= endDate; time += dayTime) {
 42    const month = moment(time).format('YYYY-MM')
 43    if (!monthMap.has(month)) {
 44      monthMap.set(month, 0)
 45    }
 46  }
 47  hexo.locals.get('posts').forEach(function (post) {
 48    const month = post.date.format('YYYY-MM')
 49    if (monthMap.has(month)) {
 50      monthMap.set(month, monthMap.get(month) + 1)
 51    }
 52  })
 53  const monthArr = JSON.stringify([...monthMap.keys()])
 54  const monthValueArr = JSON.stringify([...monthMap.values()])
 55
 56  return `
 57  <script id="postsChart">
 58    var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
 59    var postsChart = echarts.init(document.getElementById('posts-chart'), 'light');
 60    var postsOption = {
 61      title: {
 62        text: '文章发布统计图',
 63        x: 'center',
 64        textStyle: {
 65          color: color
 66        }
 67      },
 68      tooltip: {
 69        trigger: 'axis'
 70      },
 71      xAxis: {
 72        name: '日期',
 73        type: 'category',
 74        boundaryGap: false,
 75        nameTextStyle: {
 76          color: color
 77        },
 78        axisTick: {
 79          show: false
 80        },
 81        axisLabel: {
 82          show: true,
 83          color: color
 84        },
 85        axisLine: {
 86          show: true,
 87          lineStyle: {
 88            color: color
 89          }
 90        },
 91        data: ${monthArr}
 92      },
 93      yAxis: {
 94        name: '文章篇数',
 95        type: 'value',
 96        nameTextStyle: {
 97          color: color
 98        },
 99        splitLine: {
100          show: false
101        },
102        axisTick: {
103          show: false
104        },
105        axisLabel: {
106          show: true,
107          color: color
108        },
109        axisLine: {
110          show: true,
111          lineStyle: {
112            color: color
113          }
114        }
115      },
116      series: [{
117        name: '文章篇数',
118        type: 'line',
119        smooth: true,
120        lineStyle: {
121            width: 0
122        },
123        showSymbol: false,
124        itemStyle: {
125          opacity: 1,
126          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
127            offset: 0,
128            color: 'rgba(128, 255, 165)'
129          },
130          {
131            offset: 1,
132            color: 'rgba(1, 191, 236)'
133          }])
134        },
135        areaStyle: {
136          opacity: 1,
137          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
138            offset: 0,
139            color: 'rgba(128, 255, 165)'
140          }, {
141            offset: 1,
142            color: 'rgba(1, 191, 236)'
143          }])
144        },
145        data: ${monthValueArr},
146        markLine: {
147          data: [{
148            name: '平均值',
149            type: 'average',
150            label: {
151              color: color
152            }
153          }]
154        }
155      }]
156    };
157    postsChart.setOption(postsOption);
158    window.addEventListener('resize', () => { 
159      postsChart.resize();
160    });
161    postsChart.on('click', 'series', (event) => {
162      if (event.componentType === 'series') window.location.href = '/archives/' + event.name.replace('-', '/');
163    });
164  </script>`
165}
166
167function tagsChart (len) {
168  const tagArr = []
169  hexo.locals.get('tags').map(function (tag) {
170    tagArr.push({ name: tag.name, value: tag.length, path: tag.path })
171  })
172  tagArr.sort((a, b) => { return b.value - a.value })
173
174  const dataLength = Math.min(tagArr.length, len) || tagArr.length
175  const tagNameArr = []
176  for (let i = 0; i < dataLength; i++) {
177    tagNameArr.push(tagArr[i].name)
178  }
179  const tagNameArrJson = JSON.stringify(tagNameArr)
180  const tagArrJson = JSON.stringify(tagArr)
181
182  return `
183  <script id="tagsChart">
184    var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
185    var tagsChart = echarts.init(document.getElementById('tags-chart'), 'light');
186    var tagsOption = {
187      title: {
188        text: 'Top ${dataLength} 标签统计图',
189        x: 'center',
190        textStyle: {
191          color: color
192        }
193      },
194      tooltip: {},
195      xAxis: {
196        name: '标签',
197        type: 'category',
198        nameTextStyle: {
199          color: color
200        },
201        axisTick: {
202          show: false
203        },
204        axisLabel: {
205          show: true,
206          color: color,
207          interval: 0
208        },
209        axisLine: {
210          show: true,
211          lineStyle: {
212            color: color
213          }
214        },
215        data: ${tagNameArrJson}
216      },
217      yAxis: {
218        name: '文章篇数',
219        type: 'value',
220        splitLine: {
221          show: false
222        },
223        nameTextStyle: {
224          color: color
225        },
226        axisTick: {
227          show: false
228        },
229        axisLabel: {
230          show: true,
231          color: color
232        },
233        axisLine: {
234          show: true,
235          lineStyle: {
236            color: color
237          }
238        }
239      },
240      series: [{
241        name: '文章篇数',
242        type: 'bar',
243        data: ${tagArrJson},
244        itemStyle: {
245          borderRadius: [5, 5, 0, 0],
246          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
247            offset: 0,
248            color: 'rgba(128, 255, 165)'
249          },
250          {
251            offset: 1,
252            color: 'rgba(1, 191, 236)'
253          }])
254        },
255        emphasis: {
256          itemStyle: {
257            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
258              offset: 0,
259              color: 'rgba(128, 255, 195)'
260            },
261            {
262              offset: 1,
263              color: 'rgba(1, 211, 255)'
264            }])
265          }
266        },
267        markLine: {
268          data: [{
269            name: '平均值',
270            type: 'average',
271            label: {
272              color: color
273            }
274          }]
275        }
276      }]
277    };
278    tagsChart.setOption(tagsOption);
279    window.addEventListener('resize', () => { 
280      tagsChart.resize();
281    });
282    tagsChart.on('click', 'series', (event) => {
283      if(event.data.path) window.location.href = '/' + event.data.path;
284    });
285  </script>`
286}
287
288function categoriesChart (dataParent) {
289  const categoryArr = []
290  let categoryParentFlag = false
291  hexo.locals.get('categories').map(function (category) {
292    if (category.parent) categoryParentFlag = true
293    categoryArr.push({
294      name: category.name,
295      value: category.length,
296      path: category.path,
297      id: category._id,
298      parentId: category.parent || '0'
299    })
300  })
301  categoryParentFlag = categoryParentFlag && dataParent === 'true'
302  categoryArr.sort((a, b) => { return b.value - a.value })
303  function translateListToTree (data, parent) {
304    let tree = []
305    let temp
306    data.forEach((item, index) => {
307      if (data[index].parentId == parent) {
308        let obj = data[index];
309        temp = translateListToTree(data, data[index].id);
310        if (temp.length > 0) {
311          obj.children = temp
312        }
313        if (tree.indexOf())
314          tree.push(obj)
315      }
316    })
317    return tree
318  }
319  const categoryNameJson = JSON.stringify(categoryArr.map(function (category) { return category.name }))
320  const categoryArrJson = JSON.stringify(categoryArr)
321  const categoryArrParentJson = JSON.stringify(translateListToTree(categoryArr, '0'))
322
323  return `
324  <script id="categoriesChart">
325    var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
326    var categoriesChart = echarts.init(document.getElementById('categories-chart'), 'light');
327    var categoryParentFlag = ${categoryParentFlag}
328    var categoriesOption = {
329      title: {
330        text: '文章分类统计图',
331        x: 'center',
332        textStyle: {
333          color: color
334        }
335      },
336      legend: {
337        top: 'bottom',
338        data: ${categoryNameJson},
339        textStyle: {
340          color: color
341        }
342      },
343      tooltip: {
344        trigger: 'item'
345      },
346      series: []
347    };
348    categoriesOption.series.push(
349      categoryParentFlag ? 
350      {
351        nodeClick :false,
352        name: '文章篇数',
353        type: 'sunburst',
354        radius: ['15%', '90%'],
355        center: ['50%', '55%'],
356        sort: 'desc',
357        data: ${categoryArrParentJson},
358        itemStyle: {
359          borderColor: '#fff',
360          borderWidth: 2,
361          emphasis: {
362            focus: 'ancestor',
363            shadowBlur: 10,
364            shadowOffsetX: 0,
365            shadowColor: 'rgba(255, 255, 255, 0.5)'
366          }
367        }
368      }
369      :
370      {
371        name: '文章篇数',
372        type: 'pie',
373        radius: [30, 80],
374        roseType: 'area',
375        label: {
376          color: color,
377          formatter: '{b} : {c} ({d}%)'
378        },
379        data: ${categoryArrJson},
380        itemStyle: {
381          emphasis: {
382            shadowBlur: 10,
383            shadowOffsetX: 0,
384            shadowColor: 'rgba(255, 255, 255, 0.5)'
385          }
386        }
387      }
388    )
389    categoriesChart.setOption(categoriesOption);
390    window.addEventListener('resize', () => { 
391      categoriesChart.resize();
392    });
393    categoriesChart.on('click', 'series', (event) => {
394      if(event.data.path) window.location.href = '/' + event.data.path;
395    });
396  </script>`
397}
  1. 在页面使用
1<!-- 文章发布时间统计图 -->
2<div id="posts-chart" data-start="2021-01" style="border-radius: 8px; height: 300px; padding: 10px;"></div>
3<!-- 文章标签统计图 -->
4<div id="tags-chart" data-length="10" style="border-radius: 8px; height: 300px; padding: 10px;"></div>
5<!-- 文章分类统计图 -->
6<div id="categories-chart" data-parent="true" style="border-radius: 8px; height: 300px; padding: 10px;"></div>

导航栏nav模糊效果

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

 1[data-theme=light] #nav .menus_items .menus_item .menus_item_child {
 2    background-color: #ffffff4f!important;
 3    backdrop-filter: blur(7px)!important;
 4    -webkit-backdrop-filter: blur(7px)!important
 5}
 6
 7[data-theme=dark] #nav .menus_items .menus_item .menus_item_child {
 8    background-color: #1d1e224f!important;
 9    backdrop-filter: blur(7px)!important;
10    -webkit-backdrop-filter: blur(7px)!important
11}
12
13[data-theme=dark] #page-header.nav-fixed #nav {
14    background: #0000006f!important
15}
16
17[data-theme=light] #page-header.nav-fixed #nav {
18    background: #ffffff4f!important;
19}
20
21#page-header.nav-fixed #nav {
22    outline: 1px #7c7c7c43 solid!important;
23    backdrop-filter: blur(7px)!important;
24    -webkit-backdrop-filter: blur(7px)!important
25}
26
27@media screen and (max-width: 768px) {
28    #nav {
29        background:#fff0!important
30    }
31}
32
33@media screen and (max-width: 768px) {
34    body[data-type=post] #page-header #nav {
35        --font-color:#fff
36    }
37}
38
39@media screen and (max-width: 768px) {
40    #page-header.nav-fixed #nav {
41    --font-color: var(--efu-fontcolor)!important;
42    }
43}
44
45[data-theme=dark] #page-header.nav-fixed #nav {
46    background: #1d1e224f!important;
47    backdrop-filter: blur(7px)!important;
48    -webkit-backdrop-filter: blur(7px)!important
49}

footer优化

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

1#footer-bar {
2    padding: .3rem 1rem .3rem 1rem !important;
3}

首页卡片放大效果

1#recent-posts>.recent-post-item:not(a):hover {
2    box-shadow: 0 5px 15px rgba(0,0,0,.4);
3    transform: scale(1.015);
4}

隐藏侧边滚动条

 1::-webkit-scrollbar {
 2    width: 0;
 3    border: none;
 4    background: #9b9b9b;
 5}
 6::-webkit-scrollbar-thumb {
 7    border: none;
 8    background: none;
 9    -webkit-transition: all 1.7s;
10    transition: all 1.7s;
11}
12  
13::-webkit-scrollbar-track {
14    background: #f1f1f1;
15}

tags标签

仿Heo的tags样式

 1#page .category-lists .tag-cloud-list a {
 2    display: flex;
 3    width: fit-content;
 4    color: var(--efu-fontcolor) !important;
 5    font-size: 1.4em !important;
 6    padding: .2em .5em;
 7    background: var(--efu-card-bg);
 8    margin: .5em .5em  !important;
 9    border-radius: 12px;
10    -webkit-backface-visibility: hidden;
11    -webkit-transform-style: preserve-3d;
12    border: var(--style-border-always);
13    box-shadow: var(--efu-shadow-border);
14    align-items: center;
15}