From bc7808927be5fb7dc1db9c7c25035a3448d6cc18 Mon Sep 17 00:00:00 2001 From: echocbx Date: Tue, 27 Jun 2023 20:30:40 +0800 Subject: [PATCH] 1.0.1 --- .github/ISSUE_TEMPLATE/bug_report.yml | 73 + .github/ISSUE_TEMPLATE/config.yml | 22 + .github/ISSUE_TEMPLATE/feature_request.yml | 14 + .github/workflows/publish.yml | 19 + .github/workflows/stale.yml | 19 + LICENSE | 202 +++ README.md | 113 ++ README_CN.md | 113 ++ _config.yml | 955 +++++++++++ languages/default.yml | 121 ++ languages/en.yml | 121 ++ languages/zh-CN.yml | 122 ++ languages/zh-TW.yml | 122 ++ layout/archive.pug | 9 + layout/category.pug | 14 + layout/includes/404.pug | 12 + layout/includes/additional-js.pug | 69 + layout/includes/footer.pug | 52 + layout/includes/head.pug | 69 + layout/includes/head/Open_Graph.pug | 13 + layout/includes/head/analytics.pug | 31 + layout/includes/head/config.pug | 124 ++ layout/includes/head/config_site.pug | 30 + layout/includes/head/google_adsense.pug | 9 + layout/includes/head/noscript.pug | 14 + layout/includes/head/preconnect.pug | 22 + layout/includes/head/pwa.pug | 11 + layout/includes/head/site_verification.pug | 3 + layout/includes/header/index.pug | 56 + layout/includes/header/menu_item.pug | 27 + layout/includes/header/nav.pug | 34 + layout/includes/header/post-info.pug | 146 ++ layout/includes/header/social.pug | 4 + layout/includes/hometop.pug | 71 + layout/includes/layout.pug | 60 + layout/includes/loading/fullpage-loading.pug | 28 + layout/includes/loading/index.pug | 4 + layout/includes/loading/pace.pug | 2 + layout/includes/mixins/article-sort.pug | 20 + layout/includes/mixins/post-ui.pug | 128 ++ layout/includes/page/about.pug | 259 +++ layout/includes/page/categories.pug | 1 + layout/includes/page/default-page.pug | 2 + layout/includes/page/flink.pug | 15 + layout/includes/page/tags.pug | 2 + layout/includes/pagination.pug | 37 + layout/includes/post/post-copyright.pug | 30 + layout/includes/post/reward.pug | 13 + layout/includes/rightside.pug | 60 + layout/includes/sidebar.pug | 18 + layout/includes/third-party/aplayer.pug | 3 + .../third-party/card-post-count/artalk.pug | 20 + .../third-party/card-post-count/disqus.pug | 16 + .../third-party/card-post-count/fb.pug | 18 + .../third-party/card-post-count/index.pug | 16 + .../third-party/card-post-count/remark42.pug | 18 + .../third-party/card-post-count/twikoo.pug | 37 + .../third-party/card-post-count/valine.pug | 20 + .../third-party/card-post-count/waline.pug | 18 + layout/includes/third-party/chat/chatra.pug | 33 + layout/includes/third-party/chat/crisp.pug | 36 + layout/includes/third-party/chat/daovoice.pug | 40 + layout/includes/third-party/chat/gitter.pug | 43 + layout/includes/third-party/chat/index.pug | 12 + .../includes/third-party/chat/messenger.pug | 42 + layout/includes/third-party/chat/tidio.pug | 41 + .../includes/third-party/comments/artalk.pug | 45 + .../includes/third-party/comments/disqus.pug | 51 + .../third-party/comments/disqusjs.pug | 64 + .../comments/facebook_comments.pug | 36 + .../includes/third-party/comments/giscus.pug | 49 + .../includes/third-party/comments/gitalk.pug | 48 + .../includes/third-party/comments/index.pug | 46 + layout/includes/third-party/comments/js.pug | 26 + .../includes/third-party/comments/livere.pug | 26 + .../third-party/comments/remark42.pug | 67 + .../includes/third-party/comments/twikoo.pug | 53 + .../third-party/comments/utterances.pug | 34 + .../includes/third-party/comments/valine.pug | 33 + .../includes/third-party/comments/waline.pug | 40 + layout/includes/third-party/effect.pug | 35 + layout/includes/third-party/math/index.pug | 18 + layout/includes/third-party/math/katex.pug | 9 + layout/includes/third-party/math/mathjax.pug | 47 + layout/includes/third-party/math/mermaid.pug | 26 + .../third-party/newest-comments/artalk.pug | 82 + .../newest-comments/disqus-comment.pug | 82 + .../newest-comments/github-issues.pug | 109 ++ .../third-party/newest-comments/index.pug | 30 + .../third-party/newest-comments/remark42.pug | 80 + .../newest-comments/twikoo-comment.pug | 93 ++ .../third-party/newest-comments/valine.pug | 99 ++ .../third-party/newest-comments/waline.pug | 84 + layout/includes/third-party/pangu.pug | 20 + layout/includes/third-party/pjax.pug | 84 + layout/includes/third-party/prismjs.pug | 5 + .../includes/third-party/search/algolia.pug | 18 + layout/includes/third-party/search/index.pug | 4 + .../third-party/search/local-search.pug | 20 + .../includes/third-party/share/add-this.pug | 2 + .../includes/third-party/share/addtoany.pug | 10 + layout/includes/third-party/share/index.pug | 7 + .../includes/third-party/share/share-js.pug | 3 + layout/includes/third-party/subtitle.pug | 128 ++ layout/includes/waves.pug | 9 + layout/includes/widget/card_author.pug | 14 + layout/includes/widget/card_post_toc.pug | 15 + layout/includes/widget/card_tags.pug | 54 + layout/includes/widget/card_webinfo.pug | 28 + layout/includes/widget/index.pug | 21 + layout/index.pug | 7 + layout/page.pug | 21 + layout/post.pug | 32 + layout/tag.pug | 14 + package.json | 32 + plugins.yml | 200 +++ scripts/events/404.js | 18 + scripts/events/cdn.js | 94 ++ scripts/events/comment.js | 14 + scripts/events/init.js | 21 + scripts/events/stylus.js | 15 + scripts/events/welcome.js | 17 + scripts/filters/post_lazyload.js | 29 + scripts/filters/random_cover.js | 45 + scripts/helpers/aside_archives.js | 113 ++ scripts/helpers/aside_categories.js | 97 ++ scripts/helpers/findArchiveLength.js | 58 + scripts/helpers/get_arrays.js | 45 + scripts/helpers/inject_head_js.js | 148 ++ scripts/helpers/page.js | 83 + scripts/helpers/random.js | 11 + scripts/helpers/related_post.js | 99 ++ scripts/tag/btns.js | 35 + scripts/tag/button.js | 28 + scripts/tag/card.js | 48 + scripts/tag/flink.js | 39 + scripts/tag/folding.js | 34 + scripts/tag/gallery.js | 34 + scripts/tag/ghcard.js | 49 + scripts/tag/hide.js | 70 + scripts/tag/inlineImg.js | 17 + scripts/tag/label.js | 16 + scripts/tag/link.js | 22 + scripts/tag/media.js | 53 + scripts/tag/mermaid.js | 17 + scripts/tag/msgbox.js | 39 + scripts/tag/note.js | 27 + scripts/tag/poem.js | 18 + scripts/tag/progress.js | 11 + scripts/tag/reference.js | 26 + scripts/tag/span.js | 29 + scripts/tag/tabs.js | 62 + scripts/tag/timeline.js | 41 + source/css/_custom/about.css | 1403 +++++++++++++++++ source/css/_custom/aside.css | 361 +++++ source/css/_custom/bar.css | 139 ++ source/css/_custom/custom.css | 167 ++ source/css/_custom/custom.styl | 62 + source/css/_custom/footer.css | 306 ++++ source/css/_custom/hometop.styl | 230 +++ source/css/_custom/nav.css | 468 ++++++ source/css/_custom/post-double-row.css | 67 + source/css/_custom/sidebar.css | 31 + source/css/_custom/waves.css | 74 + source/css/_global/function.styl | 253 +++ source/css/_global/index.styl | 201 +++ source/css/_highlight/highlight.styl | 209 +++ source/css/_highlight/highlight/diff.styl | 79 + source/css/_highlight/highlight/index.styl | 39 + source/css/_highlight/prismjs/diff.styl | 302 ++++ source/css/_highlight/prismjs/index.styl | 22 + .../css/_highlight/prismjs/line-number.styl | 41 + source/css/_highlight/theme.styl | 119 ++ source/css/_layout/aside.styl | 406 +++++ source/css/_layout/chat.styl | 17 + source/css/_layout/comments.styl | 64 + source/css/_layout/footer.styl | 35 + source/css/_layout/head.styl | 376 +++++ source/css/_layout/loading.styl | 95 ++ source/css/_layout/pagination.styl | 83 + source/css/_layout/post.styl | 261 +++ source/css/_layout/relatedposts.styl | 43 + source/css/_layout/reward.styl | 74 + source/css/_layout/rightside.styl | 49 + source/css/_layout/sidebar.styl | 68 + source/css/_layout/third-party.styl | 116 ++ source/css/_mode/darkmode.styl | 150 ++ source/css/_mode/readmode.styl | 197 +++ source/css/_page/404.styl | 69 + source/css/_page/archives.styl | 109 ++ source/css/_page/categories.styl | 37 + source/css/_page/common.styl | 60 + source/css/_page/flink.styl | 87 + source/css/_page/homepage.styl | 113 ++ source/css/_page/tags.styl | 23 + source/css/_search/algolia.styl | 91 ++ source/css/_search/index.styl | 43 + source/css/_search/local-search.styl | 67 + source/css/_tags/btns.styl | 213 +++ source/css/_tags/button.styl | 55 + source/css/_tags/card.styl | 72 + source/css/_tags/folding.styl | 104 ++ source/css/_tags/gallery.styl | 102 ++ source/css/_tags/ghcard.styl | 10 + source/css/_tags/hexo.styl | 30 + source/css/_tags/hide.styl | 45 + source/css/_tags/inlineImg.styl | 6 + source/css/_tags/label.styl | 11 + source/css/_tags/link.styl | 40 + source/css/_tags/media.styl | 50 + source/css/_tags/msgbox.styl | 102 ++ source/css/_tags/note.styl | 121 ++ source/css/_tags/poem.styl | 31 + source/css/_tags/progress.styl | 55 + source/css/_tags/reference.styl | 135 ++ source/css/_tags/span.styl | 27 + source/css/_tags/tabs.styl | 74 + source/css/_tags/timeline.styl | 68 + source/css/_third-party/normalize.min.css | 180 +++ source/css/color.css | 177 +++ source/css/index.styl | 23 + source/css/var.styl | 182 +++ source/img/404.jpg | Bin 0 -> 16393 bytes source/img/favicon.png | Bin 0 -> 323 bytes source/img/friend_404.gif | Bin 0 -> 65097 bytes source/js/custom.js | 64 + source/js/main.js | 779 +++++++++ source/js/scroll.js | 71 + source/js/search/algolia.js | 163 ++ source/js/search/local-search.js | 188 +++ source/js/tw_cn.js | 100 ++ source/js/utils.js | 278 ++++ 232 files changed, 18572 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/stale.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 README_CN.md create mode 100644 _config.yml create mode 100644 languages/default.yml create mode 100644 languages/en.yml create mode 100644 languages/zh-CN.yml create mode 100644 languages/zh-TW.yml create mode 100644 layout/archive.pug create mode 100644 layout/category.pug create mode 100644 layout/includes/404.pug create mode 100644 layout/includes/additional-js.pug create mode 100644 layout/includes/footer.pug create mode 100644 layout/includes/head.pug create mode 100644 layout/includes/head/Open_Graph.pug create mode 100644 layout/includes/head/analytics.pug create mode 100644 layout/includes/head/config.pug create mode 100644 layout/includes/head/config_site.pug create mode 100644 layout/includes/head/google_adsense.pug create mode 100644 layout/includes/head/noscript.pug create mode 100644 layout/includes/head/preconnect.pug create mode 100644 layout/includes/head/pwa.pug create mode 100644 layout/includes/head/site_verification.pug create mode 100644 layout/includes/header/index.pug create mode 100644 layout/includes/header/menu_item.pug create mode 100644 layout/includes/header/nav.pug create mode 100644 layout/includes/header/post-info.pug create mode 100644 layout/includes/header/social.pug create mode 100644 layout/includes/hometop.pug create mode 100644 layout/includes/layout.pug create mode 100644 layout/includes/loading/fullpage-loading.pug create mode 100644 layout/includes/loading/index.pug create mode 100644 layout/includes/loading/pace.pug create mode 100644 layout/includes/mixins/article-sort.pug create mode 100644 layout/includes/mixins/post-ui.pug create mode 100644 layout/includes/page/about.pug create mode 100644 layout/includes/page/categories.pug create mode 100644 layout/includes/page/default-page.pug create mode 100644 layout/includes/page/flink.pug create mode 100644 layout/includes/page/tags.pug create mode 100644 layout/includes/pagination.pug create mode 100644 layout/includes/post/post-copyright.pug create mode 100644 layout/includes/post/reward.pug create mode 100644 layout/includes/rightside.pug create mode 100644 layout/includes/sidebar.pug create mode 100644 layout/includes/third-party/aplayer.pug create mode 100644 layout/includes/third-party/card-post-count/artalk.pug create mode 100644 layout/includes/third-party/card-post-count/disqus.pug create mode 100644 layout/includes/third-party/card-post-count/fb.pug create mode 100644 layout/includes/third-party/card-post-count/index.pug create mode 100644 layout/includes/third-party/card-post-count/remark42.pug create mode 100644 layout/includes/third-party/card-post-count/twikoo.pug create mode 100644 layout/includes/third-party/card-post-count/valine.pug create mode 100644 layout/includes/third-party/card-post-count/waline.pug create mode 100644 layout/includes/third-party/chat/chatra.pug create mode 100644 layout/includes/third-party/chat/crisp.pug create mode 100644 layout/includes/third-party/chat/daovoice.pug create mode 100644 layout/includes/third-party/chat/gitter.pug create mode 100644 layout/includes/third-party/chat/index.pug create mode 100644 layout/includes/third-party/chat/messenger.pug create mode 100644 layout/includes/third-party/chat/tidio.pug create mode 100644 layout/includes/third-party/comments/artalk.pug create mode 100644 layout/includes/third-party/comments/disqus.pug create mode 100644 layout/includes/third-party/comments/disqusjs.pug create mode 100644 layout/includes/third-party/comments/facebook_comments.pug create mode 100644 layout/includes/third-party/comments/giscus.pug create mode 100644 layout/includes/third-party/comments/gitalk.pug create mode 100644 layout/includes/third-party/comments/index.pug create mode 100644 layout/includes/third-party/comments/js.pug create mode 100644 layout/includes/third-party/comments/livere.pug create mode 100644 layout/includes/third-party/comments/remark42.pug create mode 100644 layout/includes/third-party/comments/twikoo.pug create mode 100644 layout/includes/third-party/comments/utterances.pug create mode 100644 layout/includes/third-party/comments/valine.pug create mode 100644 layout/includes/third-party/comments/waline.pug create mode 100644 layout/includes/third-party/effect.pug create mode 100644 layout/includes/third-party/math/index.pug create mode 100644 layout/includes/third-party/math/katex.pug create mode 100644 layout/includes/third-party/math/mathjax.pug create mode 100644 layout/includes/third-party/math/mermaid.pug create mode 100644 layout/includes/third-party/newest-comments/artalk.pug create mode 100644 layout/includes/third-party/newest-comments/disqus-comment.pug create mode 100644 layout/includes/third-party/newest-comments/github-issues.pug create mode 100644 layout/includes/third-party/newest-comments/index.pug create mode 100644 layout/includes/third-party/newest-comments/remark42.pug create mode 100644 layout/includes/third-party/newest-comments/twikoo-comment.pug create mode 100644 layout/includes/third-party/newest-comments/valine.pug create mode 100644 layout/includes/third-party/newest-comments/waline.pug create mode 100644 layout/includes/third-party/pangu.pug create mode 100644 layout/includes/third-party/pjax.pug create mode 100644 layout/includes/third-party/prismjs.pug create mode 100644 layout/includes/third-party/search/algolia.pug create mode 100644 layout/includes/third-party/search/index.pug create mode 100644 layout/includes/third-party/search/local-search.pug create mode 100644 layout/includes/third-party/share/add-this.pug create mode 100644 layout/includes/third-party/share/addtoany.pug create mode 100644 layout/includes/third-party/share/index.pug create mode 100644 layout/includes/third-party/share/share-js.pug create mode 100644 layout/includes/third-party/subtitle.pug create mode 100644 layout/includes/waves.pug create mode 100644 layout/includes/widget/card_author.pug create mode 100644 layout/includes/widget/card_post_toc.pug create mode 100644 layout/includes/widget/card_tags.pug create mode 100644 layout/includes/widget/card_webinfo.pug create mode 100644 layout/includes/widget/index.pug create mode 100644 layout/index.pug create mode 100644 layout/page.pug create mode 100644 layout/post.pug create mode 100644 layout/tag.pug create mode 100644 package.json create mode 100644 plugins.yml create mode 100644 scripts/events/404.js create mode 100644 scripts/events/cdn.js create mode 100644 scripts/events/comment.js create mode 100644 scripts/events/init.js create mode 100644 scripts/events/stylus.js create mode 100644 scripts/events/welcome.js create mode 100644 scripts/filters/post_lazyload.js create mode 100644 scripts/filters/random_cover.js create mode 100644 scripts/helpers/aside_archives.js create mode 100644 scripts/helpers/aside_categories.js create mode 100644 scripts/helpers/findArchiveLength.js create mode 100644 scripts/helpers/get_arrays.js create mode 100644 scripts/helpers/inject_head_js.js create mode 100644 scripts/helpers/page.js create mode 100644 scripts/helpers/random.js create mode 100644 scripts/helpers/related_post.js create mode 100644 scripts/tag/btns.js create mode 100644 scripts/tag/button.js create mode 100644 scripts/tag/card.js create mode 100644 scripts/tag/flink.js create mode 100644 scripts/tag/folding.js create mode 100644 scripts/tag/gallery.js create mode 100644 scripts/tag/ghcard.js create mode 100644 scripts/tag/hide.js create mode 100644 scripts/tag/inlineImg.js create mode 100644 scripts/tag/label.js create mode 100644 scripts/tag/link.js create mode 100644 scripts/tag/media.js create mode 100644 scripts/tag/mermaid.js create mode 100644 scripts/tag/msgbox.js create mode 100644 scripts/tag/note.js create mode 100644 scripts/tag/poem.js create mode 100644 scripts/tag/progress.js create mode 100644 scripts/tag/reference.js create mode 100644 scripts/tag/span.js create mode 100644 scripts/tag/tabs.js create mode 100644 scripts/tag/timeline.js create mode 100644 source/css/_custom/about.css create mode 100644 source/css/_custom/aside.css create mode 100644 source/css/_custom/bar.css create mode 100644 source/css/_custom/custom.css create mode 100644 source/css/_custom/custom.styl create mode 100644 source/css/_custom/footer.css create mode 100644 source/css/_custom/hometop.styl create mode 100644 source/css/_custom/nav.css create mode 100644 source/css/_custom/post-double-row.css create mode 100644 source/css/_custom/sidebar.css create mode 100644 source/css/_custom/waves.css create mode 100644 source/css/_global/function.styl create mode 100644 source/css/_global/index.styl create mode 100644 source/css/_highlight/highlight.styl create mode 100644 source/css/_highlight/highlight/diff.styl create mode 100644 source/css/_highlight/highlight/index.styl create mode 100644 source/css/_highlight/prismjs/diff.styl create mode 100644 source/css/_highlight/prismjs/index.styl create mode 100644 source/css/_highlight/prismjs/line-number.styl create mode 100644 source/css/_highlight/theme.styl create mode 100644 source/css/_layout/aside.styl create mode 100644 source/css/_layout/chat.styl create mode 100644 source/css/_layout/comments.styl create mode 100644 source/css/_layout/footer.styl create mode 100644 source/css/_layout/head.styl create mode 100644 source/css/_layout/loading.styl create mode 100644 source/css/_layout/pagination.styl create mode 100644 source/css/_layout/post.styl create mode 100644 source/css/_layout/relatedposts.styl create mode 100644 source/css/_layout/reward.styl create mode 100644 source/css/_layout/rightside.styl create mode 100644 source/css/_layout/sidebar.styl create mode 100644 source/css/_layout/third-party.styl create mode 100644 source/css/_mode/darkmode.styl create mode 100644 source/css/_mode/readmode.styl create mode 100644 source/css/_page/404.styl create mode 100644 source/css/_page/archives.styl create mode 100644 source/css/_page/categories.styl create mode 100644 source/css/_page/common.styl create mode 100644 source/css/_page/flink.styl create mode 100644 source/css/_page/homepage.styl create mode 100644 source/css/_page/tags.styl create mode 100644 source/css/_search/algolia.styl create mode 100644 source/css/_search/index.styl create mode 100644 source/css/_search/local-search.styl create mode 100644 source/css/_tags/btns.styl create mode 100644 source/css/_tags/button.styl create mode 100644 source/css/_tags/card.styl create mode 100644 source/css/_tags/folding.styl create mode 100644 source/css/_tags/gallery.styl create mode 100644 source/css/_tags/ghcard.styl create mode 100644 source/css/_tags/hexo.styl create mode 100644 source/css/_tags/hide.styl create mode 100644 source/css/_tags/inlineImg.styl create mode 100644 source/css/_tags/label.styl create mode 100644 source/css/_tags/link.styl create mode 100644 source/css/_tags/media.styl create mode 100644 source/css/_tags/msgbox.styl create mode 100644 source/css/_tags/note.styl create mode 100644 source/css/_tags/poem.styl create mode 100644 source/css/_tags/progress.styl create mode 100644 source/css/_tags/reference.styl create mode 100644 source/css/_tags/span.styl create mode 100644 source/css/_tags/tabs.styl create mode 100644 source/css/_tags/timeline.styl create mode 100644 source/css/_third-party/normalize.min.css create mode 100644 source/css/color.css create mode 100644 source/css/index.styl create mode 100644 source/css/var.styl create mode 100644 source/img/404.jpg create mode 100644 source/img/favicon.png create mode 100644 source/img/friend_404.gif create mode 100644 source/js/custom.js create mode 100644 source/js/main.js create mode 100644 source/js/scroll.js create mode 100644 source/js/search/algolia.js create mode 100644 source/js/search/local-search.js create mode 100644 source/js/tw_cn.js create mode 100644 source/js/utils.js diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..4f260da --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,73 @@ +name: Bug report +description: Create a report to help us improve +title: '[Bug]: ' + +body: + - type: markdown + attributes: + value: | + 重要:請依照該模板來提交 + Please follow the template to create a new issue + - type: input + id: butterfly-ver + attributes: + label: 使用的 Butterfly 版本? | What version of Butterfly are you use? + description: 檢視主題的 package.json | Check the theme's package.json + validations: + required: true + + - type: dropdown + id: modify + attributes: + label: 是否修改过主题文件? || Has the theme files been modified? + options: + - 是 (Yes) + - 不是 (No) + validations: + required: true + + - type: dropdown + id: browser + attributes: + label: 使用的瀏覽器? || What browse are you using? + options: + - Chrome + - Edge + - Safari + - Opera + - Other + validations: + required: true + + - type: dropdown + id: platform + attributes: + label: 使用的系統? || What operating system are you using? + options: + - Windows + - macOS + - Linux + - Android + - iOS + - Other + validations: + required: true + + - type: textarea + id: description + attributes: + label: 問題描述 | Describe the bug + description: 請描述你的問題現象 | A clear and concise description of what the bug is. + placeholder: 請儘量提供截圖來定位問題 | If applicable, add screenshots to help explain your problem + value: + validations: + required: true + + - type: input + id: website + attributes: + label: 出現問題網站 | Website + description: 請提供下可復現網站地址 | Please supply a website url which can reproduce problem. + placeholder: + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..9b338d0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,22 @@ +blank_issues_enabled: false +contact_links: + - name: Questions about Butterfly + url: https://github.com/jerryc127/hexo-theme-butterfly/discussions + about: 一些使用問題請到 Discussion 詢問。 Please ask questions in Discussion. + + - name: Butterfly Q&A + url: https://butterfly.js.org/posts/98d20436/ + about: Butterfly Q&A + + - name: Telegram + url: https://t.me/bu2fly + about: 'Official Telegram Group' + + - name: QQ 1群 + url: https://jq.qq.com/?_wv=1027&k=KU9105XR + about: '群號 1070540070,不要兩個Q群都添加' + + - name: QQ 2群 + url: https://jq.qq.com/?_wv=1027&k=r1nK0DQz + about: '群號 978221020,不要兩個Q群都添加' + diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..3bf7c30 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,14 @@ +name: Feature request +description: Suggest an idea for this project +title: '[Feature]: ' + +body: + - type: textarea + id: feature-request + attributes: + label: 想要的功能 | What feature do you want? + description: 請描述你需要的新功能 | A clear and concise description of what the feature is. + placeholder: + value: + validations: + require: true \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..d68365d --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,19 @@ +name: npm publish + +on: + release: + types: [created] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + # Setup .npmrc file to publish to npm + - uses: actions/setup-node@v1 + with: + node-version: '12.x' + registry-url: 'https://registry.npmjs.org' + - run: npm install + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..a50d9de --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,19 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v5 + with: + days-before-issue-stale: 30 + days-before-pr-stale: -1 + days-before-close: 7 + stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' + close-pr-message: 'This issue has not seen any activity since it was marked stale. Closing.' + stale-issue-label: 'Stale' + exempt-issue-labels: 'pinned,bug,enhancement,documentation,Plan' + operations-per-run: 1000 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8b7b6e3 --- /dev/null +++ b/README.md @@ -0,0 +1,113 @@ +
+ Language: + 🇺🇸 + 🇨🇳 +
+ +# hexo-theme-butterfly + +![master version](https://img.shields.io/github/package-json/v/jerryc127/hexo-theme-butterfly/master?color=%231ab1ad&label=master) +![master version](https://img.shields.io/github/package-json/v/jerryc127/hexo-theme-butterfly/dev?label=dev) +![https://img.shields.io/npm/v/hexo-theme-butterfly?color=%09%23bf00ff](https://img.shields.io/npm/v/hexo-theme-butterfly?color=%09%23bf00ff) +![hexo version](https://img.shields.io/badge/hexo-5.3.0+-0e83c) +![license](https://img.shields.io/github/license/jerryc127/hexo-theme-butterfly?color=FF5531) + +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png) + +Demo: 👍 [Butterfly](https://butterfly.js.org/) || 🤞 [CrazyWong](https://crazywong.com/) + +Docs: 📖 [Butterfly Docs](https://butterfly.js.org/posts/21cfbf15/) + +Based on [hexo-theme-melody](https://github.com/Molunerfinn/hexo-theme-melody) theme. + +## 💻 Installation + +### GIT + +> If you are in Mainland China, you can download in [Gitee](https://gitee.com/immyw/hexo-theme-butterfly.git) + +Stable branch [recommend]: + +``` +git clone -b master https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly +``` + +Dev branch: + +``` +git clone -b dev https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly +``` + +### NPM + +> It supports Hexo 5.0.0 or later + +In Hexo site root directory + +```powershell +npm i hexo-theme-butterfly +``` + +## ⚙ Configuration + + Set theme in the hexo work folder's root config file `_config.yml`: + +> theme: butterfly + + If you don't have pug & stylus renderer, try this: + +> npm install hexo-renderer-pug hexo-renderer-stylus + +## 🎉 Features + +- [x] Card UI Design +- [X] Support sub-menu +- [x] Two Column designs +- [x] Responsive Web Design +- [x] Dark Mode +- [x] Pjax +- [x] Read Mode +- [x] Conversion between Traditional and Simplified Chinese +- [X] TOC catalog is available for both computers and mobile phones +- [X] Color themes (darker/pale night/light/ocean/mac/mac light), support custom colors +- [X] Code Blocks (Display code language/close or expand Code Blocks/Copy Button/word wrap) +- [X] Disable copy/Add a Copyright Notice to the Copied Text +- [X] Search (Algolia SearchZ/Local Search) +- [x] Mathjax and Katex +- [x] Built-in 404 page +- [x] WordCount +- [x] Related articles +- [x] Displays outdated notice for a post +- [x] Share (AddThis/Sharejs/Addtoany) +- [X] Comment (Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/artalk) +- [x] Multiple Comment System Support +- [x] Online Chats (Chatra/Tidio/Daovoice/Gitter/Crisp/messenger) +- [x] Web analytics +- [x] Google AdSense +- [x] Webmaster Verification +- [x] Change website colour scheme +- [x] Typewriter Effect: activate_power_mode +- [x] Background effects (Canvas ribbon/canvas_ribbon_piao/canvas_nest) +- [x] Mouse click effects (Fireworks/Heart/Text) +- [x] Preloader/Loading Animation/pace.js +- [x] Busuanzi visitor counter +- [x] Medium Zoom/Fancybox +- [x] Mermaid +- [x] Justified Gallery +- [x] Lazyload images +- [x] Instantpage/Pangu/Snackbar notification toast/PWA...... + +## ✨ Contributors + + + + + +## 📷 Screenshots + +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-1.jpg) +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-2.jpg) +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-3.jpg) +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-4.jpg) +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN/img/theme-butterfly-readme-homepage-1.png) +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN/img/theme-butterfly-readme-homepage-2.png) \ No newline at end of file diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 0000000..1dcfc96 --- /dev/null +++ b/README_CN.md @@ -0,0 +1,113 @@ +
+ 語言: + 中文 + 英文 +
+ +# hexo-theme-butterfly + +![master version](https://img.shields.io/github/package-json/v/jerryc127/hexo-theme-butterfly/master?color=%231ab1ad&label=master) +![master version](https://img.shields.io/github/package-json/v/jerryc127/hexo-theme-butterfly/dev?label=dev) +![https://img.shields.io/npm/v/hexo-theme-butterfly?color=%09%23bf00ff](https://img.shields.io/npm/v/hexo-theme-butterfly?color=%09%23bf00ff) +![hexo version](https://img.shields.io/badge/hexo-5.3.0+-0e83c) +![license](https://img.shields.io/github/license/jerryc127/hexo-theme-butterfly?color=FF5531) + +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png) + +預覽: 👍 [Butterfly](https://butterfly.js.org/) || 🤞 [CrazyWong](https://crazywong.com/) + +文檔: 📖 [Butterfly Docs](https://butterfly.js.org/posts/21cfbf15/) + +一款基於[hexo-theme-melody](https://github.com/Molunerfinn/hexo-theme-melody)修改的主題 + +## 💻 安裝 + +### Git 安裝 + +> 本倉庫同時上傳到 [Gitee](https://gitee.com/immyw/hexo-theme-butterfly.git),如果你訪問 Github 緩慢,可從 Gitee 中下載。 + +在博客根目錄裡安裝穩定版【推薦】 + +```powershell +git clone -b master https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly +``` + +如果想要安裝比較新的dev分支,可以 + +```powershell +git clone -b dev https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly +``` + +### npm 安裝 + +> 此方法只支持Hexo 5.0.0以上版本 + +在博客根目錄裡 + +```powershell +npm i hexo-theme-butterfly +``` + +## ⚙ 應用主題 + +修改hexo配置文件`_config.yml`,把主題改為`Butterfly` + +``` +theme: butterfly +``` + +>如果你沒有pug以及stylus的渲染器,請下載安裝: npm install hexo-renderer-pug hexo-renderer-stylus --save + +## 🎉 特色 + +- [x] 卡片化設計 +- [X] 支持二級目錄 +- [x] 雙欄設計 +- [x] 響應式主題 +- [x] 夜間模式 +- [x] Pjax +- [x] 文章閲讀模式 +- [x] 簡體和繁體轉換 +- [X] 電腦和手機都可查看TOC目錄 +- [X] 內置多種代碼配色(darker/pale night/light/ocean/mac/mac light),可自定義代碼配色 +- [X] 代碼塊顯示代碼語言/關閉或展開代碼塊/代碼複製/代碼自動換行 +- [X] 可關閉文字複製/可開啟內容複製增加版權信息) +- [X] 兩種搜索(Algolia搜索和本地搜索) +- [x] Mathjax 和 Katex +- [x] 內置404頁面 +- [x] 顯示字數統計 +- [x] 顯示相關文章 +- [x] 過期文章提醒 +- [x] 多種分享系統(AddThis/Sharejs/Addtoany) +- [X] 多種評論系統(Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/artalk) +- [x] 支持雙評論部署 +- [x] 多種在線聊天(Chatra/Tidio/Daovoice/Gitter/Crisp/messenger) +- [x] 多種分析系統 +- [x] 谷歌廣告/手動廣告位置 +- [x] 各種站長驗證(Google/Bing/Baidu/360/Yandex) +- [x] 修改網站配色 +- [x] 打字特效 activate_power_mode +- [x] 多種背景特效(靜止彩帶/動態彩帶/Canvas Nest) +- [x] 多種鼠標點擊特效(煙花/文字/愛心) +- [x] 內置一種 Preloader 加載動畫和 pace.js 加載動畫條 +- [x] 不蒜子訪問統計 +- [x] 兩種大圖模式(Medium Zoom/Fancybox) +- [x] Mermaid 圖表顯示 +- [x] 照片牆 +- [x] 圖片懶加載 +- [x] Instantpage/Pangu/Snackbar彈窗/PWA...... + +## ✨ 貢獻者 + + + + + +## 📷 截圖 + +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-1.jpg) +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-2.jpg) +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-3.jpg) +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-4.jpg) +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN/img/theme-butterfly-readme-homepage-1.png) +![](https://cdn.jsdelivr.net/gh/jerryc127/CDN/img/theme-butterfly-readme-homepage-2.png) diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..5153937 --- /dev/null +++ b/_config.yml @@ -0,0 +1,955 @@ +# Main menu navigation (導航目錄) +# see https://butterfly.js.org/posts/4aa8abbe/#導航菜單 +# -------------------------------------- + +menu: + # Home: / || fas fa-home + # Archives: /archives/ || fas fa-archive + # Tags: /tags/ || fas fa-tags + # Categories: /categories/ || fas fa-folder-open + # List||fas fa-list: + # Music: /music/ || fas fa-music + # Movie: /movies/ || fas fa-video + # Link: /link/ || fas fa-link + # About: /about/ || fas fa-heart + +# Code Blocks (代碼相關) +# -------------------------------------- + +highlight_theme: light # darker / pale night / light / ocean / mac / mac light / false +highlight_copy: true # copy button +highlight_lang: true # show the code language +highlight_shrink: false # true: shrink the code blocks / false: expand the code blocks | none: expand code blocks and hide the button +highlight_height_limit: false # unit: px +code_word_wrap: false + +# copy settings +# copyright: Add the copyright information after copied content (複製的內容後面加上版權信息) +copy: + enable: true + copyright: + enable: false + limit_count: 50 + +# social settings (社交圖標設置) +# formal: +# icon: link || the description +social: + # fab fa-github: https://github.com/xxxxx || Github + # fas fa-envelope: mailto:xxxxxx@gmail.com || Email + +# search (搜索) +# see https://butterfly.js.org/posts/ceeb73f/#搜索系統 +# -------------------------------------- + +# Algolia search +algolia_search: + enable: false + hits: + per_page: 6 + +# Local search +local_search: + enable: false + preload: false + CDN: + +# Math (數學) +# -------------------------------------- +# About the per_page +# if you set it to true, it will load mathjax/katex script in each page (true 表示每一頁都加載js) +# if you set it to false, it will load mathjax/katex script according to your setting (add the 'mathjax: true' in page's front-matter) +# (false 需要時加載,須在使用的 Markdown Front-matter 加上 mathjax: true) + +# MathJax +mathjax: + enable: false + per_page: false + +# KaTeX +katex: + enable: false + per_page: false + hide_scrollbar: true + +# Image (圖片設置) +# -------------------------------------- + +# Favicon(網站圖標) +favicon: /img/favicon.png + +# Avatar (頭像) +avatar: + img: https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png + effect: false + +# Disable all banner image +disable_top_img: false + +# The banner image of home page +index_img: + +# If the banner of page not setting, it will show the top_img +default_top_img: + +# The banner image of archive page +archive_img: + +# If the banner of tag page not setting, it will show the top_img +# note: tag page, not tags page (子標籤頁面的 top_img) +tag_img: + +# The banner image of tag page +# format: +# - tag name: xxxxx +tag_per_img: + +# If the banner of category page not setting, it will show the top_img +# note: category page, not categories page (子分類頁面的 top_img) +category_img: + +# The banner image of category page +# format: +# - category name: xxxxx +category_per_img: + +cover: + # display the cover or not (是否顯示文章封面) + index_enable: true + aside_enable: true + archives_enable: true + # the position of cover in home page (封面顯示的位置) + # left/right/both + position: both + # When cover is not set, the default cover is displayed (當沒有設置cover時,默認的封面顯示) + default_cover: + # - https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg + +# Replace Broken Images (替換無法顯示的圖片) +error_img: + flink: /img/friend_404.gif + post_page: /img/404.jpg + +# A simple 404 page +error_404: + enable: false + subtitle: 'Page Not Found' + background: https://i.loli.net/2020/05/19/aKOcLiyPl2JQdFD.png + +post_meta: + page: # Home Page + date_type: created # created or updated or both 主頁文章日期是創建日或者更新日或都顯示 + date_format: date # date/relative 顯示日期還是相對日期 + categories: true # true or false 主頁是否顯示分類 + tags: false # true or false 主頁是否顯示標籤 + label: true # true or false 顯示描述性文字 + post: + date_type: both # created or updated or both 文章頁日期是創建日或者更新日或都顯示 + date_format: date # date/relative 顯示日期還是相對日期 + categories: true # true or false 文章頁是否顯示分類 + tags: true # true or false 文章頁是否顯示標籤 + label: true # true or false 顯示描述性文字 + +# wordcount (字數統計) +# see https://butterfly.js.org/posts/ceeb73f/#字數統計 +wordcount: + enable: false + post_wordcount: true + min2read: true + total_wordcount: true + +# Display the article introduction on homepage +# 1: description +# 2: both (if the description exists, it will show description, or show the auto_excerpt) +# 3: auto_excerpt (default) +# false: do not show the article introduction +index_post_content: + method: 3 + length: 500 # if you set method to 2 or 3, the length need to config + +# anchor +anchor: + button: + enable: false + always_show: false + icon: # the unicode value of Font Awesome icon, such as '\3423' + auto_update: false # when you scroll in post, the URL will update according to header id. + +# Post +# -------------------------------------- + +# toc (目錄) +toc: + post: true + page: false + number: true + expand: false + style_simple: false # for post + +post_copyright: + enable: true + decode: false + author_href: + license: CC BY-NC-SA 4.0 + license_url: https://creativecommons.org/licenses/by-nc-sa/4.0/ + +# Sponsor/reward +reward: + enable: false + QR_code: + # - img: /img/wechat.jpg + # link: + # text: wechat + # - img: /img/alipay.jpg + # link: + # text: alipay + +# Post edit +# Easily browse and edit blog source code online. +post_edit: + enable: false + # url: https://github.com/user-name/repo-name/edit/branch-name/subdirectory-name/ + # For example: https://github.com/jerryc127/butterfly.js.org/edit/main/source/ + url: + +# Related Articles +related_post: + enable: true + limit: 6 # Number of posts displayed + date_type: created # or created or updated 文章日期顯示創建日或者更新日 + +# figcaption (圖片描述文字) +photofigcaption: false + +# post_pagination (分頁) +# value: 1 || 2 || false +# 1: The 'next post' will link to old post +# 2: The 'next post' will link to new post +# false: disable pagination +post_pagination: 1 + +# Displays outdated notice for a post (文章過期提醒) +noticeOutdate: + enable: false + style: flat # style: simple/flat + limit_day: 500 # When will it be shown + position: top # position: top/bottom + message_prev: It has been + message_next: days since the last update, the content of the article may be outdated. + +# Share System (分享功能) +# -------------------------------------- + +# AddThis +# https://www.addthis.com/ +addThis: + enable: false + pubid: + +# Share.js +# https://github.com/overtrue/share.js +sharejs: + enable: true + sites: facebook,twitter,wechat,weibo,qq + +# AddToAny +# https://www.addtoany.com/ +addtoany: + enable: false + item: facebook,twitter,wechat,sina_weibo,facebook_messenger,email,copy_link + +# Comments System +# -------------------------------------- + +comments: + # Up to two comments system, the first will be shown as default + # Choose: Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/Artalk + use: # Valine,Disqus + text: true # Display the comment name next to the button + # lazyload: The comment system will be load when comment element enters the browser's viewport. + # If you set it to true, the comment count will be invalid + lazyload: false + count: false # Display comment count in post's top_img + card_post_count: false # Display comment count in Home Page + +# disqus +# https://disqus.com/ +disqus: + shortname: + apikey: # For newest comments widget + +# Alternative Disqus - Render comments with Disqus API +# DisqusJS 評論系統,可以實現在網路審查地區載入 Disqus 評論列表,兼容原版 +# https://github.com/SukkaW/DisqusJS +disqusjs: + shortname: + apikey: + option: + +# livere (來必力) +# https://www.livere.com/ +livere: + uid: + +# gitalk +# https://github.com/gitalk/gitalk +gitalk: + client_id: + client_secret: + repo: + owner: + admin: + option: + +# valine +# https://valine.js.org +valine: + appId: # leancloud application app id + appKey: # leancloud application app key + avatar: monsterid # gravatar style https://valine.js.org/#/avatar + serverURLs: # This configuration is suitable for domestic custom domain name users, overseas version will be automatically detected (no need to manually fill in) + bg: # valine background + visitor: false + option: + +# waline - A simple comment system with backend support fork from Valine +# https://waline.js.org/ +waline: + serverURL: # Waline server address url + bg: # waline background + pageview: false + option: + +# utterances +# https://utteranc.es/ +utterances: + repo: + # Issue Mapping: pathname/url/title/og:title + issue_term: pathname + # Theme: github-light/github-dark/github-dark-orange/icy-dark/dark-blue/photon-dark + light_theme: github-light + dark_theme: photon-dark + +# Facebook Comments Plugin +# https://developers.facebook.com/docs/plugins/comments/ +facebook_comments: + app_id: + user_id: # optional + pageSize: 10 # The number of comments to show + order_by: social # social/time/reverse_time + lang: zh_TW # Language en_US/zh_CN/zh_TW and so on + +# Twikoo +# https://github.com/imaegoo/twikoo +twikoo: + envId: + region: + visitor: false + option: + +# Giscus +# https://giscus.app/ +giscus: + repo: + repo_id: + category_id: + theme: + light: light + dark: dark + option: + +# Remark42 +# https://remark42.com/docs/configuration/frontend/ +remark42: + host: # Your Host URL + siteId: # Your Site ID + option: + +# Artalk +# https://artalk.js.org/guide/frontend/config.html +artalk: + server: + site: + visitor: false + option: + +# Chat Services +# -------------------------------------- + +# Chat Button [recommend] +# It will create a button in the bottom right corner of website, and hide the origin button +chat_btn: false + +# The origin chat button is displayed when scrolling up, and the button is hidden when scrolling down +chat_hide_show: false + +# chatra +# https://chatra.io/ +chatra: + enable: false + id: + +# tidio +# https://www.tidio.com/ +tidio: + enable: false + public_key: + +# daovoice +# http://daovoice.io/ +daovoice: + enable: false + app_id: + +# gitter +# https://gitter.im/ +gitter: + enable: false + room: + +# crisp +# https://crisp.chat/en/ +crisp: + enable: false + website_id: + +# messenger +# https://developers.facebook.com/docs/messenger-platform/discovery/facebook-chat-plugin/ +messenger: + enable: false + pageID: + lang: zh_TW # Language en_US/zh_CN/zh_TW and so on + +# Footer Settings +# -------------------------------------- +footer: + owner: + enable: true + since: 2020 + custom_text: + copyright: true # Copyright of theme and framework + +# Analysis +# -------------------------------------- + +# Baidu Analytics +# https://tongji.baidu.com/web/welcome/login +baidu_analytics: + +# Google Analytics +# https://analytics.google.com/analytics/web/ +google_analytics: + +# CNZZ Analytics +# https://www.umeng.com/ +cnzz_analytics: + +# Cloudflare Analytics +# https://www.cloudflare.com/zh-tw/web-analytics/ +cloudflare_analytics: + +# Microsoft Clarity +# https://clarity.microsoft.com/ +microsoft_clarity: + +# Advertisement +# -------------------------------------- + +# Google Adsense (谷歌廣告) +google_adsense: + enable: false + auto_ads: true + js: https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js + client: + enable_page_level_ads: true + +# Insert ads manually (手動插入廣告) +# ad: +# index: +# aside: +# post: + +# Verification (站長驗證) +# -------------------------------------- + +site_verification: + # - name: google-site-verification + # content: xxxxxx + # - name: baidu-site-verification + # content: xxxxxxx + +# Beautify/Effect (美化/效果) +# -------------------------------------- + +# Theme color for customize +# Notice: color value must in double quotes like "#000" or may cause error! + +# theme_color: +# enable: true +# main: "#32C9EB" +# paginator: "#32C9EB" +# button_hover: "#ff7a7a" +# text_selection: "#32C9EB" +# link_color: "#99a9bf" +# meta_color: "#858585" +# hr_color: "#A4D8FA" +# code_foreground: "#F47466" +# code_background: "rgba(27, 31, 35, .05)" +# toc_color: "#32C9EB" +# blockquote_padding_color: "#32C9EB" +# blockquote_background_color: "#32C9EB" +# scrollbar_color: "#32C9EB" +# meta_theme_color_light: "ffffff" +# meta_theme_color_dark: "#0d0d0d" + +# The top_img settings of home page +# default: top img - full screen, site info - middle (默認top_img全屏,site_info在中間) +# The position of site info, eg: 300px/300em/300rem/10% (主頁標題距離頂部距離) +index_site_info_top: +# The height of top_img, eg: 300px/300em/300rem (主頁top_img高度) +index_top_img_height: + +# The user interface setting of category and tag page (category和tag頁的UI設置) +# index - same as Homepage UI (index 值代表 UI將與首頁的UI一樣) +# default - same as archives UI 默認跟archives頁面UI一樣 +category_ui: # 留空或 index +tag_ui: # 留空或 index + +# Website Background (設置網站背景) +# can set it to color or image (可設置圖片 或者 顔色) +# The formal of image: url(http://xxxxxx.com/xxx.jpg) +background: + +# Footer Background +footer_bg: false + +# the position of bottom right button/default unit: px (右下角按鈕距離底部的距離/默認單位為px) +rightside-bottom: + +# Enter transitions (開啓網頁進入效果) +enter_transitions: true + +# Background effects (背景特效) +# -------------------------------------- + +# canvas_ribbon (靜止彩帶背景) +# See: https://github.com/hustcc/ribbon.js +canvas_ribbon: + enable: false + size: 150 + alpha: 0.6 + zIndex: -1 + click_to_change: false + mobile: false + +# Fluttering Ribbon (動態彩帶) +canvas_fluttering_ribbon: + enable: false + mobile: false + +# canvas_nest +# https://github.com/hustcc/canvas-nest.js +canvas_nest: + enable: false + color: '0,0,255' #color of lines, default: '0,0,0'; RGB values: (R,G,B).(note: use ',' to separate.) + opacity: 0.7 # the opacity of line (0~1), default: 0.5. + zIndex: -1 # z-index property of the background, default: -1. + count: 99 # the number of lines, default: 99. + mobile: false + +# Typewriter Effect (打字效果) +# https://github.com/disjukr/activate-power-mode +activate_power_mode: + enable: false + colorful: true # open particle animation (冒光特效) + shake: true # open shake (抖動特效) + mobile: false + +# Mouse click effects: fireworks (鼠標點擊效果: 煙火特效) +fireworks: + enable: false + zIndex: 9999 # -1 or 9999 + mobile: false + +# Mouse click effects: Heart symbol (鼠標點擊效果: 愛心) +click_heart: + enable: false + mobile: false + +# Mouse click effects: words (鼠標點擊效果: 文字) +ClickShowText: + enable: false + text: + # - I + # - LOVE + # - YOU + fontSize: 15px + random: false + mobile: false + +# Default display mode (網站默認的顯示模式) +# light (default) / dark +display_mode: light + +# Beautify (美化頁面顯示) +beautify: + enable: false + field: post # site/post + title-prefix-icon: # '\f0c1' + title-prefix-icon-color: # '#F47466' + +# Global font settings +# Don't modify the following settings unless you know how they work (非必要不要修改) +font: + global-font-size: + code-font-size: + font-family: + code-font-family: + +# Font settings for the site title and site subtitle +# 左上角網站名字 主頁居中網站名字 +blog_title_font: + font_link: + font-family: + +# The setting of divider icon (水平分隔線圖標設置) +hr_icon: + enable: true + icon: # the unicode value of Font Awesome icon, such as '\3423' + icon-top: + +# the subtitle on homepage (主頁subtitle) +subtitle: + enable: false + # Typewriter Effect (打字效果) + effect: true + # Effect Speed Options (打字效果速度參數) + startDelay: 300 # time before typing starts in milliseconds + typeSpeed: 150 # type speed in milliseconds + backSpeed: 50 # backspacing speed in milliseconds + # loop (循環打字) + loop: true + # source 調用第三方服務 + # source: false 關閉調用 + # source: 1 調用一言網的一句話(簡體) https://hitokoto.cn/ + # source: 2 調用一句網(簡體) http://yijuzhan.com/ + # source: 3 調用今日詩詞(簡體) https://www.jinrishici.com/ + # subtitle 會先顯示 source , 再顯示 sub 的內容 + source: false + # 如果關閉打字效果,subtitle 只會顯示 sub 的第一行文字 + sub: + +# Loading Animation (加載動畫) +preloader: + enable: false + # source + # 1. fullpage-loading + # 2. pace (progress bar) + source: 1 + # pace theme (see https://codebyzach.github.io/pace/) + pace_css_url: + +# aside (側邊欄) +# -------------------------------------- + +aside: + enable: true + hide: false + button: true + mobile: true # display on mobile + position: right # left or right + display: + archive: true + tag: true + category: true + card_author: + enable: true + description: + button: + enable: true + icon: fab fa-github + text: Follow Me + link: https://github.com/xxxxxx + card_announcement: + enable: true + content: This is my Blog + card_recent_post: + enable: true + limit: 5 # if set 0 will show all + sort: date # date or updated + sort_order: # Don't modify the setting unless you know how it works + card_categories: + enable: true + limit: 8 # if set 0 will show all + expand: none # none/true/false + sort_order: # Don't modify the setting unless you know how it works + card_tags: + enable: true + limit: 40 # if set 0 will show all + color: false + sort_order: # Don't modify the setting unless you know how it works + card_archives: + enable: true + type: monthly # yearly or monthly + format: MMMM YYYY # eg: YYYY年MM月 + order: -1 # Sort of order. 1, asc for ascending; -1, desc for descending + limit: 8 # if set 0 will show all + sort_order: # Don't modify the setting unless you know how it works + card_webinfo: + enable: true + post_count: true + last_push_date: true + sort_order: # Don't modify the setting unless you know how it works + +# busuanzi count for PV / UV in site +# 訪問人數 +busuanzi: + site_uv: true + site_pv: true + page_pv: true + +# Time difference between publish date and now (網頁運行時間) +# Formal: Month/Day/Year Time or Year/Month/Day Time +runtimeshow: + enable: false + publish_date: + +# Aside widget - Newest Comments +newest_comments: + enable: false + sort_order: # Don't modify the setting unless you know how it works + limit: 6 + storage: 10 # unit: mins, save data to localStorage + avatar: true + +# Bottom right button (右下角按鈕) +# -------------------------------------- + +# Conversion between Traditional and Simplified Chinese (簡繁轉換) +translate: + enable: false + # The text of a button + default: 繁 + # the language of website (1 - Traditional Chinese/ 2 - Simplified Chinese) + defaultEncoding: 2 + # Time delay + translateDelay: 0 + # The text of the button when the language is Simplified Chinese + msgToTraditionalChinese: '繁' + # The text of the button when the language is Traditional Chinese + msgToSimplifiedChinese: '簡' + +# Read Mode (閲讀模式) +readmode: true + +# dark mode +darkmode: + enable: true + # Toggle Button to switch dark/light mode + button: true + # Switch dark/light mode automatically (自動切換 dark mode和 light mode) + # autoChangeMode: 1 Following System Settings, if the system doesn't support dark mode, it will switch dark mode between 6 pm to 6 am + # autoChangeMode: 2 Switch dark mode between 6 pm to 6 am + # autoChangeMode: false + autoChangeMode: false + +# Don't modify the following settings unless you know how they work (非必要請不要修改 ) +# Choose: readmode,translate,darkmode,hideAside,toc,chat,comment +# Don't repeat 不要重複 +rightside_item_order: + enable: false + hide: # readmode,translate,darkmode,hideAside + show: # toc,chat,comment + +# Lightbox (圖片大圖查看模式) +# -------------------------------------- +# You can only choose one, or neither (只能選擇一個 或者 兩個都不選) + +# medium-zoom +# https://github.com/francoischalifour/medium-zoom +medium_zoom: false + +# fancybox +# http://fancyapps.com/fancybox/3/ +fancybox: true + +# Tag Plugins settings (標籤外掛) +# -------------------------------------- + +# mermaid +# see https://github.com/mermaid-js/mermaid +mermaid: + enable: false + # built-in themes: default/forest/dark/neutral + theme: + light: default + dark: dark + +# Note (Bootstrap Callout) +note: + # Note tag style values: + # - simple bs-callout old alert style. Default. + # - modern bs-callout new (v2-v3) alert style. + # - flat flat callout style with background, like on Mozilla or StackOverflow. + # - disabled disable all CSS styles import of note tag. + style: flat + icons: true + border_radius: 3 + # Offset lighter of background in % for modern and flat styles (modern: -12 | 12; flat: -18 | 6). + # Offset also applied to label tag variables. This option can work with disabled note tag. + light_bg_offset: 0 + +# other +# -------------------------------------- + +# Pjax +# It may contain bugs and unstable, give feedback when you find the bugs. +# https://github.com/MoOx/pjax +pjax: + enable: false + exclude: + # - xxxx + # - xxxx + +# Inject the css and script (aplayer/meting) +aplayerInject: + enable: false + per_page: true + +# Snackbar (Toast Notification 彈窗) +# https://github.com/polonel/SnackBar +# position 彈窗位置 +# 可選 top-left / top-center / top-right / bottom-left / bottom-center / bottom-right +snackbar: + enable: false + position: bottom-left + bg_light: '#32C9EB' # The background color of Toast Notification in light mode + bg_dark: '#1f1f1f' # The background color of Toast Notification in dark mode + +# https://instant.page/ +# prefetch (預加載) +instantpage: false + +# https://github.com/vinta/pangu.js +# Insert a space between Chinese character and English character (中英文之間添加空格) +pangu: + enable: false + field: site # site/post + +# Lazyload (圖片懶加載) +# https://github.com/verlok/vanilla-lazyload +lazyload: + enable: false + field: site # site/post + placeholder: + blur: false + +# PWA +# See https://github.com/JLHwung/hexo-offline +# --------------- +# pwa: +# enable: false +# manifest: /pwa/manifest.json +# apple_touch_icon: /pwa/apple-touch-icon.png +# favicon_32_32: /pwa/32.png +# favicon_16_16: /pwa/16.png +# mask_icon: /pwa/safari-pinned-tab.svg + +# Open graph meta tags +# https://developers.facebook.com/docs/sharing/webmasters/ +Open_Graph_meta: + enable: true + option: + # twitter_card: + # twitter_image: + # twitter_id: + # twitter_site: + # google_plus: + # fb_admins: + # fb_app_id: + +# Add the vendor prefixes to ensure compatibility +css_prefix: true + +# Inject +# Insert the code to head (before '' tag) and the bottom (before '' tag) +# 插入代码到头部 之前 和 底部 之前 +inject: + head: + # - + bottom: + # - + +# CDN +# Don't modify the following settings unless you know how they work +# 非必要請不要修改 +CDN: + # The CDN provider of internal scripts (主題內部 js 的 cdn 配置) + # option: local/jsdelivr/unpkg/cdnjs/custom + # Dev version can only choose. ( dev版的主題只能設置為 local ) + internal_provider: local + + # The CDN provider of third party scripts (第三方 js 的 cdn 配置) + # option: local/jsdelivr/unpkg/cdnjs/custom + # when set it to local, you need to install hexo-butterfly-extjs + third_party_provider: jsdelivr + + # Add version number to CDN, true or false + version: false + + # Custom format + # For example: https://cdn.staticfile.org/${cdnjs_name}/${version}/${min_cdnjs_file} + custom_format: + + option: + # main_css: + # main: + # utils: + # translate: + # local_search: + # algolia_js: + # algolia_search_v4: + # instantsearch_v4: + # pjax: + # gitalk: + # gitalk_css: + # blueimp_md5: + # valine: + # disqusjs: + # disqusjs_css: + # twikoo: + # waline_js: + # waline_css: + # sharejs: + # sharejs_css: + # mathjax: + # katex: + # katex_copytex: + # mermaid: + # canvas_ribbon: + # canvas_fluttering_ribbon: + # canvas_nest: + # lazyload: + # instantpage: + # typed: + # pangu: + # fancybox_css_v4: + # fancybox_v4: + # medium_zoom: + # snackbar_css: + # snackbar: + # activate_power_mode: + # fireworks: + # click_heart: + # ClickShowText: + # fontawesomeV6: + # flickr_justified_gallery_js: + # flickr_justified_gallery_css: + # aplayer_css: + # aplayer_js: + # meting_js: + # prismjs_js: + # prismjs_lineNumber_js: + # prismjs_autoloader: + # artalk_js: + # artalk_css: \ No newline at end of file diff --git a/languages/default.yml b/languages/default.yml new file mode 100644 index 0000000..833fb6c --- /dev/null +++ b/languages/default.yml @@ -0,0 +1,121 @@ +footer: + framework: Framework + theme: Theme + +copy: + success: Copy successfully + error: Copy error + noSupport: The browser does not support + +page: + articles: Articles + tag: Tag + category: Category + archives: Archives + +card_post_count: comments + +sticky: Sticky +no_title: No title + +post: + created: Created + updated: Updated + wordcount: Word count + min2read: Reading time + min2read_unit: min + page_pv: Post View + comments: Comments + copyright: + author: Author + link: Link + copyright_notice: Copyright Notice + copyright_content: 'All articles in this blog are licensed under %s unless stating additionally.' + recommend: Related Articles + edit: Edited on + +search: + title: Search + load_data: Loading the Database + algolia_search: + input_placeholder: Search for Posts + hits_empty: "We didn't find any results for the search: ${query}." + hits_stats: '${hits} results found in ${time} ms' + + local_search: + input_placeholder: Search for Posts + hits_empty: "We didn't find any results for the search: ${query}" + +pagination: + prev: Previous Post + next: Next Post + +comment: Comment + +aside: + articles: Articles + tags: Tags + categories: Categories + card_announcement: Announcement + card_categories: Categories + card_tags: Tags + card_archives: Archives + card_recent_post: Recent Post + card_webinfo: + headline: Info + article_name: Article + runtime: + name: Run time + unit: days + last_push_date: + name: Last Push + site_wordcount: Total Count + site_uv_name: UV + site_pv_name: PV + more_button: More + card_newest_comments: + headline: Newest Comments + loading_text: loading... + error: Unable to get the data, please make sure the settings are correct. + zero: No Comment + image: image + link: link + code: code + card_toc: Catalog + +date_suffix: + just: Just + min: minutes ago + hour: hours ago + day: days ago + month: months ago + +donate: Donate +share: Share + +rightside: + readmode_title: Read Mode + translate_title: Toggle Between Traditional Chinese And Simplified Chinese + night_mode_title: Toggle Between Light And Dark Mode + back_to_top: Back To Top + toc: Table Of Contents + scroll_to_comment: Scroll To Comments + setting: Setting + aside: Toggle between single-column and double-column + chat: Chat + +copy_copyright: + author: Author + link: Link + source: Source + info: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source. + +Snackbar: + chs_to_cht: Traditional Chinese Activated Manually + cht_to_chs: Simplified Chinese Activated Manually + day_to_night: Dark Mode Activated Manually + night_to_day: Light Mode Activated Manually + +loading: Loading... + +error404: Page not found diff --git a/languages/en.yml b/languages/en.yml new file mode 100644 index 0000000..9d303e0 --- /dev/null +++ b/languages/en.yml @@ -0,0 +1,121 @@ +footer: + framework: Framework + theme: Theme + +copy: + success: Copy successfully + error: Copy error + noSupport: The browser does not support + +page: + articles: Articles + tag: Tag + category: Category + archives: Archives + +card_post_count: comments + +sticky: Sticky +no_title: No title + +post: + created: Created + updated: Updated + wordcount: Word count + min2read: Reading time + min2read_unit: min + page_pv: Post View + comments: Comments + copyright: + author: Author + link: Link + copyright_notice: Copyright Notice + copyright_content: 'All articles in this blog are licensed under %s unless stating additionally.' + recommend: Related Articles + edit: Edited on + +search: + title: Search + load_data: Loading the Database + algolia_search: + input_placeholder: Search for Posts + hits_empty: "We didn't find any results for the search: ${query}." + hits_stats: '${hits} results found in ${time} ms' + + local_search: + input_placeholder: Search for Posts + hits_empty: "We didn't find any results for the search: ${query}" + +pagination: + prev: Previous Post + next: Next Post + +comment: Comment + +aside: + articles: Articles + tags: Tags + categories: Categories + card_announcement: Announcement + card_categories: Categories + card_tags: Tags + card_archives: Archives + card_recent_post: Recent Post + card_webinfo: + headline: Info + article_name: Article + runtime: + name: Run time + unit: days + last_push_date: + name: Last Push + site_wordcount: Total Count + site_uv_name: UV + site_pv_name: PV + more_button: More + card_newest_comments: + headline: Newest Comments + loading_text: loading... + error: Unable to get the data, please make sure the settings are correct. + zero: No Comment + image: image + link: link + code: code + card_toc: Catalog + +date_suffix: + just: Just + min: minutes ago + hour: hours ago + day: days ago + month: months ago + +donate: Donate +share: Share + +rightside: + readmode_title: Read Mode + translate_title: Switch Between Traditional Chinese And Simplified Chinese + night_mode_title: Switch Between Light And Dark Mode + back_to_top: Back To Top + toc: Table Of Contents + scroll_to_comment: Scroll To Comments + setting: Setting + aside: Toggle between single-column and double-column + chat: Chat + +copy_copyright: + author: Author + link: Link + source: Source + info: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source. + +Snackbar: + chs_to_cht: Traditional Chinese Activated Manually + cht_to_chs: Simplified Chinese Activated Manually + day_to_night: Dark Mode Activated Manually + night_to_day: Light Mode Activated Manually + +loading: Loading... + +error404: Page not found diff --git a/languages/zh-CN.yml b/languages/zh-CN.yml new file mode 100644 index 0000000..55900d2 --- /dev/null +++ b/languages/zh-CN.yml @@ -0,0 +1,122 @@ +footer: + framework: 框架 + theme: 主题 + +copy: + success: 复制成功 + error: 复制错误 + noSupport: 浏览器不支持 + +page: + articles: 文章总览 + tag: 标签 + category: 分类 + archives: 归档 + +card_post_count: 条评论 + +sticky: 置顶 +no_title: 无题 + +post: + created: 发表于 + updated: 更新于 + wordcount: 字数总计 + min2read: 阅读时长 + min2read_unit: 分钟 + page_pv: 阅读量 + comments: 评论数 + copyright: + author: 文章作者 + link: 文章链接 + copyright_notice: 版权声明 + copyright_content: '本博客所有文章除特别声明外,均采用 + %s 许可协议。转载请注明来自 %s!' + recommend: 相关推荐 + edit: 编辑 + +search: + title: 搜索 + load_data: 数据库加载中 + algolia_search: + input_placeholder: 搜索文章 + hits_empty: '找不到您查询的内容:${query}' + hits_stats: '找到 ${hits} 条结果,用时 ${time} 毫秒' + + local_search: + input_placeholder: 搜索文章 + hits_empty: '找不到您查询的内容:${query}' + +pagination: + prev: 上一篇 + next: 下一篇 + +comment: 评论 + +aside: + articles: 文章 + tags: 标签 + categories: 分类 + card_announcement: 公告 + card_categories: 分类 + card_tags: 标签 + card_archives: 归档 + card_recent_post: 最新文章 + card_webinfo: + headline: 网站资讯 + article_name: 文章数目 + runtime: + name: 已运行时间 + unit: 天 + last_push_date: + name: 最后更新时间 + site_wordcount: 本站总字数 + site_uv_name: 本站访客数 + site_pv_name: 本站总访问量 + more_button: 查看更多 + card_newest_comments: + headline: 最新评论 + loading_text: 正在加载中... + error: 无法获取评论,请确认相关配置是否正确 + zero: 没有评论 + image: 图片 + link: 链接 + code: 代码 + card_toc: 目录 + +date_suffix: + just: 刚刚 + min: 分钟前 + hour: 小时前 + day: 天前 + month: 个月前 + +donate: 打赏 +share: 分享 + +rightside: + readmode_title: 阅读模式 + translate_title: 简繁转换 + night_mode_title: 浅色和深色模式转换 + back_to_top: 回到顶部 + toc: 目录 + scroll_to_comment: 直达评论 + setting: 设置 + aside: 单栏和双栏切换 + chat: 聊天 + +copy_copyright: + author: 作者 + link: 链接 + source: 来源 + info: 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 + +Snackbar: + chs_to_cht: 你已切换为繁体 + cht_to_chs: 你已切换为简体 + day_to_night: 你已切换为深色模式 + night_to_day: 你已切换为浅色模式 + +loading: 加载中... + +error404: 页面没有找到 diff --git a/languages/zh-TW.yml b/languages/zh-TW.yml new file mode 100644 index 0000000..61d667f --- /dev/null +++ b/languages/zh-TW.yml @@ -0,0 +1,122 @@ +footer: + framework: 框架 + theme: 主題 + +copy: + success: 複製成功 + error: 複製錯誤 + noSupport: 瀏覽器不支援 + +page: + articles: 文章總覽 + tag: 標籤 + category: 分類 + archives: 歸檔 + +card_post_count: 條評論 + +sticky: 置頂 +no_title: 無題 + +post: + created: 發表於 + updated: 更新於 + wordcount: 字數總計 + min2read: 閱讀時長 + min2read_unit: 分鐘 + page_pv: 閱讀量 + comments: 評論數 + copyright: + author: 文章作者 + link: 文章連結 + copyright_notice: 版權聲明 + copyright_content: '本部落格所有文章除特別聲明外,均採用 + %s 許可協議。轉載請註明來自 %s!' + recommend: 相關推薦 + edit: 編輯 + +search: + title: 搜尋 + load_data: 資料庫載入中 + algolia_search: + input_placeholder: 搜尋文章 + hits_empty: '找不到您查詢的內容:${query}' + hits_stats: '找到 ${hits} 條結果,用時 ${time} 毫秒' + + local_search: + input_placeholder: 搜尋文章 + hits_empty: '找不到您查詢的內容:${query}' + +pagination: + prev: 上一篇 + next: 下一篇 + +comment: 評論 + +aside: + articles: 文章 + tags: 標籤 + categories: 分類 + card_announcement: 公告 + card_categories: 分類 + card_tags: 標籤 + card_archives: 歸檔 + card_recent_post: 最新文章 + card_webinfo: + headline: 網站資訊 + article_name: 文章數目 + runtime: + name: 已執行時間 + unit: 天 + last_push_date: + name: 最後更新時間 + site_wordcount: 本站總字數 + site_uv_name: 本站訪客數 + site_pv_name: 本站總訪問量 + more_button: 檢視更多 + card_newest_comments: + headline: 最新評論 + loading_text: 正在載入中... + error: 無法獲取評論,請確認相關配置是否正確 + zero: 沒有評論 + image: 圖片 + link: 連結 + code: 程式碼 + card_toc: 目錄 + +date_suffix: + just: 剛剛 + min: 分鐘前 + hour: 小時前 + day: 天前 + month: 個月前 + +donate: 打賞 +share: 分享 + +rightside: + readmode_title: 閱讀模式 + translate_title: 簡繁轉換 + night_mode_title: 淺色和深色模式轉換 + back_to_top: 回到頂部 + toc: 目錄 + scroll_to_comment: 直達評論 + setting: 設定 + aside: 單欄和雙欄切換 + chat: 聊天 + +copy_copyright: + author: 作者 + link: 連結 + source: 來源 + info: 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。 + +Snackbar: + chs_to_cht: 你已切換為繁體 + cht_to_chs: 你已切換為簡體 + day_to_night: 你已切換為深色模式 + night_to_day: 你已切換為淺色模式 + +loading: 載入中... + +error404: 頁面沒有找到 diff --git a/layout/archive.pug b/layout/archive.pug new file mode 100644 index 0000000..815cdd1 --- /dev/null +++ b/layout/archive.pug @@ -0,0 +1,9 @@ +extends includes/layout.pug + +block content + include ./includes/mixins/article-sort.pug + #archive + - const archiveLength = findArchiveLength(fragment_cache) + .article-sort-title= _p('page.articles') + ' - ' + archiveLength + +articleSort(page.posts) + include includes/pagination.pug \ No newline at end of file diff --git a/layout/category.pug b/layout/category.pug new file mode 100644 index 0000000..234a0af --- /dev/null +++ b/layout/category.pug @@ -0,0 +1,14 @@ +extends includes/layout.pug + +block content + if theme.category_ui == 'index' + include ./includes/mixins/post-ui.pug + #recent-posts.recent-posts.category_ui + +postUI + include includes/pagination.pug + else + include ./includes/mixins/article-sort.pug + #category + .article-sort-title= _p('page.category') + ' - ' + page.category + +articleSort(page.posts) + include includes/pagination.pug \ No newline at end of file diff --git a/layout/includes/404.pug b/layout/includes/404.pug new file mode 100644 index 0000000..4a022c8 --- /dev/null +++ b/layout/includes/404.pug @@ -0,0 +1,12 @@ +- var top_img_404 = theme.error_404.background || theme.default_top_img + +#body-wrap.error404 + include ./header/index.pug + + #error-wrap + .error-content + .error-img + img(src=url_for(top_img_404) alt='Page not found') + .error-info + h1.error_title= '404' + .error_subtitle= theme.error_404.subtitle || _p('error404') diff --git a/layout/includes/additional-js.pug b/layout/includes/additional-js.pug new file mode 100644 index 0000000..3ef0223 --- /dev/null +++ b/layout/includes/additional-js.pug @@ -0,0 +1,69 @@ +div + script(src=url_for(theme.asset.utils)) + script(src=url_for(theme.asset.main)) + + if theme.translate.enable + script(src=url_for(theme.asset.translate)) + + if theme.medium_zoom + script(src=url_for(theme.asset.medium_zoom)) + else if theme.fancybox + script(src=url_for(theme.asset.fancybox_v4)) + + if theme.instantpage + script(src=url_for(theme.asset.instantpage), type='module') + + if theme.lazyload.enable + script(src=url_for(theme.asset.lazyload)) + + if theme.snackbar.enable + script(src=url_for(theme.asset.snackbar)) + + if theme.pangu.enable + != partial("includes/third-party/pangu.pug", {}, { cache: true }) + + //- search + if theme.algolia_search.enable + script(src=url_for(theme.asset.algolia_search_v4)) + script(src=url_for(theme.asset.instantsearch_v4)) + script(src=url_for(theme.asset.algolia_js)) + else if theme.local_search.enable + script(src=url_for(theme.asset.local_search)) + + .js-pjax + if needLoadCountJs + != partial("includes/third-party/card-post-count/index", {}, { cache: true }) + + if loadSubJs + include ./third-party/subtitle.pug + + include ./third-party/math/index.pug + + if commentsJsLoad + include ./third-party/comments/js.pug + + != partial("includes/third-party/prismjs", {}, { cache: true }) + + if theme.aside.enable && theme.newest_comments.enable + if theme.pjax.enable + != partial("includes/third-party/newest-comments/index", {}, { cache: true }) + else if (!is_post() && page.aside !== false) + != partial("includes/third-party/newest-comments/index", {}, { cache: true }) + + != fragment_cache('injectBottom', function(){return injectHtml(theme.inject.bottom)}) + + != partial("includes/third-party/effect", {}, { cache: true }) + + != partial("includes/third-party/chat/index", {}, { cache: true }) + + if theme.aplayerInject && theme.aplayerInject.enable + if theme.pjax.enable || theme.aplayerInject.per_page + include ./third-party/aplayer.pug + else if page.aplayer + include ./third-party/aplayer.pug + + if theme.pjax.enable + != partial("includes/third-party/pjax", {}, { cache: true }) + + if theme.busuanzi.site_uv || theme.busuanzi.site_pv || theme.busuanzi.page_pv + script(async data-pjax src='//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js') diff --git a/layout/includes/footer.pug b/layout/includes/footer.pug new file mode 100644 index 0000000..c7ade67 --- /dev/null +++ b/layout/includes/footer.pug @@ -0,0 +1,52 @@ +#footer_deal + if theme.footer.footer_icons.enable + each i in theme.footer.footer_icons.left + if i.class == "in" + a.deal_link(href=`${i.link}`, title=`${i.desrc}`) + i(class=`${i.icon}`) + else if i.class == "out" + a.deal_link(target='_blank', rel='noopener external nofollow', href=`${i.link}`, title=`${i.desrc}`) + i(class=`${i.icon}`) + else + a.deal_link(href=`${i.link}`, title=`${i.desrc}`) + i(class=`${i.icon}`) + img.footer_mini_logo.entered.loading(title='返回顶部' onclick='btf.scrollToDest(0, 500)' src=`${theme.footer.footer_logo.url}` data-ll-status='loading') + if theme.footer.footer_icons.enable + each i in theme.footer.footer_icons.right + if i.class == "in" + a.deal_link(href=`${i.link}`, title=`${i.desrc}`) + i(class=`${i.icon}`) + else if i.class == "out" + a.deal_link(target='_blank', rel='noopener external nofollow', href=`${i.link}`, title=`${i.desrc}`) + i(class=`${i.icon}`) + else + a.deal_link(href=`${i.link}`, title=`${i.desrc}`) + i(class=`${i.icon}`) +#Jay-footer + each item in theme.footer.footer_group.footer_group_link + .footer-group + h3.footer-title=item.group_title + .footer-links + each i in item.footer_links + if i.class == "in" + a.footer-item(href=`${i.link}`)=i.text + else if i.class == "out" + a.footer-item(target='_blank', href=`${i.link}`)=i.text + else + a.footer-item(href=`${i.link}`)=i.text +#footer-banner + .footer-banner-links + .footer-banner-left + .footer-banner-left + #footer-banner-tips=`${theme.footer.text}` + + .footer-banner-right + a.footer-banner-link(href="https://hexo.io/zh-cn/" title="Hexo") 框架:Hexo + a.footer-banner-link | + a.footer-banner-link(href="/2023/dimension" title="theme") 主题:dimension + a.footer-banner-link | + a.footer-banner-link(href="/about/" title="about") 关于 + a.footer-banner-link | + a.footer-banner-link.cc(href="/cc/" title="cc协议") + i.fab.fa-creative-commons + span 协议。 \ No newline at end of file diff --git a/layout/includes/head.pug b/layout/includes/head.pug new file mode 100644 index 0000000..d8ff883 --- /dev/null +++ b/layout/includes/head.pug @@ -0,0 +1,69 @@ +- var pageTitle +- is_archive() ? page.title = findArchivesTitle(page, theme.menu, date) : '' +- if (is_tag()) pageTitle = _p('page.tag') + ': ' + page.tag +- else if (is_category()) pageTitle = _p('page.category') + ': ' + page.category +- else if (is_current('/404.html', [strict])) pageTitle = _p('error404') +- else pageTitle = page.title || config.title || '' + +- var isSubtitle = config.subtitle ? ' - ' + config.subtitle : '' +- var tabTitle = is_home() || !pageTitle ? config.title + isSubtitle : pageTitle + ' | ' + config.title +- var pageAuthor = config.email ? config.author + ',' + config.email : config.author +- var pageCopyright = config.copyright || config.author +- var themeColorLight = theme.theme_color && theme.theme_color.enable && theme.theme_color.meta_theme_color_light || '#ffffff' +- var themeColorDark = theme.theme_color && theme.theme_color.enable && theme.theme_color.meta_theme_color_dark || '#0d0d0d' +- var themeColor = theme.display_mode === 'dark' ? themeColorDark : themeColorLight + +meta(charset='UTF-8') +meta(http-equiv="X-UA-Compatible" content="IE=edge") +meta(name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no") +title= tabTitle +meta(name="author" content=pageAuthor) +meta(name="copyright" content=pageCopyright) +meta(name ="format-detection" content="telephone=no") +meta(name="theme-color" content=themeColor) + +//- Open_Graph +include ./head/Open_Graph.pug + +!=favicon_tag(theme.favicon || config.favicon) +link(rel="canonical" href=urlNoIndex()) + +//- 預解析 +!=partial('includes/head/preconnect', {}, {cache: true}) + +//- 網站驗證 +!=partial('includes/head/site_verification', {}, {cache: true}) + +//- PWA +if (theme.pwa && theme.pwa.enable) + !=partial('includes/head/pwa', {}, {cache: true}) + +//- main css +link(rel='stylesheet', href=url_for(theme.asset.main_css)) +link(rel='stylesheet', href=url_for(theme.asset.fontawesomeV6) media="print" onload="this.media='all'") + +if (theme.snackbar && theme.snackbar.enable) + link(rel='stylesheet', href=url_for(theme.asset.snackbar_css) media="print" onload="this.media='all'") + +if theme.fancybox + link(rel='stylesheet' href=url_for(theme.asset.fancybox_css_v4) media="print" onload="this.media='all'") + +//- google_adsense +!=partial('includes/head/google_adsense', {}, {cache: true}) + +//- analytics +!=partial('includes/head/analytics', {}, {cache: true}) + +//- font +if theme.blog_title_font && theme.blog_title_font.font_link + link(rel='stylesheet' href=url_for(theme.blog_title_font.font_link) media="print" onload="this.media='all'") + +//- global config +!=partial('includes/head/config', {}, {cache: true}) + +include ./head/config_site.pug +include ./head/noscript.pug + +!=fragment_cache('injectHeadJs', function(){return inject_head_js()}) + +!=fragment_cache('injectHead', function(){return injectHtml(theme.inject.head)}) \ No newline at end of file diff --git a/layout/includes/head/Open_Graph.pug b/layout/includes/head/Open_Graph.pug new file mode 100644 index 0000000..1d04b47 --- /dev/null +++ b/layout/includes/head/Open_Graph.pug @@ -0,0 +1,13 @@ +if theme.Open_Graph_meta.enable + - + let ogOption = Object.assign({ + type: is_post() ? 'article' : 'website', + image: (page.cover || theme.avatar.img) ? full_url_for(page.cover || theme.avatar.img) : '', + fb_admins: theme.facebook_comments.user_id || '', + fb_app_id: theme.facebook_comments.app_id || '', + }, theme.Open_Graph_meta.option) + - + != open_graph(ogOption) +else + meta(name="description" content=page_description()) + diff --git a/layout/includes/head/analytics.pug b/layout/includes/head/analytics.pug new file mode 100644 index 0000000..6452528 --- /dev/null +++ b/layout/includes/head/analytics.pug @@ -0,0 +1,31 @@ +if theme.baidu_analytics + script. + var _hmt = _hmt || []; + (function() { + var hm = document.createElement("script"); + hm.src = "https://hm.baidu.com/hm.js?!{theme.baidu_analytics}"; + var s = document.getElementsByTagName("script")[0]; + s.parentNode.insertBefore(hm, s); + })(); + +if theme.google_analytics + script(async src=`https://www.googletagmanager.com/gtag/js?id=${theme.google_analytics}`) + script. + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + gtag('config', '!{theme.google_analytics}'); + +if theme.cnzz_analytics + script(async data-pjax src=`https://s4.cnzz.com/z_stat.php?id=${theme.cnzz_analytics}&web_id=${theme.cnzz_analytics}`) + +if theme.cloudflare_analytics + script(defer data-pjax src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon=`{"token": "${theme.cloudflare_analytics}"}`) + +if theme.microsoft_clarity + script. + (function(c,l,a,r,i,t,y){ + c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; + t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; + y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); + })(window, document, "clarity", "script", "!{theme.microsoft_clarity}"); \ No newline at end of file diff --git a/layout/includes/head/config.pug b/layout/includes/head/config.pug new file mode 100644 index 0000000..5a8b8f5 --- /dev/null +++ b/layout/includes/head/config.pug @@ -0,0 +1,124 @@ +- + let algolia = 'undefined'; + let env = process.env; + if (theme.algolia_search.enable) { + algolia = JSON.stringify({ + appId: env.ALGOLIA_APP_ID || config.algolia.appId || config.algolia.applicationID, + apiKey: env.ALGOLIA_API_KEY || config.algolia.apiKey, + indexName: env.ALGOLIA_INDEX_NAME || config.algolia.indexName, + hits: theme.algolia_search.hits, + // search languages + languages: { + input_placeholder: _p("search.algolia_search.input_placeholder"), + hits_empty: _p("search.algolia_search.hits_empty"), + hits_stats: _p("search.algolia_search.hits_stats"), + } + }) + } + + let localSearch = 'undefined'; + if (theme.local_search && theme.local_search.enable) { + localSearch = JSON.stringify({ + path: theme.local_search.CDN ? theme.local_search.CDN : config.root + config.search.path, + preload: theme.local_search.preload, + languages: { + // search languages + hits_empty: _p("search.local_search.hits_empty"), + } + }) + } + + let translate = 'undefined'; + if (theme.translate && theme.translate.enable){ + translate = JSON.stringify({ + defaultEncoding: theme.translate.defaultEncoding, + translateDelay: theme.translate.translateDelay, + msgToTraditionalChinese: theme.translate.msgToTraditionalChinese, + msgToSimplifiedChinese: theme.translate.msgToSimplifiedChinese + }) + } + + let copyright = 'undefined'; + if (theme.copy.enable && theme.copy.copyright.enable){ + copyright = JSON.stringify({ + limitCount: theme.copy.copyright.limit_count, + languages: { + author: _p("copy_copyright.author") + ': ' + config.author, + link: _p("copy_copyright.link") + ': ', + source: _p("copy_copyright.source") + ': ' + config.title, + info: _p("copy_copyright.info") + } + }) + } + + let Snackbar = 'undefined'; + if (theme.snackbar && theme.snackbar.enable) { + Snackbar = JSON.stringify({ + chs_to_cht: _p("Snackbar.chs_to_cht"), + cht_to_chs: _p("Snackbar.cht_to_chs"), + day_to_night: _p("Snackbar.day_to_night"), + night_to_day: _p("Snackbar.night_to_day"), + bgLight: theme.snackbar.bg_light, + bgDark: theme.snackbar.bg_dark, + position: theme.snackbar.position, + }) + } + + let noticeOutdate = 'undefined'; + if (theme.noticeOutdate && theme.noticeOutdate.enable) { + noticeOutdate = JSON.stringify({ + limitDay: theme.noticeOutdate.limit_day, + position: theme.noticeOutdate.position, + messagePrev: theme.noticeOutdate.message_prev, + messageNext: theme.noticeOutdate.message_next, + }) + } + + let highlight = 'undefined'; + if ((config.highlight && config.highlight.enable) || (config.prismjs && config.prismjs.enable)) { + highlight = JSON.stringify({ + plugin: config.highlight.enable ? 'highlighjs' : 'prismjs', + highlightCopy: theme.highlight_copy, + highlightLang: theme.highlight_lang, + highlightHeightLimit: theme.highlight_height_limit + }) + } + +script. + const GLOBAL_CONFIG = { + root: '!{config.root}', + algolia: !{algolia}, + localSearch: !{localSearch}, + translate: !{translate}, + noticeOutdate: !{noticeOutdate}, + highlight: !{highlight}, + copy: { + success: '!{_p("copy.success")}', + error: '!{_p("copy.error")}', + noSupport: '!{_p("copy.noSupport")}' + }, + relativeDate: { + homepage: !{theme.post_meta.page.date_format === 'relative'}, + post: !{theme.post_meta.post.date_format === 'relative'} + }, + runtime: '!{theme.runtimeshow.enable ? _p("aside.card_webinfo.runtime.unit") : ""}', + date_suffix: { + just: '!{_p("date_suffix.just")}', + min: '!{_p("date_suffix.min")}', + hour: '!{_p("date_suffix.hour")}', + day: '!{_p("date_suffix.day")}', + month: '!{_p("date_suffix.month")}' + }, + copyright: !{copyright}, + lightbox: '!{ theme.medium_zoom ? "mediumZoom" : (theme.fancybox ? "fancybox" : "null" )}', + Snackbar: !{Snackbar}, + source: { + justifiedGallery: { + js: '!{url_for(theme.asset.flickr_justified_gallery_js)}', + css: '!{url_for(theme.asset.flickr_justified_gallery_css)}' + } + }, + isPhotoFigcaption: !{theme.photofigcaption}, + islazyload: !{theme.lazyload.enable}, + isAnchor: !{theme.anchor.auto_update || false} + } diff --git a/layout/includes/head/config_site.pug b/layout/includes/head/config_site.pug new file mode 100644 index 0000000..94cbb51 --- /dev/null +++ b/layout/includes/head/config_site.pug @@ -0,0 +1,30 @@ +- + const titleVal = pageTitle.replace(/'/ig,"\\'") + + let isHighlightShrink + if (theme.highlight_shrink == 'none') isHighlightShrink = 'undefined' + else if (page.highlight_shrink === true || page.highlight_shrink === false) isHighlightShrink = page.highlight_shrink + else isHighlightShrink = theme.highlight_shrink + + var showToc = false + if (theme.aside.enable && page.aside !== false) { + let tocEnable = false + if (is_post()) { + if (theme.toc.post) tocEnable = true + } else if (is_page()) { + if (theme.toc.page) tocEnable = true + } + const pageToc = page.toc === true || page.toc === false ? page.toc : tocEnable + showToc = pageToc && (toc(page.content) !== '' || page.encrypt == true ) + } +- + +script#config-diff. + var GLOBAL_CONFIG_SITE = { + title: '!{titleVal}', + isPost: !{is_post()}, + isHome: !{is_home()}, + isHighlightShrink: !{isHighlightShrink}, + isToc: !{showToc}, + postUpdate: '!{full_date(page.updated)}' + } diff --git a/layout/includes/head/google_adsense.pug b/layout/includes/head/google_adsense.pug new file mode 100644 index 0000000..3ef1af9 --- /dev/null +++ b/layout/includes/head/google_adsense.pug @@ -0,0 +1,9 @@ +if (theme.google_adsense && theme.google_adsense.enable) + script(async src=theme.google_adsense.js) + + if theme.google_adsense.auto_ads + script. + (adsbygoogle = window.adsbygoogle || []).push({ + google_ad_client: '!{theme.google_adsense.client}', + enable_page_level_ads: '!{theme.google_adsense.enable_page_level_ads}' + }); \ No newline at end of file diff --git a/layout/includes/head/noscript.pug b/layout/includes/head/noscript.pug new file mode 100644 index 0000000..cc3befa --- /dev/null +++ b/layout/includes/head/noscript.pug @@ -0,0 +1,14 @@ +noscript. + \ No newline at end of file diff --git a/layout/includes/head/preconnect.pug b/layout/includes/head/preconnect.pug new file mode 100644 index 0000000..d010b05 --- /dev/null +++ b/layout/includes/head/preconnect.pug @@ -0,0 +1,22 @@ +link(rel="preconnect" href="//cdn.jsdelivr.net") + +if theme.google_analytics + link(rel="preconnect" href="//www.google-analytics.com" crossorigin='') + +if theme.baidu_analytics + link(rel="preconnect" href="//hm.baidu.com") + +if theme.cnzz_analytics + link(rel="preconnect" href="//s4.cnzz.com") + +if theme.cloudflare_analytics + link(rel="preconnect" href="//static.cloudflareinsights.com") + +if theme.microsoft_clarity + link(rel="preconnect" href="//www.clarity.ms") + +if theme.blog_title_font && theme.blog_title_font.font_link && theme.blog_title_font.font_link.indexOf('//fonts.googleapis.com') != -1 + link(rel="preconnect" href="//fonts.googleapis.com" crossorigin='') + +if theme.busuanzi.site_uv || theme.busuanzi.site_pv || theme.busuanzi.page_pv + link(rel="preconnect" href="//busuanzi.ibruce.info") \ No newline at end of file diff --git a/layout/includes/head/pwa.pug b/layout/includes/head/pwa.pug new file mode 100644 index 0000000..e9152f2 --- /dev/null +++ b/layout/includes/head/pwa.pug @@ -0,0 +1,11 @@ +link(rel="manifest" href=url_for(theme.pwa.manifest)) +if(theme.pwa.theme_color) + meta(name="msapplication-TileColor" content=theme.pwa.theme_color) +if(theme.pwa.apple_touch_icon) + link(rel="apple-touch-icon" sizes="180x180" href=url_for(theme.pwa.apple_touch_icon)) +if(theme.pwa.favicon_32_32) + link(rel="icon" type="image/png" sizes="32x32" href=url_for(theme.pwa.favicon_32_32)) +if(theme.pwa.favicon_16_16) + link(rel="icon" type="image/png" sizes="16x16" href=url_for(theme.pwa.favicon_16_16)) +if(theme.pwa.mask_icon) + link(rel="mask-icon" href=url_for(theme.pwa.mask_icon) color="#5bbad5") diff --git a/layout/includes/head/site_verification.pug b/layout/includes/head/site_verification.pug new file mode 100644 index 0000000..8947644 --- /dev/null +++ b/layout/includes/head/site_verification.pug @@ -0,0 +1,3 @@ +if theme.site_verification + each item in theme.site_verification + meta(name=item.name content=item.content) \ No newline at end of file diff --git a/layout/includes/header/index.pug b/layout/includes/header/index.pug new file mode 100644 index 0000000..aab6c6f --- /dev/null +++ b/layout/includes/header/index.pug @@ -0,0 +1,56 @@ +if !theme.disable_top_img && page.top_img !== false + if is_post() + - var top_img = page.top_img || page.cover || page.randomcover + else if is_page() + - var top_img = false + else if is_tag() + - var top_img = false + else if is_category() + - var top_img = false + else if is_home() + - var top_img = false + else if is_archive() + - var top_img = false + else + - var top_img = page.top_img || theme.default_top_img + + if top_img !== false + - var imgSource = top_img && top_img.indexOf('/') !== -1 ? `background-image: url('${url_for(top_img)}')` : `background: ${top_img}` + - var bg_img = top_img ? imgSource : '' + - var site_title = page.title || page.tag || page.category || config.title + - var isHomeClass = is_home() ? 'full_page nav-fixed nav-visible' : 'not-home-page' + - is_post() ? isHomeClass = 'post-bg' : isHomeClass + else + - var isHomeClass = 'not-top-img' +else + - var top_img = false + - var isHomeClass = 'not-top-img' + +header#page-header(class=isHomeClass style=bg_img) + !=partial('includes/header/nav', {}, {cache: true}) + if is_post() + include ./post-info.pug + section.main-hero-waves-area.waves-area + svg.waves-svg(xmlns='http://www.w3.org/2000/svg', xlink='http://www.w3.org/1999/xlink', viewBox='0 24 150 28', preserveAspectRatio='none', shape-rendering='auto') + defs + path#gentle-wave(d='M -160 44 c 30 0 58 -18 88 -18 s 58 18 88 18 s 58 -18 88 -18 s 58 18 88 18 v 44 h -352 Z') + g.parallax + use(href='#gentle-wave', x='48', y='0') + use(href='#gentle-wave', x='48', y='3') + use(href='#gentle-wave', x='48', y='5') + use(href='#gentle-wave', x='48', y='7') + else if is_home() + //- #site-info + h1#site-title=site_title + if theme.subtitle.enable + - var loadSubJs = true + #site-subtitle + span#subtitle + if(theme.social) + #site_social_icons + !=fragment_cache('social', function(){return partial('includes/header/social')}) + #scroll-down + i.fas.fa-angle-down.scroll-down-effects + else + #page-site-info + h1#site-title=site_title \ No newline at end of file diff --git a/layout/includes/header/menu_item.pug b/layout/includes/header/menu_item.pug new file mode 100644 index 0000000..d172db7 --- /dev/null +++ b/layout/includes/header/menu_item.pug @@ -0,0 +1,27 @@ +if theme.menu + .menus_items + each value, label in theme.menu + if typeof value !== 'object' + .menus_item + - const valueArray = value.split('||') + a.site-page(href=url_for(trim(valueArray[0]))) + if valueArray[1] + i.fa-fw(class=trim(valueArray[1])) + span=' '+label + else + .menus_item + - const labelArray = label.split('||') + - const hideClass = labelArray[2] && trim(labelArray[2]) === 'hide' ? 'hide' : '' + a.site-page.group(class=`${hideClass}` href='javascript:void(0);') + if labelArray[1] + i.fa-fw(class=trim(labelArray[1])) + span=' '+ trim(labelArray[0]) + i.fas.fa-chevron-down + ul.menus_item_child + each val,lab in value + - const valArray = val.split('||') + li + a.site-page.child(href=url_for(trim(valArray[0]))) + if valArray[1] + i.fa-fw(class=trim(valArray[1])) + span=' '+ lab \ No newline at end of file diff --git a/layout/includes/header/nav.pug b/layout/includes/header/nav.pug new file mode 100644 index 0000000..53ab41b --- /dev/null +++ b/layout/includes/header/nav.pug @@ -0,0 +1,34 @@ +- const { darkmode } = theme +nav#nav + span#blog_name + a#site-name(href=url_for('/')) + .title #[=config.title] + i.fa-solid.fa-house + + #menus + if (theme.algolia_search.enable || theme.local_search.enable) + div.nav-button#search-button + a.site-page.social-icon.search + i.fas.fa-search.fa-fw + span=' '+_p('search.title') + + if darkmode.enable && darkmode.button + div.nav-button#darkmode_navswitch + a.darkmode_switchbutton(type="button" href='javascript:toggleTheme()' onclick="void(0)") + i.fas.fa-adjust + + div.nav-button#darkmode_navswitch + a.darkmode_switchbutton(type="button" href='javascript:toRandomPost()' onclick="void(0)") + i.fas.fa-shuffle + + //- div.nav-button#nav-totop + a.totopbtn + i.fas.fa-arrow-up + span#percent(onclick="btf.scrollToDest(0,500)") 0 + + + !=partial('includes/header/menu_item', {}, {cache: true}) + + #toggle-menu + a.site-page + i.fas.fa-bars.fa-fw diff --git a/layout/includes/header/post-info.pug b/layout/includes/header/post-info.pug new file mode 100644 index 0000000..47a3f19 --- /dev/null +++ b/layout/includes/header/post-info.pug @@ -0,0 +1,146 @@ +- let comments = theme.comments +#post-info + h1.post-title= page.title || _p('no_title') + if theme.post_edit.enable + a.post-edit-link(href=theme.post_edit.url + page.source title=_p('post.edit') target="_blank") + i.fas.fa-pencil-alt + + #post-meta + .meta-firstline + if (theme.post_meta.post.date_type) + span.post-meta-date + if (theme.post_meta.post.date_type === 'both') + i.far.fa-calendar-alt.fa-fw.post-meta-icon + span.post-meta-label= _p('post.created') + time.post-meta-date-created(datetime=date_xml(page.date) title=_p('post.created') + ' ' + full_date(page.date))=date(page.date, config.date_format) + span.post-meta-separator | + i.fas.fa-history.fa-fw.post-meta-icon + span.post-meta-label= _p('post.updated') + time.post-meta-date-updated(datetime=date_xml(page.updated) title=_p('post.updated') + ' ' + full_date(page.updated))=date(page.updated, config.date_format) + else + - let data_type_update = theme.post_meta.post.date_type === 'updated' + - let date_type = data_type_update ? 'updated' : 'date' + - let date_icon = data_type_update ? 'fas fa-history' :'far fa-calendar-alt' + - let date_title = data_type_update ? _p('post.updated') : _p('post.created') + i.fa-fw.post-meta-icon(class=date_icon) + span.post-meta-label= date_title + time(datetime=date_xml(page[date_type]) title=date_title + ' ' + full_date(page[date_type]))=date(page[date_type], config.date_format) + if (theme.post_meta.post.categories && page.categories.data.length > 0) + span.post-meta-categories + if (theme.post_meta.post.date_type) + span.post-meta-separator | + + each item, index in page.categories.data + i.fas.fa-inbox.fa-fw.post-meta-icon + a(href=url_for(item.path)).post-meta-categories #[=item.name] + if (index < page.categories.data.length - 1) + i.fas.fa-angle-right.post-meta-separator + + .meta-secondline + - let postWordcount = theme.wordcount.enable && (theme.wordcount.post_wordcount || theme.wordcount.min2read) + if (postWordcount) + span.post-meta-separator | + span.post-meta-wordcount + if theme.wordcount.post_wordcount + i.far.fa-file-word.fa-fw.post-meta-icon + span.post-meta-label= _p('post.wordcount') + ':' + span.word-count= wordcount(page.content) + if theme.wordcount.min2read + span.post-meta-separator | + if theme.wordcount.min2read + i.far.fa-clock.fa-fw.post-meta-icon + span.post-meta-label= _p('post.min2read') + ':' + span= min2read(page.content, {cn: 350, en: 160}) + _p('post.min2read_unit') + + //- for pv and count + mixin pvBlock(parent_id,parent_class,parent_title) + span.post-meta-separator | + span(class=parent_class id=parent_id data-flag-title=page.title) + i.far.fa-eye.fa-fw.post-meta-icon + span.post-meta-label=_p('post.page_pv') + ':' + if block + block + + - const commentUse = comments.use + if page.comments !== false && commentUse && !comments.lazyload + if commentUse[0] === 'Valine' && theme.valine.visitor + +pvBlock(url_for(page.path),'leancloud_visitors',page.title) + span.leancloud-visitors-count + i.fa-solid.fa-spinner.fa-spin + else if commentUse[0] === 'Waline' && theme.waline.pageview + +pvBlock('','','') + span.waline-pageview-count(data-path=url_for(page.path)) + i.fa-solid.fa-spinner.fa-spin + else if commentUse[0] === 'Twikoo' && theme.twikoo.visitor + +pvBlock('','','') + span#twikoo_visitors + i.fa-solid.fa-spinner.fa-spin + else if commentUse[0] === 'Artalk' && theme.artalk.visitor + +pvBlock('','','') + span#ArtalkPV + i.fa-solid.fa-spinner.fa-spin + else if theme.busuanzi.page_pv + +pvBlock('','post-meta-pv-cv','') + span#busuanzi_value_page_pv + i.fa-solid.fa-spinner.fa-spin + else if theme.busuanzi.page_pv + +pvBlock('','post-meta-pv-cv','') + span#busuanzi_value_page_pv + i.fa-solid.fa-spinner.fa-spin + + if comments.count && !comments.lazyload && page.comments !== false && comments.use + - var whichCount = comments.use[0] + + mixin countBlock + span.post-meta-separator | + span.post-meta-commentcount + i.far.fa-comments.fa-fw.post-meta-icon + span.post-meta-label= _p('post.comments') + ':' + if block + block + + case whichCount + when 'Disqus' + +countBlock + span.disqus-comment-count + a(href=full_url_for(page.path) + '#disqus_thread') + i.fa-solid.fa-spinner.fa-spin + when 'Disqusjs' + +countBlock + a(href=full_url_for(page.path) + '#disqusjs') + span.disqus-comment-count(data-disqus-url=full_url_for(page.path)) + i.fa-solid.fa-spinner.fa-spin + when 'Valine' + +countBlock + a(href=url_for(page.path) + '#post-comment' itemprop="discussionUrl") + span.valine-comment-count(data-xid=url_for(page.path) itemprop="commentCount") + i.fa-solid.fa-spinner.fa-spin + when 'Waline' + +countBlock + a(href=url_for(page.path) + '#post-comment') + span.waline-comment-count(data-path=url_for(page.path)) + i.fa-solid.fa-spinner.fa-spin + when 'Gitalk' + +countBlock + a(href=url_for(page.path) + '#post-comment') + span.gitalk-comment-count + i.fa-solid.fa-spinner.fa-spin + when 'Twikoo' + +countBlock + a(href=url_for(page.path) + '#post-comment') + span#twikoo-count + i.fa-solid.fa-spinner.fa-spin + when 'Facebook Comments' + +countBlock + a(href=url_for(page.path) + '#post-comment') + span.fb-comments-count(data-href=urlNoIndex()) + when 'Remark42' + +countBlock + a(href=url_for(page.path) + '#post-comment') + span.remark42__counter(data-url=urlNoIndex()) + i.fa-solid.fa-spinner.fa-spin + when 'Artalk' + +countBlock + a(href=url_for(page.path) + '#post-comment') + span.artalk-count + i.fa-solid.fa-spinner.fa-spin \ No newline at end of file diff --git a/layout/includes/header/social.pug b/layout/includes/header/social.pug new file mode 100644 index 0000000..80adfe9 --- /dev/null +++ b/layout/includes/header/social.pug @@ -0,0 +1,4 @@ +each url, icon in theme.social + a.social-icon(href=url_for(trim(url.split('||')[0])) target="_blank" + title=url.split('||')[1] === undefined ? '' : trim(url.split('||')[1])) + i(class=icon) \ No newline at end of file diff --git a/layout/includes/hometop.pug b/layout/includes/hometop.pug new file mode 100644 index 0000000..61a9409 --- /dev/null +++ b/layout/includes/hometop.pug @@ -0,0 +1,71 @@ +- var hometop = theme.hometop +- var fposts = theme.hometop.featured_posts + +.hometop + .hometopin + .blog-title + span.title=config.title + .fposts + .ftags + #category-bar.hometop_item + .category-bar-items#category-bar-items + !=getarray_bar("tag") + a.category-bar-more(href=url_for(fposts.tags_more_url)) 更多标签 + #category-bar.hometop_item + .category-bar-items#category-bar-items + !=getarray_bar("category") + a.category-bar-more(href=url_for(fposts.categroies_more_url)) 更多分类 + .group1 + .recent-top-post-group#recent-top-post-group.hometop_item + .recent-post-top#recent-post-top + .topGroup#topGroup + if fposts.posts + each i in fposts.posts + .recent-post-item#recent-post-item + .post_cover.left_radius + a(href=url_for(i.link), title=i.title) + img.post_bg.entered.loaded(src=url_for(i.cover) onerror="this.onerror=null,this.src='/img/404.png'") + .recent-post-info(href=url_for(i.link)) + a.article-title(href=url_for(i.link), title=i.title)= i.title + .hometop-creativity.hometop_item + .inbar + img(src="https://bu.dusays.com/2023/04/21/6442840244ea8.webp", style="background:#e9572b", alt="html") + img(src="https://bu.dusays.com/2023/04/21/644284024536b.webp", style="background:#2c51db", alt="css3") + img(src="https://bu.dusays.com/2023/04/21/6442840245873.webp", style="background:#f7cb4f", alt="js") + img(src="https://bu.dusays.com/2023/04/21/6442840245495.webp", style="background:#df5b40", alt="git") + img(src="https://bu.dusays.com/2023/04/28/644bdead5d78f.webp", style="background:#57b6e6", alt="docker") + img(src="https://npm.elemecdn.com/anzhiyu-blog@2.1.1/img/svg/node-logo.svg", style="background:#333", alt="node") + img(src="https://bu.dusays.com/2023/04/21/6442840244ea8.webp", style="background:#e9572b", alt="html") + img(src="https://bu.dusays.com/2023/04/21/644284024536b.webp", style="background:#2c51db", alt="css3") + img(src="https://bu.dusays.com/2023/04/21/6442840245873.webp", style="background:#f7cb4f", alt="js") + img(src="https://bu.dusays.com/2023/04/21/6442840245495.webp", style="background:#df5b40", alt="git") + img(src="https://bu.dusays.com/2023/04/28/644bdead5d78f.webp", style="background:#57b6e6", alt="docker") + img(src="https://npm.elemecdn.com/anzhiyu-blog@2.1.1/img/svg/node-logo.svg", style="background:#333", alt="node") + img(src="https://bu.dusays.com/2023/04/21/6442840244ea8.webp", style="background:#e9572b", alt="html") + img(src="https://bu.dusays.com/2023/04/21/644284024536b.webp", style="background:#2c51db", alt="css3") + img(src="https://bu.dusays.com/2023/04/21/6442840245873.webp", style="background:#f7cb4f", alt="js") + img(src="https://bu.dusays.com/2023/04/21/6442840245495.webp", style="background:#df5b40", alt="git") + img(src="https://bu.dusays.com/2023/04/28/644bdead5d78f.webp", style="background:#57b6e6", alt="docker") + img(src="https://npm.elemecdn.com/anzhiyu-blog@2.1.1/img/svg/node-logo.svg", style="background:#333", alt="node") + img(src="https://bu.dusays.com/2023/04/21/6442840244ea8.webp", style="background:#e9572b", alt="html") + img(src="https://bu.dusays.com/2023/04/21/644284024536b.webp", style="background:#2c51db", alt="css3") + img(src="https://bu.dusays.com/2023/04/21/6442840245873.webp", style="background:#f7cb4f", alt="js") + img(src="https://bu.dusays.com/2023/04/21/6442840245495.webp", style="background:#df5b40", alt="git") + img(src="https://bu.dusays.com/2023/04/28/644bdead5d78f.webp", style="background:#57b6e6", alt="docker") + img(src="https://npm.elemecdn.com/anzhiyu-blog@2.1.1/img/svg/node-logo.svg", style="background:#333", alt="node") + .group2 + .siteinfo.hometop_item + include widget/card_webinfo.pug + .descr.hometop_item + img(src=url_for(hometop.descr.img)) + .subtitle subtitle + span=hometop.descr.subtitle + section.main-hero-waves-area.waves-area + svg.waves-svg(xmlns='http://www.w3.org/2000/svg', xlink='http://www.w3.org/1999/xlink', viewBox='0 24 150 28', preserveAspectRatio='none', shape-rendering='auto') + defs + path#gentle-wave(d='M -160 44 c 30 0 58 -18 88 -18 s 58 18 88 18 s 58 -18 88 -18 s 58 18 88 18 v 44 h -352 Z') + g.parallax + use(href='#gentle-wave', x='48', y='0') + use(href='#gentle-wave', x='48', y='3') + use(href='#gentle-wave', x='48', y='5') + use(href='#gentle-wave', x='48', y='7') \ No newline at end of file diff --git a/layout/includes/layout.pug b/layout/includes/layout.pug new file mode 100644 index 0000000..c5c3a61 --- /dev/null +++ b/layout/includes/layout.pug @@ -0,0 +1,60 @@ +- var htmlClassHideAside = theme.aside.enable && theme.aside.hide ? 'hide-aside' : '' +- page.aside = is_archive() ? theme.aside.display.archive: is_category() ? theme.aside.display.category : is_tag() ? theme.aside.display.tag : page.aside +- var hideAside = !theme.aside.enable || page.aside === false ? 'hide-aside' : '' +- var pageType = is_post() ? 'post' : 'page' + +doctype html +html(lang=config.language data-theme=theme.display_mode class=htmlClassHideAside) + head + include ./head.pug + link(rel="stylesheet", href="/css/color.css") + link(rel="stylesheet", href="https://unpkg.com/swiper@8/swiper-bundle.min.css") + body + script(src="https://unpkg.com/swiper@8/swiper-bundle.min.js") + if theme.preloader.enable + !=partial('includes/loading/index', {}, {cache: true}) + + if theme.background + #web_bg + + !=partial('includes/sidebar', {}, {cache: true}) + + if page.type !== '404' + #body-wrap(class=pageType) + include ./header/index.pug + if is_home() + include ./hometop.pug + + main#content-inner.layout(class=hideAside) + if body + div!= body + else + block content + if theme.aside.enable && page.aside !== false + include widget/index.pug + + - var footerBg = theme.footer_bg + if (footerBg) + if (footerBg === true) + - var footer_bg = bg_img + else + - var footer_bg = theme.footer_bg.indexOf('/') !== -1 ? `background-image: url('${url_for(footerBg)}')` : `background: ${footerBg}` + else + - var footer_bg = '' + + footer#footer(style=footer_bg) + !=partial('includes/footer', {}, {cache: true}) + + else + include ./404.pug + + include ./rightside.pug + !=partial('includes/third-party/search/index', {}, {cache: true}) + include ./additional-js.pug + .totopbutton(onclick="btf.scrollToDest(0,500)") + i.fas.fa-arrow-up + span#percent 0 + include ./waves.pug + script(async='' data-pjax='' src="/js/scroll.js") + script(src="/js/random.js") + script(src="/js/custom.js") \ No newline at end of file diff --git a/layout/includes/loading/fullpage-loading.pug b/layout/includes/loading/fullpage-loading.pug new file mode 100644 index 0000000..75a2041 --- /dev/null +++ b/layout/includes/loading/fullpage-loading.pug @@ -0,0 +1,28 @@ +#loading-box + .loading-left-bg + .loading-right-bg + .spinner-box + .configure-border-1 + .configure-core + .configure-border-2 + .configure-core + .loading-word= _p('loading') + +script. + const preloader = { + endLoading: () => { + document.body.style.overflow = 'auto'; + document.getElementById('loading-box').classList.add("loaded") + }, + initLoading: () => { + document.body.style.overflow = ''; + document.getElementById('loading-box').classList.remove("loaded") + + } + } + window.addEventListener('load',()=> { preloader.endLoading() }) + + if (!{theme.pjax && theme.pjax.enable}) { + document.addEventListener('pjax:send', () => { preloader.initLoading() }) + document.addEventListener('pjax:complete', () => { preloader.endLoading() }) + } \ No newline at end of file diff --git a/layout/includes/loading/index.pug b/layout/includes/loading/index.pug new file mode 100644 index 0000000..663fe50 --- /dev/null +++ b/layout/includes/loading/index.pug @@ -0,0 +1,4 @@ +if theme.preloader.source === 1 + include ./fullpage-loading.pug +else + include ./pace.pug \ No newline at end of file diff --git a/layout/includes/loading/pace.pug b/layout/includes/loading/pace.pug new file mode 100644 index 0000000..e6813ba --- /dev/null +++ b/layout/includes/loading/pace.pug @@ -0,0 +1,2 @@ +link(rel="stylesheet", href=url_for(theme.preloader.pace_css_url || theme.asset.pace_default_css)) +script(src=url_for(theme.asset.pace_js)) \ No newline at end of file diff --git a/layout/includes/mixins/article-sort.pug b/layout/includes/mixins/article-sort.pug new file mode 100644 index 0000000..01e9ef2 --- /dev/null +++ b/layout/includes/mixins/article-sort.pug @@ -0,0 +1,20 @@ +mixin articleSort(posts) + .article-sort + - var year + - posts.each(function (article) { + - let tempYear = date(article.date, 'YYYY') + - let no_cover = article.cover === false || !theme.cover.archives_enable ? 'no-article-cover' : '' + - let title = article.title || _p('no_title') + if tempYear !== year + - year = tempYear + .article-sort-item.year= year + .article-sort-item(class=no_cover) + if article.cover && theme.cover.archives_enable + a.article-sort-item-img(href=url_for(article.path) title=title) + img(src=url_for(article.cover) alt=title onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'`) + .article-sort-item-info + .article-sort-item-time + i.far.fa-calendar-alt + time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))= date(article.date, config.date_format) + a.article-sort-item-title(href=url_for(article.path) title=title)= title + - }) \ No newline at end of file diff --git a/layout/includes/mixins/post-ui.pug b/layout/includes/mixins/post-ui.pug new file mode 100644 index 0000000..4fe6f91 --- /dev/null +++ b/layout/includes/mixins/post-ui.pug @@ -0,0 +1,128 @@ +mixin postUI(posts) + each article , index in page.posts.data + .recent-post-item + - + let link = article.link || article.path + let title = article.title || _p('no_title') + let post_cover = article.cover + let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : '' + - + if post_cover && theme.cover.index_enable + .post_cover.left + a(href=url_for(link) title=title) + img.post_bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=title) + .recent-post-info(class=no_cover href=url_for(link) title=title) + a.article-title(href=url_for(link) title=title)= title + .article-meta-wrap + if (is_home() && (article.top || article.sticky > 0)) + span.article-meta + i.fas.fa-thumbtack.sticky + span.sticky= _p('sticky') + span.article-meta-separator | + if (theme.post_meta.page.date_type) + span.post-meta-date + if (theme.post_meta.page.date_type === 'both') + i.far.fa-calendar-alt + span.article-meta-label=_p('post.created') + time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format) + span.article-meta-separator | + i.fas.fa-history + span.article-meta-label=_p('post.updated') + time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format) + else + - let data_type_updated = theme.post_meta.page.date_type === 'updated' + - let date_type = data_type_updated ? 'updated' : 'date' + - let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt' + - let date_title = data_type_updated ? _p('post.updated') : _p('post.created') + i(class=date_icon) + span.article-meta-label=date_title + time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format) + if (theme.post_meta.page.categories && article.categories.data.length > 0) + span.article-meta + span.article-meta-separator | + i.fas.fa-inbox + each item, index in article.categories.data + a(href=url_for(item.path)).article-meta__categories #[=item.name] + if (index < article.categories.data.length - 1) + i.fas.fa-angle-right.article-meta-link + if (theme.post_meta.page.tags && article.tags.data.length > 0) + span.article-meta.tags + span.article-meta-separator | + i.fas.fa-tag + each item, index in article.tags.data + a(href=url_for(item.path)).article-meta__tags #[=item.name] + if (index < article.tags.data.length - 1) + span.article-meta-link #[='•'] + + mixin countBlockInIndex + - needLoadCountJs = true + span.article-meta + span.article-meta-separator | + i.fas.fa-comments + if block + block + span.article-meta-label= ' ' + _p('card_post_count') + + if theme.comments.card_post_count + case theme.comments.use[0] + when 'Disqus' + +countBlockInIndex + a(href=full_url_for(link) + '#disqus_thread') + i.fa-solid.fa-spinner.fa-spin + when 'Disqusjs' + +countBlockInIndex + a(href=full_url_for(link) + '#disqusjs') + span.disqus-comment-count(data-disqus-url=full_url_for(link)) + i.fa-solid.fa-spinner.fa-spin + when 'Valine' + +countBlockInIndex + a(href=url_for(link) + '#post-comment') + span.valine-comment-count(data-xid=url_for(link)) + i.fa-solid.fa-spinner.fa-spin + when 'Waline' + +countBlockInIndex + a(href=url_for(link) + '#post-comment') + span.waline-comment-count(id=url_for(link)) + i.fa-solid.fa-spinner.fa-spin + when 'Twikoo' + +countBlockInIndex + a.twikoo-count(href=url_for(link) + '#post-comment') + i.fa-solid.fa-spinner.fa-spin + when 'Facebook Comments' + +countBlockInIndex + a(href=url_for(link) + '#post-comment') + span.fb-comments-count(data-href=urlNoIndex(article.permalink)) + when 'Remark42' + +countBlockInIndex + a(href=url_for(link) + '#post-comment') + span.remark42__counter(data-url=urlNoIndex(article.permalink)) + i.fa-solid.fa-spinner.fa-spin + when 'Artalk' + +countBlockInIndex + a(href=url_for(link) + '#post-comment') + span.artalk-count(data-page-key=url_for(link)) + i.fa-solid.fa-spinner.fa-spin + + //- Display the article introduction on homepage + case theme.index_post_content.method + when false + - break + when 1 + .content!= article.description + when 2 + if article.description + .content!= article.description + else + - const content = strip_html(article.content) + - let expert = content.substring(0, theme.index_post_content.length) + - content.length > theme.index_post_content.length ? expert += ' ...' : '' + .content!= expert + default + - const content = strip_html(article.content) + - let expert = content.substring(0, theme.index_post_content.length) + - content.length > theme.index_post_content.length ? expert += ' ...' : '' + .content!= expert + + if theme.ad && theme.ad.index + if (index + 1) % 3 == 0 + .recent-post-item.ads-wrap!=theme.ad.index diff --git a/layout/includes/page/about.pug b/layout/includes/page/about.pug new file mode 100644 index 0000000..6d340b6 --- /dev/null +++ b/layout/includes/page/about.pug @@ -0,0 +1,259 @@ +#about-page + .author-box + .author-img + img.no-lightbox(src=url_for(theme.about_page.avatar)) + .image-dot + center + h1 + p.p.center.logo.large 关于我 + p.p.center.small 九月露湿,待君之前✨ + + .author-content + .author-content-item.myInfoAndSayHello + .title1 你好,很高兴认识你👋 + .title2 + | 我是 + span.inline-word=`${theme.about_page.author}` + .title1=`${theme.about_page.introduce}` + .aboutsiteTips.author-content-item + .author-content-item-tips 追求 + h2 + | 源于 + br + | 热爱而去 + span.inline-word 感受 + .mask + span.first-tips 学习 + | + span 生活 + | + span(data-up) 程序 + | + span(data-show) 体验 + + .hello-about + .cursor(style='translate:none;rotate:none;scale:none;transform:translate(721px,180px)') + .shapes + .shape.shape-1(style='translate:none;rotate:none;scale:none;transform:translate(721px,180px)') + .shape.shape-2(style='translate:none;rotate:none;scale:none;transform:translate(721px,180px)') + .shape.shape-3(style='translate:none;rotate:none;scale:none;transform:translate(721px,180px)') + .content + h1 Hello there! + + .author-content + .author-content-item.skills + .card-content + .author-content-item-tips 技能 + span.author-content-item-title 开启创造力 + .skills-style-group + .tags-group-all + .tags-group-wrapper + each i in site.data.creativity + - const evenNum = i.creativity_list.filter((x, index) => index % 2 === 0); + - const oddNum = i.creativity_list.filter((x, index) => index % 2 === 1); + each item, index in i.creativity_list + if ((index+1 <= evenNum.length) && (index+1 <= oddNum.length)) + .tags-group-icon-pair + .tags-group-icon(style=`background: ${evenNum[index].color}`) + img.no-lightbox(title=evenNum[index].name, src=evenNum[index].icon) + .tags-group-icon(style=`background: ${oddNum[index].color}`) + img.no-lightbox(title=oddNum[index].name, src=oddNum[index].icon) + .skills-list + each i in site.data.creativity + each item, index in i.creativity_list + .skill-info + .skill-icon(style=`background: ${item.color}`) + img.no-lightbox(title=item.name, src=item.icon) + .skill-name + span=item.name + .etc ... + .author-content-item.careers + .card-content + .author-content-item-tips 生涯 + span.author-content-item-title 无限进步 + .careers-group + .careers-item + .circle(style='background:#357ef5') + .name=`${theme.about_page.careers}` + img.author-content-img.no-lightbox(alt='生涯', src='https://img02.anzhiy.cn/adminuploads/1/2022/09/26/6330e9bcc39cc.png') + + .author-content + .author-content-item.personalities + .author-content-item-tips 人格 + span.author-content-item-title=`${theme.about_page.personalities}` + .title2(style='color:#ac899c') INTP-A + .post-tips + | 在 + a(href='https://www.16personalities.com/', target='_blank', rel='noopener nofollow') 16personalities + | 了解更多关于 + a(target='_blank', rel='noopener external nofollow', href='https://www.16personalities.com/ch/esfj-%E4%BA%BA%E6%A0%BC')=`${theme.about_page.personalities}` + .image + img.no-lightbox(src='/img/16pers.png') + .author-content-item.myphoto + img.author-content-img.no-lightbox(alt='自拍', src='/img/5.jpg') + + .author-content + .author-content-item.maxim + .author-content-item-tips 座右铭 + span.maxim-title + span(style='opacity:.6;margin-bottom:8px')=`${theme.about_page.say_first_line}` + | + span=`${theme.about_page.say_last_line}` + .author-content-item.buff + .card-content + .author-content-item-tips 特性 + span.buff-title + span(style='opacity:.6;margin-bottom:8px') + span.inline-word=`${theme.about_page.character_1}` + | + span=`${theme.about_page.character_2}` + .card-background-icon + i.fas.fa-dice-d20 + + .author-content-item.comic-content + .card-content + .author-content-item-tips 爱好番剧 + span.author-content-item-title=`${theme.about_page.anime}` + .content-bottom + .banner-button-group + + .author-content-item.like-music + .card-content + .author-content-item-tips 音乐偏好 + span.author-content-item-title=`${theme.about_page.music}` + .content-bottom + .tips 跟 Aegcbx 一起欣赏更多音乐 + + .author-content + .author-content-item.single.reward + .author-content-item-tips 致谢 + span.author-content-item-title 赞赏名单 + .author-content-item-description 感谢因为有你们,让我更加有创作的动力。 + each i in site.data.reward + - let rawData = [...i.reward_list] + .reward-list-all + - let reward_list_amount = i.reward_list.sort((a,b)=>b.amount - a.amount) + each item, index in reward_list_amount + .reward-list-item + .reward-list-item-name=item.name + .reward-list-bottom-group + if item.amount >= 50 + .reward-list-item-money(style='background:var(--anzhiyu-yellow)')=`¥${item.amount}` + else + .reward-list-item-money=`¥${item.amount + (item.suffix ? item.suffix : "")}` + .datatime.reward-list-item-time(datatime=item.datatime)=new Date(item.datatime).toISOString().slice(0, -14) + .reward-list-updateDate + | 最新更新时间: + time.datatime.reward-list-updateDate-time(datatime=rawData[0].datatime)=new Date(rawData[0].datatime).toISOString().slice(0, -14) + +script. + (() => { + function isInViewPortOfOne(el) { + if (!el) return; + const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; + const offsetTop = el.offsetTop; + const scrollTop = document.documentElement.scrollTop; + const top = offsetTop - scrollTop; + return top <= viewPortHeight; + } + fetch('https://v6-widget.51.la/v6/{掩码ID}/quote.js').then(res => res.text()).then((data) => { + let title = ['最近活跃', '今日人数', '今日访问', '昨日人数', '昨日访问', '本月访问', '总访问量'] + let num = data.match(/(<\/span>).*?(\/span><\/p>)/g) + + num = num.map((el) => { + let val = el.replace(/(<\/span>)/g, '') + let str = val.replace(/(<\/span><\/p>)/g, '') + return str + }) + + let statisticEl = document.getElementById('statistic') + + // 自定义不显示哪个或者显示哪个,如下为不显示 最近活跃访客 和 总访问量 + let statistic = [] + for (let i = 0; i < num.length; i++) { + if (!statisticEl) return + if (i == 0 || i == num.length - 1) continue; + statisticEl.innerHTML += '
' + title[i] + '' + num[i] + '
' + queueMicrotask(()=> { + statistic.push(new CountUp(title[i], 0, num[i], 0, 2, { + useEasing: true, + useGrouping: true, + separator: ',', + decimal: '.', + prefix: '', + suffix: '' + })) + }) + } + + function statisticUP () { + let statisticElment = document.querySelector('.about-statistic.author-content-item'); + if(isInViewPortOfOne(statisticElment)) { + for (let i = 0; i < num.length; i++) { + if (i == 0 || i == num.length - 1) continue; + statistic[i-1].start(); + } + document.removeEventListener('scroll', throttleStatisticUP); + } + } + + const selfInfoContentYear = new CountUp('selfInfo-content-year', 0, 2002, 0, 2, { + useEasing: true, + useGrouping: false, + separator: ',', + decimal: '.', + prefix: '', + suffix: '' + }) + + function scrollSelfInfoContentYear() { + let selfInfoContentYearElment = document.querySelector('.author-content-item.selfInfo.single'); + if (selfInfoContentYearElment && isInViewPortOfOne(selfInfoContentYearElment)) { + selfInfoContentYear.start() + document.removeEventListener('scroll', throttleScrollSelfInfoContentYear); + } + } + const throttleStatisticUP = btf.throttle(statisticUP, 200) + document.addEventListener('scroll', throttleStatisticUP, {passive: true}) + + const throttleScrollSelfInfoContentYear = btf.throttle(scrollSelfInfoContentYear, 200) + document.addEventListener('scroll', throttleScrollSelfInfoContentYear, {passive: true}) + }); + + var pursuitInterval = null; + pursuitInterval = setInterval(function () { + const show = document.querySelector('span[data-show]') + const next = show.nextElementSibling || document.querySelector('.first-tips') + const up = document.querySelector('span[data-up]') + + if (up) { + up.removeAttribute('data-up') + } + + show.removeAttribute('data-show') + show.setAttribute('data-up', '') + + next.setAttribute('data-show', '') + }, 2000) + + document.addEventListener('pjax:send', function(){ + clearInterval(pursuitInterval); + }); + + var helloAboutEl = document.querySelector('.hello-about') + helloAboutEl.addEventListener("mousemove", evt => { + const mouseX = evt.offsetX; + const mouseY = evt.offsetY; + gsap.set(".cursor", { + x: mouseX, + y: mouseY, + }) + + gsap.to(".shape", { + x: mouseX, + y: mouseY, + stagger: -0.1 + }) + }) + })() + diff --git a/layout/includes/page/categories.pug b/layout/includes/page/categories.pug new file mode 100644 index 0000000..79153c8 --- /dev/null +++ b/layout/includes/page/categories.pug @@ -0,0 +1 @@ +.category-lists!= list_categories() \ No newline at end of file diff --git a/layout/includes/page/default-page.pug b/layout/includes/page/default-page.pug new file mode 100644 index 0000000..e7057f7 --- /dev/null +++ b/layout/includes/page/default-page.pug @@ -0,0 +1,2 @@ +#article-container + != page.content \ No newline at end of file diff --git a/layout/includes/page/flink.pug b/layout/includes/page/flink.pug new file mode 100644 index 0000000..1e719fe --- /dev/null +++ b/layout/includes/page/flink.pug @@ -0,0 +1,15 @@ +#article-container + .flink + if site.data.link + each i in site.data.link + if i.class_name + .flink-name!=i.class_name + .flink-list + .btns.rounded.grid5 + each item in i.link_list + a.button(href=url_for(item.link) title=item.name target="_blank") + img.no-lightbox(src=url_for(item.avatar) onerror=`this.onerror=null;this.src='` + url_for(theme.error_img.flink) + `'` alt=item.name ) + #text= item.name + hr + + != page.content \ No newline at end of file diff --git a/layout/includes/page/tags.pug b/layout/includes/page/tags.pug new file mode 100644 index 0000000..8caac11 --- /dev/null +++ b/layout/includes/page/tags.pug @@ -0,0 +1,2 @@ +.tag-cloud-list.is-center + !=cloudTags({source: site.tags, minfontsize: 1.2, maxfontsize: 2.1, limit: 0, unit: 'em'}) \ No newline at end of file diff --git a/layout/includes/pagination.pug b/layout/includes/pagination.pug new file mode 100644 index 0000000..c50b81a --- /dev/null +++ b/layout/includes/pagination.pug @@ -0,0 +1,37 @@ +- + var options = { + prev_text: '', + next_text: '', + mid_size: 1, + escape: false + } + +if is_post() + - let prev = theme.post_pagination === 1 ? page.prev : page.next + - let next = theme.post_pagination === 1 ? page.next : page.prev + nav#pagination.pagination-post + if(prev) + - var hasPageNext = next ? 'pull-left' : 'pull-full' + .prev-post(class=hasPageNext) + - var pagination_cover = prev.cover === false ? prev.randomcover : prev.cover + a(href=url_for(prev.path)) + img.prev-cover(src=url_for(pagination_cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of previous post') + .pagination-info + .label=_p('pagination.prev') + .prev_info=prev.title + + if(next) + - var hasPagePrev = prev ? 'pull-right' : 'pull-full' + - var pagination_cover = next.cover == false ? next.randomcover : next.cover + .next-post(class=hasPagePrev) + a(href=url_for(next.path)) + img.next-cover(src=url_for(pagination_cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of next post') + .pagination-info + .label=_p('pagination.next') + .next_info=next.title +else + nav#pagination + .pagination + if is_home() + - options.format = 'page/%d/#content-inner' + !=paginator(options) \ No newline at end of file diff --git a/layout/includes/post/post-copyright.pug b/layout/includes/post/post-copyright.pug new file mode 100644 index 0000000..824f782 --- /dev/null +++ b/layout/includes/post/post-copyright.pug @@ -0,0 +1,30 @@ +if theme.post_copyright.enable && page.copyright !== false + - let author = page.copyright_author ? page.copyright_author : config.author + - let url = page.copyright_url ? page.copyright_url : page.permalink + .post-copyright + .post-copyright__title + span.post-copyright-info + h #[=page.title] + .post-copyright__type + span.post-copyright-info + a(href=url_for(url))= theme.post_copyright.decode ? decodeURI(url) : url + .post-copyright-m + .post-copyright-m-info + .post-copyright-a(style="display: inline-block;width: 120px") + h 作者 + .post-copyright-cc-info + h=author + .post-copyright-c(style="display: inline-block;width: 120px") + h 发布于 + .post-copyright-cc-info + h=date(page.date, config.date_format) + .post-copyright-u(style="display: inline-block;width: 120px") + h 更新于 + .post-copyright-cc-info + h=date(page.updated, config.date_format) + .post-copyright-c(style="display: inline-block;width: 120px") + h 许可协议 + .post-copyright-cc-info + a.icon(rel='noopener' target='_blank' title='Creative Commons' href='https://creativecommons.org/') + i.fab.fa-creative-commons + a(rel='noopener' target='_blank' title='CC BY 4.0' href='https://creativecommons.org/licenses/by/4.0/deed.zh') CC BY 4.0 \ No newline at end of file diff --git a/layout/includes/post/reward.pug b/layout/includes/post/reward.pug new file mode 100644 index 0000000..71daa98 --- /dev/null +++ b/layout/includes/post/reward.pug @@ -0,0 +1,13 @@ +.post-reward + .reward-button + i.fas.fa-qrcode + = ' ' + _p('donate') + .reward-main + ul.reward-all + each item in theme.reward.QR_code + - var clickTo = item.link ? item.link : item.img + li.reward-item + a(href=url_for(clickTo) target='_blank') + img.post-qr-code-img(src=url_for(item.img) alt=item.text) + .post-qr-code-desc=item.text + diff --git a/layout/includes/rightside.pug b/layout/includes/rightside.pug new file mode 100644 index 0000000..716f07d --- /dev/null +++ b/layout/includes/rightside.pug @@ -0,0 +1,60 @@ +- const { readmode, translate, darkmode, aside, chat_btn } = theme +mixin rightsideItem(array) + each item in array + case item + //-when 'readmode' + if is_post() && readmode + button#readmode(type="button" title=_p('rightside.readmode_title')) + i.fas.fa-book-open + //-when 'translate' + if translate.enable + button#translateLink(type="button" title=_p('rightside.translate_title'))= translate.default + //-when 'darkmode' + if darkmode.enable && darkmode.button + button#darkmode(type="button" title=_p('rightside.night_mode_title')) + i.fas.fa-adjust + //-when 'hideAside' + if aside.enable && aside.button && page.aside !== false + button#hide-aside-btn(type="button" title=_p('rightside.aside')) + i.fas.fa-arrows-alt-h + when 'toc' + if showToc + button#mobile-toc-button.close(type="button" title=_p("rightside.toc")) + i.fas.fa-list-ul + //-when 'chat' + if chat_btn + button#chat_btn(type="button" title=_p("rightside.chat")) + i.fas.fa-sms + //-when 'comment' + if commentsJsLoad + a#to_comment(href="#post-comment" title=_p("rightside.scroll_to_comment")) + i.fas.fa-comments + +#rightside + - const { enable, hide, show } = theme.rightside_item_order + - const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode','hideAside'] + - const showArray = enable ? show && show.split(',') : ['toc','chat','comment'] + + + #rightside-config-hide + if hideArray + +rightsideItem(hideArray) + //-#rightside-config-show + if enable + if hide + button#rightside_config(type="button" title=_p("rightside.setting")) + i.fas.fa-cog.fa-spin + else + if is_post() + if (readmode || translate.enable || (darkmode.enable && darkmode.button)) + button#rightside_config(type="button" title=_p("rightside.setting")) + i.fas.fa-cog.fa-spin + else if translate.enable || (darkmode.enable && darkmode.button) + button#rightside_config(type="button" title=_p("rightside.setting")) + i.fas.fa-cog.fa-spin + + if showArray + +rightsideItem(showArray) + + //-button#go-up(type="button" title=_p("rightside.back_to_top")) + i.fas.fa-arrow-up \ No newline at end of file diff --git a/layout/includes/sidebar.pug b/layout/includes/sidebar.pug new file mode 100644 index 0000000..11bddf8 --- /dev/null +++ b/layout/includes/sidebar.pug @@ -0,0 +1,18 @@ +#sidebar + #menu-mask + #sidebar-menus + .avatar-img.is-center + img(src=url_for(theme.avatar.img) onerror=`onerror=null;src='${theme.error_img.flink}'` alt="avatar") + .sidebar-site-data.site-data.is-center + a(href=url_for(config.archive_dir) + '/') + .headline= _p('aside.articles') + .length-num= site.posts.length + a(href=url_for(config.tag_dir) + '/' ) + .headline= _p('aside.tags') + .length-num= site.tags.length + a(href=url_for(config.category_dir) + '/') + .headline= _p('aside.categories') + .length-num= site.categories.length + + hr + !=partial('includes/header/menu_item', {}, {cache: true}) diff --git a/layout/includes/third-party/aplayer.pug b/layout/includes/third-party/aplayer.pug new file mode 100644 index 0000000..c439c4c --- /dev/null +++ b/layout/includes/third-party/aplayer.pug @@ -0,0 +1,3 @@ +link(rel='stylesheet' href=url_for(theme.asset.aplayer_css) media="print" onload="this.media='all'") +script(src=url_for(theme.asset.aplayer_js)) +script(src=url_for(theme.asset.meting_js)) \ No newline at end of file diff --git a/layout/includes/third-party/card-post-count/artalk.pug b/layout/includes/third-party/card-post-count/artalk.pug new file mode 100644 index 0000000..762c88d --- /dev/null +++ b/layout/includes/third-party/card-post-count/artalk.pug @@ -0,0 +1,20 @@ +- const { server, site } = theme.artalk + +script. + (() => { + const getArtalkCount = () => { + const runWidget = () => { + Artalk.LoadCountWidget({ + server: '!{server}', + site: '!{site}', + countEl: '.artalk-count' + }) + } + + if (typeof Artalk === 'function') runWidget() + else getScript('!{theme.asset.artalk_js}').then(runWidget) + } + + + window.pjax ? getArtalkCount() : window.addEventListener('load', getArtalkCount) + })() \ No newline at end of file diff --git a/layout/includes/third-party/card-post-count/disqus.pug b/layout/includes/third-party/card-post-count/disqus.pug new file mode 100644 index 0000000..1dfe327 --- /dev/null +++ b/layout/includes/third-party/card-post-count/disqus.pug @@ -0,0 +1,16 @@ +script. + (() => { + const getCount = () => { + if (window.DISQUSWIDGETS === undefined) { + var d = document, s = d.createElement('script'); + s.src = 'https://!{theme.disqus.shortname}.disqus.com/count.js'; + s.id = 'dsq-count-scr'; + (d.head || d.body).appendChild(s); + } else { + DISQUSWIDGETS.getCount({reset: true}); + } + } + + window.pjax ? getCount() : window.addEventListener('load', getCount) + + })() diff --git a/layout/includes/third-party/card-post-count/fb.pug b/layout/includes/third-party/card-post-count/fb.pug new file mode 100644 index 0000000..eee1974 --- /dev/null +++ b/layout/includes/third-party/card-post-count/fb.pug @@ -0,0 +1,18 @@ +- const fbSDKVer = 'v15.0' +- const fbSDK = theme.messenger.enable ? `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk/xfbml.customerchat.js#xfbml=1&version=${fbSDKVer}` : `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk.js#xfbml=1&version=${fbSDKVer}` + +script. + (()=>{ + function loadFBComment () { + if (typeof FB === 'object') FB.XFBML.parse(document.getElementById('recent-posts')) + else { + let ele = document.createElement('script') + ele.setAttribute('src','!{fbSDK}') + ele.setAttribute('async', 'true') + ele.setAttribute('defer', 'true') + ele.setAttribute('crossorigin', 'anonymous') + document.body.appendChild(ele) + } + } + window.pjax ? loadFBComment() : window.addEventListener('load', loadFBComment) + })() diff --git a/layout/includes/third-party/card-post-count/index.pug b/layout/includes/third-party/card-post-count/index.pug new file mode 100644 index 0000000..5b2685c --- /dev/null +++ b/layout/includes/third-party/card-post-count/index.pug @@ -0,0 +1,16 @@ +case theme.comments.use[0] + when 'Twikoo' + include ./twikoo.pug + when 'Disqus' + when 'Disqusjs' + include ./disqus.pug + when 'Valine' + include ./valine.pug + when 'Waline' + include ./waline.pug + when 'Facebook Comments' + include ./fb.pug + when 'Remark42' + include ./remark42.pug + when 'Artalk' + include ./artalk.pug \ No newline at end of file diff --git a/layout/includes/third-party/card-post-count/remark42.pug b/layout/includes/third-party/card-post-count/remark42.pug new file mode 100644 index 0000000..b67164f --- /dev/null +++ b/layout/includes/third-party/card-post-count/remark42.pug @@ -0,0 +1,18 @@ +- const { host, siteId, option } = theme.remark42 + +script. + (()=>{ + window.remark_config = Object.assign({ + host: '!{host}', + site_id: '!{siteId}', + },!{JSON.stringify(option)}) + + function getCount () { + const s = document.createElement('script') + s.src = remark_config.host + '/web/counter.js' + s.defer = true + document.head.appendChild(s) + } + + window.pjax ? getCount() : window.addEventListener('load', getCount) + })() \ No newline at end of file diff --git a/layout/includes/third-party/card-post-count/twikoo.pug b/layout/includes/third-party/card-post-count/twikoo.pug new file mode 100644 index 0000000..314e4ac --- /dev/null +++ b/layout/includes/third-party/card-post-count/twikoo.pug @@ -0,0 +1,37 @@ +script. + (() => { + const getCommentUrl = () => { + const eleGroup = document.querySelectorAll('#recent-posts .article-title') + let urlArray = [] + eleGroup.forEach(i=>{ + urlArray.push(i.getAttribute('href')) + }) + return urlArray + } + + const getCount = () => { + const runTwikoo = () => { + twikoo.getCommentsCount({ + envId: '!{theme.twikoo.envId}', + region: '!{theme.twikoo.region}', + urls: getCommentUrl(), + includeReply: false + }).then(function (res) { + document.querySelectorAll('#recent-posts .twikoo-count').forEach((item,index) => { + item.innerText = res[index].count + }) + }).catch(function (err) { + console.log(err) + }) + } + + if (typeof twikoo === 'object') { + runTwikoo() + } else { + getScript('!{url_for(theme.asset.twikoo)}').then(runTwikoo) + } + } + + window.pjax ? getCount() : window.addEventListener('load', getCount) + + })() \ No newline at end of file diff --git a/layout/includes/third-party/card-post-count/valine.pug b/layout/includes/third-party/card-post-count/valine.pug new file mode 100644 index 0000000..dfe9b6d --- /dev/null +++ b/layout/includes/third-party/card-post-count/valine.pug @@ -0,0 +1,20 @@ +script. + (() => { + function loadValine () { + function initValine () { + let initData = { + el: '#vcomment', + appId: '#{theme.valine.appId}', + appKey: '#{theme.valine.appKey}', + serverURLs: '#{theme.valine.serverURLs}' + } + + const valine = new Valine(initData) + } + + if (typeof Valine === 'function') initValine() + else getScript('!{url_for(theme.asset.valine)}').then(initValine) + } + + window.pjax ? loadValine() : window.addEventListener('load', loadValine) + })() diff --git a/layout/includes/third-party/card-post-count/waline.pug b/layout/includes/third-party/card-post-count/waline.pug new file mode 100644 index 0000000..c43a18d --- /dev/null +++ b/layout/includes/third-party/card-post-count/waline.pug @@ -0,0 +1,18 @@ +script. + (() => { + function loadWaline () { + function initWaline () { + let initData = { + el: null, + serverURL: '!{theme.waline.serverURL}', + comment: true + } + const waline = Waline.init(initData) + } + + if (typeof Waline === 'function') initWaline() + else getScript('!{url_for(theme.asset.waline_js)}').then(initWaline) + } + + window.pjax ? loadWaline() : window.addEventListener('load', loadWaline) + })() diff --git a/layout/includes/third-party/chat/chatra.pug b/layout/includes/third-party/chat/chatra.pug new file mode 100644 index 0000000..b6c1201 --- /dev/null +++ b/layout/includes/third-party/chat/chatra.pug @@ -0,0 +1,33 @@ +//- https://chatra.io/help/api/ +script. + (function(d, w, c) { + w.ChatraID = '#{theme.chatra.id}'; + var s = d.createElement('script'); + w[c] = w[c] || function() { + (w[c].q = w[c].q || []).push(arguments); + }; + s.async = true; + s.src = 'https://call.chatra.io/chatra.js'; + if (d.head) d.head.appendChild(s); + })(document, window, 'Chatra'); + + if (!{theme.chat_btn}) { + var chatBtnFn = () => { + var chatBtn = document.getElementById("chat_btn") + chatBtn.addEventListener("click", function(){ + Chatra('openChat') + }); + } + chatBtnFn() + } else { + if (!{theme.chat_hide_show}) { + function chatBtnHide () { + Chatra('hide') + } + function chatBtnShow () { + Chatra('show') + } + } + } + + diff --git a/layout/includes/third-party/chat/crisp.pug b/layout/includes/third-party/chat/crisp.pug new file mode 100644 index 0000000..cc57e8d --- /dev/null +++ b/layout/includes/third-party/chat/crisp.pug @@ -0,0 +1,36 @@ +script. + window.$crisp = []; + window.CRISP_WEBSITE_ID = "!{theme.crisp.website_id}"; + (function () { + d = document; + s = d.createElement("script"); + s.src = "https://client.crisp.chat/l.js"; + s.async = 1; + d.getElementsByTagName("head")[0].appendChild(s); + })(); + $crisp.push(["safe", true]) + + if (!{theme.chat_btn}) { + $crisp.push(["do", "chat:hide"]) + $crisp.push(["on", "chat:closed", function() { + $crisp.push(["do", "chat:hide"]) + }]) + var chatBtnFn = () => { + var chatBtn = document.getElementById("chat_btn") + chatBtn.addEventListener("click", function(){ + $crisp.push(["do", "chat:show"]) + $crisp.push(["do", "chat:open"]) + + }); + } + chatBtnFn() + } else { + if (!{theme.chat_hide_show}) { + function chatBtnHide () { + $crisp.push(["do", "chat:hide"]) + } + function chatBtnShow () { + $crisp.push(["do", "chat:show"]) + } + } + } \ No newline at end of file diff --git a/layout/includes/third-party/chat/daovoice.pug b/layout/includes/third-party/chat/daovoice.pug new file mode 100644 index 0000000..3c6b064 --- /dev/null +++ b/layout/includes/third-party/chat/daovoice.pug @@ -0,0 +1,40 @@ +//- https://guide.daocloud.io/daovoice/javascript-api-5869833.html +script. + (function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/!{theme.daovoice.app_id}.js","daovoice") + +script. + var isChatBtn = !{theme.chat_btn} + daovoice('init', { + app_id: '!{theme.daovoice.app_id}',},{ + launcher: { + disableLauncherIcon: isChatBtn // 悬浮 ICON 是否显示 + }, + }); + daovoice('update'); + + if (isChatBtn) { + var chatBtnFn = () => { + var chatBtn = document.getElementById("chat_btn") + chatBtn.addEventListener("click", function(){ + daovoice('show') + }); + } + chatBtnFn() + } else { + if (!{theme.chat_hide_show}) { + function chatBtnHide () { + daovoice('update', {},{ + launcher: { + disableLauncherIcon: true // 悬浮 ICON 是否显示 + }, + }); + } + function chatBtnShow () { + daovoice('update', {},{ + launcher: { + disableLauncherIcon: false // 悬浮 ICON 是否显示 + }, + }); + } + } + } \ No newline at end of file diff --git a/layout/includes/third-party/chat/gitter.pug b/layout/includes/third-party/chat/gitter.pug new file mode 100644 index 0000000..46f979a --- /dev/null +++ b/layout/includes/third-party/chat/gitter.pug @@ -0,0 +1,43 @@ +if theme.chat_btn + script. + ((window.gitter = {}).chat = {}).options = { + disableDefaultChat: true, + }; + document.addEventListener('gitter-sidecar-ready', (e) => { + const GitterChat = e.detail.Chat + let chat + + function initGitter () { + chat = new GitterChat({ + room: '#{theme.gitter.room}', + activationElement: '#chat_btn' + }); + } + + initGitter() + + if (!{theme.pjax.enable}) { + document.addEventListener('pjax:complete', () => { + chat.destroy() + initGitter() + }) + } + + }) +else + script. + ((window.gitter = {}).chat = {}).options = { + room: '#{theme.gitter.room}', + }; + + if (!{theme.chat_hide_show}) { + function chatBtnHide () { + document.getElementsByClassName('gitter-open-chat-button')[0].style.display= 'none' + } + + function chatBtnShow () { + document.getElementsByClassName('gitter-open-chat-button')[0].style.display= 'block' + } + } + +script(src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer) diff --git a/layout/includes/third-party/chat/index.pug b/layout/includes/third-party/chat/index.pug new file mode 100644 index 0000000..dc6d0f8 --- /dev/null +++ b/layout/includes/third-party/chat/index.pug @@ -0,0 +1,12 @@ +if theme.chatra && theme.chatra.enable + include ./chatra.pug +else if theme.tidio && theme.tidio.enable + include ./tidio.pug +else if theme.daovoice && theme.daovoice.enable + include ./daovoice.pug +else if theme.gitter && theme.gitter.enable + include ./gitter.pug +else if theme.crisp && theme.crisp.enable + include ./crisp.pug +else if theme.messenger && theme.messenger.enable + include ./messenger.pug \ No newline at end of file diff --git a/layout/includes/third-party/chat/messenger.pug b/layout/includes/third-party/chat/messenger.pug new file mode 100644 index 0000000..e7798ee --- /dev/null +++ b/layout/includes/third-party/chat/messenger.pug @@ -0,0 +1,42 @@ +- let { pageID, lang } = theme.messenger +- lang = theme.comments.use && theme.comments.use.includes('Facebook Comments') ? theme.facebook_comments.lang : lang + +#fb-customer-chat.fb-customerchat(page_id=pageID attribution='biz_inbox') + +script. + document.getElementById('fb-root') ? '' : document.body.insertAdjacentHTML('afterend', '
') + + window.fbAsyncInit = function() { + FB.init({ + xfbml: true, + version: 'v15.0' + }); + }; + + (function(d, s, id) { + var js, fjs = d.getElementsByTagName(s)[0]; + if (d.getElementById(id)) return; + js = d.createElement(s); js.id = id; + js.src = 'https://connect.facebook.net/!{lang}/sdk/xfbml.customerchat.js'; + fjs.parentNode.insertBefore(js, fjs); + }(document, 'script', 'facebook-jssdk')); + + if (!{theme.chat_btn}) { + var chatBtnFn = () => { + var chatBtn = document.getElementById("chat_btn") + chatBtn.addEventListener("click", function(){ + FB.CustomerChat.show(); + }); + } + chatBtnFn() + } else { + if (!{theme.chat_hide_show}) { + function chatBtnHide () { + FB.CustomerChat.hide() + } + function chatBtnShow () { + FB.CustomerChat.show(false) + } + } + } + diff --git a/layout/includes/third-party/chat/tidio.pug b/layout/includes/third-party/chat/tidio.pug new file mode 100644 index 0000000..6b0097f --- /dev/null +++ b/layout/includes/third-party/chat/tidio.pug @@ -0,0 +1,41 @@ +script(src=`//code.tidio.co/${theme.tidio.public_key}.js` async) + +if theme.chat_btn + script. + function onTidioChatApiReady() { + window.tidioChatApi.hide(); + window.tidioChatApi.on("close", function() { + window.tidioChatApi.hide(); + }); + } + if (window.tidioChatApi) { + window.tidioChatApi.on("ready", onTidioChatApiReady); + } else { + document.addEventListener("tidioChat-ready", onTidioChatApiReady); + } + + var chatBtnFn = () => { + document.getElementById("chat_btn").addEventListener("click", function(){ + window.tidioChatApi.show(); + window.tidioChatApi.open(); + }); + } + chatBtnFn() + +else if theme.chat_hide_show + script. + function chatBtnHide () { + if (window.tidioChatApi) { + //- window.tidioChatApi.hide(); + document.getElementById('tidio-chat').style.display= 'none' + } + } + + function chatBtnShow () { + if (window.tidioChatApi) { + //- window.tidioChatApi.show(); + document.getElementById('tidio-chat').style.display= 'block' + } + } + + diff --git a/layout/includes/third-party/comments/artalk.pug b/layout/includes/third-party/comments/artalk.pug new file mode 100644 index 0000000..97a5cd5 --- /dev/null +++ b/layout/includes/third-party/comments/artalk.pug @@ -0,0 +1,45 @@ +- const { server, site, option } = theme.artalk + +script. + function addArtalkSource () { + const ele = document.createElement('link') + ele.rel = 'stylesheet' + ele.href= '!{theme.asset.artalk_css}' + document.getElementsByTagName('head')[0].appendChild(ele) + } + + function loadArtalk () { + function initArtalk () { + window.artalkItem = new Artalk(Object.assign({ + el: '#artalk-wrap', + server: '!{server}', + site: '!{site}', + pageKey: location.pathname, + darkMode: document.documentElement.getAttribute('data-theme') === 'dark', + countEl: '.artalk-count' + },!{JSON.stringify(option)})) + } + + if (typeof window.artalkItem === 'object') setTimeout(()=>{initArtalk()},200) + else { + addArtalkSource() + typeof Artalk !== 'function' ? getScript('!{theme.asset.artalk_js}').then(initArtalk) + : setTimeout(()=>{initArtalk()},200) + } + } + + document.getElementById('darkmode').addEventListener('click',()=> { + if (typeof window.artalkItem !== 'object') return + let isDark = document.documentElement.getAttribute('data-theme') === 'dark' + window.artalkItem.setDarkMode(!isDark) + }) + + + if ('!{theme.comments.use[0]}' === 'Artalk' || !!{theme.comments.lazyload}) { + if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('artalk-wrap'), loadArtalk) + else loadArtalk() + } else { + function loadOtherComment () { + loadArtalk() + } + } \ No newline at end of file diff --git a/layout/includes/third-party/comments/disqus.pug b/layout/includes/third-party/comments/disqus.pug new file mode 100644 index 0000000..caa1222 --- /dev/null +++ b/layout/includes/third-party/comments/disqus.pug @@ -0,0 +1,51 @@ +- let disqusPageTitle = page.title.replace(/'/ig,"\\'") + +script. + function loadDisqus () { + var disqus_config = function () { + this.page.url = '!{ page.permalink }' + this.page.identifier = '!{ url_for(page.path) }' + this.page.title = '!{ disqusPageTitle }' + }; + + window.disqusReset = () => { + DISQUS.reset({ + reload: true, + config: disqus_config + }) + } + + if (window.DISQUS) disqusReset() + else { + (function() { + var d = document, s = d.createElement('script'); + s.src = 'https://!{theme.disqus.shortname}.disqus.com/embed.js'; + s.setAttribute('data-timestamp', +new Date()); + (d.head || d.body).appendChild(s); + })(); + } + + document.getElementById('darkmode').addEventListener('click', () => { + setTimeout(() => window.disqusReset(), 200) + }) + } + + if ('!{theme.comments.use[0]}' === 'Disqus' || !!{theme.comments.lazyload}) { + if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('disqus_thread'), loadDisqus) + else loadDisqus() + } else { + function loadOtherComment () { + loadDisqus() + } + } + +if is_post() && !theme.comments.lazyload && theme.comments.count && theme.comments.use[0] === 'Disqus' + script. + if (window.DISQUSWIDGETS === undefined) { + var d = document, s = d.createElement('script'); + s.src = 'https://!{theme.disqus.shortname}.disqus.com/count.js'; + s.id = 'dsq-count-scr'; + (d.head || d.body).appendChild(s); + } else { + DISQUSWIDGETS.getCount({reset: true}); + } diff --git a/layout/includes/third-party/comments/disqusjs.pug b/layout/includes/third-party/comments/disqusjs.pug new file mode 100644 index 0000000..1e66555 --- /dev/null +++ b/layout/includes/third-party/comments/disqusjs.pug @@ -0,0 +1,64 @@ +- let disqusjsPageTitle = page.title.replace(/'/ig,"\\'") + +script. + function loadDisqusjs () { + function addDisqusjsCSS () { + const ele = document.createElement('link') + ele.rel = 'stylesheet' + ele.href= '!{url_for(theme.asset.disqusjs_css)}' + document.getElementsByTagName('head')[0].appendChild(ele) + } + + function initDisqusjs () { + window.disqusjs = null + disqusjs = new DisqusJS(Object.assign({ + shortname: '!{theme.disqusjs.shortname}', + identifier: '!{ url_for(page.path) }', + url: '!{ page.permalink }', + title: '!{ disqusjsPageTitle }', + apikey: '!{theme.disqusjs.apikey}', + },!{JSON.stringify(theme.disqusjs.option)})) + + disqusjs.render(document.getElementById('disqusjs')) + } + + const themeChange = () => { + const ele = document.getElementById('disqus_thread') + if(!ele) return + disqusjs.destroy() + initDisqusjs() + } + + + document.getElementById('darkmode').addEventListener('click', themeChange) + + if (window.disqusJsLoad) initDisqusjs() + else { + addDisqusjsCSS() + getScript('!{url_for(theme.asset.disqusjs)}').then(initDisqusjs) + window.disqusJsLoad = true + } + } + + if ('!{theme.comments.use[0]}' === 'Disqusjs' || !!{theme.comments.lazyload}) { + if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('disqusjs'), loadDisqusjs) + else loadDisqusjs() + } + else { + function loadOtherComment () { + loadDisqusjs() + } + } + + +if is_post() && !theme.comments.lazyload && theme.comments.count && theme.comments.use[0] === 'Disqusjs' + script. + if (window.DISQUSWIDGETS === undefined) { + var d = document, s = d.createElement('script'); + s.src = 'https://!{theme.disqus.shortname}.disqus.com/count.js'; + s.id = 'dsq-count-scr'; + (d.head || d.body).appendChild(s); + } else { + DISQUSWIDGETS.getCount({reset: true}); + } + diff --git a/layout/includes/third-party/comments/facebook_comments.pug b/layout/includes/third-party/comments/facebook_comments.pug new file mode 100644 index 0000000..5d4d399 --- /dev/null +++ b/layout/includes/third-party/comments/facebook_comments.pug @@ -0,0 +1,36 @@ +- const fbSDKVer = 'v15.0' +- const fbSDK = theme.messenger.enable ? `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk/xfbml.customerchat.js#xfbml=1&version=${fbSDKVer}` : `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk.js#xfbml=1&version=${fbSDKVer}` + +script. + function loadFBComment () { + document.getElementById('fb-root') ? '' : document.body.insertAdjacentHTML('afterend', '
') + + const themeNow = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' + const $fbComment = document.getElementsByClassName('fb-comments')[0] + $fbComment.setAttribute('data-colorscheme',themeNow) + $fbComment.setAttribute('data-href', '!{urlNoIndex(page.permalink)}') + + if (typeof FB === 'object') { + FB.XFBML.parse(document.getElementsByClassName('post-meta-commentcount')[0]) + FB.XFBML.parse(document.getElementById('post-comment')) + } + else { + let ele = document.createElement('script') + ele.setAttribute('src','!{fbSDK}') + ele.setAttribute('async', 'true') + ele.setAttribute('defer', 'true') + ele.setAttribute('crossorigin', 'anonymous') + ele.setAttribute('id', 'facebook-jssdk') + document.getElementById('fb-root').insertAdjacentElement('afterbegin',ele) + } + } + + if ('!{theme.comments.use[0]}' === 'Facebook Comments' || !!{theme.comments.lazyload}) { + if (!{theme.comments.lazyload}) btf.loadComment(document.querySelector('#post-comment .fb-comments'), loadFBComment) + else loadFBComment() + } else { + function loadOtherComment () { + loadFBComment() + } + } + diff --git a/layout/includes/third-party/comments/giscus.pug b/layout/includes/third-party/comments/giscus.pug new file mode 100644 index 0000000..df19568 --- /dev/null +++ b/layout/includes/third-party/comments/giscus.pug @@ -0,0 +1,49 @@ +- const { repo, repo_id, category_id, option } = theme.giscus +- const themes = theme.giscus.theme +script. + function loadGiscus () { + let nowTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{themes.dark}' : '!{themes.light}' + + const config = Object.assign({ + src: 'https://giscus.app/client.js', + 'data-repo': '!{repo}', + 'data-repo-id': '!{repo_id}', + 'data-category-id': '!{category_id}', + 'data-mapping': 'pathname', + 'data-theme': nowTheme, + 'data-reactions-enabled': '1', + crossorigin: 'anonymous', + async: true + },!{JSON.stringify(option)}) + + let ele = document.createElement('script') + for (let key in config) { + ele.setAttribute(key, config[key]) + } + document.getElementById('giscus-wrap').insertAdjacentElement('afterbegin',ele) + } + + function changeGiscusTheme () { + const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{themes.dark}' : '!{themes.light}' + + function sendMessage(message) { + const iframe = document.querySelector('iframe.giscus-frame'); + if (!iframe) return; + iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app'); + } + + sendMessage({ + setConfig: { + theme: theme + } + }); + } + + if ('!{theme.comments.use[0]}' === 'Giscus' || !!{theme.comments.lazyload}) { + if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('giscus-wrap'), loadGiscus) + else loadGiscus() + } else { + function loadOtherComment () { + loadGiscus() + } + } diff --git a/layout/includes/third-party/comments/gitalk.pug b/layout/includes/third-party/comments/gitalk.pug new file mode 100644 index 0000000..fccb64d --- /dev/null +++ b/layout/includes/third-party/comments/gitalk.pug @@ -0,0 +1,48 @@ +script. + function addGitalkSource () { + const ele = document.createElement('link') + ele.rel = 'stylesheet' + ele.href= '!{url_for(theme.asset.gitalk_css)}' + document.getElementsByTagName('head')[0].appendChild(ele) + } + + function loadGitalk () { + function initGitalk () { + var gitalk = new Gitalk(Object.assign({ + clientID: '!{theme.gitalk.client_id}', + clientSecret: '!{theme.gitalk.client_secret}', + repo: '!{theme.gitalk.repo}', + owner: '!{theme.gitalk.owner}', + admin: ['!{theme.gitalk.admin}'], + id: '!{md5(page.path)}', + updateCountCallback: commentCount + },!{JSON.stringify(theme.gitalk.option)})) + + gitalk.render('gitalk-container') + } + + if (typeof Gitalk === 'function') initGitalk() + else { + addGitalkSource() + getScript('!{url_for(theme.asset.gitalk)}').then(initGitalk) + } + } + + function commentCount(n){ + let isCommentCount = document.querySelector('#post-meta .gitalk-comment-count') + if (isCommentCount) { + isCommentCount.innerHTML= n + } + } + + if ('!{theme.comments.use[0]}' === 'Gitalk' || !!{theme.comments.lazyload}) { + if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('gitalk-container'), loadGitalk) + else loadGitalk() + } else { + function loadOtherComment () { + loadGitalk() + } + } + + + diff --git a/layout/includes/third-party/comments/index.pug b/layout/includes/third-party/comments/index.pug new file mode 100644 index 0000000..0821ae5 --- /dev/null +++ b/layout/includes/third-party/comments/index.pug @@ -0,0 +1,46 @@ +- let defaultComment = theme.comments.use[0] +hr +#post-comment + .comment-head + .comment-headline + i.fas.fa-comments.fa-fw + span= ' ' + _p('comment') + + if theme.comments.use.length > 1 + #comment-switch + span.first-comment=defaultComment + span.switch-btn + span.second-comment=theme.comments.use[1] + + + .comment-wrap + each name in theme.comments.use + div + case name + when 'Disqus' + #disqus_thread + when 'Valine' + #vcomment.vcomment + when 'Disqusjs' + #disqusjs + when 'Livere' + #lv-container(data-id="city" data-uid=theme.livere.uid) + when 'Gitalk' + #gitalk-container + when 'Utterances' + #utterances-wrap + when 'Twikoo' + #twikoo-wrap + when 'Waline' + #waline-wrap + when 'Giscus' + #giscus-wrap + when 'Facebook Comments' + .fb-comments(data-colorscheme = theme.display_mode === 'dark' ? 'dark' : 'light' + data-numposts= theme.facebook_comments.pageSize || 10 + data-order-by= theme.facebook_comments.order_by || 'social' + data-width="100%") + when 'Remark42' + #remark42 + when 'Artalk' + #artalk-wrap diff --git a/layout/includes/third-party/comments/js.pug b/layout/includes/third-party/comments/js.pug new file mode 100644 index 0000000..bf1d872 --- /dev/null +++ b/layout/includes/third-party/comments/js.pug @@ -0,0 +1,26 @@ +each name in theme.comments.use + case name + when 'Valine' + !=partial('includes/third-party/comments/valine', {}, {cache: true}) + when 'Disqus' + include ./disqus.pug + when 'Disqusjs' + include ./disqusjs.pug + when 'Livere' + !=partial('includes/third-party/comments/livere', {}, {cache: true}) + when 'Gitalk' + include ./gitalk.pug + when 'Utterances' + !=partial('includes/third-party/comments/utterances', {}, {cache: true}) + when 'Twikoo' + !=partial('includes/third-party/comments/twikoo', {}, {cache: true}) + when 'Waline' + !=partial('includes/third-party/comments/waline', {}, {cache: true}) + when 'Giscus' + !=partial('includes/third-party/comments/giscus', {}, {cache: true}) + when 'Facebook Comments' + include ./facebook_comments.pug + when 'Remark42' + !=partial('includes/third-party/comments/remark42', {}, {cache: true}) + when 'Artalk' + !=partial('includes/third-party/comments/artalk', {}, {cache: true}) \ No newline at end of file diff --git a/layout/includes/third-party/comments/livere.pug b/layout/includes/third-party/comments/livere.pug new file mode 100644 index 0000000..85b6d78 --- /dev/null +++ b/layout/includes/third-party/comments/livere.pug @@ -0,0 +1,26 @@ +script. + function loadLivere () { + if (typeof LivereTower === 'object') { + window.LivereTower.init() + } + else { + (function(d, s) { + var j, e = d.getElementsByTagName(s)[0]; + if (typeof LivereTower === 'function') { return; } + j = d.createElement(s); + j.src = 'https://cdn-city.livere.com/js/embed.dist.js'; + j.async = true; + e.parentNode.insertBefore(j, e); + })(document, 'script'); + } + } + + if ('!{theme.comments.use[0]}' === 'Livere' || !!{theme.comments.lazyload}) { + if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('lv-container'), loadLivere) + else loadLivere() + } + else { + function loadOtherComment () { + loadLivere() + } + } \ No newline at end of file diff --git a/layout/includes/third-party/comments/remark42.pug b/layout/includes/third-party/comments/remark42.pug new file mode 100644 index 0000000..d6d49a6 --- /dev/null +++ b/layout/includes/third-party/comments/remark42.pug @@ -0,0 +1,67 @@ +- const { host, siteId, option } = theme.remark42 +script. + var remark_config = Object.assign({ + host: '!{host}', + site_id: '!{siteId}', + components: ['embed'], + theme: document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' + },!{JSON.stringify(option)}) + + function addRemark42(){ + for (let i = 0; i < remark_config.components.length; i++) { + const s = document.createElement('script') + s.src = remark_config.host + '/web/' + remark_config.components[i] + '.js' + s.defer = true + document.head.appendChild(s) + } + } + + function initRemark42() { + if (window.REMARK42) { + if (this.remark42Instance) { + this.remark42Instance.destroy() + } + + this.remark42Instance = window.REMARK42.createInstance({ + ...remark_config + }) + } + } + + function getCount () { + const ele = document.querySelector('.remark42__counter') + if (ele) { + const s = document.createElement('script') + s.src = remark_config.host + '/web/counter.js' + s.defer = true + document.head.appendChild(s) + } + } + + function loadRemark42 () { + if (window.REMARK42) { + this.initRemark42() + getCount() + } else { + addRemark42() + window.addEventListener('REMARK42::ready', () => { + this.initRemark42() + getCount() + }) + } + } + + document.getElementById('darkmode').addEventListener('click',()=>{ + if (!window.REMARK42) return + let theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark' + window.REMARK42.changeTheme(theme) + }) + + if ('!{theme.comments.use[0]}' === 'Remark42' || !!{theme.comments.lazyload}) { + if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('remark42'), loadRemark42) + else loadRemark42() + } else { + function loadOtherComment () { + loadRemark42() + } + } diff --git a/layout/includes/third-party/comments/twikoo.pug b/layout/includes/third-party/comments/twikoo.pug new file mode 100644 index 0000000..437a42f --- /dev/null +++ b/layout/includes/third-party/comments/twikoo.pug @@ -0,0 +1,53 @@ +- const { envId, region, option } = theme.twikoo +- const { use, lazyload, count } = theme.comments + +script. + (()=>{ + const init = () => { + twikoo.init(Object.assign({ + el: '#twikoo-wrap', + envId: '!{envId}', + region: '!{region}', + onCommentLoaded: function () { + btf.loadLightbox(document.querySelectorAll('#twikoo .tk-content img:not(.tk-owo-emotion)')) + } + }, !{JSON.stringify(option)})) + } + + const getCount = () => { + const countELement = document.getElementById('twikoo-count') + if(!countELement) return + twikoo.getCommentsCount({ + envId: '!{envId}', + region: '!{region}', + urls: [window.location.pathname], + includeReply: false + }).then(function (res) { + countELement.innerText = res[0].count + }).catch(function (err) { + console.error(err); + }); + } + + const runFn = () => { + init() + !{count ? 'GLOBAL_CONFIG_SITE.isPost && getCount()' : ''} + } + + const loadTwikoo = () => { + if (typeof twikoo === 'object') { + setTimeout(runFn,0) + return + } + getScript('!{url_for(theme.asset.twikoo)}').then(runFn) + } + + if ('!{use[0]}' === 'Twikoo' || !!{lazyload}) { + if (!{lazyload}) btf.loadComment(document.getElementById('twikoo-wrap'), loadTwikoo) + else loadTwikoo() + } else { + window.loadOtherComment = () => { + loadTwikoo() + } + } + })() \ No newline at end of file diff --git a/layout/includes/third-party/comments/utterances.pug b/layout/includes/third-party/comments/utterances.pug new file mode 100644 index 0000000..7f61831 --- /dev/null +++ b/layout/includes/third-party/comments/utterances.pug @@ -0,0 +1,34 @@ +script. + function loadUtterances () { + let ele = document.createElement('script') + ele.setAttribute('id', 'utterances_comment') + ele.setAttribute('src', 'https://utteranc.es/client.js') + ele.setAttribute('repo', '!{theme.utterances.repo}') + ele.setAttribute('issue-term', '!{theme.utterances.issue_term}') + let nowTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? '#{theme.utterances.dark_theme}' : '#{theme.utterances.light_theme}' + ele.setAttribute('theme', nowTheme) + ele.setAttribute('crossorigin', 'anonymous') + ele.setAttribute('async', 'true') + document.getElementById('utterances-wrap').insertAdjacentElement('afterbegin',ele) + } + + function utterancesTheme () { + const iframe = document.querySelector('.utterances-frame') + if (iframe) { + const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '#{theme.utterances.dark_theme}' : '#{theme.utterances.light_theme}' + const message = { + type: 'set-theme', + theme: theme + }; + iframe.contentWindow.postMessage(message, 'https://utteranc.es'); + } + } + + if ('!{theme.comments.use[0]}' === 'Utterances' || !!{theme.comments.lazyload}) { + if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('utterances-wrap'), loadUtterances) + else loadUtterances() + } else { + function loadOtherComment () { + loadUtterances() + } + } diff --git a/layout/includes/third-party/comments/valine.pug b/layout/includes/third-party/comments/valine.pug new file mode 100644 index 0000000..025849e --- /dev/null +++ b/layout/includes/third-party/comments/valine.pug @@ -0,0 +1,33 @@ +- let emojiMaps = '""' +if site.data.valine + - emojiMaps = JSON.stringify(site.data.valine) + +script. + function loadValine () { + function initValine () { + const valine = new Valine(Object.assign({ + el: '#vcomment', + appId: '#{theme.valine.appId}', + appKey: '#{theme.valine.appKey}', + avatar: '#{theme.valine.avatar}', + serverURLs: '#{theme.valine.serverURLs}', + emojiMaps: !{emojiMaps}, + path: window.location.pathname, + visitor: #{theme.valine.visitor} + }, !{JSON.stringify(theme.valine.option)})) + } + + if (typeof Valine === 'function') initValine() + else getScript('!{url_for(theme.asset.valine)}').then(initValine) + } + + if ('!{theme.comments.use[0]}' === 'Valine' || !!{theme.comments.lazyload}) { + if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('vcomment'),loadValine) + else setTimeout(loadValine, 0) + } else { + function loadOtherComment () { + loadValine() + } + } + + diff --git a/layout/includes/third-party/comments/waline.pug b/layout/includes/third-party/comments/waline.pug new file mode 100644 index 0000000..06e8078 --- /dev/null +++ b/layout/includes/third-party/comments/waline.pug @@ -0,0 +1,40 @@ +- const { serverURL, option, pageview } = theme.waline +- const { lazyload, count, use } = theme.comments + +script. + function loadWaline () { + function insertCSS () { + const link = document.createElement("link") + link.rel = "stylesheet" + link.href = "!{url_for(theme.asset.waline_css)}" + document.head.appendChild(link) + } + + function initWaline () { + const waline = Waline.init(Object.assign({ + el: '#waline-wrap', + serverURL: '!{serverURL}', + pageview: !{lazyload ? false : pageview}, + dark: 'html[data-theme="dark"]', + path: window.location.pathname, + comment: !{lazyload ? false : count}, + }, !{JSON.stringify(option)})) + } + + if (typeof Waline === 'function') initWaline() + else { + insertCSS() + getScript('!{url_for(theme.asset.waline_js)}').then(initWaline) + } + } + + if ('!{use[0]}' === 'Waline' || !!{lazyload}) { + if (!{lazyload}) btf.loadComment(document.getElementById('waline-wrap'),loadWaline) + else setTimeout(loadWaline, 0) + } else { + function loadOtherComment () { + loadWaline() + } + } + + diff --git a/layout/includes/third-party/effect.pug b/layout/includes/third-party/effect.pug new file mode 100644 index 0000000..275297c --- /dev/null +++ b/layout/includes/third-party/effect.pug @@ -0,0 +1,35 @@ +if theme.fireworks && theme.fireworks.enable + canvas.fireworks(mobile=`${theme.fireworks.mobile}`) + script(src=url_for(theme.asset.fireworks)) + +if (theme.canvas_ribbon && theme.canvas_ribbon.enable) + script(defer id="ribbon" src=url_for(theme.asset.canvas_ribbon) size=theme.canvas_ribbon.size + alpha=theme.canvas_ribbon.alpha zIndex=theme.canvas_ribbon.zIndex mobile=`${theme.canvas_ribbon.mobile}` data-click=`${theme.canvas_ribbon.click_to_change}`) + +if (theme.canvas_fluttering_ribbon && theme.canvas_fluttering_ribbon.enable) + script(defer id="fluttering_ribbon" mobile=`${theme.canvas_fluttering_ribbon.mobile}` src=url_for(theme.asset.canvas_fluttering_ribbon)) + +if (theme.canvas_nest && theme.canvas_nest.enable) + script#canvas_nest(defer color=theme.canvas_nest.color opacity=theme.canvas_nest.opacity zIndex=theme.canvas_nest.zIndex count=theme.canvas_nest.count mobile=`${theme.canvas_nest.mobile}` src=url_for(theme.asset.canvas_nest)) + +if theme.activate_power_mode.enable + script(src=url_for(theme.asset.activate_power_mode)) + script. + POWERMODE.colorful = !{theme.activate_power_mode.colorful}; + POWERMODE.shake = !{theme.activate_power_mode.shake}; + POWERMODE.mobile = !{theme.activate_power_mode.mobile}; + document.body.addEventListener('input', POWERMODE); + +//- 鼠標特效 +if theme.click_heart && theme.click_heart.enable + script#click-heart(src=url_for(theme.asset.click_heart) async mobile=`${theme.click_heart.mobile}`) + +if theme.ClickShowText && theme.ClickShowText.enable + script#click-show-text( + src= url_for(theme.asset.ClickShowText) + data-mobile= `${theme.ClickShowText.mobile}` + data-text= theme.ClickShowText.text.join(",") + data-fontsize= theme.ClickShowText.fontSize + data-random= `${theme.ClickShowText.random}` + async + ) \ No newline at end of file diff --git a/layout/includes/third-party/math/index.pug b/layout/includes/third-party/math/index.pug new file mode 100644 index 0000000..2b16302 --- /dev/null +++ b/layout/includes/third-party/math/index.pug @@ -0,0 +1,18 @@ +if theme.mathjax && theme.mathjax.enable + if theme.mathjax.per_page + if is_post() || is_page() + include ./mathjax.pug + else + if page.mathjax + include ./mathjax.pug + +if theme.katex && theme.katex.enable + if theme.katex.per_page + if is_post() || is_page() + include ./katex.pug + else + if page.katex + include ./katex.pug + +if theme.mermaid.enable + include ./mermaid.pug \ No newline at end of file diff --git a/layout/includes/third-party/math/katex.pug b/layout/includes/third-party/math/katex.pug new file mode 100644 index 0000000..c1f0bd6 --- /dev/null +++ b/layout/includes/third-party/math/katex.pug @@ -0,0 +1,9 @@ +link(rel="stylesheet" type="text/css" href=url_for(theme.asset.katex)) +script(src=url_for(theme.asset.katex_copytex)) +script. + (() => { + document.querySelectorAll('#article-container span.katex-display').forEach(item => { + btf.wrap(item, 'div', { class: 'katex-wrap'}) + }) + })() + \ No newline at end of file diff --git a/layout/includes/third-party/math/mathjax.pug b/layout/includes/third-party/math/mathjax.pug new file mode 100644 index 0000000..229d472 --- /dev/null +++ b/layout/includes/third-party/math/mathjax.pug @@ -0,0 +1,47 @@ +//- Mathjax 3 +script. + if (!window.MathJax) { + window.MathJax = { + tex: { + inlineMath: [ ['$','$'], ["\\(","\\)"]], + tags: 'ams' + }, + chtml: { + scale: 1.1 + }, + options: { + renderActions: { + findScript: [10, doc => { + for (const node of document.querySelectorAll('script[type^="math/tex"]')) { + const display = !!node.type.match(/; *mode=display/) + const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display) + const text = document.createTextNode('') + node.parentNode.replaceChild(text, node) + math.start = {node: text, delim: '', n: 0} + math.end = {node: text, delim: '', n: 0} + doc.math.push(math) + } + }, ''], + insertScript: [200, () => { + document.querySelectorAll('mjx-container').forEach(node => { + if (node.hasAttribute('display')) { + btf.wrap(node, 'div', { class: 'mathjax-overflow' }) + } else { + btf.wrap(node, 'span', { class: 'mathjax-overflow' }) + } + }); + }, '', false] + } + } + } + + const script = document.createElement('script') + script.src = '!{url_for(theme.asset.mathjax)}' + script.id = 'MathJax-script' + script.async = true + document.head.appendChild(script) + } else { + MathJax.startup.document.state(0) + MathJax.texReset() + MathJax.typeset() + } \ No newline at end of file diff --git a/layout/includes/third-party/math/mermaid.pug b/layout/includes/third-party/math/mermaid.pug new file mode 100644 index 0000000..5b7b496 --- /dev/null +++ b/layout/includes/third-party/math/mermaid.pug @@ -0,0 +1,26 @@ +script. + (() => { + const $mermaidWrap = document.querySelectorAll('#article-container .mermaid-wrap') + if ($mermaidWrap.length) { + window.runMermaid = () => { + window.loadMermaid = true + const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{theme.mermaid.theme.dark}' : '!{theme.mermaid.theme.light}' + + Array.from($mermaidWrap).forEach((item, index) => { + const mermaidSrc = item.firstElementChild + const mermaidThemeConfig = '%%{init:{ \'theme\':\'' + theme + '\'}}%%\n' + const mermaidID = 'mermaid-' + index + const mermaidDefinition = mermaidThemeConfig + mermaidSrc.textContent + mermaid.mermaidAPI.render(mermaidID, mermaidDefinition, (svgCode) => { + mermaidSrc.insertAdjacentHTML('afterend', svgCode) + }) + }) + } + + const loadMermaid = () => { + window.loadMermaid ? runMermaid() : getScript('!{url_for(theme.asset.mermaid)}').then(runMermaid) + } + + window.pjax ? loadMermaid() : document.addEventListener('DOMContentLoaded', loadMermaid) + } + })() \ No newline at end of file diff --git a/layout/includes/third-party/newest-comments/artalk.pug b/layout/includes/third-party/newest-comments/artalk.pug new file mode 100644 index 0000000..a51df13 --- /dev/null +++ b/layout/includes/third-party/newest-comments/artalk.pug @@ -0,0 +1,82 @@ +- const { server, option } = theme.artalk +- const avatarCdn = option !== null && option.gravatar ? option.gravatar.mirror : 'https://sdn.geekzu.org/avatar/' +- const avatarDefault = option !== null && option.gravatar ? option.gravatar.default : 'mp' + +script. + window.addEventListener('load', () => { + const changeContent = (content) => { + if (content === '') return content + + content = content.replace(/]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link + content = content.replace(/]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url + content = content.replace(/
.*?<\/pre>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
+      content = content.replace(/<[^>]+>/g,"") // remove html tag
+
+      if (content.length > 150) {
+        content = content.substring(0,150) + '...'
+      }
+      return content
+    }
+
+    const generateHtml = array => {
+      let result = ''
+
+      if (array.length) {
+        for (let i = 0; i < array.length; i++) {
+          result += '
' + + if (!{theme.newest_comments.avatar}) { + const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}' + result += `${array[i].nick}` + } + + result += `
+ ${array[i].content} +
${array[i].nick} /
+
` + } + } else { + result += '!{_p("aside.card_newest_comments.zero")}' + } + + let $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= result + window.lazyLoadInstance && window.lazyLoadInstance.update() + window.pjax && window.pjax.refresh($dom) + } + + const getComment = () => { + fetch('!{server}/api/stat?type=latest_comments&limit=!{theme.newest_comments.limit}',{method: "POST"}) + .then(response => response.json()) + .then(d => { + const artalk = d.data.map(function (e) { + return { + 'avatar': '!{avatarCdn}' + e.email_encrypted + '?d=!{avatarDefault}', + 'content': changeContent(e.content_marked), + 'nick': e.nick, + 'url': e.page_url, + 'date': e.date, + } + }) + saveToLocal.set('artalk-newest-comments', JSON.stringify(artalk), !{theme.newest_comments.storage}/(60*24)) + generateHtml(artalk) + }).catch(e => { + const $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" + }) + } + + const newestCommentInit = () => { + if (document.querySelector('#card-newest-comments .aside-list')) { + const data = saveToLocal.get('artalk-newest-comments') + if (data) { + generateHtml(JSON.parse(data)) + } else { + getComment() + } + } + } + + newestCommentInit() + document.addEventListener('pjax:complete', newestCommentInit) + }) diff --git a/layout/includes/third-party/newest-comments/disqus-comment.pug b/layout/includes/third-party/newest-comments/disqus-comment.pug new file mode 100644 index 0000000..5b95e74 --- /dev/null +++ b/layout/includes/third-party/newest-comments/disqus-comment.pug @@ -0,0 +1,82 @@ +script. + window.addEventListener('load', () => { + const changeContent = (content) => { + if (content === '') return content + + content = content.replace(/]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link + content = content.replace(/]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url + content = content.replace(/.*?<\/code>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code + content = content.replace(/<[^>]+>/g,"") // remove html tag + + if (content.length > 150) { + content = content.substring(0,150) + '...' + } + return content + } + + const getComment = () => { + fetch('https://disqus.com/api/3.0/forums/listPosts.json?forum=!{forum}&related=thread&limit=!{theme.newest_comments.limit}&api_key=!{apiKey}') + .then(response => response.json()) + .then(data => { + const disqusArray = data.response.map(item => { + return { + 'avatar': item.author.avatar.cache, + 'content': changeContent(item.message), + 'nick': item.author.name, + 'url': item.url, + 'date': item.createdAt + } + }) + + saveToLocal.set('disqus-newest-comments', JSON.stringify(disqusArray), !{theme.newest_comments.storage}/(60*24)) + generateHtml(disqusArray) + }).catch(e => { + const $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" + }) + } + + const generateHtml = array => { + let result = '' + + if (array.length) { + for (let i = 0; i < array.length; i++) { + result += '
' + + if (!{theme.newest_comments.avatar}) { + const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}' + result += `${array[i].nick}` + } + + result += `
+ ${array[i].content} +
${array[i].nick}
+
` + } + } else { + result += '!{_p("aside.card_newest_comments.zero")}' + } + + let $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= result + window.lazyLoadInstance && window.lazyLoadInstance.update() + window.pjax && window.pjax.refresh($dom) + } + + const newestCommentInit = () => { + if (document.querySelector('#card-newest-comments .aside-list')) { + const data = saveToLocal.get('disqus-newest-comments') + if (data) { + generateHtml(JSON.parse(data)) + } else { + getComment() + } + } + } + + newestCommentInit() + document.addEventListener('pjax:complete', newestCommentInit) + }) + + + diff --git a/layout/includes/third-party/newest-comments/github-issues.pug b/layout/includes/third-party/newest-comments/github-issues.pug new file mode 100644 index 0000000..2153b11 --- /dev/null +++ b/layout/includes/third-party/newest-comments/github-issues.pug @@ -0,0 +1,109 @@ +script. + window.addEventListener('load', () => { + const changeContent = (content) => { + if (content === '') return content + + content = content.replace(/]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link + content = content.replace(/]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url + content = content.replace(/
.*?<\/pre>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
+      content = content.replace(/<[^>]+>/g,"") // remove html tag
+
+      if (content.length > 150) {
+        content = content.substring(0,150) + '...'
+      }
+      return content
+    }
+
+    const findTrueUrl = (array) => {
+      Promise.all(array.map(item =>
+        fetch(item.url).then(resp => resp.json()).then(data => {
+          const urlArray = data.body.match(/(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?/ig)
+          if (data.user.login === 'utterances-bot') {
+            return urlArray.pop()
+          } else {
+            return urlArray.shift()
+          }
+        })
+      )).then(res => {
+          array = array.map((i,index)=> {
+            return {
+              ...i,
+              url: res[index]
+            }
+          })
+
+          saveToLocal.set('github-newest-comments', JSON.stringify(array), !{theme.newest_comments.storage}/(60*24))
+          generateHtml(array)
+      });
+    }
+
+    const getComment = () => {
+      fetch('https://api.github.com/repos/!{userRepo}/issues/comments?sort=updated&direction=desc&per_page=!{theme.newest_comments.limit}&page=1',{
+        "headers": {
+          Accept: 'application/vnd.github.v3.html+json'
+        }
+      })
+        .then(response => response.json())
+        .then(data => {
+          const githubArray = data.map(item => {
+            return {
+              'avatar': item.user.avatar_url,
+              'content': changeContent(item.body_html),
+              'nick': item.user.login,
+              'url': item.issue_url,
+              'date': item.updated_at,
+              'githubUrl': item.html_url
+            }
+          })
+          findTrueUrl(githubArray)
+        }).catch(e => {
+          const $dom = document.querySelector('#card-newest-comments .aside-list')
+          $dom.innerHTML= "!{_p('aside.card_newest_comments.error')}"
+        })
+    }
+
+    const generateHtml = array => {
+      let result = ''
+
+      if (array.length) {
+        for (let i = 0; i < array.length; i++) {
+          result += '
' + + if (!{theme.newest_comments.avatar}) { + const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}' + result += `${array[i].nick}` + } + + result += `
+ ${array[i].content} +
${array[i].nick} /
+
` + } + } else { + result += '!{_p("aside.card_newest_comments.zero")}' + } + + let $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= result + window.lazyLoadInstance && window.lazyLoadInstance.update() + window.pjax && window.pjax.refresh($dom) + } + + const newestCommentInit = () => { + if (document.querySelector('#card-newest-comments .aside-list')) { + const data = saveToLocal.get('github-newest-comments') + if (data) { + generateHtml(JSON.parse(data)) + } else { + getComment() + } + } + } + + newestCommentInit() + document.addEventListener('pjax:complete', newestCommentInit) + }) + + + + diff --git a/layout/includes/third-party/newest-comments/index.pug b/layout/includes/third-party/newest-comments/index.pug new file mode 100644 index 0000000..8ceaccf --- /dev/null +++ b/layout/includes/third-party/newest-comments/index.pug @@ -0,0 +1,30 @@ +- let { use } = theme.comments + +if use + - let forum,apiKey,userRepo + case use[0] + when 'Valine' + include ./valine.pug + when 'Waline' + include ./waline.pug + when 'Twikoo' + include ./twikoo-comment.pug + when 'Disqus' + - forum = theme.disqus.shortname + - apiKey = theme.disqus.apikey + include ./disqus-comment.pug + when 'Disqusjs' + - forum = theme.disqusjs.shortname + - apiKey = theme.disqusjs.apikey + include ./disqus-comment.pug + when 'Gitalk' + - let { repo,owner } = theme.gitalk + - userRepo = owner + '/' + repo + include ./github-issues.pug + when 'Utterances' + - userRepo = theme.utterances.repo + include ./github-issues.pug + when 'Remark42' + include ./remark42.pug + when 'Artalk' + include ./artalk.pug \ No newline at end of file diff --git a/layout/includes/third-party/newest-comments/remark42.pug b/layout/includes/third-party/newest-comments/remark42.pug new file mode 100644 index 0000000..8ead708 --- /dev/null +++ b/layout/includes/third-party/newest-comments/remark42.pug @@ -0,0 +1,80 @@ +- const { host, siteId } = theme.remark42 + +script. + window.addEventListener('load', () => { + const changeContent = (content) => { + if (content === '') return content + + content = content.replace(/]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link + content = content.replace(/]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url + content = content.replace(/
.*?<\/pre>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
+      content = content.replace(/<[^>]+>/g,"") // remove html tag
+
+      if (content.length > 150) {
+        content = content.substring(0,150) + '...'
+      }
+      return content
+    }
+
+    const generateHtml = array => {
+      let result = ''
+
+      if (array.length) {
+        for (let i = 0; i < array.length; i++) {
+          result += '
' + + if (!{theme.newest_comments.avatar}) { + const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}' + result += `${array[i].nick}` + } + + result += `
+ ${array[i].content} +
${array[i].nick} /
+
` + } + } else { + result += '!{_p("aside.card_newest_comments.zero")}' + } + + let $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= result + window.lazyLoadInstance && window.lazyLoadInstance.update() + window.pjax && window.pjax.refresh($dom) + } + + const getComment = () => { + fetch('!{host}/api/v1/last/!{theme.newest_comments.limit}?site=!{siteId}') + .then(response => response.json()) + .then(data => { + const remark42 = data.map(function (e) { + return { + 'avatar': e.user.picture, + 'content': changeContent(e.text), + 'nick': e.user.name, + 'url': e.locator.url, + 'date': e.time, + } + }) + saveToLocal.set('remark42-newest-comments', JSON.stringify(remark42), !{theme.newest_comments.storage}/(60*24)) + generateHtml(remark42) + }).catch(e => { + const $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" + }) + } + + const newestCommentInit = () => { + if (document.querySelector('#card-newest-comments .aside-list')) { + const data = saveToLocal.get('remark42-newest-comments') + if (data) { + generateHtml(JSON.parse(data)) + } else { + getComment() + } + } + } + + newestCommentInit() + document.addEventListener('pjax:complete', newestCommentInit) + }) diff --git a/layout/includes/third-party/newest-comments/twikoo-comment.pug b/layout/includes/third-party/newest-comments/twikoo-comment.pug new file mode 100644 index 0000000..e362623 --- /dev/null +++ b/layout/includes/third-party/newest-comments/twikoo-comment.pug @@ -0,0 +1,93 @@ +script. + window.addEventListener('load', () => { + const changeContent = (content) => { + if (content === '') return content + + content = content.replace(/]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link + content = content.replace(/]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url + content = content.replace(/
.*?<\/pre>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
+      content = content.replace(/<[^>]+>/g,"") // remove html tag
+
+      if (content.length > 150) {
+        content = content.substring(0,150) + '...'
+      }
+      return content
+    }
+
+    const getComment = () => {
+      const runTwikoo = () => {
+        twikoo.getRecentComments({
+          envId: '!{theme.twikoo.envId}',
+          region: '!{theme.twikoo.region}',
+          pageSize: !{theme.newest_comments.limit},
+          includeReply: true
+        }).then(function (res) {
+          const twikooArray = res.map(e => {
+            return {
+              'content': changeContent(e.comment),
+              'avatar': e.avatar,
+              'nick': e.nick,
+              'url': e.url + '#' + e.id,
+              'date': new Date(e.created).toISOString()
+            }
+          })
+
+          saveToLocal.set('twikoo-newest-comments', JSON.stringify(twikooArray), !{theme.newest_comments.storage}/(60*24))
+          generateHtml(twikooArray)
+        }).catch(function (err) {
+          const $dom = document.querySelector('#card-newest-comments .aside-list')
+          $dom.innerHTML= "!{_p('aside.card_newest_comments.error')}"
+        })
+      }
+
+      if (typeof twikoo === 'object') {
+        runTwikoo()
+      } else {
+        getScript('!{url_for(theme.asset.twikoo)}').then(runTwikoo)
+      }
+    }
+
+    const generateHtml = array => {
+      let result = ''
+
+      if (array.length) {
+        for (let i = 0; i < array.length; i++) {
+          result += '
' + + if (!{theme.newest_comments.avatar}) { + const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}' + result += `${array[i].nick}` + } + + result += `
+ ${array[i].content} +
${array[i].nick} /
+
` + } + } else { + result += '!{_p("aside.card_newest_comments.zero")}' + } + + let $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= result + window.lazyLoadInstance && window.lazyLoadInstance.update() + window.pjax && window.pjax.refresh($dom) + } + + const newestCommentInit = () => { + if (document.querySelector('#card-newest-comments .aside-list')) { + const data = saveToLocal.get('twikoo-newest-comments') + if (data) { + generateHtml(JSON.parse(data)) + } else { + getComment() + } + } + } + + newestCommentInit() + document.addEventListener('pjax:complete', newestCommentInit) + }) + + + diff --git a/layout/includes/third-party/newest-comments/valine.pug b/layout/includes/third-party/newest-comments/valine.pug new file mode 100644 index 0000000..ef0bb10 --- /dev/null +++ b/layout/includes/third-party/newest-comments/valine.pug @@ -0,0 +1,99 @@ +- let default_avatar = theme.valine.avatar + +script(src=url_for(theme.asset.blueimp_md5)) +script. + window.addEventListener('load', () => { + const changeContent = (content) => { + if (content === '') return content + + content = content.replace(/]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link + content = content.replace(/]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url + content = content.replace(/
.*?<\/pre>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
+      content = content.replace(/<[^>]+>/g,"") // remove html tag
+
+      if (content.length > 150) {
+        content = content.substring(0,150) + '...'
+      }
+      return content
+    }
+
+    const getIcon = (icon, mail) => {
+      if (icon) return icon
+      let defaultIcon = '!{ default_avatar ? `?d=${default_avatar}` : ''}'
+      let iconUrl = `https://gravatar.loli.net/avatar/${md5(mail.toLowerCase()) + defaultIcon}`
+      return iconUrl
+    }
+
+    const generateHtml = array => {
+      let result = ''
+
+      if (array.length) {
+        for (let i = 0; i < array.length; i++) {
+          result += '
' + + if (!{theme.newest_comments.avatar}) { + const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}' + result += `${array[i].nick}` + } + + result += `
+ ${array[i].content} +
${array[i].nick} /
+
` + } + } else { + result += '!{_p("aside.card_newest_comments.zero")}' + } + + let $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= result + window.lazyLoadInstance && window.lazyLoadInstance.update() + window.pjax && window.pjax.refresh($dom) + } + + const getComment = () => { + const serverURL = '!{theme.valine.serverURLs || `https://${theme.valine.appId.substring(0,8)}.api.lncldglobal.com` }' + + var settings = { + "method": "GET", + "headers": { + "X-LC-Id": '!{theme.valine.appId}', + "X-LC-Key": '!{theme.valine.appKey}', + "Content-Type": "application/json" + }, + } + + fetch(`${serverURL}/1.1/classes/Comment?limit=!{theme.newest_comments.limit}&order=-createdAt`,settings) + .then(response => response.json()) + .then(data => { + const valineArray = data.results.map(function (e) { + return { + 'avatar': getIcon(e.QQAvatar, e.mail), + 'content': changeContent(e.comment), + 'nick': e.nick, + 'url': e.url + '#' + e.objectId, + 'date': e.updatedAt, + } + }) + saveToLocal.set('valine-newest-comments', JSON.stringify(valineArray), !{theme.newest_comments.storage}/(60*24)) + generateHtml(valineArray) + }).catch(e => { + const $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" + }) + } + + const newestCommentInit = () => { + if (document.querySelector('#card-newest-comments .aside-list')) { + const data = saveToLocal.get('valine-newest-comments') + if (data) { + generateHtml(JSON.parse(data)) + } else { + getComment() + } + } + } + + newestCommentInit() + document.addEventListener('pjax:complete', newestCommentInit) + }) diff --git a/layout/includes/third-party/newest-comments/waline.pug b/layout/includes/third-party/newest-comments/waline.pug new file mode 100644 index 0000000..15ca44c --- /dev/null +++ b/layout/includes/third-party/newest-comments/waline.pug @@ -0,0 +1,84 @@ +script. + window.addEventListener('load', () => { + const changeContent = (content) => { + if (content === '') return content + + content = content.replace(/]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link + content = content.replace(/]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url + content = content.replace(/
.*?<\/pre>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
+      content = content.replace(/<[^>]+>/g,"") // remove html tag
+
+      if (content.length > 150) {
+        content = content.substring(0,150) + '...'
+      }
+      return content
+    }
+
+    const generateHtml = array => {
+      let result = ''
+
+      if (array.length) {
+        for (let i = 0; i < array.length; i++) {
+          result += '
' + + if (!{theme.newest_comments.avatar}) { + const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}' + result += `${array[i].nick}` + } + + result += `
+ ${array[i].content} +
${array[i].nick} /
+
` + } + } else { + result += '!{_p("aside.card_newest_comments.zero")}' + } + + let $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= result + window.lazyLoadInstance && window.lazyLoadInstance.update() + window.pjax && window.pjax.refresh($dom) + } + + const getComment = () => { + const loadWaline = () => { + Waline.RecentComments({ + serverURL: '!{theme.waline.serverURL}', + count: !{theme.newest_comments.limit} + }).then(({comments}) => { + const walineArray = comments.map(e => { + return { + 'content': changeContent(e.comment), + 'avatar': e.avatar, + 'nick': e.nick, + 'url': e.url + '#' + e.objectId, + 'date': e.insertedAt, + } + }) + saveToLocal.set('waline-newest-comments', JSON.stringify(walineArray), !{theme.newest_comments.storage}/(60*24)) + generateHtml(walineArray) + }).catch(e => { + const $dom = document.querySelector('#card-newest-comments .aside-list') + $dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" + }) + } + + if (typeof Waline === 'function') loadWaline() + else getScript('!{url_for(theme.asset.waline_js)}').then(loadWaline) + } + + const newestCommentInit = () => { + if (document.querySelector('#card-newest-comments .aside-list')) { + const data = saveToLocal.get('waline-newest-comments') + if (data) { + generateHtml(JSON.parse(data)) + } else { + getComment() + } + } + } + + newestCommentInit() + document.addEventListener('pjax:complete', newestCommentInit) + }) diff --git a/layout/includes/third-party/pangu.pug b/layout/includes/third-party/pangu.pug new file mode 100644 index 0000000..2027ca7 --- /dev/null +++ b/layout/includes/third-party/pangu.pug @@ -0,0 +1,20 @@ +script. + function panguFn () { + if (typeof pangu === 'object') pangu.autoSpacingPage() + else { + getScript('!{url_for(theme.asset.pangu)}') + .then(() => { + pangu.autoSpacingPage() + }) + } + } + + function panguInit () { + if (!{theme.pangu.field === 'post'}){ + GLOBAL_CONFIG_SITE.isPost && panguFn() + } else { + panguFn() + } + } + + document.addEventListener('DOMContentLoaded', panguInit) diff --git a/layout/includes/third-party/pjax.pug b/layout/includes/third-party/pjax.pug new file mode 100644 index 0000000..3048856 --- /dev/null +++ b/layout/includes/third-party/pjax.pug @@ -0,0 +1,84 @@ +- var pjaxExclude = 'a:not([target="_blank"])' +if theme.pjax.exclude + each val in theme.pjax.exclude + - pjaxExclude = pjaxExclude + `:not([href="${val}"])` + +- let pjaxSelectors = ['head > title','#config-diff','#body-wrap','#rightside-config-hide','#rightside-config-show','.js-pjax'] + +- let choose = theme.comments.use +if choose + if theme.Open_Graph_meta.enable && (choose.includes('Livere') || choose.includes('Utterances') || choose.includes('Giscus')) + - pjaxSelectors.unshift('meta[property="og:image"]', 'meta[property="og:title"]', 'meta[property="og:url"]') + if choose.includes('Utterances') || choose.includes('Giscus') + - pjaxSelectors.unshift('link[rel="canonical"]') + +script(src=url_for(theme.asset.pjax)) +script. + let pjaxSelectors = !{JSON.stringify(pjaxSelectors)} + + var pjax = new Pjax({ + elements: '!{pjaxExclude}', + selectors: pjaxSelectors, + cacheBust: false, + analytics: !{theme.google_analytics ? true : false}, + scrollRestoration: false + }) + + document.addEventListener('pjax:send', function () { + + // removeEventListener scroll + window.tocScrollFn && window.removeEventListener('scroll', window.tocScrollFn) + window.scrollCollect && window.removeEventListener('scroll', scrollCollect) + + document.getElementById('rightside').style.cssText = "opacity: ''; transform: ''" + + if (window.aplayers) { + for (let i = 0; i < window.aplayers.length; i++) { + if (!window.aplayers[i].options.fixed) { + window.aplayers[i].destroy() + } + } + } + + typeof typed === 'object' && typed.destroy() + + //reset readmode + const $bodyClassList = document.body.classList + $bodyClassList.contains('read-mode') && $bodyClassList.remove('read-mode') + + typeof disqusjs === 'object' && disqusjs.destroy() + }) + + document.addEventListener('pjax:complete', function () { + window.refreshFn() + + document.querySelectorAll('script[data-pjax]').forEach(item => { + const newScript = document.createElement('script') + const content = item.text || item.textContent || item.innerHTML || "" + Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value)) + newScript.appendChild(document.createTextNode(content)) + item.parentNode.replaceChild(newScript, item) + }) + + GLOBAL_CONFIG.islazyload && window.lazyLoadInstance.update() + + typeof chatBtnFn === 'function' && chatBtnFn() + typeof panguInit === 'function' && panguInit() + + // google analytics + typeof gtag === 'function' && gtag('config', '!{theme.google_analytics}', {'page_path': window.location.pathname}); + + // baidu analytics + typeof _hmt === 'object' && _hmt.push(['_trackPageview',window.location.pathname]); + + typeof loadMeting === 'function' && document.getElementsByClassName('aplayer').length && loadMeting() + + // prismjs + typeof Prism === 'object' && Prism.highlightAll() + }) + + document.addEventListener('pjax:error', (e) => { + if (e.request.status === 404) { + pjax.loadUrl('/404.html') + } + }) diff --git a/layout/includes/third-party/prismjs.pug b/layout/includes/third-party/prismjs.pug new file mode 100644 index 0000000..6af44dd --- /dev/null +++ b/layout/includes/third-party/prismjs.pug @@ -0,0 +1,5 @@ +if config.prismjs && config.prismjs.enable && !config.prismjs.preprocess + script(src=url_for(theme.asset.prismjs_js)) + script(src=url_for(theme.asset.prismjs_autoloader)) + if config.prismjs.line_number + script(src=url_for(theme.asset.prismjs_lineNumber_js)) diff --git a/layout/includes/third-party/search/algolia.pug b/layout/includes/third-party/search/algolia.pug new file mode 100644 index 0000000..8a439e0 --- /dev/null +++ b/layout/includes/third-party/search/algolia.pug @@ -0,0 +1,18 @@ +#algolia-search + .search-dialog + nav.search-nav + span.search-dialog-title= _p('search.title') + button.search-close-button + i.fas.fa-times + + .search-wrap + #algolia-search-input + hr + #algolia-search-results + #algolia-hits + #algolia-pagination + #algolia-info + .algolia-stats + .algolia-poweredBy + + #search-mask diff --git a/layout/includes/third-party/search/index.pug b/layout/includes/third-party/search/index.pug new file mode 100644 index 0000000..c1bd03a --- /dev/null +++ b/layout/includes/third-party/search/index.pug @@ -0,0 +1,4 @@ +if theme.algolia_search.enable + include ./algolia.pug +else if theme.local_search.enable + include ./local-search.pug \ No newline at end of file diff --git a/layout/includes/third-party/search/local-search.pug b/layout/includes/third-party/search/local-search.pug new file mode 100644 index 0000000..3d1508f --- /dev/null +++ b/layout/includes/third-party/search/local-search.pug @@ -0,0 +1,20 @@ +#local-search + .search-dialog + nav.search-nav + span.search-dialog-title= _p('search.title') + span#loading-status + button.search-close-button + i.fas.fa-times + + #loading-database.is-center + i.fas.fa-spinner.fa-pulse + span= ' ' + _p("search.load_data") + + .search-wrap + #local-search-input + .local-search-box + input(placeholder=_p("search.local_search.input_placeholder") type="text").local-search-box--input + hr + #local-search-results + + #search-mask \ No newline at end of file diff --git a/layout/includes/third-party/share/add-this.pug b/layout/includes/third-party/share/add-this.pug new file mode 100644 index 0000000..ab44267 --- /dev/null +++ b/layout/includes/third-party/share/add-this.pug @@ -0,0 +1,2 @@ +.addthis_inline_share_toolbox +script(src=`//s7.addthis.com/js/300/addthis_widget.js#pubid=${theme.addThis.pubid}` async) \ No newline at end of file diff --git a/layout/includes/third-party/share/addtoany.pug b/layout/includes/third-party/share/addtoany.pug new file mode 100644 index 0000000..d42f3be --- /dev/null +++ b/layout/includes/third-party/share/addtoany.pug @@ -0,0 +1,10 @@ +.addtoany + .a2a_kit.a2a_kit_size_32.a2a_default_style + - let addtoanyItem = theme.addtoany.item.split(',') + each name in addtoanyItem + a(class="a2a_button_" + name) + + a.a2a_dd(href="https://www.addtoany.com/share") +script(async src='https://static.addtoany.com/menu/page.js') + + diff --git a/layout/includes/third-party/share/index.pug b/layout/includes/third-party/share/index.pug new file mode 100644 index 0000000..f28ceab --- /dev/null +++ b/layout/includes/third-party/share/index.pug @@ -0,0 +1,7 @@ +.post_share + if theme.addThis.enable + !=partial('includes/third-party/share/add-this', {}, {cache: true}) + else if theme.sharejs.enable + include ./share-js.pug + else if theme.addtoany.enable + !=partial('includes/third-party/share/addtoany', {}, {cache: true}) diff --git a/layout/includes/third-party/share/share-js.pug b/layout/includes/third-party/share/share-js.pug new file mode 100644 index 0000000..0a566fa --- /dev/null +++ b/layout/includes/third-party/share/share-js.pug @@ -0,0 +1,3 @@ +.social-share(data-image=url_for(page.cover|| theme.avatar.img) data-sites= theme.sharejs.sites) +link(rel='stylesheet' href=url_for(theme.asset.sharejs_css) media="print" onload="this.media='all'") +script(src=url_for(theme.asset.sharejs) defer) \ No newline at end of file diff --git a/layout/includes/third-party/subtitle.pug b/layout/includes/third-party/subtitle.pug new file mode 100644 index 0000000..9236757 --- /dev/null +++ b/layout/includes/third-party/subtitle.pug @@ -0,0 +1,128 @@ +- const { effect,loop,source,sub,startDelay,typeSpeed,backSpeed } = theme.subtitle +- let subContent = sub || new Array() + +case source + when 1 + script. + function subtitleType () { + fetch('https://v1.hitokoto.cn') + .then(response => response.json()) + .then(data => { + if (!{effect}) { + const from = '出自 ' + data.from + const sub = !{JSON.stringify(subContent)} + sub.unshift(data.hitokoto, from) + window.typed = new Typed('#subtitle', { + strings: sub, + startDelay: !{startDelay}, + typeSpeed: !{typeSpeed}, + loop: !{loop}, + backSpeed: !{backSpeed}, + }) + } else { + document.getElementById('subtitle').innerHTML = data.hitokoto + } + }) + } + + if (!{effect}) { + if (typeof Typed === 'function') { + subtitleType() + } else { + getScript('!{url_for(theme.asset.typed)}').then(subtitleType) + } + } else { + subtitleType() + } + + when 2 + script. + function subtitleType () { + getScript('https://yijuzhan.com/api/word.php?m=js').then(() => { + const con = str[0] + if (!{effect}) { + const from = '出自 ' + str[1] + const sub = !{JSON.stringify(subContent)} + sub.unshift(con, from) + window.typed = new Typed('#subtitle', { + strings: sub, + startDelay: !{startDelay}, + typeSpeed: !{typeSpeed}, + loop: !{loop}, + backSpeed: !{backSpeed}, + }) + } else { + document.getElementById('subtitle').innerHTML = con + } + }) + } + + if (!{effect}) { + if (typeof Typed === 'function') { + subtitleType() + } else { + getScript('!{url_for(theme.asset.typed)}').then(subtitleType) + } + } else { + subtitleType() + } + + when 3 + script. + function subtitleType () { + getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js').then(() => { + jinrishici.load(result =>{ + if (!{effect}) { + const sub = !{JSON.stringify(subContent)} + const content = result.data.content + sub.unshift(content) + window.typed = new Typed('#subtitle', { + strings: sub, + startDelay: !{startDelay}, + typeSpeed: !{typeSpeed}, + loop: !{loop}, + backSpeed: !{backSpeed}, + }) + } else { + document.getElementById('subtitle').innerHTML = result.data.content + } + }) + }) + } + + if (!{effect}) { + if (typeof Typed === 'function') { + subtitleType() + } else { + getScript('!{url_for(theme.asset.typed)}').then(subtitleType) + } + } else { + subtitleType() + } + + default + - subContent = subContent.length ? subContent : new Array(config.subtitle) + script. + function subtitleType () { + if (!{effect}) { + window.typed = new Typed("#subtitle", { + strings: !{JSON.stringify(subContent)}, + startDelay: !{startDelay}, + typeSpeed: !{typeSpeed}, + loop: !{loop}, + backSpeed: !{backSpeed} + }) + } else { + document.getElementById("subtitle").innerHTML = '!{subContent[0]}' + } + } + + if (!{effect}) { + if (typeof Typed === 'function') { + subtitleType() + } else { + getScript('!{url_for(theme.asset.typed)}').then(subtitleType) + } + } else { + subtitleType() + } diff --git a/layout/includes/waves.pug b/layout/includes/waves.pug new file mode 100644 index 0000000..5b3631e --- /dev/null +++ b/layout/includes/waves.pug @@ -0,0 +1,9 @@ +section.main-hero-waves-area.waves-area + svg.waves-svg(xmlns='http://www.w3.org/2000/svg', xlink='http://www.w3.org/1999/xlink', viewBox='0 24 150 28', preserveAspectRatio='none', shape-rendering='auto') + defs + path#gentle-wave(d='M -160 44 c 30 0 58 -18 88 -18 s 58 18 88 18 s 58 -18 88 -18 s 58 18 88 18 v 44 h -352 Z') + g.parallax + use(href='#gentle-wave', x='48', y='0') + use(href='#gentle-wave', x='48', y='3') + use(href='#gentle-wave', x='48', y='5') + use(href='#gentle-wave', x='48', y='7') \ No newline at end of file diff --git a/layout/includes/widget/card_author.pug b/layout/includes/widget/card_author.pug new file mode 100644 index 0000000..bec6254 --- /dev/null +++ b/layout/includes/widget/card_author.pug @@ -0,0 +1,14 @@ +if theme.aside.card_author.enable + .card-widget.card-info + .card-content + .card-info-avatar.is-center + .author-info__sayhi#author-info__sayhi 晚上好!我是 + .author-info__name= config.author + .avatar-img + img(src=url_for(theme.avatar.img) onerror=`this.onerror=null;this.src='` + url_for(theme.error_img.flink) + `'` alt="avatar") + .banner-button-group + a.banner-button(href="/about/") + i.fas.fa-circle-chevron-right + span.banner-button-te + xt 了解更多 + line.line(style="margin-top: 10px") \ No newline at end of file diff --git a/layout/includes/widget/card_post_toc.pug b/layout/includes/widget/card_post_toc.pug new file mode 100644 index 0000000..4154221 --- /dev/null +++ b/layout/includes/widget/card_post_toc.pug @@ -0,0 +1,15 @@ +- let tocNumber = page.toc_number !== undefined ? page.toc_number : theme.toc.number +- let tocExpand = page.toc_expand !== undefined ? page.toc_expand : theme.toc.expand +- let tocExpandClass = tocExpand ? 'is-expand' : '' + +#card-toc.card-widget + .item-headline + i.fas.fa-stream + span= _p('aside.card_toc') + span.toc-percentage + + if (page.encrypt == true) + .toc-content.toc-div-class(class=tocExpandClass style="display:none")!=toc(page.origin, {list_number: tocNumber}) + else + .toc-content(class=tocExpandClass)!=toc(page.content, {list_number: tocNumber}) + \ No newline at end of file diff --git a/layout/includes/widget/card_tags.pug b/layout/includes/widget/card_tags.pug new file mode 100644 index 0000000..9aeb1a9 --- /dev/null +++ b/layout/includes/widget/card_tags.pug @@ -0,0 +1,54 @@ +if theme.aside.card_tags.enable + if site.tags.length + .card-widget.card-tags + .item-headline + i.fas.fa-tags + span= _p('aside.card_tags') + + - let tagLimit = theme.aside.card_tags.limit === 0 ? 0 : theme.aside.card_tags.limit || 40 + if theme.aside.card_tags.color + .card-tag-cloud!= cloudTags({source: site.tags, minfontsize: 1.15, maxfontsize: 1.45, limit: tagLimit, unit: 'em'}) + else + .card-tag-cloud!= tagcloud({min_font: 1.1, max_font: 1.5, amount: tagLimit , color: true, start_color: '#999', end_color: '#99a9bf', unit: 'em'}) + hrl.line +if theme.aside.card_categories.enable + if site.categories.length + .card-widget.card-categories + !=aside_categories({ limit: theme.aside.card_categories.limit === 0 ? 0 : theme.aside.card_categories.limit || 8 , expand: theme.aside.card_categories.expand }) + hrl.line +if theme.aside.card_archives.enable + .card-widget.card-archives + - let type = theme.aside.card_archives.type || 'monthly' + - let format = theme.aside.card_archives.format || 'MMMM YYYY' + - let order = theme.aside.card_archives.order || -1 + - let limit = theme.aside.card_archives.limit === 0 ? 0 : theme.aside.card_archives.limit || 8 + != aside_archives({ type:type, format: format, order: order, limit: limit }) + hrl.line +.card-widget.card-webinfo + .item-headline + i.fas.fa-chart-line.fa-bounce + span= _p('aside.card_webinfo.headline') + .webinfo + .webinfo-item + .item-name + i.fas.fa-folder-open.fa-beat + .text 文章总数 + .item-count= site.posts.length + .webinfo-item + .item-name + i.fas.fa-clock.fa-shake + .text 建站天数 + .item-count#runtimeshow(data-publishDate=date_xml(theme.runtimeshow.publish_date)) + i.fa-solid.fa-spinner.fa-spin + .webinfo-item + .item-name + i.fas.fa-pen-to-square.fa-beat + .text 全站字数 + .item-count=totalcount(site) + .webinfo-item + .item-name + i.fas.fa-upload.fa-shake + .text 最后更新 + .item-count#last-push-date(data-lastPushDate=date_xml(Date.now())) + i.fa-solid.fa-spinner.fa-spin + diff --git a/layout/includes/widget/card_webinfo.pug b/layout/includes/widget/card_webinfo.pug new file mode 100644 index 0000000..5bffaf5 --- /dev/null +++ b/layout/includes/widget/card_webinfo.pug @@ -0,0 +1,28 @@ +.card-widget.card-webinfo + .item-headline + i.fas.fa-chart-line.fa-bounce + span= _p('aside.card_webinfo.headline') + .webinfo + .webinfo-item + .item-name + i.fas.fa-folder-open.fa-beat + .text 文章总数 + .item-count= site.posts.length + .webinfo-item + .item-name + i.fas.fa-clock.fa-shake + .text 建站天数 + .item-count#runtimeshow(data-publishDate=date_xml(theme.runtimeshow.publish_date)) + i.fa-solid.fa-spinner.fa-spin + .webinfo-item + .item-name + i.fas.fa-pen-to-square.fa-beat + .text 全站字数 + .item-count=totalcount(site) + .webinfo-item + .item-name + i.fas.fa-upload.fa-shake + .text 最后更新 + .item-count#last-push-date(data-lastPushDate=date_xml(Date.now())) + i.fa-solid.fa-spinner.fa-spin + diff --git a/layout/includes/widget/index.pug b/layout/includes/widget/index.pug new file mode 100644 index 0000000..3990487 --- /dev/null +++ b/layout/includes/widget/index.pug @@ -0,0 +1,21 @@ +#aside-content.aside-content + //- post + if is_post() + - const tocStyle = page.toc_style_simple + - const tocStyleVal = tocStyle === true || tocStyle === false ? tocStyle : theme.toc.style_simple + if showToc && tocStyleVal + .sticky_layout + include ./card_post_toc.pug + else + !=partial('includes/widget/card_author', {}, {cache: true}) + .sticky_layout + if showToc + include ./card_post_toc.pug + else + //- page + !=partial('includes/widget/card_author', {}, {cache: true}) + + .sticky_layout + if showToc + include ./card_post_toc.pug + !=partial('includes/widget/card_tags', {}, {cache: true}) \ No newline at end of file diff --git a/layout/index.pug b/layout/index.pug new file mode 100644 index 0000000..2655cb4 --- /dev/null +++ b/layout/index.pug @@ -0,0 +1,7 @@ +extends includes/layout.pug + +block content + include ./includes/mixins/post-ui.pug + #recent-posts.recent-posts + +postUI + include includes/pagination.pug \ No newline at end of file diff --git a/layout/page.pug b/layout/page.pug new file mode 100644 index 0000000..416950a --- /dev/null +++ b/layout/page.pug @@ -0,0 +1,21 @@ +extends includes/layout.pug + +block content + #page + h1.page-title= page.title + + case page.type + when 'tags' + include includes/page/tags.pug + when 'link' + include includes/page/flink.pug + when 'categories' + include includes/page/categories.pug + when 'about' + include includes/page/about.pug + default + include includes/page/default-page.pug + + if page.comments !== false && theme.comments && theme.comments.use + - var commentsJsLoad = true + !=partial('includes/third-party/comments/index', {}, {cache: true}) \ No newline at end of file diff --git a/layout/post.pug b/layout/post.pug new file mode 100644 index 0000000..f54ab7a --- /dev/null +++ b/layout/post.pug @@ -0,0 +1,32 @@ +extends includes/layout.pug + +block content + #post + if top_img === false + include includes/header/post-info.pug + + article#article-container.post-content!=page.content + include includes/post/post-copyright.pug + .tag_share + if (theme.post_meta.post.tags) + .post-meta__tag-list + each item, index in page.tags.data + a(href=url_for(item.path)).post-meta__tags #[=item.name] + include includes/third-party/share/index.pug + + if theme.reward.enable && theme.reward.QR_code + !=partial('includes/post/reward', {}, {cache: true}) + + //- ad + if theme.ad && theme.ad.post + .ads-wrap!=theme.ad.post + + if theme.post_pagination + include includes/pagination.pug + if theme.related_post && theme.related_post.enable + != related_posts(page,site.posts) + + if page.comments !== false && theme.comments && theme.comments.use + - var commentsJsLoad = true + !=partial('includes/third-party/comments/index', {}, {cache: true}) + \ No newline at end of file diff --git a/layout/tag.pug b/layout/tag.pug new file mode 100644 index 0000000..9f99658 --- /dev/null +++ b/layout/tag.pug @@ -0,0 +1,14 @@ +extends includes/layout.pug + +block content + if theme.tag_ui == 'index' + include ./includes/mixins/post-ui.pug + #recent-posts.recent-posts + +postUI + include includes/pagination.pug + else + include ./includes/mixins/article-sort.pug + #tag + .article-sort-title= _p('page.tag') + ' - ' + page.tag + +articleSort(page.posts) + include includes/pagination.pug \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..bd793bb --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "hexo-theme-butterfly", + "version": "1.0.1", + "description": "A Simple and Card UI Design theme for Hexo", + "main": "package.json", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "hexo", + "theme", + "butterfly", + "Card UI Design", + "Jerry", + "hexo-theme-butterfly" + ], + "repository": { + "type" : "git", + "url" : "https://github.com/jerryc127/hexo-theme-butterfly.git" + }, + "bugs": { + "url": "https://github.com/jerryc127/hexo-theme-butterfly/issues", + "email": "my@crazywong.com" + }, + "dependencies": { + "hexo-renderer-stylus": "^2.1.0", + "hexo-renderer-pug": "^3.0.0" + }, + "homepage": "https://butterfly.js.org/", + "author": "Jerry ", + "license": "Apache-2.0" +} diff --git a/plugins.yml b/plugins.yml new file mode 100644 index 0000000..9590b68 --- /dev/null +++ b/plugins.yml @@ -0,0 +1,200 @@ +algolia_search_v4: + name: algoliasearch + file: dist/algoliasearch-lite.umd.js + version: 4.14.2 +instantsearch_v4: + name: instantsearch.js + file: dist/instantsearch.production.min.js + version: 4.49.0 +pjax: + name: pjax + file: pjax.min.js + version: 0.2.8 +gitalk: + name: gitalk + file: dist/gitalk.min.js + version: 1.8.0 +gitalk_css: + name: gitalk + file: dist/gitalk.css + version: 1.8.0 +blueimp_md5: + name: blueimp-md5 + file: js/md5.min.js + version: 2.19.0 +valine: + name: valine + file: dist/Valine.min.js + version: 1.5.1 +disqusjs: + name: disqusjs + file: dist/browser/disqusjs.es2015.umd.min.js + version: 3.0.2 +disqusjs_css: + name: disqusjs + file: dist/browser/styles/disqusjs.css + version: 3.0.2 +twikoo: + name: twikoo + file: dist/twikoo.all.min.js + version: 1.6.7 +waline_js: + name: '@waline/client' + file: dist/waline.js + other_name: waline + version: 2.13.0 +waline_css: + name: '@waline/client' + file: dist/waline.css + other_name: waline + version: 2.13.0 +sharejs: + name: butterfly-extsrc + file: sharejs/dist/js/social-share.min.js + version: 1.1.3 +sharejs_css: + name: butterfly-extsrc + file: sharejs/dist/css/share.min.css + version: 1.1.3 +mathjax: + name: mathjax + file: es5/tex-mml-chtml.js + version: 3.2.2 +katex: + name: katex + file: dist/katex.min.css + other_name: KaTeX + version: 0.16.3 +katex_copytex: + name: katex + file: dist/contrib/copy-tex.min.js + other_name: KaTeX + version: 0.16.3 +mermaid: + name: mermaid + file: dist/mermaid.min.js + version: 9.1.7 +canvas_ribbon: + name: butterfly-extsrc + file: dist/canvas-ribbon.min.js + version: 1.1.3 +canvas_fluttering_ribbon: + name: butterfly-extsrc + file: dist/canvas-fluttering-ribbon.min.js + version: 1.1.3 +canvas_nest: + name: butterfly-extsrc + file: dist/canvas-nest.min.js + version: 1.1.3 +activate_power_mode: + name: butterfly-extsrc + file: dist/activate-power-mode.min.js + version: 1.1.3 +fireworks: + name: butterfly-extsrc + file: dist/fireworks.min.js + version: 1.1.3 +click_heart: + name: butterfly-extsrc + file: dist/click-heart.min.js + version: 1.1.3 +ClickShowText: + name: butterfly-extsrc + file: dist/click-show-text.min.js + version: 1.1.3 +lazyload: + name: vanilla-lazyload + file: dist/lazyload.iife.min.js + version: 17.8.3 +instantpage: + name: instant.page + file: instantpage.js + version: 5.1.1 +typed: + name: typed.js + file: lib/typed.min.js + version: 2.0.12 +pangu: + name: pangu + file: dist/browser/pangu.min.js + version: 4.0.7 +fancybox_css_v4: + name: '@fancyapps/ui' + file: dist/fancybox.css + version: 4.0.31 + other_name: fancyapps-ui +fancybox_v4: + name: '@fancyapps/ui' + file: dist/fancybox.umd.js + version: 4.0.31 + other_name: fancyapps-ui +medium_zoom: + name: medium-zoom + file: dist/medium-zoom.min.js + version: 1.0.6 +snackbar_css: + name: node-snackbar + file: dist/snackbar.min.css + version: 0.1.16 +snackbar: + name: node-snackbar + file: dist/snackbar.min.js + version: 0.1.16 +fontawesomeV6: + name: '@fortawesome/fontawesome-free' + file: css/all.min.css + other_name: font-awesome + version: 6.2.0 +flickr_justified_gallery_js: + name: flickr-justified-gallery + file: dist/fjGallery.min.js + version: 2.1.2 +flickr_justified_gallery_css: + name: flickr-justified-gallery + file: dist/fjGallery.css + version: 2.1.2 +aplayer_css: + name: aplayer + file: dist/APlayer.min.css + version: 1.10.1 +aplayer_js: + name: aplayer + file: dist/APlayer.min.js + version: 1.10.1 +meting_js: + name: butterfly-extsrc + file: metingjs/dist/Meting.min.js + version: 1.1.3 +prismjs_js: + name: prismjs + file: prism.js + other_name: prism + version: 1.29.0 +prismjs_lineNumber_js: + name: prismjs + file: plugins/line-numbers/prism-line-numbers.min.js + other_name: prism + version: 1.29.0 +prismjs_autoloader: + name: prismjs + file: plugins/autoloader/prism-autoloader.min.js + other_name: prism + version: 1.29.0 +artalk_js: + name: artalk + file: dist/Artalk.js + version: 2.4.3 +artalk_css: + name: artalk + file: dist/Artalk.css + version: 2.4.3 +pace_js: + name: pace-js + other_name: pace + file: pace.min.js + version: 1.2.4 +pace_default_css: + name: pace-js + other_name: pace + file: themes/blue/pace-theme-minimal.css + version: 1.2.4 diff --git a/scripts/events/404.js b/scripts/events/404.js new file mode 100644 index 0000000..02491ce --- /dev/null +++ b/scripts/events/404.js @@ -0,0 +1,18 @@ +/** + * Butterfly + * 404 error page + */ + +'use strict' + +hexo.extend.generator.register('404', function (locals) { + if (!hexo.theme.config.error_404.enable) return + return { + path: '404.html', + layout: ['page'], + data: { + type: '404', + top_img: false + } + } +}) diff --git a/scripts/events/cdn.js b/scripts/events/cdn.js new file mode 100644 index 0000000..7d77e63 --- /dev/null +++ b/scripts/events/cdn.js @@ -0,0 +1,94 @@ +/** + * Butterfly + * Merge CDN + */ + +'use strict' + +const { version } = require('../../package.json') +const path = require('path') + +hexo.extend.filter.register('before_generate', () => { + const themeConfig = hexo.theme.config + const { CDN } = themeConfig + + const thirdPartySrc = hexo.render.renderSync({ path: path.join(hexo.theme_dir,'/plugins.yml'), engine: 'yaml'}) + const internalSrc = { + main: { + name: 'hexo-theme-butterfly', + file: 'js/main.js', + version + }, + utils: { + name: 'hexo-theme-butterfly', + file: 'js/utils.js', + version + }, + translate: { + name: 'hexo-theme-butterfly', + file: 'js/tw_cn.js', + version + }, + local_search: { + name: 'hexo-theme-butterfly', + file: 'js/search/local-search.js', + version + }, + algolia_js: { + name: 'hexo-theme-butterfly', + file: 'js/search/algolia.js', + version + } + } + + const minFile = (file) => { + return file.replace(/(? '.min' + ext) + } + + const createCDNLink = (data, type, cond = '') => { + Object.keys(data).map(key => { + let { name, version, file, other_name } = data[key] + + const min_file = minFile(file) + const cdnjs_name = other_name || name + const cdnjs_file = file.replace(/^[lib|dist]*\/|browser\//g, '') + const min_cdnjs_file = minFile(cdnjs_file) + if (cond === 'internal') file = `source/${file}` + const verType = CDN.version ? `@${version}` : '' + + const value = { + version, + name, + file, + cdnjs_file, + min_file, + min_cdnjs_file, + cdnjs_name + } + const cdnSource = { + local: cond === 'internal' ? cdnjs_file : `/pluginsSrc/${name}/${file}`, + jsdelivr: `https://cdn.jsdelivr.net/npm/${name}${verType}/${min_file}`, + unpkg: `https://unpkg.com/${name}${verType}/${file}`, + cdnjs: `https://cdnjs.cloudflare.com/ajax/libs/${cdnjs_name}/${version}/${min_cdnjs_file}`, + custom: (CDN.custom_format || '').replace(/\$\{(.+?)\}/g, (match, $1) => value[$1]) + } + + data[key] = cdnSource[type] + }) + + if (cond === 'internal') data['main_css'] = 'css/index.css' + return data + } + + // delete null value + const deleteNullValue = obj => { + if (!obj) return + for (const i in obj) { + obj[i] === null && delete obj[i] + } + return obj + } + + themeConfig.asset = Object.assign(createCDNLink(internalSrc,CDN.internal_provider,'internal'), + createCDNLink(thirdPartySrc,CDN.third_party_provider), deleteNullValue(CDN.option)) +}) diff --git a/scripts/events/comment.js b/scripts/events/comment.js new file mode 100644 index 0000000..b1ef856 --- /dev/null +++ b/scripts/events/comment.js @@ -0,0 +1,14 @@ +/** + * Capitalize the first letter of comment name + */ + +hexo.extend.filter.register('before_generate', () => { + const themeConfig = hexo.theme.config + let { use } = themeConfig.comments + if (!use) return + if (typeof use === 'string') { + use = use.split(',') + } + const newArray = use.map(item => item.toLowerCase().replace(/\b[a-z]/g, s => s.toUpperCase())) + themeConfig.comments.use = newArray +}) \ No newline at end of file diff --git a/scripts/events/init.js b/scripts/events/init.js new file mode 100644 index 0000000..69c2807 --- /dev/null +++ b/scripts/events/init.js @@ -0,0 +1,21 @@ +const logger = require('hexo-log')() + +hexo.extend.filter.register('before_generate', () => { + // Get first two digits of the Hexo version number + const hexoVer = hexo.version.replace(/(^.*\..*)\..*/, '$1') + + if (hexoVer < 5.3) { + logger.error('Please update Hexo to V5.3.0 or higher!') + logger.error('請把 Hexo 升級到 V5.3.0 或更高的版本!') + process.exit(-1) + } + + if (hexo.locals.get) { + const data = hexo.locals.get('data') + if (data && data.butterfly) { + logger.error(" 'butterfly.yml' is deprecated. Please use '_config.butterfly.yml' ") + logger.error(" 'butterfly.yml' 已經棄用,請使用 '_config.butterfly.yml' ") + process.exit(-1) + } + } +}) diff --git a/scripts/events/stylus.js b/scripts/events/stylus.js new file mode 100644 index 0000000..4b95538 --- /dev/null +++ b/scripts/events/stylus.js @@ -0,0 +1,15 @@ +/** + * stylus + */ + +'use strict' + +hexo.extend.filter.register('stylus:renderer', function (style) { + const { highlight, prismjs } = hexo.config + style + .define('$highlight_enable', highlight && highlight.enable) + .define('$highlight_line_number', highlight && highlight.line_number) + .define('$prismjs_enable', prismjs && prismjs.enable) + .define('$prismjs_line_number', prismjs && prismjs.line_number) + // .import(this.source_dir.replace(/\\/g, '/') + '_data/css/*') +}) diff --git a/scripts/events/welcome.js b/scripts/events/welcome.js new file mode 100644 index 0000000..ae1859e --- /dev/null +++ b/scripts/events/welcome.js @@ -0,0 +1,17 @@ +const logger = require('hexo-log')() + +hexo.on('ready', () => { + const { version } = require('../../package.json') + console.log(`╔═════════════════════════════════════════════════════════════════════════════╗ + + ██████╗ ██╗ ██╗ ███══╗ ██║ █████╗ ██████╗ █████████╗ ██╗ ██╗ + ██╔═══██║ ╚██╗ ██╔╝ ██║██║ ██║ ██╔════██║ ██╔════╝ ██╔═══╝ ╚██╗ ██╔╝ + ██║ ██║ ╚████╔╝ ██║██╚╗ ██║ ██║ ██║ ██║ ██║ ╚████╔╝ + ██║ ██║ ╚██╔╝ ██║ ██╚╗██║ █████████║ ███████╗ ██║ ╚██╔╝ + ██║ ██║ ██║ ██║ ██║██║ ██╔════██║ ╚════██║ ██║ ██║ + ██║ ██║ ██║ ██║ ██║██║ ██║ ██║ ██║ ██║ ██║ + ██████╔═╝ ██║ ██║ ███║ ██║ ██║ ██████╔╝ ██║ ██║ + ╚═════╝ ╚═╝ ╚═╝ ╚══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ + ${version} + ╚═════════════════════════════════════════════════════════════════════════════╝`) +}) diff --git a/scripts/filters/post_lazyload.js b/scripts/filters/post_lazyload.js new file mode 100644 index 0000000..c4267d1 --- /dev/null +++ b/scripts/filters/post_lazyload.js @@ -0,0 +1,29 @@ +/** + * Butterfly + * lazyload + * replace src to data-lazy-src + */ + +'use strict' + +const urlFor = require('hexo-util').url_for.bind(hexo) + +function lazyload (htmlContent) { + const bg = hexo.theme.config.lazyload.placeholder ? urlFor(hexo.theme.config.lazyload.placeholder) : 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' + return htmlContent.replace(/( { + const config = hexo.theme.config.lazyload + if (!config.enable) return + if (config.field !== 'post') return + data.content = lazyload.call(this, data.content) + return data +}) diff --git a/scripts/filters/random_cover.js b/scripts/filters/random_cover.js new file mode 100644 index 0000000..47ed4fe --- /dev/null +++ b/scripts/filters/random_cover.js @@ -0,0 +1,45 @@ +/** + * Butterfly + * ramdom cover + */ + +'use strict' + +hexo.extend.filter.register('before_post_render', function (data) { + const { config } = this + if (config.post_asset_folder) { + const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/ + const topImg = data.top_img + const cover = data.cover + if (topImg && topImg.indexOf('/') === -1 && imgTestReg.test(topImg)) data.top_img = data.path + topImg + if (cover && cover.indexOf('/') === -1) data.cover = data.path + cover + } + + if (data.cover === false) { + data.randomcover = randomCover() + return data + } + + data.cover = data.cover || randomCover() + return data +}) + +function randomCover () { + const theme = hexo.theme.config + let cover + let num + + if (theme.cover && theme.cover.default_cover) { + if (!Array.isArray(theme.cover.default_cover)) { + cover = theme.cover.default_cover + return cover + } else { + num = Math.floor(Math.random() * theme.cover.default_cover.length) + cover = theme.cover.default_cover[num] + return cover + } + } else { + cover = theme.default_top_img || 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' + return cover + } +} diff --git a/scripts/helpers/aside_archives.js b/scripts/helpers/aside_archives.js new file mode 100644 index 0000000..779c1d4 --- /dev/null +++ b/scripts/helpers/aside_archives.js @@ -0,0 +1,113 @@ +/** + * Butterfly + * for aside archives + */ + +'use strict' + +hexo.extend.helper.register('aside_archives', function (options = {}) { + const { config } = this + const archiveDir = config.archive_dir + const { timezone } = config + const lang = toMomentLocale(this.page.lang || this.page.language || config.language) + let { format } = options + const type = options.type || 'monthly' + const { transform } = options + const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count') ? options.show_count : true + const order = options.order || -1 + const compareFunc = type === 'monthly' + ? (yearA, monthA, yearB, monthB) => yearA === yearB && monthA === monthB + : (yearA, monthA, yearB, monthB) => yearA === yearB + const limit = options.limit + let result = '' + + if (!format) { + format = type === 'monthly' ? 'MMMM YYYY' : 'YYYY' + } + + const posts = this.site.posts.sort('date', order) + if (!posts.length) return result + + const data = [] + let length = 0 + + posts.forEach(post => { + // Clone the date object to avoid pollution + let date = post.date.clone() + + if (timezone) date = date.tz(timezone) + + const year = date.year() + const month = date.month() + 1 + const lastData = data[length - 1] + + if (!lastData || !compareFunc(lastData.year, lastData.month, year, month)) { + if (lang) date = date.locale(lang) + const name = date.format(format) + length = data.push({ + name, + year, + month, + count: 1 + }) + } else { + lastData.count++ + } + }) + + const link = item => { + let url = `${archiveDir}/${item.year}/` + + if (type === 'monthly') { + if (item.month < 10) url += '0' + url += `${item.month}/` + } + + return this.url_for(url) + } + + const len = data.length + const Judge = limit === 0 ? len : Math.min(len, limit) + + result += `
${this._p('aside.card_archives')}` + + if (len > Judge) { + result += ` + ` + } + + result += '
' + return result +}) + +const toMomentLocale = function (lang) { + if (lang === undefined) { + return undefined + } + + // moment.locale('') equals moment.locale('en') + // moment.locale(null) equals moment.locale('en') + if (!lang || lang === 'en' || lang === 'default') { + return 'en' + } + return lang.toLowerCase().replace('_', '-') +} diff --git a/scripts/helpers/aside_categories.js b/scripts/helpers/aside_categories.js new file mode 100644 index 0000000..0e60b8e --- /dev/null +++ b/scripts/helpers/aside_categories.js @@ -0,0 +1,97 @@ +/** + * Butterfly + * for aside categories + */ + +'use strict' + +hexo.extend.helper.register('aside_categories', function (categories, options) { + if (!options && (!categories || !Object.prototype.hasOwnProperty.call(categories, 'length')) + ) { + options = categories + categories = this.site.categories + } + + if (!categories || !categories.length) return '' + options = options || {} + const { config } = this + const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count') + ? options.show_count + : true + const depth = options.depth ? parseInt(options.depth, 10) : 0 + const orderby = options.orderby || 'name' + const order = options.order || 1 + const categoryDir = this.url_for(config.category_dir) + const limit = options.limit === 0 ? categories.length : options.limit + const isExpand = options.expand !== 'none' + const expandClass = isExpand && options.expand === true ? 'expand' : '' + const buttonLabel = this._p('aside.more_button') + const prepareQuery = (parent) => { + const query = {} + if (parent) { query.parent = parent } else { query.parent = { $exists: false } } + return categories.find(query).sort(orderby, order).filter((cat) => cat.length) + } + + const hierarchicalList = (t, level, parent, topparent = true) => { + let result = '' + const isTopParent = topparent + if (t > 0) { + prepareQuery(parent).forEach((cat, i) => { + if (t > 0) { + t = t - 1 + let child + if (!depth || level + 1 < depth) { + const childList = hierarchicalList(t, level + 1, cat._id, false) + child = childList[0] + t = childList[1] + } + + const parentClass = isExpand && isTopParent && child ? 'parent' : '' + + result += `
  • ` + + result += `` + + result += `${cat.name}` + + if (showCount) { + result += `${cat.length}` + } + + if (isExpand && isTopParent && child) { + result += `` + } + + result += '' + + if (child) { + result += `
      ${child}
    ` + } + + result += '
  • ' + } + }) + } + + return [result, t] + } + + const list = hierarchicalList(limit, 0) + + const moreButton = function () { + if (categories.length <= limit) return '' + const moreHtml = ` + ` + + return moreHtml + } + + return `
    + + ${this._p('aside.card_categories')} + ${moreButton()} +
    +
      + ${list[0]} +
    ` +}) diff --git a/scripts/helpers/findArchiveLength.js b/scripts/helpers/findArchiveLength.js new file mode 100644 index 0000000..e55dc0f --- /dev/null +++ b/scripts/helpers/findArchiveLength.js @@ -0,0 +1,58 @@ +hexo.extend.helper.register('findArchiveLength', function (func) { + const allPostsLength = this.site.posts.length; + if (hexo.config.archive_generator && hexo.config.archive_generator.enable === false ) return allPostsLength + const { yearly, monthly, daily } = hexo.config.archive_generator + const { year, month, day } = this.page + if (yearly === false || !year) return allPostsLength + + const posts = this.site.posts.sort('date') + + const compareFunc = (type,y1,m1,d1,y2,m2,d2) => { + if (type === 'year') { + return y1 === y2 + } else if (type === 'month') { + return y1 === y2 && m1 === m2 + } else if (type === 'day') { + return y1 === y2 && m1 === m2 && d1 === d2 + } + } + + const generateDateObj = (type) => { + let dateObj = [] + let length = 0 + + posts.forEach(post => { + let date = post.date.clone() + const year = date.year() + const month = date.month() + 1 + const day = date.date() + let lastData = dateObj[length - 1] + + if (!lastData || !compareFunc(type, lastData.year, lastData.month, lastData.day, year, month, day)) { + const name = type === 'year' ? year : type === 'month' ? `${year}-${month}` : `${year}-${month}-${day}` + length = dateObj.push({ + name, + year, + month, + day, + count: 1 + }) + } else { + lastData.count++ + } + }); + + return dateObj + } + + const data = func('createArchiveObj', ()=> { + const yearObj = yearly ? generateDateObj('year') : [] + const monthObj = monthly ? generateDateObj('month') : [] + const dayObj = daily ? generateDateObj('day') : [] + const fullObj = [...yearObj, ...monthObj, ...dayObj] + return fullObj + }) + + const name = month ? day ? `${year}-${month}-${day}` : `${year}-${month}` : year + return data.find(item => item.name === name).count +}) \ No newline at end of file diff --git a/scripts/helpers/get_arrays.js b/scripts/helpers/get_arrays.js new file mode 100644 index 0000000..da27c1d --- /dev/null +++ b/scripts/helpers/get_arrays.js @@ -0,0 +1,45 @@ +hexo.extend.helper.register('getarray_bar', function (types) { + if (!types) { + types = "category" + } + const categoriesBar = function (categories) { + if (!categories || !categories.length) return `` + const categoryArr = [] + hexo.locals.get('categories').map(function (category) { + categoryArr.push({ name: category.name, value: category.length }) + }) + categoryArr.sort((a, b) => { return b.value - a.value }) + let strCategoriesBar = `` + for (let i = 0; i < categories.length; i++) { + strTemp=` + ` + strCategoriesBar+=strTemp + } + return strCategoriesBar + } + const tagsBar = function(tags) { + if (!tags || !tags.length) return `` + const tagArr = [] + hexo.locals.get('tags').map(function (tag) { + tagArr.push({ name: tag.name, value: tag.length }) + }) + tagArr.sort((a, b) => { return b.value - a.value }) + let strTagsBar = `` + for (let i = 0; i < tags.length; i++) { + strTemp=` + ` + strTagsBar+=strTemp + } + return strTagsBar + } + if (types == "category"){ + return categoriesBar(this.site.categories) + } + if (types == "tag"){ + return tagsBar(this.site.tags) + } +}) \ No newline at end of file diff --git a/scripts/helpers/inject_head_js.js b/scripts/helpers/inject_head_js.js new file mode 100644 index 0000000..9c845d4 --- /dev/null +++ b/scripts/helpers/inject_head_js.js @@ -0,0 +1,148 @@ +/** + * Butterfly + * inject js to head + */ + +'use strict' + +hexo.extend.helper.register('inject_head_js', function () { + const { darkmode, aside } = this.theme + + const { theme_color } = hexo.theme.config + const themeColorLight = theme_color && theme_color.enable && theme_color.meta_theme_color_light || '#ffffff' + const themeColorDark = theme_color && theme_color.enable && theme_color.meta_theme_color_dark || '#0d0d0d' + + const localStore = ` + win.saveToLocal = { + set: function setWithExpiry(key, value, ttl) { + if (ttl === 0) return + const now = new Date() + const expiryDay = ttl * 86400000 + const item = { + value: value, + expiry: now.getTime() + expiryDay, + } + localStorage.setItem(key, JSON.stringify(item)) + }, + + get: function getWithExpiry(key) { + const itemStr = localStorage.getItem(key) + + if (!itemStr) { + return undefined + } + const item = JSON.parse(itemStr) + const now = new Date() + + if (now.getTime() > item.expiry) { + localStorage.removeItem(key) + return undefined + } + return item.value + } + } + ` + + // https://stackoverflow.com/questions/16839698/jquery-getscript-alternative-in-native-javascript + const getScript = ` + win.getScript = url => new Promise((resolve, reject) => { + const script = document.createElement('script') + script.src = url + script.async = true + script.onerror = reject + script.onload = script.onreadystatechange = function() { + const loadState = this.readyState + if (loadState && loadState !== 'loaded' && loadState !== 'complete') return + script.onload = script.onreadystatechange = null + resolve() + } + document.head.appendChild(script) + }) + ` + + let darkmodeJs = '' + if (darkmode.enable) { + darkmodeJs = ` + win.activateDarkMode = function () { + document.documentElement.setAttribute('data-theme', 'dark') + if (document.querySelector('meta[name="theme-color"]') !== null) { + document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorDark}') + } + } + win.activateLightMode = function () { + document.documentElement.setAttribute('data-theme', 'light') + if (document.querySelector('meta[name="theme-color"]') !== null) { + document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorLight}') + } + } + const t = saveToLocal.get('theme') + ` + + const autoChangeMode = darkmode.autoChangeMode + + if (autoChangeMode === 1) { + darkmodeJs += ` + const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches + const isLightMode = window.matchMedia('(prefers-color-scheme: light)').matches + const isNotSpecified = window.matchMedia('(prefers-color-scheme: no-preference)').matches + const hasNoSupport = !isDarkMode && !isLightMode && !isNotSpecified + + if (t === undefined) { + if (isLightMode) activateLightMode() + else if (isDarkMode) activateDarkMode() + else if (isNotSpecified || hasNoSupport) { + const now = new Date() + const hour = now.getHours() + const isNight = hour <= 6 || hour >= 18 + isNight ? activateDarkMode() : activateLightMode() + } + window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) { + if (saveToLocal.get('theme') === undefined) { + e.matches ? activateDarkMode() : activateLightMode() + } + }) + } else if (t === 'light') activateLightMode() + else activateDarkMode() + ` + } else if (autoChangeMode === 2) { + darkmodeJs += ` + const now = new Date() + const hour = now.getHours() + const isNight = hour <= 6 || hour >= 18 + if (t === undefined) isNight ? activateDarkMode() : activateLightMode() + else if (t === 'light') activateLightMode() + else activateDarkMode() + ` + } else { + darkmodeJs += ` + if (t === 'dark') activateDarkMode() + else if (t === 'light') activateLightMode() + ` + } + } + + let asideStatus = '' + if (aside.enable && aside.button) { + asideStatus = ` + const asideStatus = saveToLocal.get('aside-status') + if (asideStatus !== undefined) { + if (asideStatus === 'hide') { + document.documentElement.classList.add('hide-aside') + } else { + document.documentElement.classList.remove('hide-aside') + } + } + ` + } + + const detectApple = ` + const detectApple = () => { + if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){ + document.documentElement.classList.add('apple') + } + } + detectApple() + ` + + return `` +}) diff --git a/scripts/helpers/page.js b/scripts/helpers/page.js new file mode 100644 index 0000000..a01092a --- /dev/null +++ b/scripts/helpers/page.js @@ -0,0 +1,83 @@ +/** + * Butterfly + * @example + * page_description() + * cloudTags(source, minfontsize, maxfontsize, limit) + */ + +'use strict' + +const { stripHTML, escapeHTML, prettyUrls } = require('hexo-util') +const crypto = require('crypto') + +hexo.extend.helper.register('page_description', function () { + const { config, page } = this + let description = page.description || page.content || page.title || config.description + + if (description) { + description = escapeHTML(stripHTML(description).substring(0, 150) + .trim() + ).replace(/\n/g, ' ') + return description + } +}) + +hexo.extend.helper.register('cloudTags', function (options = {}) { + const env = this + let source = options.source + const limit = options.limit + + let result = '' + if (limit > 0) { + source = source.limit(limit) + } + + source.forEach(tag => { + const color = 'rgb(' + Math.floor(Math.random() * 201) + ', ' + Math.floor(Math.random() * 201) + ', ' + Math.floor(Math.random() * 201) + ')' // 0,0,0 -> 200,200,200 + style += ` color: ${color}` + result += `${tag.name}` + }) + return result +}) + +hexo.extend.helper.register('urlNoIndex', function (url = null) { + return prettyUrls(url || this.url, { trailing_index: false, trailing_html: false }) +}) + +hexo.extend.helper.register('md5', function (path) { + return crypto.createHash('md5').update(decodeURI(this.url_for(path))).digest('hex') +}) + +hexo.extend.helper.register('injectHtml', function (data) { + let result = '' + if (!data) return '' + for (let i = 0; i < data.length; i++) { + result += data[i] + } + return result +}) + +hexo.extend.helper.register('findArchivesTitle', function (page, menu, date) { + if (page.year) { + const dateStr = page.month ? `${page.year}-${page.month}` : `${page.year}` + const date_format = page.month ? hexo.theme.config.aside.card_archives.format : 'YYYY' + return date(dateStr, date_format) + } + + const defaultTitle = this._p('page.archives') + if (!menu) return defaultTitle + + const loop = (m) => { + for (const key in m) { + if (typeof m[key] === 'object') { + loop(m[key]) + } + + if (/\/archives\//.test(m[key])) { + return key + } + } + } + + return loop(menu) || defaultTitle +}) diff --git a/scripts/helpers/random.js b/scripts/helpers/random.js new file mode 100644 index 0000000..286171c --- /dev/null +++ b/scripts/helpers/random.js @@ -0,0 +1,11 @@ +hexo.extend.generator.register('random', function (locals) { + const config = hexo.config.random || {} + const posts = [] + for (const post of locals.posts.data) { + if (post.random !== false) posts.push(post.path) + } + return { + path: config.path || 'js/random.js', + data: `var posts=${JSON.stringify(posts)};function toRandomPost(){window.open('/'+posts[Math.floor(Math.random() * posts.length)],"_self");};` + } +}) \ No newline at end of file diff --git a/scripts/helpers/related_post.js b/scripts/helpers/related_post.js new file mode 100644 index 0000000..6809ac7 --- /dev/null +++ b/scripts/helpers/related_post.js @@ -0,0 +1,99 @@ +/** + * Butterfly + * Related Posts + * According the tag + */ + +'use strict' + +hexo.extend.helper.register('related_posts', function (currentPost, allPosts) { + let relatedPosts = [] + currentPost.tags.forEach(function (tag) { + allPosts.forEach(function (post) { + if (isTagRelated(tag.name, post.tags)) { + const relatedPost = { + title: post.title, + path: post.path, + cover: post.cover, + randomcover: post.randomcover, + weight: 1, + updated: post.updated, + created: post.date + } + const index = findItem(relatedPosts, 'path', post.path) + if (index !== -1) { + relatedPosts[index].weight += 1 + } else { + if (currentPost.path !== post.path) { + relatedPosts.push(relatedPost) + } + } + } + }) + }) + if (relatedPosts.length === 0) { + return '' + } + let result = '' + const hexoConfig = hexo.config + const config = hexo.theme.config + + const limitNum = config.related_post.limit || 6 + const dateType = config.related_post.date_type || 'created' + const headlineLang = this._p('post.recommend') + + relatedPosts = relatedPosts.sort(compare('weight')) + + if (relatedPosts.length > 0) { + result += '