记录一下魔改的主题的过程,有一些是在其他博主的魔改的方法。
评论链接安全转跳
{% 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' %}
- 创建页面
1hexo new page charts
- 配置文件引入部分引入
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
- 新建文件路径: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(/&#/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<!-- 文章发布时间统计图 -->
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#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}