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.
Files changed (113) hide show
  1. package/index.js +6 -0
  2. package/languages/en.yml +39 -0
  3. package/languages/zh-CN.yml +39 -0
  4. package/layout/archive.ejs +92 -0
  5. package/layout/category.ejs +8 -0
  6. package/layout/index.ejs +11 -0
  7. package/layout/layout.ejs +131 -0
  8. package/layout/page.ejs +6 -0
  9. package/layout/partials/footer.ejs +12 -0
  10. package/layout/partials/header.ejs +41 -0
  11. package/layout/partials/paginator.ejs +5 -0
  12. package/layout/partials/post-item.ejs +35 -0
  13. package/layout/partials/recent-posts.ejs +18 -0
  14. package/layout/partials/related-posts.ejs +33 -0
  15. package/layout/partials/share-meta.ejs +10 -0
  16. package/layout/partials/site-info.ejs +22 -0
  17. package/layout/partials/top-posts.ejs +36 -0
  18. package/layout/partials/words.ejs +33 -0
  19. package/layout/post.ejs +368 -0
  20. package/layout/series.ejs +59 -0
  21. package/layout/tag.ejs +8 -0
  22. package/package.json +34 -6
  23. package/scripts/appendRawMarkdownContent.js +19 -0
  24. package/scripts/folded-code-block.js +56 -0
  25. package/scripts/font-version.js +14 -0
  26. package/scripts/helpers/tools.js +218 -0
  27. package/scripts/index.js +21 -0
  28. package/scripts/lazyload/client.js +362 -0
  29. package/scripts/lazyload/config.js +10 -0
  30. package/scripts/lazyload/index.js +13 -0
  31. package/scripts/lazyload/inject.js +183 -0
  32. package/scripts/lazyload/process.js +464 -0
  33. package/scripts/lib/comments.js +26 -0
  34. package/scripts/lib/custom.js +30 -0
  35. package/scripts/markdown-it-image-grid.js +34 -0
  36. package/scripts/series-generator.js +52 -0
  37. package/source/css/animations.css +17 -0
  38. package/source/css/font-version.scss +1 -0
  39. package/source/css/highlight-github.scss +122 -0
  40. package/source/css/lazyload.css +107 -0
  41. package/source/css/linen.scss +2528 -0
  42. package/source/css/linkcard.scss +233 -0
  43. package/source/css/mediaquery.scss +447 -0
  44. package/source/css/normalize.css +1 -0
  45. package/source/css/noscript.css +67 -0
  46. package/source/css/photoswipe-dynamic-caption-plugin.css +160 -0
  47. package/source/css/photoswipe.css +448 -0
  48. package/source/css/rss-en.xsl +35 -0
  49. package/source/css/rss-zh.xsl +35 -0
  50. package/source/css/vars.scss +114 -0
  51. package/source/favicon.svg +3 -0
  52. package/source/fonts/SourceHanSerifCN-Regular.woff2 +0 -0
  53. package/source/fonts/SourceSerif4-Regular.ttf.woff2 +0 -0
  54. package/source/img/icons/ZIP.svg +1 -0
  55. package/source/img/icons/about.svg +1 -0
  56. package/source/img/icons/arrow-down.svg +1 -0
  57. package/source/img/icons/binary.svg +1 -0
  58. package/source/img/icons/checked-checkbox.svg +1 -0
  59. package/source/img/icons/chinese.svg +6 -0
  60. package/source/img/icons/code.svg +1 -0
  61. package/source/img/icons/collapsed.svg +6 -0
  62. package/source/img/icons/copied.png +0 -0
  63. package/source/img/icons/copy.png +0 -0
  64. package/source/img/icons/copyright.svg +1 -0
  65. package/source/img/icons/date.svg +1 -0
  66. package/source/img/icons/email.svg +1 -0
  67. package/source/img/icons/english.svg +6 -0
  68. package/source/img/icons/exif/aperture.svg +1 -0
  69. package/source/img/icons/exif/camera.svg +1 -0
  70. package/source/img/icons/exif/ev.svg +1 -0
  71. package/source/img/icons/exif/focusLength.svg +1 -0
  72. package/source/img/icons/exif/hdr.svg +1 -0
  73. package/source/img/icons/exif/iso.svg +1 -0
  74. package/source/img/icons/exif/lens.svg +1 -0
  75. package/source/img/icons/exif/location.svg +1 -0
  76. package/source/img/icons/exif/shutterSpeed.svg +1 -0
  77. package/source/img/icons/github.svg +1 -0
  78. package/source/img/icons/hdr.svg +1 -0
  79. package/source/img/icons/hdr_off.svg +1 -0
  80. package/source/img/icons/link.svg +1 -0
  81. package/source/img/icons/location.svg +1 -0
  82. package/source/img/icons/more.svg +4 -0
  83. package/source/img/icons/new.svg +1 -0
  84. package/source/img/icons/new1.svg +1 -0
  85. package/source/img/icons/next.svg +1 -0
  86. package/source/img/icons/prev.svg +1 -0
  87. package/source/img/icons/redirect.svg +1 -0
  88. package/source/img/icons/rss.svg +5 -0
  89. package/source/img/icons/search.svg +1 -0
  90. package/source/img/icons/shelf.svg +1 -0
  91. package/source/img/icons/tag.svg +1 -0
  92. package/source/img/icons/toc.svg +1 -0
  93. package/source/img/icons/toc1.svg +1 -0
  94. package/source/img/icons/up-down.svg +1 -0
  95. package/source/img/lazyload/error-tip.svg +1 -0
  96. package/source/img/lazyload/loading.svg +9 -0
  97. package/source/img/logo.svg +3 -0
  98. package/source/img/logo_black.svg +4 -0
  99. package/source/img/pattern-randomized.jpg +0 -0
  100. package/source/img/pattern-randomized.svg +1 -0
  101. package/source/img/related-post.jpg +0 -0
  102. package/source/img/vue-color-avatar.png +0 -0
  103. package/source/js/gitalk/gitalk.css +1251 -0
  104. package/source/js/gitalk/gitalk.min.js +35 -0
  105. package/source/js/hdr.js +90 -0
  106. package/source/js/lazyload.js +362 -0
  107. package/source/js/linen.js +481 -0
  108. package/source/js/photoswipe/photoswipe-dynamic-caption-plugin.esm.js +359 -0
  109. package/source/js/photoswipe/photoswipe-lightbox.esm.min.js +5 -0
  110. package/source/js/photoswipe/photoswipe.esm.min.js +6817 -0
  111. package/source/js/replace-emoji.js +45 -0
  112. package/source/js/toc.js +233 -0
  113. package/README.md +0 -11
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ // Register theme views
5
+ views: __dirname + '/layout'
6
+ };
@@ -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>
@@ -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>
@@ -0,0 +1,6 @@
1
+ <article id="page">
2
+ <h1><%=page.title%></h1>
3
+ <%-page.content%>
4
+ </article>
5
+
6
+ <%-partial('partials/paginator')%>
@@ -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>&nbsp;<%=date(Date.now(), 'YYYY')+' '+config.author%></span>
6
+ <span class="footerItem">Powered by&nbsp;<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,5 @@
1
+ <% if (page.total > 1) { %>
2
+ <div id="paginator">
3
+ <%-paginator({ prev_text: __('common.prev'), next_text: __('common.next')})%>
4
+ </div>
5
+ <% } %>
@@ -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
+ <% }); %>