hexo-theme-ayeria 1.9.7-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +38 -0
- package/README.md +553 -0
- package/_config.yml +271 -0
- package/_scaffolds/post.md +8 -0
- package/index.js +2 -0
- package/languages/de.yml +39 -0
- package/languages/default.yml +39 -0
- package/languages/en.yml +39 -0
- package/languages/es.yml +39 -0
- package/languages/fr.yml +39 -0
- package/languages/ja.yml +39 -0
- package/languages/ko.yml +39 -0
- package/languages/nl.yml +39 -0
- package/languages/no.yml +39 -0
- package/languages/pt.yml +39 -0
- package/languages/ru.yml +39 -0
- package/languages/vi.yml +39 -0
- package/languages/zh-CN.yml +39 -0
- package/languages/zh-TW.yml +39 -0
- package/layout/_partial/ads.ejs +9 -0
- package/layout/_partial/after-footer.ejs +84 -0
- package/layout/_partial/archive-post.ejs +14 -0
- package/layout/_partial/archive.ejs +62 -0
- package/layout/_partial/article.ejs +94 -0
- package/layout/_partial/ayeria.ejs +53 -0
- package/layout/_partial/baidu-analytics.ejs +11 -0
- package/layout/_partial/broadcast.ejs +20 -0
- package/layout/_partial/float-btns.ejs +8 -0
- package/layout/_partial/footer.ejs +62 -0
- package/layout/_partial/google-analytics.ejs +10 -0
- package/layout/_partial/head.ejs +67 -0
- package/layout/_partial/katex.ejs +22 -0
- package/layout/_partial/lock.ejs +37 -0
- package/layout/_partial/mathjax.ejs +19 -0
- package/layout/_partial/modal.ejs +77 -0
- package/layout/_partial/music.ejs +16 -0
- package/layout/_partial/post/albums.ejs +17 -0
- package/layout/_partial/post/author.ejs +8 -0
- package/layout/_partial/post/busuanzi.ejs +5 -0
- package/layout/_partial/post/category.ejs +10 -0
- package/layout/_partial/post/clipboard.ejs +54 -0
- package/layout/_partial/post/date.ejs +3 -0
- package/layout/_partial/post/gallery.ejs +15 -0
- package/layout/_partial/post/giscus.ejs +40 -0
- package/layout/_partial/post/gitalk.ejs +12 -0
- package/layout/_partial/post/justifiedGallery.ejs +9 -0
- package/layout/_partial/post/nav.ejs +22 -0
- package/layout/_partial/post/search.ejs +4 -0
- package/layout/_partial/post/share.ejs +51 -0
- package/layout/_partial/post/tag.ejs +6 -0
- package/layout/_partial/post/title.ejs +16 -0
- package/layout/_partial/post/tocbot.ejs +6 -0
- package/layout/_partial/post/topping.ejs +3 -0
- package/layout/_partial/post/twikoo.ejs +7 -0
- package/layout/_partial/post/valine.ejs +48 -0
- package/layout/_partial/post/word.ejs +20 -0
- package/layout/_partial/sidebar.ejs +34 -0
- package/layout/_partial/viewer.ejs +106 -0
- package/layout/archive.ejs +1 -0
- package/layout/categories.ejs +8 -0
- package/layout/friends.ejs +20 -0
- package/layout/index.ejs +4 -0
- package/layout/layout.ejs +31 -0
- package/layout/page.ejs +3 -0
- package/layout/plain-page.ejs +4 -0
- package/layout/post.ejs +3 -0
- package/layout/tags.ejs +88 -0
- package/logo.png +0 -0
- package/package.json +38 -0
- package/scripts/default_config.js +6 -0
- package/scripts/events/index.js +11 -0
- package/scripts/events/lib/hello.js +45 -0
- package/scripts/events/lib/merge-configs.js +28 -0
- package/scripts/filters/index.js +13 -0
- package/scripts/filters/meta_generator.js +17 -0
- package/scripts/helpers/ayeria-plus-vendors.js +9 -0
- package/scripts/helpers/category-tree.js +90 -0
- package/scripts/helpers/wordcount.js +39 -0
- package/scripts/lib/core.js +25 -0
- package/scripts/utils/join-path.js +12 -0
- package/scripts/utils/object.js +31 -0
- package/source/404.html +187 -0
- package/source/css/clipboard.styl +37 -0
- package/source/css/custom.styl +971 -0
- package/source/css/fonts/remixicon.css +1816 -0
- package/source/css/fonts/remixicon.eot +0 -0
- package/source/css/fonts/remixicon.svg +5329 -0
- package/source/css/fonts/remixicon.ttf +0 -0
- package/source/css/fonts/remixicon.woff +0 -0
- package/source/css/fonts/remixicon.woff2 +0 -0
- package/source/data/random-sentences.txt +136 -0
- package/source/dist/main.css +1 -0
- package/source/dist/main.js +1 -0
- package/source/favicon.svg +1 -0
- package/source/images/ayeria-side.svg +1 -0
- package/source/images/ayeria.png +0 -0
- package/source/images/ayeria.svg +1 -0
- package/source/images/beian.png +0 -0
- package/source/images/cover1.jpg +0 -0
- package/source/images/cover2.webp +0 -0
- package/source/images/cover3.jpg +0 -0
- package/source/images/cover4.jpg +0 -0
- package/source/images/cover5.jpg +0 -0
- package/source/images/cover6.jpg +0 -0
- package/source/images/forkme.png +0 -0
- package/source/images/gitee.png +0 -0
- package/source/images/github.png +0 -0
- package/source/images/hexo-tag-chart.png +0 -0
- package/source/images/hexo.png +0 -0
- package/source/images/mouse.cur +0 -0
- package/source/js/busuanzi-2.3.pure.min.js +1 -0
- package/source/js/clickBoom1.js +152 -0
- package/source/js/clickBoom2.js +180 -0
- package/source/js/clickLove.js +1 -0
- package/source/js/dz.js +1 -0
- package/source/js/jquery-3.6.0.min.js +2 -0
- package/source/js/lazyload.min.js +8 -0
- package/source/js/random-sentences.js +166 -0
- package/source/js/search.js +127 -0
- package/source/js/tocbot.min.js +1 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<!-- Root element of PhotoSwipe. Must have class pswp. -->
|
|
2
|
+
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
|
|
3
|
+
|
|
4
|
+
<!-- Background of PhotoSwipe.
|
|
5
|
+
It's a separate element as animating opacity is faster than rgba(). -->
|
|
6
|
+
<div class="pswp__bg"></div>
|
|
7
|
+
|
|
8
|
+
<!-- Slides wrapper with overflow:hidden. -->
|
|
9
|
+
<div class="pswp__scroll-wrap">
|
|
10
|
+
|
|
11
|
+
<!-- Container that holds slides.
|
|
12
|
+
PhotoSwipe keeps only 3 of them in the DOM to save memory.
|
|
13
|
+
Don't modify these 3 pswp__item elements, data is added later on. -->
|
|
14
|
+
<div class="pswp__container">
|
|
15
|
+
<div class="pswp__item"></div>
|
|
16
|
+
<div class="pswp__item"></div>
|
|
17
|
+
<div class="pswp__item"></div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
|
|
21
|
+
<div class="pswp__ui pswp__ui--hidden">
|
|
22
|
+
|
|
23
|
+
<div class="pswp__top-bar">
|
|
24
|
+
|
|
25
|
+
<!-- Controls are self-explanatory. Order can be changed. -->
|
|
26
|
+
|
|
27
|
+
<div class="pswp__counter"></div>
|
|
28
|
+
|
|
29
|
+
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
|
|
30
|
+
|
|
31
|
+
<button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>
|
|
32
|
+
|
|
33
|
+
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
|
|
34
|
+
|
|
35
|
+
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
|
|
36
|
+
|
|
37
|
+
<!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
|
|
38
|
+
<!-- element will get class pswp__preloader--active when preloader is running -->
|
|
39
|
+
<div class="pswp__preloader">
|
|
40
|
+
<div class="pswp__preloader__icn">
|
|
41
|
+
<div class="pswp__preloader__cut">
|
|
42
|
+
<div class="pswp__preloader__donut"></div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
|
|
49
|
+
<div class="pswp__share-tooltip"></div>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
|
|
53
|
+
</button>
|
|
54
|
+
|
|
55
|
+
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
|
|
56
|
+
</button>
|
|
57
|
+
|
|
58
|
+
<div class="pswp__caption">
|
|
59
|
+
<div class="pswp__caption__center"></div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<link rel="stylesheet" href="https://cdn.staticfile.org/photoswipe/4.1.3/photoswipe.min.css">
|
|
69
|
+
<link rel="stylesheet" href="https://cdn.staticfile.org/photoswipe/4.1.3/default-skin/default-skin.min.css">
|
|
70
|
+
<script src="https://cdn.staticfile.org/photoswipe/4.1.3/photoswipe.min.js"></script>
|
|
71
|
+
<script src="https://cdn.staticfile.org/photoswipe/4.1.3/photoswipe-ui-default.min.js"></script>
|
|
72
|
+
|
|
73
|
+
<script>
|
|
74
|
+
function viewer_init() {
|
|
75
|
+
let pswpElement = document.querySelectorAll('.pswp')[0];
|
|
76
|
+
let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))
|
|
77
|
+
|
|
78
|
+
$imgArr.forEach(($em, i) => {
|
|
79
|
+
$em.onclick = () => {
|
|
80
|
+
// slider展开状态
|
|
81
|
+
// todo: 这样不好,后面改成状态
|
|
82
|
+
if (document.querySelector('.left-col.show')) return
|
|
83
|
+
let items = []
|
|
84
|
+
$imgArr.forEach(($em2, i2) => {
|
|
85
|
+
let img = $em2.getAttribute('data-idx', i2)
|
|
86
|
+
let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
|
|
87
|
+
let title = $em2.getAttribute('alt')
|
|
88
|
+
// 获得原图尺寸
|
|
89
|
+
const image = new Image()
|
|
90
|
+
image.src = src
|
|
91
|
+
items.push({
|
|
92
|
+
src: src,
|
|
93
|
+
w: image.width || $em2.width,
|
|
94
|
+
h: image.height || $em2.height,
|
|
95
|
+
title: title
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
|
|
99
|
+
index: parseInt(i)
|
|
100
|
+
});
|
|
101
|
+
gallery.init()
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
viewer_init()
|
|
106
|
+
</script>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%- partial('_partial/archive', {pagination: config.archive, index: true}) %>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<section class="outer">
|
|
2
|
+
<% if(theme.friends_link && theme.friends_link.length != 0){ %>
|
|
3
|
+
<h1 class="page-type-title"><%= __('friends') %></h1>
|
|
4
|
+
<ul id="friends_link">
|
|
5
|
+
<% for (var i in theme.friends_link){ %>
|
|
6
|
+
<li class="friends_li">
|
|
7
|
+
<a href="<%- url_for(theme.friends_link[i].url) %>" target="_blank" class="search-title"
|
|
8
|
+
<% if (theme.friends_link[i].description){ %>title="<%= theme.friends_link[i].description %>" <% } %>>
|
|
9
|
+
<% if (theme.friends_link[i].img){ %>
|
|
10
|
+
<img src="<%- url_for(theme.friends_link[i].img) %>">
|
|
11
|
+
<% } else { %>
|
|
12
|
+
<i class="ri-user-fill"></i>
|
|
13
|
+
<% } %>
|
|
14
|
+
<%= i %>
|
|
15
|
+
</a>
|
|
16
|
+
</li>
|
|
17
|
+
<% } %>
|
|
18
|
+
</ul>
|
|
19
|
+
<%}%>
|
|
20
|
+
</section>
|
package/layout/index.ejs
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<%- partial('_partial/head') %>
|
|
2
|
+
|
|
3
|
+
<body class="darkmode">
|
|
4
|
+
<div id="app">
|
|
5
|
+
<% if (theme.click_effect === 2) { %>
|
|
6
|
+
<canvas class="click-effect-canvas"></canvas>
|
|
7
|
+
<% } %>
|
|
8
|
+
<% if (theme.click_effect === 3) { %>
|
|
9
|
+
<canvas class="click-effect-canvas" width="1777" height="841"></canvas>
|
|
10
|
+
<% } %>
|
|
11
|
+
<main class="content on">
|
|
12
|
+
<%- body %>
|
|
13
|
+
<%- partial('_partial/footer', null, {cache: !config.relative_link}) %>
|
|
14
|
+
</main>
|
|
15
|
+
<div class="float_btns">
|
|
16
|
+
<%- partial('_partial/float-btns') %>
|
|
17
|
+
</div>
|
|
18
|
+
<aside class="sidebar on">
|
|
19
|
+
<%- partial('_partial/sidebar') %>
|
|
20
|
+
</aside>
|
|
21
|
+
<%- partial('_partial/modal') %>
|
|
22
|
+
<%- partial('_partial/after-footer') %>
|
|
23
|
+
|
|
24
|
+
<% if (theme.music&&theme.music.enable){ %>
|
|
25
|
+
<%- partial('_partial/music') %>
|
|
26
|
+
<% } %>
|
|
27
|
+
<%- partial('_partial/lock') %>
|
|
28
|
+
</div>
|
|
29
|
+
</body>
|
|
30
|
+
|
|
31
|
+
</html>
|
package/layout/page.ejs
ADDED
package/layout/post.ejs
ADDED
package/layout/tags.ejs
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<section class="outer">
|
|
2
|
+
<% if (site.tags.length) { %>
|
|
3
|
+
<h1 class="page-type-title"><%= __('tags') %></h1>
|
|
4
|
+
|
|
5
|
+
<% var tagList = site.tags.sort('name'); %>
|
|
6
|
+
|
|
7
|
+
<div class="tag-cloud">
|
|
8
|
+
<div class="tag-cloud-header">
|
|
9
|
+
<span class="tag-cloud-stats">
|
|
10
|
+
共 <strong><%= site.tags.length %></strong> 个标签,<strong><%= site.posts.length %></strong> 篇文章
|
|
11
|
+
</span>
|
|
12
|
+
<div class="tag-cloud-controls">
|
|
13
|
+
<div class="tag-cloud-search">
|
|
14
|
+
<input type="text"
|
|
15
|
+
class="tag-cloud-input"
|
|
16
|
+
placeholder="搜索标签…"
|
|
17
|
+
aria-label="搜索标签" />
|
|
18
|
+
</div>
|
|
19
|
+
<div class="tag-cloud-sort">
|
|
20
|
+
<button type="button" class="tag-sort-btn is-active" data-sort="name">名称</button>
|
|
21
|
+
<button type="button" class="tag-sort-btn" data-sort="count">热度</button>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div class="tag-cloud-wrap">
|
|
27
|
+
<% tagList.each(function(tag) { %>
|
|
28
|
+
<a class="tag-cloud-item"
|
|
29
|
+
href="<%- url_for(tag.path) %>"
|
|
30
|
+
data-count="<%= tag.posts.length %>"
|
|
31
|
+
data-name="<%= tag.name.toLowerCase() %>">
|
|
32
|
+
<span class="tag-cloud-name"><%= tag.name %></span>
|
|
33
|
+
<span class="tag-cloud-count"><%= tag.posts.length %> 篇文章</span>
|
|
34
|
+
</a>
|
|
35
|
+
<% }); %>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<p class="tag-cloud-empty">没有匹配的标签</p>
|
|
39
|
+
</div>
|
|
40
|
+
<% } %>
|
|
41
|
+
</section>
|
|
42
|
+
|
|
43
|
+
<script>
|
|
44
|
+
(function () {
|
|
45
|
+
var wrap = document.querySelector('.tag-cloud-wrap');
|
|
46
|
+
if (!wrap) return;
|
|
47
|
+
|
|
48
|
+
var allItems = Array.prototype.slice.call(wrap.querySelectorAll('.tag-cloud-item'));
|
|
49
|
+
var input = document.querySelector('.tag-cloud-input');
|
|
50
|
+
var sortBtns = document.querySelectorAll('.tag-sort-btn');
|
|
51
|
+
var empty = document.querySelector('.tag-cloud-empty');
|
|
52
|
+
|
|
53
|
+
if (input) {
|
|
54
|
+
var timer;
|
|
55
|
+
input.addEventListener('input', function () {
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
var self = this;
|
|
58
|
+
timer = setTimeout(function () {
|
|
59
|
+
var q = self.value.trim().toLowerCase();
|
|
60
|
+
var visible = 0;
|
|
61
|
+
allItems.forEach(function (el) {
|
|
62
|
+
var match = !q || el.getAttribute('data-name').indexOf(q) !== -1;
|
|
63
|
+
el.style.display = match ? '' : 'none';
|
|
64
|
+
if (match) visible++;
|
|
65
|
+
});
|
|
66
|
+
if (empty) empty.style.display = visible ? 'none' : '';
|
|
67
|
+
}, 120);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
sortBtns.forEach(function (btn) {
|
|
72
|
+
btn.addEventListener('click', function () {
|
|
73
|
+
sortBtns.forEach(function (b) { b.classList.remove('is-active'); });
|
|
74
|
+
btn.classList.add('is-active');
|
|
75
|
+
|
|
76
|
+
var mode = btn.getAttribute('data-sort');
|
|
77
|
+
allItems.sort(function (a, b) {
|
|
78
|
+
if (mode === 'count') {
|
|
79
|
+
var diff = (+b.getAttribute('data-count')) - (+a.getAttribute('data-count'));
|
|
80
|
+
if (diff !== 0) return diff;
|
|
81
|
+
}
|
|
82
|
+
return a.getAttribute('data-name').localeCompare(b.getAttribute('data-name'), 'zh-CN');
|
|
83
|
+
});
|
|
84
|
+
allItems.forEach(function (el) { wrap.appendChild(el); });
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
})();
|
|
88
|
+
</script>
|
package/logo.png
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hexo-theme-ayeria",
|
|
3
|
+
"version": "1.9.7-0",
|
|
4
|
+
"description": "A clean and elegant theme for Hexo. Maintained fork of Shen-Yu/hexo-theme-ayer.",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "rollup -c -w",
|
|
7
|
+
"build": "rollup -c",
|
|
8
|
+
"test": "stylint source-src/css/style.styl -c .stylintrc"
|
|
9
|
+
},
|
|
10
|
+
"source": "source-src/main.js",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/KaleidScoper/hexo-theme-ayeria.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"hexo",
|
|
17
|
+
"theme",
|
|
18
|
+
"blog",
|
|
19
|
+
"ayeria",
|
|
20
|
+
"ayer"
|
|
21
|
+
],
|
|
22
|
+
"author": "Kaleid_5coper <kaleided.scoper@gmail.com>",
|
|
23
|
+
"contributors": [
|
|
24
|
+
"Shen-Yu <shenyu@hotmail.com> (original author)"
|
|
25
|
+
],
|
|
26
|
+
"license": "SATA",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/KaleidScoper/hexo-theme-ayeria/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/KaleidScoper/hexo-theme-ayeria",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"autoprefixer": "^9.8.6",
|
|
33
|
+
"rollup": "^2.50.2",
|
|
34
|
+
"rollup-plugin-styles": "^3.14.1",
|
|
35
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
36
|
+
"stylint": "^2.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
module.exports = (hexo) => {
|
|
4
|
+
const isZh = hexo.theme.i18n.languages[0].search(/zh-CN/i) !== -1;
|
|
5
|
+
const title = hexo.config.title || 'My Blog';
|
|
6
|
+
const url = hexo.config.url || '';
|
|
7
|
+
|
|
8
|
+
const pad = (str, width) => {
|
|
9
|
+
const gap = width - str.length;
|
|
10
|
+
if (gap <= 0) return str;
|
|
11
|
+
const left = Math.floor(gap / 2);
|
|
12
|
+
return ' '.repeat(left) + str + ' '.repeat(gap - left);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const art = [
|
|
16
|
+
' _ __ _______ ____ ___ _',
|
|
17
|
+
' / \\\\ \\ / / ____| _ \\|_ _| / \\',
|
|
18
|
+
' / _ \\\\ V /| _| | |_) || | / _ \\',
|
|
19
|
+
' / ___ \\| | | |___| _ < | | / ___ \\',
|
|
20
|
+
' /_/ \\_\\_| |_____|_| \\_\\___/_/ \\_\\'
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const W = 46;
|
|
24
|
+
const line1 = pad(title, W);
|
|
25
|
+
const line2 = isZh
|
|
26
|
+
? pad('Hexo 博客 · Ayeria 主题', W)
|
|
27
|
+
: pad('Hexo Blog · Theme Ayeria', W);
|
|
28
|
+
const line3 = pad(url, W);
|
|
29
|
+
|
|
30
|
+
const border = '-'.repeat(W + 2);
|
|
31
|
+
const empty = '|' + ' '.repeat(W) + '|';
|
|
32
|
+
const artStr = art.map(l => '|' + pad(l, W) + '|').join('\n');
|
|
33
|
+
|
|
34
|
+
hexo.log.info(`
|
|
35
|
+
${border}
|
|
36
|
+
${empty}
|
|
37
|
+
${artStr}
|
|
38
|
+
${empty}
|
|
39
|
+
|${line1}|
|
|
40
|
+
|${line2}|
|
|
41
|
+
|${line3}|
|
|
42
|
+
${empty}
|
|
43
|
+
${border}
|
|
44
|
+
`);
|
|
45
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const objUtil = require("../../utils/object");
|
|
4
|
+
const { isNotEmptyObject } = require("../../utils/object");
|
|
5
|
+
|
|
6
|
+
module.exports = (hexo) => {
|
|
7
|
+
const isZh = hexo.theme.i18n.languages[0].search(/zh-CN/i) !== -1;
|
|
8
|
+
|
|
9
|
+
if (isNotEmptyObject(hexo.config.theme_config)) {
|
|
10
|
+
hexo.theme.config = objUtil.merge(
|
|
11
|
+
{},
|
|
12
|
+
hexo.theme.config,
|
|
13
|
+
hexo.config.theme_config
|
|
14
|
+
);
|
|
15
|
+
if (isZh) {
|
|
16
|
+
hexo.log.info("[Ayeria] 读取 _config.yml 中 theme_config 配置项覆盖配置");
|
|
17
|
+
} else {
|
|
18
|
+
hexo.log.info(
|
|
19
|
+
"[Ayeria] Merge theme config from theme_config in _config.yml"
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
hexo.log.debug(
|
|
25
|
+
"[Ayeria] Output theme config:\n",
|
|
26
|
+
JSON.stringify(hexo.theme.config, undefined, 2)
|
|
27
|
+
);
|
|
28
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const metaGeneratorPath = './meta_generator';
|
|
4
|
+
|
|
5
|
+
module.exports = hexo => {
|
|
6
|
+
/* const {
|
|
7
|
+
filter
|
|
8
|
+
} = hexo.extend; */
|
|
9
|
+
// filter.register('after_render:html', require('./meta_generator'));
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// 保持过滤器最先执行
|
|
13
|
+
hexo.extend.filter.register('after_render:html', require(metaGeneratorPath), 1);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const defaultConfig = require('../default_config');
|
|
4
|
+
|
|
5
|
+
function hexoMetaGeneratorInject(data) {
|
|
6
|
+
const config = defaultConfig;
|
|
7
|
+
if (!config.meta_generator || !data ||
|
|
8
|
+
data.match(/<meta\s+name=['|"]?generator['|"]?/i)) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const hexoGeneratorTag = `\n <meta name="generator" content="hexo-theme-ayeria">`;
|
|
13
|
+
|
|
14
|
+
return data.replace('</title>', '</title>' + hexoGeneratorTag);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = hexoMetaGeneratorInject;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Custom category tree helper for the /categories page.
|
|
5
|
+
*
|
|
6
|
+
* Generates a "dual-column block" per root category:
|
|
7
|
+
* Left — category name (large) + total post count
|
|
8
|
+
* Right — subcategories as a tree list with indent guide lines
|
|
9
|
+
*
|
|
10
|
+
* Usage in EJS: <%- category_tree([options]) %>
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
hexo.extend.helper.register('category_tree', function (options) {
|
|
14
|
+
const opts = Object.assign(
|
|
15
|
+
{
|
|
16
|
+
orderby: 'name',
|
|
17
|
+
order: 1,
|
|
18
|
+
},
|
|
19
|
+
(this.theme || {}).category_tree,
|
|
20
|
+
options
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const categories = this.site.categories;
|
|
24
|
+
if (!categories || !categories.length) return '';
|
|
25
|
+
|
|
26
|
+
const self = this;
|
|
27
|
+
|
|
28
|
+
function sortCategories(cats) {
|
|
29
|
+
const arr = cats.toArray();
|
|
30
|
+
const key = opts.orderby === 'count' ? 'length' : 'name';
|
|
31
|
+
arr.sort((a, b) => {
|
|
32
|
+
const va = key === 'length' ? a.posts.length : a.name;
|
|
33
|
+
const vb = key === 'length' ? b.posts.length : b.name;
|
|
34
|
+
if (va < vb) return -1 * opts.order;
|
|
35
|
+
if (va > vb) return 1 * opts.order;
|
|
36
|
+
return 0;
|
|
37
|
+
});
|
|
38
|
+
return arr;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function renderSubtree(cats) {
|
|
42
|
+
const sorted = sortCategories(cats);
|
|
43
|
+
if (!sorted.length) return '';
|
|
44
|
+
|
|
45
|
+
let html = '<ul class="cat-subtree">';
|
|
46
|
+
|
|
47
|
+
sorted.forEach(cat => {
|
|
48
|
+
const children = categories.filter(c => c.parent === cat._id);
|
|
49
|
+
const hasChildren = children.length > 0;
|
|
50
|
+
|
|
51
|
+
html += '<li class="cat-subitem">';
|
|
52
|
+
html += `<a class="cat-sublink" href="${self.url_for(cat.path)}">${cat.name}</a>`;
|
|
53
|
+
html += `<span class="cat-subcount">\uff08${cat.posts.length}\uff09</span>`;
|
|
54
|
+
|
|
55
|
+
if (hasChildren) {
|
|
56
|
+
html += renderSubtree(children);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
html += '</li>';
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
html += '</ul>';
|
|
63
|
+
return html;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const roots = sortCategories(categories.filter(cat => !cat.parent));
|
|
67
|
+
let html = '';
|
|
68
|
+
|
|
69
|
+
roots.forEach(cat => {
|
|
70
|
+
const total = cat.posts.length;
|
|
71
|
+
const children = categories.filter(c => c.parent === cat._id);
|
|
72
|
+
|
|
73
|
+
html += '<div class="cat-block">';
|
|
74
|
+
|
|
75
|
+
html += '<div class="cat-block-left">';
|
|
76
|
+
html += `<a class="cat-block-name" href="${self.url_for(cat.path)}">${cat.name}</a>`;
|
|
77
|
+
html += `<span class="cat-block-total">${self.__('posts_count', total)}</span>`;
|
|
78
|
+
html += '</div>';
|
|
79
|
+
|
|
80
|
+
html += '<div class="cat-block-right">';
|
|
81
|
+
if (children.length > 0) {
|
|
82
|
+
html += renderSubtree(children);
|
|
83
|
+
}
|
|
84
|
+
html += '</div>';
|
|
85
|
+
|
|
86
|
+
html += '</div>';
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return html;
|
|
90
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
var util = require('hexo-util');
|
|
2
|
+
var stripHTML = util.stripHTML;
|
|
3
|
+
|
|
4
|
+
var counter = function (content) {
|
|
5
|
+
content = stripHTML(content);
|
|
6
|
+
const cn = (content.match(/[\u4E00-\u9FA5]/g) || []).length;
|
|
7
|
+
const en = (content.replace(/[\u4E00-\u9FA5]/g, '').match(/[a-zA-Z0-9_\u0392-\u03c9\u0400-\u04FF]+|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af\u0400-\u04FF]+|[\u00E4\u00C4\u00E5\u00C5\u00F6\u00D6]+|\w+/g) || []).length;
|
|
8
|
+
return [cn, en];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
hexo.extend.helper.register('min2read', function (content, {
|
|
12
|
+
cn = 300,
|
|
13
|
+
en = 160
|
|
14
|
+
} = {}) {
|
|
15
|
+
var len = counter(content);
|
|
16
|
+
var readingTime = len[0] / cn + len[1] / en;
|
|
17
|
+
return readingTime < 1 ? '1' : parseInt(readingTime, 10);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
hexo.extend.helper.register('wordcount', function (content) {
|
|
21
|
+
var len = counter(content);
|
|
22
|
+
var count = len[0] + len[1];
|
|
23
|
+
if (count < 1000) {
|
|
24
|
+
return count;
|
|
25
|
+
}
|
|
26
|
+
return Math.round(count / 100) / 10 + 'k';
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
hexo.extend.helper.register('totalcount', function (site) {
|
|
30
|
+
var count = 0;
|
|
31
|
+
site.posts.forEach(function (post) {
|
|
32
|
+
var len = counter(post.content);
|
|
33
|
+
count += len[0] + len[1];
|
|
34
|
+
});
|
|
35
|
+
if (count < 1000) {
|
|
36
|
+
return count;
|
|
37
|
+
}
|
|
38
|
+
return Math.round(count / 100) / 10 + 'k';
|
|
39
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* global hexo */
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
// Hexo事件:https://hexo.io/zh-cn/api/events
|
|
6
|
+
|
|
7
|
+
/** 在静态文件生成前发布 */
|
|
8
|
+
hexo.on('generateBefore', () => {
|
|
9
|
+
// Merge config.
|
|
10
|
+
//require('./../filters/index')(hexo);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/** 在文章文件建立后发布。该事件返回文章参数。 */
|
|
14
|
+
hexo.on('new', function (post) {
|
|
15
|
+
//console.log(post)
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
/** 在文章开始渲染前执行 */
|
|
19
|
+
hexo.extend.filter.register('before_post_render', function (data) {
|
|
20
|
+
//var config = hexo.config;
|
|
21
|
+
//console.log(3);
|
|
22
|
+
//console.log(config);
|
|
23
|
+
//console.log(hexo.theme.config);
|
|
24
|
+
|
|
25
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const joinPath = function(base, relative) {
|
|
4
|
+
if (relative && /^https*:\/\//.test(relative)) {
|
|
5
|
+
return relative;
|
|
6
|
+
}
|
|
7
|
+
return relative
|
|
8
|
+
? base.replace(/\/+$/, '') + '/' + relative.replace(/^\/+/, '')
|
|
9
|
+
: base;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
module.exports = joinPath;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const isObject = (obj) => {
|
|
4
|
+
return obj && typeof obj === 'object' && !Array.isArray(obj);
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const isNotEmptyObject = (obj) => {
|
|
8
|
+
return obj && typeof obj === 'object' && Object.getOwnPropertyNames(obj).length !== 0;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const merge = (target, ...sources) => {
|
|
12
|
+
for (const source of sources) {
|
|
13
|
+
for (const key in source) {
|
|
14
|
+
if (!Object.prototype.hasOwnProperty.call(source, key)) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (isObject(target[key]) && isObject(source[key])) {
|
|
18
|
+
merge(target[key], source[key]);
|
|
19
|
+
} else {
|
|
20
|
+
target[key] = source[key];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return target;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
module.exports = {
|
|
28
|
+
isObject,
|
|
29
|
+
isNotEmptyObject,
|
|
30
|
+
merge
|
|
31
|
+
};
|