hexo-theme-linen 0.0.1-security → 1.0.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/index.js +6 -0
- package/languages/en.yml +39 -0
- package/languages/zh-CN.yml +39 -0
- package/layout/archive.ejs +92 -0
- package/layout/category.ejs +8 -0
- package/layout/index.ejs +11 -0
- package/layout/layout.ejs +131 -0
- package/layout/page.ejs +6 -0
- package/layout/partials/footer.ejs +12 -0
- package/layout/partials/header.ejs +41 -0
- package/layout/partials/paginator.ejs +5 -0
- package/layout/partials/post-item.ejs +35 -0
- package/layout/partials/recent-posts.ejs +18 -0
- package/layout/partials/related-posts.ejs +33 -0
- package/layout/partials/share-meta.ejs +10 -0
- package/layout/partials/site-info.ejs +22 -0
- package/layout/partials/top-posts.ejs +36 -0
- package/layout/partials/words.ejs +33 -0
- package/layout/post.ejs +368 -0
- package/layout/series.ejs +59 -0
- package/layout/tag.ejs +8 -0
- package/package.json +34 -6
- package/scripts/appendRawMarkdownContent.js +19 -0
- package/scripts/folded-code-block.js +56 -0
- package/scripts/font-version.js +14 -0
- package/scripts/helpers/tools.js +218 -0
- package/scripts/index.js +21 -0
- package/scripts/lazyload/client.js +362 -0
- package/scripts/lazyload/config.js +10 -0
- package/scripts/lazyload/index.js +13 -0
- package/scripts/lazyload/inject.js +183 -0
- package/scripts/lazyload/process.js +464 -0
- package/scripts/lib/comments.js +26 -0
- package/scripts/lib/custom.js +30 -0
- package/scripts/markdown-it-image-grid.js +34 -0
- package/scripts/series-generator.js +52 -0
- package/source/css/animations.css +17 -0
- package/source/css/font-version.scss +1 -0
- package/source/css/highlight-github.scss +122 -0
- package/source/css/lazyload.css +107 -0
- package/source/css/linen.scss +2528 -0
- package/source/css/linkcard.scss +233 -0
- package/source/css/mediaquery.scss +447 -0
- package/source/css/normalize.css +1 -0
- package/source/css/noscript.css +67 -0
- package/source/css/photoswipe-dynamic-caption-plugin.css +160 -0
- package/source/css/photoswipe.css +448 -0
- package/source/css/rss-en.xsl +35 -0
- package/source/css/rss-zh.xsl +35 -0
- package/source/css/vars.scss +114 -0
- package/source/favicon.svg +3 -0
- package/source/fonts/SourceHanSerifCN-Regular.woff2 +0 -0
- package/source/fonts/SourceSerif4-Regular.ttf.woff2 +0 -0
- package/source/img/icons/ZIP.svg +1 -0
- package/source/img/icons/about.svg +1 -0
- package/source/img/icons/arrow-down.svg +1 -0
- package/source/img/icons/binary.svg +1 -0
- package/source/img/icons/checked-checkbox.svg +1 -0
- package/source/img/icons/chinese.svg +6 -0
- package/source/img/icons/code.svg +1 -0
- package/source/img/icons/collapsed.svg +6 -0
- package/source/img/icons/copied.png +0 -0
- package/source/img/icons/copy.png +0 -0
- package/source/img/icons/copyright.svg +1 -0
- package/source/img/icons/date.svg +1 -0
- package/source/img/icons/email.svg +1 -0
- package/source/img/icons/english.svg +6 -0
- package/source/img/icons/exif/aperture.svg +1 -0
- package/source/img/icons/exif/camera.svg +1 -0
- package/source/img/icons/exif/ev.svg +1 -0
- package/source/img/icons/exif/focusLength.svg +1 -0
- package/source/img/icons/exif/hdr.svg +1 -0
- package/source/img/icons/exif/iso.svg +1 -0
- package/source/img/icons/exif/lens.svg +1 -0
- package/source/img/icons/exif/location.svg +1 -0
- package/source/img/icons/exif/shutterSpeed.svg +1 -0
- package/source/img/icons/github.svg +1 -0
- package/source/img/icons/hdr.svg +1 -0
- package/source/img/icons/hdr_off.svg +1 -0
- package/source/img/icons/link.svg +1 -0
- package/source/img/icons/location.svg +1 -0
- package/source/img/icons/more.svg +4 -0
- package/source/img/icons/new.svg +1 -0
- package/source/img/icons/new1.svg +1 -0
- package/source/img/icons/next.svg +1 -0
- package/source/img/icons/prev.svg +1 -0
- package/source/img/icons/redirect.svg +1 -0
- package/source/img/icons/rss.svg +5 -0
- package/source/img/icons/search.svg +1 -0
- package/source/img/icons/shelf.svg +1 -0
- package/source/img/icons/tag.svg +1 -0
- package/source/img/icons/toc.svg +1 -0
- package/source/img/icons/toc1.svg +1 -0
- package/source/img/icons/up-down.svg +1 -0
- package/source/img/lazyload/error-tip.svg +1 -0
- package/source/img/lazyload/loading.svg +9 -0
- package/source/img/logo.svg +3 -0
- package/source/img/logo_black.svg +4 -0
- package/source/img/pattern-randomized.jpg +0 -0
- package/source/img/pattern-randomized.svg +1 -0
- package/source/img/related-post.jpg +0 -0
- package/source/img/vue-color-avatar.png +0 -0
- package/source/js/gitalk/gitalk.css +1251 -0
- package/source/js/gitalk/gitalk.min.js +35 -0
- package/source/js/hdr.js +90 -0
- package/source/js/lazyload.js +362 -0
- package/source/js/linen.js +481 -0
- package/source/js/photoswipe/photoswipe-dynamic-caption-plugin.esm.js +359 -0
- package/source/js/photoswipe/photoswipe-lightbox.esm.min.js +5 -0
- package/source/js/photoswipe/photoswipe.esm.min.js +6817 -0
- package/source/js/replace-emoji.js +45 -0
- package/source/js/toc.js +233 -0
- package/README.md +0 -11
package/index.js
ADDED
package/languages/en.yml
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
common:
|
|
2
|
+
archives: "Archives"
|
|
3
|
+
categories: "Categories"
|
|
4
|
+
category: "Category"
|
|
5
|
+
tags: "Tags"
|
|
6
|
+
tag: "Tag"
|
|
7
|
+
prev: "Prev"
|
|
8
|
+
next: "Next"
|
|
9
|
+
about: "About"
|
|
10
|
+
latest: "Latest"
|
|
11
|
+
posts: "Posts"
|
|
12
|
+
aboutThisSite: "About This Site"
|
|
13
|
+
approximately: "About"
|
|
14
|
+
photos: "Photos"
|
|
15
|
+
photo: "Photo"
|
|
16
|
+
words: "Words"
|
|
17
|
+
whatsNew: "What's New"
|
|
18
|
+
toc: "Table of Contents"
|
|
19
|
+
undated: "Undated"
|
|
20
|
+
prevPost: "Prev"
|
|
21
|
+
nextPost: "Next"
|
|
22
|
+
copyright: "This site and its content are licensed under a Creative Commons Attribution-NonCommercial 4.0 International License."
|
|
23
|
+
gallery: "Gallery"
|
|
24
|
+
relatedPosts: "Related Posts"
|
|
25
|
+
series: "Series"
|
|
26
|
+
donateToAuthor: "Buy Me a Coffee"
|
|
27
|
+
details: "Details"
|
|
28
|
+
copyrightDesc: "All text and images in this article are original. Please do not reproduce or use them for commercial purposes without permission."
|
|
29
|
+
reads: "Reads"
|
|
30
|
+
seriesPostCount: "articles"
|
|
31
|
+
total: "A total of"
|
|
32
|
+
age_notice: "This post was created <span class='days-value'></span> days ago, and the information may have changed."
|
|
33
|
+
minsRead: "min read"
|
|
34
|
+
switchTo: "Switch to "
|
|
35
|
+
renderedContent: "Rendered Content"
|
|
36
|
+
rawMarkdownContent: "Raw MarkdownContent"
|
|
37
|
+
thanks: "Thanks to"
|
|
38
|
+
sponsored: "sponsored"
|
|
39
|
+
seriesPostCountShort: "articles"
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
common:
|
|
2
|
+
archives: "归档"
|
|
3
|
+
categories: "分类"
|
|
4
|
+
category: "分类"
|
|
5
|
+
tags: "标签"
|
|
6
|
+
tag: "标签"
|
|
7
|
+
prev: "上一页"
|
|
8
|
+
next: "下一页"
|
|
9
|
+
about: "关于我"
|
|
10
|
+
latest: "最新文章"
|
|
11
|
+
posts: "文章"
|
|
12
|
+
aboutThisSite: "关于本站"
|
|
13
|
+
approximately: "约"
|
|
14
|
+
photos: "张图片"
|
|
15
|
+
photo: "张图片"
|
|
16
|
+
words: "个字"
|
|
17
|
+
whatsNew: "新特性"
|
|
18
|
+
toc: "目录"
|
|
19
|
+
undated: "未注明"
|
|
20
|
+
prevPost: "上一篇"
|
|
21
|
+
nextPost: "下一篇"
|
|
22
|
+
copyright: "本网站及其所有内容都遵循创意共享署名-非商业性使用 4.0 国际许可协议。"
|
|
23
|
+
gallery: "图库"
|
|
24
|
+
relatedPosts: "相关文章"
|
|
25
|
+
series: "系列"
|
|
26
|
+
donateToAuthor: "赞赏作者"
|
|
27
|
+
details: "详情"
|
|
28
|
+
copyrightDesc: "本文照片和文字为原创内容,未经授权,请勿转载或用于商业用途。"
|
|
29
|
+
reads: "阅读"
|
|
30
|
+
seriesPostCount: "篇文章"
|
|
31
|
+
total: "共"
|
|
32
|
+
age_notice: "这是一个创建于 <span class='days-value'></span> 天前的主题,其中的信息可能已经有所发展或是发生改变。"
|
|
33
|
+
minsRead: "分钟阅读"
|
|
34
|
+
switchTo: "切换到"
|
|
35
|
+
renderedContent: "渲染后的内容"
|
|
36
|
+
rawMarkdownContent: "原始 Markdown 内容"
|
|
37
|
+
thanks: "感谢"
|
|
38
|
+
sponsored: "赞赏了"
|
|
39
|
+
seriesPostCountShort: "篇"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const tagsList = list_tags({ show_count: false });
|
|
3
|
+
const seriesList = Array.from(new Set(site.posts.filter(item=>item.series).map(item=>item.series))).map(seriesName=>({
|
|
4
|
+
name: seriesName,
|
|
5
|
+
count: site.posts.filter(post=>post.series === seriesName).length
|
|
6
|
+
}));
|
|
7
|
+
const categoriesList = Object.entries(site.posts.reduce((acc, post) => {
|
|
8
|
+
(post?.categories || []).forEach(cat => acc[cat.name] = (acc[cat.name] || 0) + 1);
|
|
9
|
+
return acc;
|
|
10
|
+
}, {})).map(([name, count]) => ({ name, count }));
|
|
11
|
+
const archivesList = Object.entries(site.posts.filter(post=>!post?.hide?.archive).reduce((acc, post) => {
|
|
12
|
+
const year = post.date.year();
|
|
13
|
+
acc[year] = (acc[year] || 0) + 1;
|
|
14
|
+
return acc;
|
|
15
|
+
}, {})).map(([name, count]) => ({ year: name, name: name.startsWith('1970') ? '__' : name, count })).reverse();
|
|
16
|
+
%>
|
|
17
|
+
|
|
18
|
+
<% if (is_year() === false) { %>
|
|
19
|
+
<div id="archive">
|
|
20
|
+
<div class="two-columns">
|
|
21
|
+
<% if(categoriesList.length) {%>
|
|
22
|
+
<aside>
|
|
23
|
+
<h2 id="categories"><%=__('common.categories')%></h2>
|
|
24
|
+
<ul class="archive-list">
|
|
25
|
+
<% categoriesList.forEach(category => { %>
|
|
26
|
+
<li class="archive-list-item">
|
|
27
|
+
<a class="archive-list-link" data-firstletter="<%=category.name.charAt(0)%>" href="<%='/categories/' + category.name + '/'%>">
|
|
28
|
+
<%=category.name%>
|
|
29
|
+
<span class="archive-list-count"><%=category.count%></span>
|
|
30
|
+
</a>
|
|
31
|
+
</li>
|
|
32
|
+
<% }) %>
|
|
33
|
+
</ul>
|
|
34
|
+
</aside>
|
|
35
|
+
<% } %>
|
|
36
|
+
<aside>
|
|
37
|
+
<h2 id="archives"><%=__('common.posts')%></h2>
|
|
38
|
+
<ul class="archive-list">
|
|
39
|
+
<% archivesList.forEach(archive => { %>
|
|
40
|
+
<li class="archive-list-item">
|
|
41
|
+
<a class="archive-list-link" data-firstletter="<%=archive.name.charAt(archive.name.length-1)%>" href="<%='/archives/' + archive.year + '/'%>">
|
|
42
|
+
<%=archive.name%>
|
|
43
|
+
<span class="archive-list-count"><%=archive.count%></span>
|
|
44
|
+
</a>
|
|
45
|
+
</li>
|
|
46
|
+
<% }) %>
|
|
47
|
+
</ul>
|
|
48
|
+
</aside>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
<% if(categoriesList.length) { %>
|
|
54
|
+
<br>
|
|
55
|
+
<aside>
|
|
56
|
+
<h2 id="series"><%=__('common.series')%></h2>
|
|
57
|
+
<ul class="archive-list">
|
|
58
|
+
<% seriesList.forEach(series => { %>
|
|
59
|
+
<li class="archive-list-item">
|
|
60
|
+
<a class="archive-list-link" data-firstletter="<%=series.name.charAt(0)%>" href="<%='/series/' + series.name + '/'%>">
|
|
61
|
+
<%=series.name%>
|
|
62
|
+
<span class="archive-list-count"><%=series.count%></span>
|
|
63
|
+
</a>
|
|
64
|
+
</li>
|
|
65
|
+
<% }) %>
|
|
66
|
+
</ul>
|
|
67
|
+
</aside>
|
|
68
|
+
<% } %>
|
|
69
|
+
|
|
70
|
+
<% if(tagsList.length) { %>
|
|
71
|
+
<br>
|
|
72
|
+
<aside>
|
|
73
|
+
<h2 id="tags"><%=__('common.tags')%></h2>
|
|
74
|
+
<div class="tag-list-wrap">
|
|
75
|
+
<% if (tagsList !== "") { %>
|
|
76
|
+
<%-tagsList%>
|
|
77
|
+
<% } %>
|
|
78
|
+
</div>
|
|
79
|
+
</aside>
|
|
80
|
+
<% } %>
|
|
81
|
+
|
|
82
|
+
</div>
|
|
83
|
+
<% } else { %>
|
|
84
|
+
<h1 id="archieve-h1"><%=page.year.toString().startsWith('1970') ? '__' : (page.month ? page.month + '/' : '') + page.year%></h1>
|
|
85
|
+
<div class="posts-info-layout">
|
|
86
|
+
<div class="posts-wrap">
|
|
87
|
+
<%-partial('partials/recent-posts', { showHidden: true })%>
|
|
88
|
+
<%-partial('partials/paginator')%>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="info-wrap"><%-partial('partials/site-info')%></div>
|
|
91
|
+
</div>
|
|
92
|
+
<% } %>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<h1 id="archieve-h1"><%=__('common.category') + ': ' + page.category%></h1>
|
|
2
|
+
<div class="posts-info-layout">
|
|
3
|
+
<div class="posts-wrap">
|
|
4
|
+
<%-partial('partials/recent-posts', { showHidden: true })%>
|
|
5
|
+
<%-partial('partials/paginator')%>
|
|
6
|
+
</div>
|
|
7
|
+
<div class="info-wrap"><%-partial('partials/site-info')%></div>
|
|
8
|
+
</div>
|
package/layout/index.ejs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<% if (is_home_first_page()) { %> <%-partial('partials/top-posts')%> <% } %>
|
|
2
|
+
|
|
3
|
+
<div class="posts-info-layout">
|
|
4
|
+
<div class="posts-wrap">
|
|
5
|
+
<% if (is_home_first_page()) { %>
|
|
6
|
+
<div class="section-title"><%=__('common.latest')%></div>
|
|
7
|
+
<% } %> <%-partial('partials/recent-posts', { showHidden: false })%>
|
|
8
|
+
<%-partial('partials/paginator')%>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="info-wrap"><%-partial('partials/site-info')%></div>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const version = theme.version;
|
|
3
|
+
%>
|
|
4
|
+
|
|
5
|
+
<%
|
|
6
|
+
var tocs = is_post() ? extractTocFromHtml(page.content) : null;
|
|
7
|
+
var series = is_post() ? site.posts.filter(item=>item.series && item.series === page?.series).sort('date', -1) : []
|
|
8
|
+
%>
|
|
9
|
+
|
|
10
|
+
<!DOCTYPE html>
|
|
11
|
+
<html lang="<%=page.language || config.language%>">
|
|
12
|
+
|
|
13
|
+
<head>
|
|
14
|
+
<meta charset="UTF-8" />
|
|
15
|
+
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
|
16
|
+
<title><%=getPageTitle()%></title>
|
|
17
|
+
<link rel="icon" type="image/x-icon" href="/favicon.svg" />
|
|
18
|
+
<meta name="referrer" content="no-referrer-when-downgrade" />
|
|
19
|
+
<% if (page.hide && page.hide.seo) { %>
|
|
20
|
+
<meta name="robots" content="noindex, nofollow">
|
|
21
|
+
<% } %>
|
|
22
|
+
<meta name="description" content="<%=page?.excerpt||config?.description||''%>" />
|
|
23
|
+
<%-partial('partials/share-meta')%> <% if (theme.stylesheets !== undefined
|
|
24
|
+
&& theme.stylesheets.length > 0) { %>
|
|
25
|
+
<% if (is_post()) { %>
|
|
26
|
+
<link rel="stylesheet" href="/css/linkcard.css?v=<%=version%>" />
|
|
27
|
+
<% } %>
|
|
28
|
+
<!-- stylesheets list from _config.yml -->
|
|
29
|
+
<% theme.stylesheets.forEach(url => { %>
|
|
30
|
+
<link rel="stylesheet" href="<%=url%>?v=<%=version%>" />
|
|
31
|
+
<% }); %> <% } %>
|
|
32
|
+
<% if (theme?.lazyload?.enable) { %>
|
|
33
|
+
<link rel="stylesheet" href="/css/lazyload.css?v=<%=version%>" />
|
|
34
|
+
<% } %>
|
|
35
|
+
<% if (theme?.heads) { %>
|
|
36
|
+
<% theme?.heads.forEach(head => { %>
|
|
37
|
+
<%-head%>
|
|
38
|
+
<% }); %>
|
|
39
|
+
<% } %>
|
|
40
|
+
<% if (page?.heads) { %>
|
|
41
|
+
<% page.heads.forEach(head => { %>
|
|
42
|
+
<%-head%>
|
|
43
|
+
<% }); %>
|
|
44
|
+
<% } %>
|
|
45
|
+
</head>
|
|
46
|
+
|
|
47
|
+
<body>
|
|
48
|
+
<div id=" "></div>
|
|
49
|
+
<div id="page-top"></div>
|
|
50
|
+
<%-partial('partials/header', {
|
|
51
|
+
hasTocs: page?.toc ?? !!tocs?.length
|
|
52
|
+
})%> <% if (is_post()) { %>
|
|
53
|
+
<div class="banner-bg"></div>
|
|
54
|
+
<% } %>
|
|
55
|
+
<div id="safe-area-test" style="position: fixed; bottom: 0; height: env(safe-area-inset-bottom);"></div>
|
|
56
|
+
<div class="page-body">
|
|
57
|
+
<div class="side-content">
|
|
58
|
+
<% if (page?.toc !== false && tocs?.length) { %>
|
|
59
|
+
<div id="toc" class="toc<%=page.tocType === 'flat' ? ' flat' : ''%>">
|
|
60
|
+
<div class="toc-title"></div>
|
|
61
|
+
<div class="toc-items">
|
|
62
|
+
<% tocs.forEach((toc, index) => { %>
|
|
63
|
+
<div class="toc-item-wrap<%-index ===0 ? ' active': ''%>">
|
|
64
|
+
<a class="toc-item-link" data-id="<%-toc.id%>" href="#<%-toc.id%>"><%-toc.title%></a>
|
|
65
|
+
<% if(toc?.children?.length) { %>
|
|
66
|
+
<ul class="toc-sub-item-wrap">
|
|
67
|
+
<% toc.children.forEach(subItem => { %>
|
|
68
|
+
<li><a class="toc-sub-item-link" data-id="<%-subItem.id%>" href="#<%-subItem.id%>"><%-subItem.title%></a></li>
|
|
69
|
+
<% }); %>
|
|
70
|
+
</ul>
|
|
71
|
+
<% }; %>
|
|
72
|
+
</div>
|
|
73
|
+
<% }); %>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
<% } %>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="side-content">
|
|
79
|
+
<% if (series.length) { %>
|
|
80
|
+
<div class="post-series">
|
|
81
|
+
<a class="series-title" href="<%='/series/' + page.series + '/'%>"><%=__('common.series')%>-<%=page.series%></a>
|
|
82
|
+
<div class="series-items">
|
|
83
|
+
<% take(series, 50).forEach((item, index) => { %>
|
|
84
|
+
<a class="series-item-link<%-item.source === page.source ? ' active': ''%>" href="<%=url_for(item.path)%>"><%-`${item.title}`%><% if (item.subTitle) { %><span class="sub-title"><%=item.subTitle%></span><% } %></a>
|
|
85
|
+
<% }); %>
|
|
86
|
+
<% if(series.length > 50) { %>
|
|
87
|
+
<a class="series-item-link view-more" href="<%='/series/' + page.series + '/'%>"><%-`${__('common.total')} ${series.length} ${__('common.seriesPostCountShort')}`%></a>
|
|
88
|
+
<% } %>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
<% } %>
|
|
92
|
+
</div>
|
|
93
|
+
<div id="content-outer" class="<%= is_post() ? 'post-outer' : page.seriesInfo?.cover ? 'series-outer': '' %>">
|
|
94
|
+
<div id="content-inner">
|
|
95
|
+
<%- body %>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<%-partial('partials/footer')%>
|
|
101
|
+
<div id="mask"></div>
|
|
102
|
+
<a id="back-to-top" href="# " title="back to top"></a>
|
|
103
|
+
<noscript id="noscript-styles"></noscript>
|
|
104
|
+
<% if(is_post()) { %>
|
|
105
|
+
<script src="/js/toc.js?v=<%=version%>" defer></script>
|
|
106
|
+
<% } %>
|
|
107
|
+
<% if (theme.scripts !== undefined && theme.scripts.length > 0) { %>
|
|
108
|
+
<!-- scripts list from theme config.yml -->
|
|
109
|
+
<% theme.scripts.forEach(url => { %>
|
|
110
|
+
<script src="<%=url%>?v=<%=version%>"></script>
|
|
111
|
+
<% }); %>
|
|
112
|
+
<% } %>
|
|
113
|
+
<% if (theme?.lazyload?.enable) { %>
|
|
114
|
+
<script src="/js/lazyload.js?v=<%=version%>"></script>
|
|
115
|
+
<% } %>
|
|
116
|
+
<% if (page.hdrAssetsPrefix) { %>
|
|
117
|
+
<script>
|
|
118
|
+
var hdrAssetsPrefix = "<%-page.hdrAssetsPrefix%>"
|
|
119
|
+
</script>
|
|
120
|
+
<% } %>
|
|
121
|
+
<% if (page.hdrSwitch) { %>
|
|
122
|
+
<script src="/js/hdr.js?v=<%=version%>"></script>
|
|
123
|
+
<% } %>
|
|
124
|
+
<% if (theme?.appends?.length > 0) { %>
|
|
125
|
+
<% theme.appends.forEach(appendItem => { %>
|
|
126
|
+
<%-appendItem%>
|
|
127
|
+
<% }); %>
|
|
128
|
+
<% } %>
|
|
129
|
+
</body>
|
|
130
|
+
|
|
131
|
+
</html>
|
package/layout/page.ejs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<footer id="footer">
|
|
2
|
+
<div class="footerInner">
|
|
3
|
+
<div class="footerItems">
|
|
4
|
+
<!-- <a class="footerItem" href="">About This Blog</a> -->
|
|
5
|
+
<span class="footerItem"><abbr title="<%=__('common.copyright')%>" style="cursor: help;">©</abbr> <%=date(Date.now(), 'YYYY')+' '+config.author%></span>
|
|
6
|
+
<span class="footerItem">Powered by <a href="https://hexo.io/" target="_blank">Hexo</a></span>
|
|
7
|
+
<% if (theme?.info?.registration) { %>
|
|
8
|
+
<span class="footerItem"><%=theme.info.registration%></span>
|
|
9
|
+
<% } %>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
</footer>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const { hasTranslatation, targetLanguagePath, targetLanguage } = getTranslationPage();
|
|
3
|
+
|
|
4
|
+
const logoConfig = theme?.logo || {};
|
|
5
|
+
const { src: logoSrc, text: logoText, width: logoWidth, height: logoHeight } = logoConfig;
|
|
6
|
+
const rssPath = config?.feed?.path || theme?.feed?.path;
|
|
7
|
+
%>
|
|
8
|
+
|
|
9
|
+
<% if (is_post()) { %>
|
|
10
|
+
<div class="nav-header-pleaceholder"></div>
|
|
11
|
+
<% } %>
|
|
12
|
+
<div class="nav-header<%=is_post() ? ' is-post': ''%>">
|
|
13
|
+
<div class="header-inner">
|
|
14
|
+
<a class="title" href="/" title="index" style="<%=[logoSrc ? `background-image: url(${logoSrc})`: '', logoWidth && logoHeight ? `aspect-ratio: ${logoWidth}/${logoHeight}` : ''].filter(v => v).join(';')%>"><%=logoText||''%></a>
|
|
15
|
+
<div class="right">
|
|
16
|
+
<div class="navItems">
|
|
17
|
+
<% (theme?.navItems || []).forEach(({ name, path }) => { %>
|
|
18
|
+
<a class="navItem<%=`/${page.path}`.startsWith(path) ? ' active' : ''%>" href="<%=path%>"><%=name%></a>
|
|
19
|
+
<% }); %>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="buttonSet">
|
|
22
|
+
<% if (page.hdrSwitch) { %>
|
|
23
|
+
<span class="button hdr-switch" title="Switch HDR/SDR content">
|
|
24
|
+
</span>
|
|
25
|
+
<% } %>
|
|
26
|
+
<% if (hasTranslatation) { %>
|
|
27
|
+
<a class="button language <%=targetLanguage%>" href="<%=targetLanguagePath%>" target="_self" title="switch language"></a>
|
|
28
|
+
<% } %>
|
|
29
|
+
<% if (theme?.info?.github) { %>
|
|
30
|
+
<a class="button github" href="<%=theme?.info?.github || ''%>" target="_blank" title="github"></a>
|
|
31
|
+
<% } %>
|
|
32
|
+
<% if (rssPath) { %>
|
|
33
|
+
<a class="button rss" href="<%=rssPath%>" target="_blank" title="rss"></a>
|
|
34
|
+
<% } %>
|
|
35
|
+
<% if (hasTocs) { %>
|
|
36
|
+
<div id="toc-toggle" class="button toc"></div>
|
|
37
|
+
<% } %>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<div class="post-item" href="<%=url_for(post.path)%>" onclick="onclickPostItem(this)">
|
|
2
|
+
<div class="item-body">
|
|
3
|
+
<div class="title-excerpt">
|
|
4
|
+
<div class="title-excerpt-text">
|
|
5
|
+
<a class="title" href="<%=url_for(post.path)%>" onclick="event.stopPropagation()"><%=post.title%><% if (post.subTitle) { %><span class="sub-title"><%=post.subTitle%></span><% } %></a>
|
|
6
|
+
<% if(post?.tags?.length) { %>
|
|
7
|
+
<div class="tags">
|
|
8
|
+
<% (post.tags || []).forEach(tag => { %>
|
|
9
|
+
<a class="tag-item" href="<%='/'+tag.path%>" onclick="event.stopPropagation()"><%=tag.name%></a>
|
|
10
|
+
<% }) %>
|
|
11
|
+
</div>
|
|
12
|
+
<% } %>
|
|
13
|
+
<div class="excerpt"><%-post?.excerpt||''%></div>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="post-meta">
|
|
16
|
+
<% if (post.date && !date(post.date).startsWith('1970')) { %>
|
|
17
|
+
<time class="date" datetime="<%=post.date.toJSON()%>">
|
|
18
|
+
<%=getPostDate(post)%>
|
|
19
|
+
</time>
|
|
20
|
+
<% } %>
|
|
21
|
+
<span class="categories">
|
|
22
|
+
<% (post?.categories || []).forEach(category => { %>
|
|
23
|
+
<a class="category-item" href="<%='/'+category.path%>" onclick="event.stopPropagation()"><%=category.name%></a>
|
|
24
|
+
<% }); %>
|
|
25
|
+
</span>
|
|
26
|
+
<span class="read-time"><%-partial('partials/words', { post, count: false, readTime: true })%></span>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<% if (post.thumbnail || post.cover) { %>
|
|
30
|
+
<div class="cover-img">
|
|
31
|
+
<img src="<%=post.thumbnail || post.cover%>" alt="" loading="lazy" />
|
|
32
|
+
</div>
|
|
33
|
+
<% } %>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<% if (page.posts.length > 0) {
|
|
2
|
+
let topPosts = [];
|
|
3
|
+
function getFirstFour(arr) {
|
|
4
|
+
return arr.slice(0, 4);
|
|
5
|
+
}
|
|
6
|
+
(theme?.topArticles || []).forEach(path=>{
|
|
7
|
+
const post = site.posts.findOne({ source: path });
|
|
8
|
+
if(post){ topPosts.push(post) }
|
|
9
|
+
})
|
|
10
|
+
topPosts = getFirstFour(topPosts);
|
|
11
|
+
const isArchive = is_archive();
|
|
12
|
+
%>
|
|
13
|
+
<div id="recent-posts">
|
|
14
|
+
<% page.posts.filter(post=>is_home()?!(topPosts.map(v=>v.source)).includes(post.source): true).filter(v=>showHidden ? (isArchive ? !v?.hide?.archive : true) : !v?.hide?.recent).sort('date', -1).each(post => { %>
|
|
15
|
+
<%-partial('partials/post-item', { post: post })%>
|
|
16
|
+
<% }); %>
|
|
17
|
+
</div>
|
|
18
|
+
<% } %>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const tags = page.tags.data.map(tag=>tag.name);
|
|
3
|
+
const relatedPosts = site.posts.filter(item=>item.source !== page.source).filter((item) => {
|
|
4
|
+
let count = 0;
|
|
5
|
+
const itemTags = item.tags.data.map(tag=>tag.name);
|
|
6
|
+
(tags).forEach((tag) => {
|
|
7
|
+
if(itemTags.includes(tag)){
|
|
8
|
+
count ++;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
return count >=2;
|
|
12
|
+
}).sort('date', -1).limit(3);
|
|
13
|
+
%>
|
|
14
|
+
<% if (page?.showRelated !== false && relatedPosts.length > 0) { %>
|
|
15
|
+
<div id="related-posts">
|
|
16
|
+
<div class="related-posts-title"><%=__('common.relatedPosts')%></div>
|
|
17
|
+
<% relatedPosts.each(post => {
|
|
18
|
+
const coverImg = post.thumbnail || post.cover || '/img/related-post.jpg'
|
|
19
|
+
%>
|
|
20
|
+
<a href="<%=url_for(post.path)%>">
|
|
21
|
+
<div class="shared-link">
|
|
22
|
+
<div class="cover-img">
|
|
23
|
+
<img no-lazy class="not-gallery-item" src="<%=coverImg%>" alt="" loading="lazy">
|
|
24
|
+
</div>
|
|
25
|
+
<div class="link-content">
|
|
26
|
+
<span class="link-title"><%=post.title%></span>
|
|
27
|
+
<span class="link-desc"><%-post?.excerpt||''%></span>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</a>
|
|
31
|
+
<% }); %>
|
|
32
|
+
</div>
|
|
33
|
+
<% } %>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<%
|
|
2
|
+
var pageTitle = getPageTitle();
|
|
3
|
+
%>
|
|
4
|
+
<meta property="og:type" content="blog">
|
|
5
|
+
<meta property="og:title" content="<%=pageTitle%>">
|
|
6
|
+
<meta property="og:url" content="<%=config.url + '/' + page.path%>">
|
|
7
|
+
<meta property="og:site_name" content="<%=config.title%>">
|
|
8
|
+
<meta property="og:description" content="<%=page?.seriesInfo?.description||page.excerpt||''%>">
|
|
9
|
+
<meta property="og:locale" content="<%=page.language||config.language%>">
|
|
10
|
+
<meta property="og:image" content="<%=page.seriesInfo?.cover||page.ogImage||page.cover||theme?.info?.siteCardBg||''%>">
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const series = Array.from(new Set(site.posts.filter(item=>item.series).sort('date', -1).map(item=>item.series)))
|
|
3
|
+
%>
|
|
4
|
+
<div class="site-info<%=is_home_first_page() ? ' home' : ''%>">
|
|
5
|
+
<div class="info-row">
|
|
6
|
+
<div class="author">
|
|
7
|
+
<img class="avatar" src="<%=theme?.info?.avatar || '/img/vue-color-avatar.png'%>" alt="" />
|
|
8
|
+
<div class="name"><%=config?.author || ''%></div>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="info-row description"><%=theme?.info?.site_desc || ''%></div>
|
|
12
|
+
<div class="info-row site-statisc">
|
|
13
|
+
<a href="/archives/#posts" target="_self"><%=site.posts?.filter(post=>!post?.hide?.archive).length%> <%=__('common.posts')%></a>
|
|
14
|
+
<span class="divider">/</span>
|
|
15
|
+
<a href="/archives/#categories" target="_self"><%=site.categories.length%> <%=__('common.categories')%></a>
|
|
16
|
+
<span class="divider">/</span>
|
|
17
|
+
<a href="/archives/#tags" target="_self"><%=site.tags.length%> <%=__('common.tags')%></a>
|
|
18
|
+
<% if (series.length) { %>
|
|
19
|
+
<span class="divider">/</span>
|
|
20
|
+
<a href="/archives/#series" target="_self"><%=series.length%> <%=__('common.series')%></a><% } %>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<% let topPosts = [];
|
|
2
|
+
function getFirstFour(arr) {
|
|
3
|
+
return arr.slice(0, 4);
|
|
4
|
+
}
|
|
5
|
+
(theme?.topArticles || []).forEach(path=>{
|
|
6
|
+
const post = site.posts.findOne({ source: path });
|
|
7
|
+
if(post){ topPosts.push(post) }
|
|
8
|
+
})
|
|
9
|
+
topPosts = getFirstFour(topPosts);
|
|
10
|
+
%>
|
|
11
|
+
<div id="top-posts">
|
|
12
|
+
<% topPosts.forEach(post => { %>
|
|
13
|
+
<a class="post-item" href="<%=url_for(post.path)%>">
|
|
14
|
+
<div class="item-body">
|
|
15
|
+
<div class="cover-img">
|
|
16
|
+
<img src="<%=post.thumbnail || post.cover%>" alt="" />
|
|
17
|
+
</div>
|
|
18
|
+
<div class="title-excerpt">
|
|
19
|
+
<div class="title"><%=post.title%><% if (post.subTitle) { %><span class="sub-title"><%=post.subTitle%></span><% } %></div>
|
|
20
|
+
<div class="excerpt"><%=post?.excerpt||''%></div>
|
|
21
|
+
<div class="post-meta">
|
|
22
|
+
<time class="date" datetime="<%=post.date.toJSON()%>">
|
|
23
|
+
<%=getPostDate(post)%>
|
|
24
|
+
</time>
|
|
25
|
+
<span class="categories">
|
|
26
|
+
<% (post?.categories || []).forEach(category => { %>
|
|
27
|
+
<span class="category-item"><%=category.name%></span>
|
|
28
|
+
<% }); %>
|
|
29
|
+
</span>
|
|
30
|
+
<span class="read-time"><%-partial('partials/words', { post, count: false, readTime: true })%></span>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</a>
|
|
35
|
+
<% }); %>
|
|
36
|
+
</div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<%
|
|
2
|
+
const content = post.content || "";
|
|
3
|
+
const text = content
|
|
4
|
+
.replace(/<figure[^>]*>.*?<\/figure>/gs, "")
|
|
5
|
+
.replace(/<span class=\"pswp-caption-content\">.*?<\/span>/gs, "")
|
|
6
|
+
.replace(/<noscript[^>]*>.*?<\/noscript>/gs, "")
|
|
7
|
+
.replace(/<style[^>]*>.*?<\/style>/gs, "")
|
|
8
|
+
.replace(/<script[^>]*>.*?<\/script>/gs, "")
|
|
9
|
+
.replace(/<\/?[^>]+(>|$)/g, "")
|
|
10
|
+
|
|
11
|
+
const currentLanguage = page?.language || config?.language;
|
|
12
|
+
const comma = currentLanguage === 'en' ? ', ' : ','
|
|
13
|
+
const words = (currentLanguage === 'en'? text?.split(' ')?.length : text?.trim()?.replace(/[\s\t\n]/g, '')?.length) || 0;
|
|
14
|
+
const photos = content.match(/class="gallery-item/gi, '')?.length || 0;
|
|
15
|
+
let res = [];
|
|
16
|
+
let smallRes = [];
|
|
17
|
+
if(count && (words || photos)) {
|
|
18
|
+
res = [__('common.approximately'), ' ', ...(words ? [words, __('common.words')] : []), words && photos ? comma : '', ...(photos ? [photos, photos > 1 ? __('common.photos') : __('common.photo')]: [])].filter(item=>item);
|
|
19
|
+
}
|
|
20
|
+
if(readTime) {
|
|
21
|
+
res = res.concat([res.length ? comma : __('common.approximately'), estimateReadingTime(text, photos, content), __('common.minsRead')])
|
|
22
|
+
}
|
|
23
|
+
if(count && readTime) {
|
|
24
|
+
res = [__('common.approximately'), estimateReadingTime(text, photos, content), __('common.minsRead')].filter(item=>item);
|
|
25
|
+
smallRes = words ? ['(', ...(words ? [words, __('common.words')] : []), words && photos ? comma : '', ...(photos ? [photos, photos > 1 ? __('common.photos') : __('common.photo')]: []), ')'].filter(item=>item) : [];
|
|
26
|
+
}
|
|
27
|
+
%>
|
|
28
|
+
<% res.forEach(function(item) { %>
|
|
29
|
+
<span><%= item %></span>
|
|
30
|
+
<% }); %>
|
|
31
|
+
<% smallRes.forEach(function(item) { %>
|
|
32
|
+
<small><%= item %></small>
|
|
33
|
+
<% }); %>
|