├── source ├── css │ ├── _custom │ │ ├── custom.styl │ │ ├── font.css │ │ ├── flink.css │ │ ├── sidebar.css │ │ ├── tag.styl │ │ ├── snackbar.css │ │ ├── animations.css │ │ ├── comment.styl │ │ └── bar.css │ ├── _layout │ │ ├── relatedposts.styl │ │ ├── chat.styl │ │ ├── rightside.styl │ │ ├── loading.styl │ │ ├── footer.styl │ │ ├── comments.styl │ │ ├── reward.styl │ │ ├── sidebar.styl │ │ ├── pagination.styl │ │ └── third-party.styl │ ├── _tags │ │ ├── inlineImg.styl │ │ ├── ghcard.styl │ │ ├── label.styl │ │ ├── span.styl │ │ ├── hexo.styl │ │ ├── poem.styl │ │ ├── hide.styl │ │ ├── link.styl │ │ ├── media.styl │ │ ├── button.styl │ │ ├── progress.styl │ │ ├── card.styl │ │ ├── tabs.styl │ │ ├── timeline.styl │ │ ├── gallery.styl │ │ └── folding.styl │ ├── _page │ │ ├── tags.styl │ │ ├── categories.styl │ │ ├── common.styl │ │ ├── 404.styl │ │ ├── flink.styl │ │ ├── archives.styl │ │ └── homepage.styl │ ├── _highlight │ │ ├── prismjs │ │ │ ├── index.styl │ │ │ └── line-number.styl │ │ └── highlight │ │ │ ├── index.styl │ │ │ └── diff.styl │ ├── index.styl │ ├── _search │ │ ├── index.styl │ │ ├── local-search.styl │ │ └── algolia.styl │ └── post-double-row.css ├── img │ ├── 404.jpg │ ├── favicon.png │ └── friend_404.gif ├── font │ ├── alifangyuan.ttf │ └── iconfont.woff2 └── js │ ├── sub.js │ ├── swiper.js │ └── scroll.js ├── layout ├── includes │ ├── page │ │ ├── categories.pug │ │ ├── default-page.pug │ │ ├── tags.pug │ │ ├── comments.pug │ │ └── flink.pug │ ├── head │ │ ├── site_verification.pug │ │ ├── noscript.pug │ │ ├── google_adsense.pug │ │ ├── Open_Graph.pug │ │ ├── pwa.pug │ │ ├── preconnect.pug │ │ ├── config_site.pug │ │ └── analytics.pug │ ├── third-party │ │ ├── search │ │ │ ├── index.pug │ │ │ ├── algolia.pug │ │ │ └── local-search.pug │ │ ├── share │ │ │ ├── add-this.pug │ │ │ ├── share-js.pug │ │ │ ├── index.pug │ │ │ └── addtoany.pug │ │ ├── aplayer.pug │ │ ├── prismjs.pug │ │ ├── math │ │ │ ├── katex.pug │ │ │ ├── index.pug │ │ │ ├── mermaid.pug │ │ │ └── mathjax.pug │ │ ├── card-post-count │ │ │ ├── index.pug │ │ │ ├── disqus.pug │ │ │ ├── remark42.pug │ │ │ ├── waline.pug │ │ │ ├── artalk.pug │ │ │ ├── valine.pug │ │ │ ├── fb.pug │ │ │ └── twikoo.pug │ │ ├── chat │ │ │ ├── index.pug │ │ │ ├── chatra.pug │ │ │ ├── crisp.pug │ │ │ ├── gitter.pug │ │ │ ├── tidio.pug │ │ │ ├── messenger.pug │ │ │ └── daovoice.pug │ │ ├── pangu.pug │ │ ├── effect.pug │ │ ├── comments │ │ │ ├── livere.pug │ │ │ ├── js.pug │ │ │ ├── valine.pug │ │ │ ├── waline.pug │ │ │ ├── index.pug │ │ │ ├── utterances.pug │ │ │ ├── gitalk.pug │ │ │ ├── artalk.pug │ │ │ ├── twikoo.pug │ │ │ ├── disqus.pug │ │ │ ├── facebook_comments.pug │ │ │ ├── giscus.pug │ │ │ ├── remark42.pug │ │ │ └── disqusjs.pug │ │ ├── newest-comments │ │ │ └── index.pug │ │ └── subtitle.pug │ ├── header │ │ ├── social.pug │ │ ├── menu_item.pug │ │ ├── nav.pug │ │ └── index.pug │ ├── pagination.pug │ ├── 404.pug │ ├── post │ │ ├── reward.pug │ │ └── post-copyright.pug │ ├── waves.pug │ ├── widget │ │ ├── card_post_toc.pug │ │ ├── card_author.pug │ │ ├── index.pug │ │ ├── card_webinfo.pug │ │ └── card_tags.pug │ ├── sidebar.pug │ ├── mixins │ │ └── article-sort.pug │ ├── swiper.pug │ ├── loading │ │ └── index.pug │ ├── footer.pug │ ├── additional-js.pug │ └── rightside.pug ├── index.pug ├── archive.pug ├── tag.pug ├── category.pug ├── page.pug └── post.pug ├── theme.png ├── scripts ├── events │ ├── 404.js │ ├── comment.js │ ├── stylus.js │ ├── init.js │ ├── welcome.js │ └── cdn.js ├── tag │ ├── label.js │ ├── mermaid.js │ ├── inlineImg.js │ ├── poem.js │ ├── progress.js │ ├── button.js │ ├── gh.js │ ├── span.js │ ├── note.js │ ├── gallery.js │ ├── folding.js │ ├── btns.js │ ├── reference.js │ ├── flink.js │ ├── ghcard.js │ ├── timeline.js │ ├── card.js │ ├── msgbox.js │ ├── media.js │ ├── hide.js │ └── tabs.js ├── helpers │ ├── random.js │ ├── get_arrays.js │ ├── findArchiveLength.js │ └── page.js └── filters │ ├── post_lazyload.js │ └── random_cover.js ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.yml │ └── bug_report.yml └── workflows │ ├── publish.yml │ └── stale.yml ├── package.json ├── README.md └── languages ├── zh-CN.yml └── zh-TW.yml /source/css/_custom/custom.styl: -------------------------------------------------------------------------------- 1 | nav#pagination 2 | margin: auto -------------------------------------------------------------------------------- /layout/includes/page/categories.pug: -------------------------------------------------------------------------------- 1 | .category-lists!= list_categories() -------------------------------------------------------------------------------- /source/css/_layout/relatedposts.styl: -------------------------------------------------------------------------------- 1 | .relatedPosts 2 | display: none -------------------------------------------------------------------------------- /layout/includes/page/default-page.pug: -------------------------------------------------------------------------------- 1 | #article-container 2 | != page.content -------------------------------------------------------------------------------- /theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ezgx/hexo-theme-Dynasty/HEAD/theme.png -------------------------------------------------------------------------------- /source/img/404.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ezgx/hexo-theme-Dynasty/HEAD/source/img/404.jpg -------------------------------------------------------------------------------- /layout/includes/page/tags.pug: -------------------------------------------------------------------------------- 1 | .tag-cloud-list.is-center 2 | !=cloudTags({source: site.tags, limit: 0}) -------------------------------------------------------------------------------- /source/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ezgx/hexo-theme-Dynasty/HEAD/source/img/favicon.png -------------------------------------------------------------------------------- /source/font/alifangyuan.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ezgx/hexo-theme-Dynasty/HEAD/source/font/alifangyuan.ttf -------------------------------------------------------------------------------- /source/font/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ezgx/hexo-theme-Dynasty/HEAD/source/font/iconfont.woff2 -------------------------------------------------------------------------------- /source/img/friend_404.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ezgx/hexo-theme-Dynasty/HEAD/source/img/friend_404.gif -------------------------------------------------------------------------------- /layout/includes/head/site_verification.pug: -------------------------------------------------------------------------------- 1 | if theme.site_verification 2 | each item in theme.site_verification 3 | meta(name=item.name content=item.content) -------------------------------------------------------------------------------- /source/css/_custom/font.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | font-family: "PingFang SC","Hiragino Sans GB","Microsoft YaHei"; 4 | font-size: 16px; 5 | font-weight: 600; 6 | } -------------------------------------------------------------------------------- /source/js/sub.js: -------------------------------------------------------------------------------- 1 | var mySwiper = new Swiper ('.swiper-container', { 2 | direction: 'vertical', 3 | loop: true, 4 | autoplay: true, 5 | delay: 1500, 6 | }) -------------------------------------------------------------------------------- /layout/includes/third-party/search/index.pug: -------------------------------------------------------------------------------- 1 | if theme.algolia_search.enable 2 | include ./algolia.pug 3 | else if theme.local_search.enable 4 | include ./local-search.pug -------------------------------------------------------------------------------- /layout/includes/third-party/share/add-this.pug: -------------------------------------------------------------------------------- 1 | .addthis_inline_share_toolbox 2 | script(src=`//s7.addthis.com/js/300/addthis_widget.js#pubid=${theme.addThis.pubid}` async) -------------------------------------------------------------------------------- /source/css/_tags/inlineImg.styl: -------------------------------------------------------------------------------- 1 | #article-container 2 | .inline-img 3 | display: inline 4 | margin: 0 3px 5 | height: 1.1em 6 | vertical-align: text-bottom -------------------------------------------------------------------------------- /layout/index.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | include ./includes/mixins/post-ui.pug 5 | #recent-posts.recent-posts.maininner 6 | +postUI 7 | include includes/pagination.pug -------------------------------------------------------------------------------- /layout/includes/third-party/aplayer.pug: -------------------------------------------------------------------------------- 1 | link(rel='stylesheet' href=url_for(theme.asset.aplayer_css) media="print" onload="this.media='all'") 2 | script(src=url_for(theme.asset.aplayer_js)) 3 | script(src=url_for(theme.asset.meting_js)) -------------------------------------------------------------------------------- /layout/includes/header/social.pug: -------------------------------------------------------------------------------- 1 | each url, icon in theme.social 2 | a.social-icon(href=url_for(trim(url.split('||')[0])) target="_blank" 3 | title=url.split('||')[1] === undefined ? '' : trim(url.split('||')[1])) 4 | i(class=icon) -------------------------------------------------------------------------------- /source/css/_tags/ghcard.styl: -------------------------------------------------------------------------------- 1 | a.ghcard 2 | display: inline-block 3 | line-height: 0 4 | 5 | .md .ghcard-group 6 | column-count: 2 7 | column-gap: 0 8 | margin: 0 0 - 10px * 0.5 9 | .ghcard 10 | margin: 10px * 0.5 11 | -------------------------------------------------------------------------------- /layout/includes/third-party/share/share-js.pug: -------------------------------------------------------------------------------- 1 | .social-share(data-image=url_for(page.cover|| theme.avatar.img) data-sites= theme.sharejs.sites) 2 | link(rel='stylesheet' href=url_for(theme.asset.sharejs_css) media="print" onload="this.media='all'") 3 | script(src=url_for(theme.asset.sharejs) defer) -------------------------------------------------------------------------------- /source/css/_tags/label.styl: -------------------------------------------------------------------------------- 1 | .hl-label 2 | padding: 2px 4px 3 | border-radius: 3px 4 | color: $btn-color 5 | 6 | &.default 7 | background-color: $btn-default-color 8 | 9 | for $type in $color-types 10 | &.{$type} 11 | background-color: lookup('$tagsP-' + $type + '-color') 12 | -------------------------------------------------------------------------------- /layout/includes/head/noscript.pug: -------------------------------------------------------------------------------- 1 | noscript. 2 | -------------------------------------------------------------------------------- /layout/includes/third-party/prismjs.pug: -------------------------------------------------------------------------------- 1 | if config.prismjs && config.prismjs.enable && !config.prismjs.preprocess 2 | script(src=url_for(theme.asset.prismjs_js)) 3 | script(src=url_for(theme.asset.prismjs_autoloader)) 4 | if config.prismjs.line_number 5 | script(src=url_for(theme.asset.prismjs_lineNumber_js)) 6 | -------------------------------------------------------------------------------- /layout/includes/third-party/share/index.pug: -------------------------------------------------------------------------------- 1 | .post_share 2 | if theme.addThis.enable 3 | !=partial('includes/third-party/share/add-this', {}, {cache: true}) 4 | else if theme.sharejs.enable 5 | include ./share-js.pug 6 | else if theme.addtoany.enable 7 | !=partial('includes/third-party/share/addtoany', {}, {cache: true}) 8 | -------------------------------------------------------------------------------- /layout/archive.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | include ./includes/mixins/article-sort.pug 5 | #archive 6 | - const archiveLength = findArchiveLength(fragment_cache) 7 | .article-sort-title= _p('page.articles') + ' - ' + archiveLength 8 | +articleSort(page.posts) 9 | include includes/pagination.pug -------------------------------------------------------------------------------- /layout/includes/third-party/math/katex.pug: -------------------------------------------------------------------------------- 1 | link(rel="stylesheet" type="text/css" href=url_for(theme.asset.katex)) 2 | script(src=url_for(theme.asset.katex_copytex)) 3 | script. 4 | (() => { 5 | document.querySelectorAll('#article-container span.katex-display').forEach(item => { 6 | btf.wrap(item, 'div', { class: 'katex-wrap'}) 7 | }) 8 | })() 9 | -------------------------------------------------------------------------------- /layout/includes/third-party/share/addtoany.pug: -------------------------------------------------------------------------------- 1 | .addtoany 2 | .a2a_kit.a2a_kit_size_32.a2a_default_style 3 | - let addtoanyItem = theme.addtoany.item.split(',') 4 | each name in addtoanyItem 5 | a(class="a2a_button_" + name) 6 | 7 | a.a2a_dd(href="https://www.addtoany.com/share") 8 | script(async src='https://static.addtoany.com/menu/page.js') 9 | 10 | 11 | -------------------------------------------------------------------------------- /scripts/events/404.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Butterfly 3 | * 404 error page 4 | */ 5 | 6 | 'use strict' 7 | 8 | hexo.extend.generator.register('404', function (locals) { 9 | if (!hexo.theme.config.error_404.enable) return 10 | return { 11 | path: '404.html', 12 | layout: ['page'], 13 | data: { 14 | type: '404', 15 | top_img: false 16 | } 17 | } 18 | }) 19 | -------------------------------------------------------------------------------- /source/css/_page/tags.styl: -------------------------------------------------------------------------------- 1 | .tag-cloud 2 | &-list 3 | a 4 | display: inline-block 5 | padding: 0 8px 6 | transition: all .3s 7 | 8 | +maxWidth768() 9 | zoom: .85 10 | 11 | &-title 12 | font-size: 2.57em 13 | 14 | +maxWidth768() 15 | font-size: 2em 16 | 17 | h1.page-title 18 | & + .tag-cloud-list 19 | text-align: left 20 | -------------------------------------------------------------------------------- /scripts/tag/label.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Butterfly 3 | * label 4 | * {% label text color %} 5 | */ 6 | 7 | 'use strict' 8 | 9 | function addLabel (args, content) { 10 | const text = args[0] 11 | const className = args[1] || 'default' 12 | 13 | return `${text} ` 14 | } 15 | 16 | hexo.extend.tag.register('label', addLabel, { ends: false }) 17 | -------------------------------------------------------------------------------- /layout/includes/pagination.pug: -------------------------------------------------------------------------------- 1 | - 2 | var options = { 3 | prev_text: '', 4 | next_text: '', 5 | mid_size: 1, 6 | escape: false 7 | } 8 | 9 | if is_post() 10 | block content 11 | else 12 | nav#pagination 13 | .pagination 14 | if is_home() 15 | - options.format = 'page/%d/' 16 | !=paginator(options) -------------------------------------------------------------------------------- /layout/includes/head/google_adsense.pug: -------------------------------------------------------------------------------- 1 | if (theme.google_adsense && theme.google_adsense.enable) 2 | script(async src=theme.google_adsense.js) 3 | 4 | if theme.google_adsense.auto_ads 5 | script. 6 | (adsbygoogle = window.adsbygoogle || []).push({ 7 | google_ad_client: '!{theme.google_adsense.client}', 8 | enable_page_level_ads: '!{theme.google_adsense.enable_page_level_ads}' 9 | }); -------------------------------------------------------------------------------- /layout/includes/404.pug: -------------------------------------------------------------------------------- 1 | - var top_img_404 = theme.error_404.background || theme.default_top_img 2 | 3 | #body-wrap.error404 4 | include ./header/index.pug 5 | 6 | #error-wrap 7 | .error-content 8 | .error-img 9 | img(src=url_for(top_img_404) alt='Page not found') 10 | .error-info 11 | h1.error_title= '404' 12 | .error_subtitle= theme.error_404.subtitle || _p('error404') 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: QQ 2群 4 | url: http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=qk2lHfzjy1zxBBH4Gzpdby_D5l5BBRTy&authKey=e4gai6kHIffsLOnjR5hP6U%2BuU5JX%2B8LoU3LM%2BVmSjJCkuyBj1NqDjGtEgpUpFSV4&noverify=0&group_code=741440379 5 | about: 群号741440379 6 | - name: 作者QQ 7 | url: http://wpa.qq.com/msgrd?v=3&uin=3387251845&site=qq&menu=yes 8 | about: 添加主题作者qq -------------------------------------------------------------------------------- /scripts/tag/mermaid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Butterfly 3 | * mermaid 4 | * https://github.com/mermaid-js/mermaid 5 | */ 6 | 7 | 'use strict' 8 | 9 | const { escapeHTML } = require('hexo-util') 10 | 11 | function mermaid (args, content) { 12 | return `
` 15 | } 16 | 17 | hexo.extend.tag.register('mermaid', mermaid, { ends: true }) 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for this project 3 | title: '[Feature]: ' 4 | 5 | body: 6 | - type: textarea 7 | id: feature-request 8 | attributes: 9 | label: 想要的功能 | What feature do you want? 10 | description: 請描述你需要的新功能 | A clear and concise description of what the feature is. 11 | placeholder: 12 | value: 13 | validations: 14 | require: true -------------------------------------------------------------------------------- /layout/includes/third-party/card-post-count/index.pug: -------------------------------------------------------------------------------- 1 | case theme.comments.use[0] 2 | when 'Twikoo' 3 | include ./twikoo.pug 4 | when 'Disqus' 5 | when 'Disqusjs' 6 | include ./disqus.pug 7 | when 'Valine' 8 | include ./valine.pug 9 | when 'Waline' 10 | include ./waline.pug 11 | when 'Facebook Comments' 12 | include ./fb.pug 13 | when 'Remark42' 14 | include ./remark42.pug 15 | when 'Artalk' 16 | include ./artalk.pug -------------------------------------------------------------------------------- /layout/tag.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | if theme.tag_ui == 'index' 5 | include ./includes/mixins/post-ui.pug 6 | #recent-posts.recent-posts 7 | +postUI 8 | include includes/pagination.pug 9 | else 10 | include ./includes/mixins/article-sort.pug 11 | #tag 12 | .article-sort-title= _p('page.tag') + ' - ' + page.tag 13 | +articleSort(page.posts) 14 | include includes/pagination.pug -------------------------------------------------------------------------------- /source/js/swiper.js: -------------------------------------------------------------------------------- 1 | var mySwiper = new Swiper ('.hometop-swiper', { 2 | direction: 'vertical', // 垂直切换选项 3 | loop: true, // 循环模式选项 4 | effect: 'creative', 5 | mousewheel: true, 6 | autoplay:true, 7 | // 如果需要分页器 8 | pagination: { 9 | el: '.swiper-pagination', 10 | }, 11 | // 如果需要前进后退按钮 12 | navigation: { 13 | nextEl: '.hometop-swiper-button-next', 14 | prevEl: '.hometop-swiper-button-prev', 15 | }, 16 | }) -------------------------------------------------------------------------------- /scripts/tag/inlineImg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * inlineImg 圖片 3 | * {% inlineImg src height %} 4 | */ 5 | 6 | 'use strict' 7 | 8 | const urlFor = require('hexo-util').url_for.bind(hexo) 9 | 10 | function inlineImg (args) { 11 | const img = args[0] 12 | const height = args[1] ? `style="height:${args[1]}"` : '' 13 | 14 | return `` 15 | } 16 | 17 | hexo.extend.tag.register('inlineImg', inlineImg, { ends: false }) 18 | -------------------------------------------------------------------------------- /layout/includes/post/reward.pug: -------------------------------------------------------------------------------- 1 | .post-reward 2 | .reward-button 3 | i.fas.fa-qrcode 4 | = ' ' + _p('donate') 5 | .reward-main 6 | ul.reward-all 7 | each item in theme.reward.QR_code 8 | - var clickTo = item.link ? item.link : item.img 9 | li.reward-item 10 | a(href=url_for(clickTo) target='_blank') 11 | img.post-qr-code-img(src=url_for(item.img) alt=item.text) 12 | .post-qr-code-desc=item.text 13 | 14 | -------------------------------------------------------------------------------- /scripts/events/comment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Capitalize the first letter of comment name 3 | */ 4 | 5 | hexo.extend.filter.register('before_generate', () => { 6 | const themeConfig = hexo.theme.config 7 | let { use } = themeConfig.comments 8 | if (!use) return 9 | if (typeof use === 'string') { 10 | use = use.split(',') 11 | } 12 | const newArray = use.map(item => item.toLowerCase().replace(/\b[a-z]/g, s => s.toUpperCase())) 13 | themeConfig.comments.use = newArray 14 | }) -------------------------------------------------------------------------------- /layout/includes/third-party/chat/index.pug: -------------------------------------------------------------------------------- 1 | if theme.chatra && theme.chatra.enable 2 | include ./chatra.pug 3 | else if theme.tidio && theme.tidio.enable 4 | include ./tidio.pug 5 | else if theme.daovoice && theme.daovoice.enable 6 | include ./daovoice.pug 7 | else if theme.gitter && theme.gitter.enable 8 | include ./gitter.pug 9 | else if theme.crisp && theme.crisp.enable 10 | include ./crisp.pug 11 | else if theme.messenger && theme.messenger.enable 12 | include ./messenger.pug -------------------------------------------------------------------------------- /layout/category.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | if theme.category_ui == 'index' 5 | include ./includes/mixins/post-ui.pug 6 | #recent-posts.recent-posts.category_ui 7 | +postUI 8 | include includes/pagination.pug 9 | else 10 | include ./includes/mixins/article-sort.pug 11 | #category 12 | .article-sort-title= _p('page.category') + ' - ' + page.category 13 | +articleSort(page.posts) 14 | include includes/pagination.pug -------------------------------------------------------------------------------- /source/css/_tags/span.styl: -------------------------------------------------------------------------------- 1 | span.p.center.logo.large 2 | font-size 2.5rem 3 | text-align center 4 | display block 5 | 6 | span.p.center.small 7 | text-align center 8 | display block 9 | font-size 1rem 10 | 11 | span.p.red 12 | color #fe5f58 13 | 14 | span.p.yellow 15 | color #ffbd2b 16 | 17 | span.p.green 18 | color #3dc550 19 | 20 | span.p.cyan 21 | color #1bcdfc 22 | 23 | span.p.blue 24 | color #2196f3 25 | 26 | span.p.gray 27 | color #999 -------------------------------------------------------------------------------- /layout/includes/third-party/math/index.pug: -------------------------------------------------------------------------------- 1 | if theme.mathjax && theme.mathjax.enable 2 | if theme.mathjax.per_page 3 | if is_post() || is_page() 4 | include ./mathjax.pug 5 | else 6 | if page.mathjax 7 | include ./mathjax.pug 8 | 9 | if theme.katex && theme.katex.enable 10 | if theme.katex.per_page 11 | if is_post() || is_page() 12 | include ./katex.pug 13 | else 14 | if page.katex 15 | include ./katex.pug 16 | 17 | if theme.mermaid.enable 18 | include ./mermaid.pug -------------------------------------------------------------------------------- /layout/includes/third-party/search/algolia.pug: -------------------------------------------------------------------------------- 1 | #algolia-search 2 | .search-dialog 3 | nav.search-nav 4 | span.search-dialog-title= _p('search.title') 5 | button.search-close-button 6 | i.fas.fa-times 7 | 8 | .search-wrap 9 | #algolia-search-input 10 | hrl.line 11 | #algolia-search-results 12 | #algolia-hits 13 | #algolia-pagination 14 | #algolia-info 15 | .algolia-stats 16 | .algolia-poweredBy 17 | 18 | #search-mask 19 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: npm publish 2 | 3 | on: 4 | release: 5 | types: [created] 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | # Setup .npmrc file to publish to npm 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: '12.x' 15 | registry-url: 'https://registry.npmjs.org' 16 | - run: npm install 17 | - run: npm publish 18 | env: 19 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /layout/includes/head/Open_Graph.pug: -------------------------------------------------------------------------------- 1 | if theme.Open_Graph_meta.enable 2 | - 3 | let ogOption = Object.assign({ 4 | type: is_post() ? 'article' : 'website', 5 | image: (page.cover || theme.avatar.img) ? full_url_for(page.cover || theme.avatar.img) : '', 6 | fb_admins: theme.facebook_comments.user_id || '', 7 | fb_app_id: theme.facebook_comments.app_id || '', 8 | }, theme.Open_Graph_meta.option) 9 | - 10 | != open_graph(ogOption) 11 | else 12 | meta(name="description" content=page_description()) 13 | 14 | -------------------------------------------------------------------------------- /layout/includes/third-party/pangu.pug: -------------------------------------------------------------------------------- 1 | script. 2 | function panguFn () { 3 | if (typeof pangu === 'object') pangu.autoSpacingPage() 4 | else { 5 | getScript('!{url_for(theme.asset.pangu)}') 6 | .then(() => { 7 | pangu.autoSpacingPage() 8 | }) 9 | } 10 | } 11 | 12 | function panguInit () { 13 | if (!{theme.pangu.field === 'post'}){ 14 | GLOBAL_CONFIG_SITE.isPost && panguFn() 15 | } else { 16 | panguFn() 17 | } 18 | } 19 | 20 | document.addEventListener('DOMContentLoaded', panguInit) 21 | -------------------------------------------------------------------------------- /layout/includes/waves.pug: -------------------------------------------------------------------------------- 1 | section.main-hero-waves-area.waves-area 2 | 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') 3 | defs 4 | 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') 5 | g.parallax 6 | use(href='#gentle-wave', x='48', y='0') 7 | use(href='#gentle-wave', x='48', y='3') 8 | use(href='#gentle-wave', x='48', y='5') 9 | use(href='#gentle-wave', x='48', y='7') -------------------------------------------------------------------------------- /scripts/events/stylus.js: -------------------------------------------------------------------------------- 1 | /** 2 | * stylus 3 | */ 4 | 5 | 'use strict' 6 | 7 | hexo.extend.filter.register('stylus:renderer', function (style) { 8 | const { highlight, prismjs } = hexo.config 9 | style 10 | .define('$highlight_enable', highlight && highlight.enable) 11 | .define('$highlight_line_number', highlight && highlight.line_number) 12 | .define('$prismjs_enable', prismjs && prismjs.enable) 13 | .define('$prismjs_line_number', prismjs && prismjs.line_number) 14 | // .import(this.source_dir.replace(/\\/g, '/') + '_data/css/*') 15 | }) 16 | -------------------------------------------------------------------------------- /source/css/_custom/flink.css: -------------------------------------------------------------------------------- 1 | .flink .btns a.button { 2 | height: auto !important; 3 | } 4 | .flink .btns #text { 5 | font-size: 18px; 6 | font-weight: 700; 7 | } 8 | .flink .btns p { 9 | font-weight: 700; 10 | font-size: 15px; 11 | border-top: 3px dashed var(--heo-theme); 12 | padding-top: 5px; 13 | } 14 | @media screen and (min-width: 1024px) { 15 | .flink .btns a { 16 | width: 24% !important; 17 | } 18 | } 19 | @media screen and (max-width: 450px) { 20 | .flink .btns a { 21 | width: 100% !important; 22 | } 23 | } -------------------------------------------------------------------------------- /source/css/_highlight/prismjs/index.styl: -------------------------------------------------------------------------------- 1 | if $prismjs_line_number 2 | @require 'line-number' 3 | 4 | if $highlight_theme != false 5 | @require 'diff' 6 | 7 | #article-container 8 | pre[class*='language-'] 9 | scrollbar-color: var(--hlscrollbar-bg) transparent 10 | 11 | &::-webkit-scrollbar-thumb 12 | background: var(--hlscrollbar-bg) 13 | 14 | &:not(.line-numbers) 15 | padding: 10px 20px 16 | 17 | .caption 18 | margin-left: -3.8em 19 | padding: 4px 16px !important 20 | 21 | a 22 | padding: 0 !important 23 | -------------------------------------------------------------------------------- /layout/includes/third-party/card-post-count/disqus.pug: -------------------------------------------------------------------------------- 1 | script. 2 | (() => { 3 | const getCount = () => { 4 | if (window.DISQUSWIDGETS === undefined) { 5 | var d = document, s = d.createElement('script'); 6 | s.src = 'https://!{theme.disqus.shortname}.disqus.com/count.js'; 7 | s.id = 'dsq-count-scr'; 8 | (d.head || d.body).appendChild(s); 9 | } else { 10 | DISQUSWIDGETS.getCount({reset: true}); 11 | } 12 | } 13 | 14 | window.pjax ? getCount() : window.addEventListener('load', getCount) 15 | 16 | })() 17 | -------------------------------------------------------------------------------- /source/css/_layout/chat.styl: -------------------------------------------------------------------------------- 1 | // chat 2 | if hexo-config('chat_btn') == true && hexo-config('chatra.enable') 3 | #chatra:not(.chatra--expanded) 4 | visibility: hidden !important 5 | width: 1px !important 6 | height: 1px !important 7 | opacity: 0 !important 8 | pointer-events: none 9 | 10 | if hexo-config('chat_btn') == true && hexo-config('messenger.enable') 11 | .fb_dialog, 12 | .fb-customerchat 13 | visibility: hidden !important 14 | width: 1px !important 15 | height: 1px !important 16 | opacity: 0 !important 17 | pointer-events: none -------------------------------------------------------------------------------- /layout/includes/third-party/card-post-count/remark42.pug: -------------------------------------------------------------------------------- 1 | - const { host, siteId, option } = theme.remark42 2 | 3 | script. 4 | (()=>{ 5 | window.remark_config = Object.assign({ 6 | host: '!{host}', 7 | site_id: '!{siteId}', 8 | },!{JSON.stringify(option)}) 9 | 10 | function getCount () { 11 | const s = document.createElement('script') 12 | s.src = remark_config.host + '/web/counter.js' 13 | s.defer = true 14 | document.head.appendChild(s) 15 | } 16 | 17 | window.pjax ? getCount() : window.addEventListener('load', getCount) 18 | })() -------------------------------------------------------------------------------- /layout/includes/third-party/card-post-count/waline.pug: -------------------------------------------------------------------------------- 1 | script. 2 | (() => { 3 | function loadWaline () { 4 | function initWaline () { 5 | let initData = { 6 | el: null, 7 | serverURL: '!{theme.waline.serverURL}', 8 | comment: true 9 | } 10 | const waline = Waline.init(initData) 11 | } 12 | 13 | if (typeof Waline === 'function') initWaline() 14 | else getScript('!{url_for(theme.asset.waline_js)}').then(initWaline) 15 | } 16 | 17 | window.pjax ? loadWaline() : window.addEventListener('load', loadWaline) 18 | })() 19 | -------------------------------------------------------------------------------- /source/css/_tags/hexo.styl: -------------------------------------------------------------------------------- 1 | // pullquote 2 | blockquote 3 | &.pullquote 4 | position: relative 5 | max-width: 45% 6 | font-size: 110% 7 | 8 | &.left 9 | float: left 10 | margin: 1em .5em 0 0 11 | 12 | &.right 13 | float: right 14 | margin: 1em 0 0 .5em 15 | 16 | // hexo tag video 17 | .video-container 18 | position: relative 19 | overflow: hidden 20 | margin-bottom: 16px 21 | padding-top: 56.25% 22 | height: 0 23 | 24 | iframe 25 | position: absolute 26 | top: 0 27 | left: 0 28 | margin-top: 0 29 | width: 100% 30 | height: 100% 31 | -------------------------------------------------------------------------------- /scripts/tag/poem.js: -------------------------------------------------------------------------------- 1 | // 'use strict' 2 | // 3 | // function poem (args, content) { 4 | // return `
${content}
` 5 | // } 6 | // 7 | // hexo.extend.tag.register('poem', poem, { ends: true }) 8 | 9 | 'use strict' 10 | 11 | function poem (args, content) { 12 | args = args.join(' ').split(',') 13 | let p0 = args[0] 14 | let p1 = args[1]?args[1]:'' 15 | return `
${p0}
${p1}
${hexo.render.renderSync({ text: content, engine: 'markdown' })}
` 16 | } 17 | 18 | hexo.extend.tag.register('poem',poem,{ ends: true }); 19 | -------------------------------------------------------------------------------- /scripts/tag/progress.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | function postprogress(args) { 3 | args = args.join(',').split(',') 4 | if (args.length > 1) { 5 | let pwidth = args[0].trim() 6 | let pcolor = args[1].trim() 7 | let text = args[2].trim() 8 | return `
${hexo.render.renderSync({text: text, engine: 'markdown'}).split('\n').join('')}
`; 9 | } 10 | } 11 | hexo.extend.tag.register('progress', postprogress); 12 | -------------------------------------------------------------------------------- /layout/includes/third-party/card-post-count/artalk.pug: -------------------------------------------------------------------------------- 1 | - const { server, site } = theme.artalk 2 | 3 | script. 4 | (() => { 5 | const getArtalkCount = () => { 6 | const runWidget = () => { 7 | Artalk.LoadCountWidget({ 8 | server: '!{server}', 9 | site: '!{site}', 10 | countEl: '.artalk-count' 11 | }) 12 | } 13 | 14 | if (typeof Artalk === 'function') runWidget() 15 | else getScript('!{theme.asset.artalk_js}').then(runWidget) 16 | } 17 | 18 | 19 | window.pjax ? getArtalkCount() : window.addEventListener('load', getArtalkCount) 20 | })() -------------------------------------------------------------------------------- /scripts/helpers/random.js: -------------------------------------------------------------------------------- 1 | hexo.extend.generator.register('random', function (locals) { 2 | const config = hexo.config.random || {} 3 | const posts = [] 4 | for (const post of locals.posts.data) { 5 | if (post.random !== false) posts.push(post.path) 6 | } 7 | return { 8 | path: 'js/random.js', 9 | data: `var posts=${JSON.stringify(posts)}; 10 | function toRandomPost() { 11 | window.open('/'+posts[Math.floor(Math.random() * posts.length)],"_self"); 12 | nav.randompost() 13 | };` 14 | } 15 | }) -------------------------------------------------------------------------------- /layout/includes/widget/card_post_toc.pug: -------------------------------------------------------------------------------- 1 | - let tocNumber = page.toc_number !== undefined ? page.toc_number : theme.toc.number 2 | - let tocExpand = page.toc_expand !== undefined ? page.toc_expand : theme.toc.expand 3 | - let tocExpandClass = tocExpand ? 'is-expand' : '' 4 | 5 | #card-toc.card-widget 6 | .item-headline 7 | i.dys.categroy 8 | span= _p('aside.card_toc') 9 | span.toc-percentage 10 | 11 | if (page.encrypt == true) 12 | .toc-content.toc-div-class(class=tocExpandClass style="display:none")!=toc(page.origin, {list_number: tocNumber}) 13 | else 14 | .toc-content(class=tocExpandClass)!=toc(page.content, {list_number: tocNumber}) -------------------------------------------------------------------------------- /layout/includes/head/pwa.pug: -------------------------------------------------------------------------------- 1 | link(rel="manifest" href=url_for(theme.pwa.manifest)) 2 | if(theme.pwa.theme_color) 3 | meta(name="msapplication-TileColor" content=theme.pwa.theme_color) 4 | if(theme.pwa.apple_touch_icon) 5 | link(rel="apple-touch-icon" sizes="180x180" href=url_for(theme.pwa.apple_touch_icon)) 6 | if(theme.pwa.favicon_32_32) 7 | link(rel="icon" type="image/png" sizes="32x32" href=url_for(theme.pwa.favicon_32_32)) 8 | if(theme.pwa.favicon_16_16) 9 | link(rel="icon" type="image/png" sizes="16x16" href=url_for(theme.pwa.favicon_16_16)) 10 | if(theme.pwa.mask_icon) 11 | link(rel="mask-icon" href=url_for(theme.pwa.mask_icon) color="#5bbad5") 12 | -------------------------------------------------------------------------------- /layout/includes/third-party/card-post-count/valine.pug: -------------------------------------------------------------------------------- 1 | script. 2 | (() => { 3 | function loadValine () { 4 | function initValine () { 5 | let initData = { 6 | el: '#vcomment', 7 | appId: '#{theme.valine.appId}', 8 | appKey: '#{theme.valine.appKey}', 9 | serverURLs: '#{theme.valine.serverURLs}' 10 | } 11 | 12 | const valine = new Valine(initData) 13 | } 14 | 15 | if (typeof Valine === 'function') initValine() 16 | else getScript('!{url_for(theme.asset.valine)}').then(initValine) 17 | } 18 | 19 | window.pjax ? loadValine() : window.addEventListener('load', loadValine) 20 | })() 21 | -------------------------------------------------------------------------------- /scripts/events/init.js: -------------------------------------------------------------------------------- 1 | hexo.extend.filter.register('before_generate', () => { 2 | // Get first two digits of the Hexo version number 3 | const { version, log, locals } = hexo 4 | const hexoVer = version.replace(/(^.*\..*)\..*/, '$1') 5 | 6 | if (hexoVer < 5.3) { 7 | log.error('Please update Hexo to V5.3.0 or higher!') 8 | log.error('請把 Hexo 升級到 V5.3.0 或更高的版本!') 9 | process.exit(-1) 10 | } 11 | 12 | if (locals.get) { 13 | const data = locals.get('data') 14 | if (data && data.butterfly) { 15 | log.error("'butterfly.yml' is deprecated. Please use '_config.butterfly.yml'") 16 | log.error("'butterfly.yml' 已經棄用,請使用 '_config.butterfly.yml'") 17 | process.exit(-1) 18 | } 19 | } 20 | }) -------------------------------------------------------------------------------- /layout/includes/third-party/effect.pug: -------------------------------------------------------------------------------- 1 | if theme.fireworks && theme.fireworks.enable 2 | canvas.fireworks(mobile=`${theme.fireworks.mobile}`) 3 | script(src=url_for(theme.asset.fireworks)) 4 | 5 | //- 鼠標特效 6 | if theme.click_heart && theme.click_heart.enable 7 | script#click-heart(src=url_for(theme.asset.click_heart) async mobile=`${theme.click_heart.mobile}`) 8 | 9 | if theme.ClickShowText && theme.ClickShowText.enable 10 | script#click-show-text( 11 | src= url_for(theme.asset.ClickShowText) 12 | data-mobile= `${theme.ClickShowText.mobile}` 13 | data-text= theme.ClickShowText.text.join(",") 14 | data-fontsize= theme.ClickShowText.fontSize 15 | data-random= `${theme.ClickShowText.random}` 16 | async 17 | ) -------------------------------------------------------------------------------- /source/css/_page/categories.styl: -------------------------------------------------------------------------------- 1 | .category-lists 2 | .category-title 3 | font-size: 2.57em 4 | 5 | +maxWidth768() 6 | font-size: 2em 7 | 8 | .category-list 9 | margin-bottom: 0 10 | 11 | a 12 | color: var(--font-color) 13 | 14 | &:hover 15 | color: $text-hover 16 | 17 | .category-list-count 18 | margin-left: 8px 19 | color: $theme-meta-color 20 | 21 | &:before 22 | content: '(' 23 | 24 | &:after 25 | content: ')' 26 | 27 | ul 28 | padding: 0 0 0 20px 29 | @extend .list-beauty 30 | 31 | ul 32 | padding-left: 4px 33 | 34 | li 35 | position: relative 36 | margin: 6px 0 37 | padding: .12em .4em .12em 1.4em 38 | -------------------------------------------------------------------------------- /layout/page.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | #page 5 | h1.page-title= page.title 6 | 7 | case page.type 8 | when 'tags' 9 | include includes/page/tags.pug 10 | when 'link' 11 | include includes/page/flink.pug 12 | when 'categories' 13 | include includes/page/categories.pug 14 | when 'about' 15 | include includes/page/about.pug 16 | when 'comments' 17 | include includes/page/comments.pug 18 | default 19 | include includes/page/default-page.pug 20 | 21 | if page.comments !== false && theme.comments && theme.comments.use 22 | - var commentsJsLoad = true 23 | !=partial('includes/third-party/comments/index', {}, {cache: true}) -------------------------------------------------------------------------------- /layout/includes/sidebar.pug: -------------------------------------------------------------------------------- 1 | #sidebar 2 | #menu-mask 3 | #sidebar-menus 4 | .avatar-img.is-center 5 | img(src=url_for(theme.avatar.img) onerror=`onerror=null;src='${theme.error_img.flink}'` alt="avatar") 6 | .sidebar-site-data.site-data.is-center 7 | a(href=url_for(config.archive_dir) + '/') 8 | .headline= _p('aside.articles') 9 | .length-num= site.posts.length 10 | a(href=url_for(config.tag_dir) + '/' ) 11 | .headline= _p('aside.tags') 12 | .length-num= site.tags.length 13 | a(href=url_for(config.category_dir) + '/') 14 | .headline= _p('aside.categories') 15 | .length-num= site.categories.length 16 | 17 | hr 18 | !=partial('includes/header/menu_item', {}, {cache: true}) 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hexo-theme-dynasty", 3 | "version": "1.0.3", 4 | "description": "新一代简洁华美hexo主题", 5 | "main": "package.json", 6 | "keywords": [ 7 | "hexo", 8 | "theme", 9 | "butterfly", 10 | "Aegcbx", 11 | "hexo-theme-dimension", 12 | "hexo主题" 13 | ], 14 | "repository": { 15 | "type" : "git", 16 | "url" : "https://github.com/ezgx/hexo-theme-Dynasty.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/ezgx/hexo-theme-Dynasty/issues", 20 | "email": "liusx0619@qq.com" 21 | }, 22 | "dependencies": { 23 | "hexo-renderer-stylus": "^2.1.0", 24 | "hexo-renderer-pug": "^3.0.0" 25 | }, 26 | "homepage": "https://uu.sssu.us/", 27 | "author": "Aegcbx", 28 | "license": "GPL-V3" 29 | } 30 | -------------------------------------------------------------------------------- /layout/includes/third-party/search/local-search.pug: -------------------------------------------------------------------------------- 1 | #local-search 2 | .search-dialog 3 | nav.search-nav 4 | span#loading-status 5 | button.search-close-button 6 | i.fas.fa-times 7 | 8 | #loading-database.is-center 9 | i.dys.spinner3.spin.ani.fa-pulse 10 | span= ' ' + _p("search.load_data") 11 | 12 | .search-wrap 13 | #local-search-input 14 | .local-search-box 15 | input(placeholder=_p("search.local_search.input_placeholder") type="text").local-search-box--input 16 | hrl.line(style='margin-top:15px; border: 2px dashed var(--search-border-color) !important;') 17 | #local-search-results 18 | hrl.line(style='border: 2px dashed var(--search-border-color) !important;') 19 | 20 | #search-mask -------------------------------------------------------------------------------- /source/css/_custom/sidebar.css: -------------------------------------------------------------------------------- 1 | #sidebar #sidebar-menus .menus_items .menus_item_child { 2 | margin: 0; 3 | list-style: none; 4 | display: flex; 5 | flex-direction: row; 6 | flex-wrap: wrap 7 | } 8 | 9 | #sidebar #sidebar-menus .menus_item_child li { 10 | width: calc(50% - 8px); 11 | margin: 4px 12 | } 13 | 14 | #sidebar #sidebar-menus .menus_item_child .site-page.child { 15 | display: flex; 16 | flex-direction: column; 17 | align-items: center; 18 | padding: 8px; 19 | border-radius: 12px; 20 | border: var(--style-border-always); 21 | background: var(--zhsher-card-bg); 22 | font-size: 14px 23 | } 24 | 25 | #sidebar #sidebar-menus .menus_items a.site-page, #sidebar .menus_item ul { 26 | padding-left: 0 27 | } 28 | -------------------------------------------------------------------------------- /layout/includes/widget/card_author.pug: -------------------------------------------------------------------------------- 1 | if theme.aside.card_author.enable 2 | .card-widget.card-info 3 | .card-content 4 | .card-info-avatar.is-center 5 | .author-info__sayhi#author-info__sayhi 晚上好!我是 6 | .author-info__name= config.author 7 | .avatar-img 8 | img(src=url_for(theme.avatar.img) onerror=`this.onerror=null;this.src='` + url_for(theme.error_img.flink) + `'` alt="avatar") 9 | .loading-image-dot 10 | img(src="https://pic.imgdb.cn/item/65032bf5661c6c8e542969ff.webp", alt="") 11 | .banner-button-group 12 | a.banner-button(href="/about/") 13 | i.dys.caozuo-wailian 14 | span.banner-button-te 15 | xt 了解更多 16 | hrl.line(style="margin-top: 10px") -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | on: 3 | schedule: 4 | - cron: '30 1 * * *' 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v5 11 | with: 12 | days-before-issue-stale: 30 13 | days-before-pr-stale: -1 14 | days-before-close: 7 15 | 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.' 16 | close-pr-message: 'This issue has not seen any activity since it was marked stale. Closing.' 17 | stale-issue-label: 'Stale' 18 | exempt-issue-labels: 'pinned,bug,enhancement,documentation,Plan' 19 | operations-per-run: 1000 -------------------------------------------------------------------------------- /layout/includes/page/comments.pug: -------------------------------------------------------------------------------- 1 | #article-container 2 | #maincontent 3 | #form-wrap 4 | img#beforeimg(src='https://pic.imgdb.cn/item/64a3021e1ddac507ccbe96d8.png') 5 | #envelope 6 | form 7 | .formmain 8 | img.headerimg(src=url_for(theme.envelope_comment.cover)) 9 | .comments-main 10 | h3.title3=`这里是` + config.author + `的留言板` 11 | .comments 12 | each i in theme.envelope_comment.message 13 | div=`${i}` 14 | .bottomcontent 15 | img.bottomimg(src='https://ae01.alicdn.com/kf/U0968ee80fd5c4f05a02bdda9709b041eE.png') 16 | p.bottomhr=`${theme.envelope_comment.bottom}` 17 | img#afterimg(src='https://pic.imgdb.cn/item/64a3021e1ddac507ccbe968a.png') 18 | != page.content -------------------------------------------------------------------------------- /source/css/index.styl: -------------------------------------------------------------------------------- 1 | if hexo-config('css_prefix') 2 | @import 'nib' 3 | 4 | @import '_third-party/normalize.min.css' 5 | // project 6 | @import 'var' 7 | @import '_global/*' 8 | @import '_highlight/highlight' 9 | @import '_page/*' 10 | @import '_layout/*' 11 | @import '_tags/*' 12 | @import '_mode/*' 13 | @import '_custom/*' 14 | @import '_custom/*.css' 15 | 16 | // search 17 | if hexo-config('algolia_search.enable') 18 | @import '_search/index' 19 | @import '_search/algolia' 20 | 21 | if hexo-config('local_search') && hexo-config('local_search.enable') 22 | @import '_search/index' 23 | @import '_search/local-search' 24 | 25 | if hexo-config('post_double_row') == true 26 | @import 'post-double-row.css' 27 | else 28 | #recent-posts>.recent-post-item 29 | height: 223px 30 | +maxwidth768() 31 | height: 350px -------------------------------------------------------------------------------- /scripts/tag/button.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Button 3 | * {% btn url text icon option %} 4 | * option: color outline center block larger 5 | * color : default/blue/pink/red/purple/orange/green 6 | */ 7 | 8 | 'use strict' 9 | 10 | const urlFor = require('hexo-util').url_for.bind(hexo) 11 | 12 | function btn (args) { 13 | args = args.join(' ').split(',') 14 | let url = args[0] || '' 15 | let text = args[1] || '' 16 | let icon = args[2] || '' 17 | let option = args[3] || '' 18 | 19 | url = url.trim() 20 | text = text.trim() 21 | icon = icon.trim() 22 | option = option.trim() 23 | 24 | return `${icon.length ? `` : ''}${text.length ? `${text}` : ''}` 26 | } 27 | 28 | hexo.extend.tag.register('btn', btn, { ends: false }) 29 | -------------------------------------------------------------------------------- /source/css/_tags/poem.styl: -------------------------------------------------------------------------------- 1 | @media (min-width: 1200px) 2 | .poem 3 | margin 0 auto 4 | height auto 5 | writing-mode vertical-rl 6 | writing-mode tb-rl 7 | p 8 | text-decoration underline 9 | text-decoration-color rgba(193, 11, 11, 0.72) 10 | text-decoration-style dashed 11 | @font-face 12 | font-family 'Poem' 13 | src url('https://unpkg.zhimg.com/akilar-candyassets/fonts/Poem.ttf') 14 | font-display swap 15 | 16 | .poem 17 | p 18 | font-family 'Poem','KaiTi',sans-serif!important 19 | font-size 25px 20 | text-align center 21 | 22 | .poem-title 23 | font-family 'Poem','KaiTi',sans-serif!important 24 | font-size 2.5em 25 | text-align center 26 | 27 | .poem-author 28 | text-align center!important 29 | font-family 'Poem','KaiTi',sans-serif!important 30 | font-size 16px 31 | color rgb(66, 66, 66) 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hexo-theme-dynasty 2 | 3 | ![](https://img.shields.io/github/package-json/v/ezgx/hexo-theme-dynasty/main?color=ff7a7a&label=main) 4 | ![](https://img.shields.io/npm/v/hexo-theme-dynasty?color=32C9EB) 5 | ![](https://img.shields.io/badge/hexo-5.3.0+-0e83c?color=425AEF) 6 | ![](https://img.shields.io/github/license/ezgx/hexo-theme-dynasty?color=FF7a7a) 7 | 8 | Demo: 👍 [dynasty](https://uu.sssu.us) 9 | 10 | Docs: 📖 [dynasty Docs](https://dynasty.uu.sssu.us) 11 | 12 | Based on [hexo-theme-butterfly](https://github.com/jerryc127/hexo-theme-butterfly). 13 | 14 | ![](theme.png) 15 | 16 | Dimspace -------------------------------------------------------------------------------- /scripts/tag/gh.js: -------------------------------------------------------------------------------- 1 | function gh(ghp) { 2 | ghp = ghp.join(' ').split(','); 3 | const p0 = ghp[0].trim(); 4 | const p1 = ghp[1].trim(); 5 | return ``; 6 | } 7 | hexo.extend.tag.register('ghp', gh); 8 | function ghp(ghpt) { 9 | ghpt = ghpt.join(' ').split(','); 10 | const p0 = ghpt[0].trim(); 11 | const p1 = ghpt[1].trim(); 12 | const p2 = ghpt[2].trim(); 13 | const p3 = ghpt[3].trim(); 14 | return ``; 15 | } 16 | hexo.extend.tag.register('ghpt', ghp); -------------------------------------------------------------------------------- /scripts/tag/span.js: -------------------------------------------------------------------------------- 1 | //- 移植自volantis 2 | 3 | 'use strict'; 4 | 5 | function postP(args) { 6 | if(/::/g.test(args)){ 7 | args = args.join(' ').split('::'); 8 | } 9 | else{ 10 | args = args.join(' ').split(','); 11 | } 12 | const p0 = args[0].trim(); 13 | const p1 = args[1].trim(); 14 | return `

${p1}

`; 15 | } 16 | function postSpan(args) { 17 | if(/::/g.test(args)){ 18 | args = args.join(' ').split('::'); 19 | } 20 | else{ 21 | args = args.join(' ').split(','); 22 | } 23 | const p0 = args[0].trim(); 24 | const p1 = args[1].trim(); 25 | return `${p1}`; 26 | } 27 | 28 | hexo.extend.tag.register('p', postP); 29 | hexo.extend.tag.register('span', postSpan); 30 | 31 | function sj(tab) { 32 | tab = tab.join(' ').split(','); 33 | return `
`; 34 | } 35 | hexo.extend.tag.register('tab', sj); -------------------------------------------------------------------------------- /layout/includes/third-party/comments/livere.pug: -------------------------------------------------------------------------------- 1 | script. 2 | function loadLivere () { 3 | if (typeof LivereTower === 'object') { 4 | window.LivereTower.init() 5 | } 6 | else { 7 | (function(d, s) { 8 | var j, e = d.getElementsByTagName(s)[0]; 9 | if (typeof LivereTower === 'function') { return; } 10 | j = d.createElement(s); 11 | j.src = 'https://cdn-city.livere.com/js/embed.dist.js'; 12 | j.async = true; 13 | e.parentNode.insertBefore(j, e); 14 | })(document, 'script'); 15 | } 16 | } 17 | 18 | if ('!{theme.comments.use[0]}' === 'Livere' || !!{theme.comments.lazyload}) { 19 | if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('lv-container'), loadLivere) 20 | else loadLivere() 21 | } 22 | else { 23 | function loadOtherComment () { 24 | loadLivere() 25 | } 26 | } -------------------------------------------------------------------------------- /layout/includes/head/preconnect.pug: -------------------------------------------------------------------------------- 1 | link(rel="preconnect" href="//cdn.jsdelivr.net") 2 | 3 | if theme.google_analytics 4 | link(rel="preconnect" href="//www.google-analytics.com" crossorigin='') 5 | 6 | if theme.baidu_analytics 7 | link(rel="preconnect" href="//hm.baidu.com") 8 | 9 | if theme.cnzz_analytics 10 | link(rel="preconnect" href="//s4.cnzz.com") 11 | 12 | if theme.cloudflare_analytics 13 | link(rel="preconnect" href="//static.cloudflareinsights.com") 14 | 15 | if theme.microsoft_clarity 16 | link(rel="preconnect" href="//www.clarity.ms") 17 | 18 | if theme.blog_title_font && theme.blog_title_font.font_link && theme.blog_title_font.font_link.indexOf('//fonts.googleapis.com') != -1 19 | link(rel="preconnect" href="//fonts.googleapis.com" crossorigin='') 20 | 21 | if theme.busuanzi.site_uv || theme.busuanzi.site_pv || theme.busuanzi.page_pv 22 | link(rel="preconnect" href="//busuanzi.ibruce.info") -------------------------------------------------------------------------------- /layout/includes/page/flink.pug: -------------------------------------------------------------------------------- 1 | #article-container 2 | .flink 3 | if site.data.link 4 | each i in site.data.link 5 | if i.class_name 6 | .flink-name!=i.class_name 7 | .flink-list 8 | .btns.circle.grid5 9 | each item in i.link_list 10 | - var snapshot = item.snapshot ? url_for(item.snapshot) : 'https://s0.wp.com/mshots/v1/' + item.link + '?w=800&h=500' 11 | a.button(href=url_for(item.link) title=item.name target="_blank") 12 | img.no-lightbox(src=url_for(item.avatar) onerror=`this.onerror=null;this.src='` + url_for(theme.error_img.flink) + `'` alt=item.name ) 13 | #text= item.name 14 | if item.descr 15 | p=item.descr 16 | else 17 | p 博主很懒,未填写网站描述 18 | img.no-lightbox(src=snapshot) 19 | hrl.line 20 | 21 | != page.content -------------------------------------------------------------------------------- /layout/includes/third-party/card-post-count/fb.pug: -------------------------------------------------------------------------------- 1 | - const fbSDKVer = 'v15.0' 2 | - 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}` 3 | 4 | script. 5 | (()=>{ 6 | function loadFBComment () { 7 | if (typeof FB === 'object') FB.XFBML.parse(document.getElementById('recent-posts')) 8 | else { 9 | let ele = document.createElement('script') 10 | ele.setAttribute('src','!{fbSDK}') 11 | ele.setAttribute('async', 'true') 12 | ele.setAttribute('defer', 'true') 13 | ele.setAttribute('crossorigin', 'anonymous') 14 | document.body.appendChild(ele) 15 | } 16 | } 17 | window.pjax ? loadFBComment() : window.addEventListener('load', loadFBComment) 18 | })() 19 | -------------------------------------------------------------------------------- /source/css/_tags/hide.styl: -------------------------------------------------------------------------------- 1 | // tag-hide 2 | .hide-inline, 3 | .hide-block 4 | & > .hide-button 5 | display: inline-block 6 | padding: 5px 18px 7 | background: $tag-hide-bg 8 | color: var(--white) 9 | 10 | &:hover 11 | background-color: var(--btn-hover-color) 12 | 13 | &.open 14 | display: none 15 | 16 | & + div 17 | display: block 18 | 19 | & + span 20 | display: inline 21 | 22 | & > .hide-content 23 | display: none 24 | 25 | .hide-inline 26 | & > .hide-button 27 | margin: 0 6px 28 | 29 | & > .hide-content 30 | margin: 0 6px 31 | 32 | .hide-block 33 | margin: 0 0 16px 34 | 35 | .toggle 36 | margin-bottom: 20px 37 | border: 1px solid $tag-hide-toggle-bg 38 | 39 | & > .toggle-button 40 | padding: 6px 15px 41 | background: $tag-hide-toggle-bg 42 | color: #1F2D3D 43 | 44 | & > .toggle-content 45 | margin: 30px 24px 46 | -------------------------------------------------------------------------------- /scripts/tag/note.js: -------------------------------------------------------------------------------- 1 | /** 2 | * note.js 3 | * transplant from hexo-theme-next 4 | * Modify by Jerry 5 | */ 6 | 7 | 'use strict' 8 | 9 | function postNote (args, content) { 10 | const styleConfig = hexo.theme.config.note.style 11 | const lastArgs = args[args.length - 1] 12 | if (!(lastArgs === 'flat' || lastArgs === 'modern' || lastArgs === 'simple' || lastArgs === 'disabled')) { 13 | args.push(styleConfig) 14 | } 15 | 16 | let icon = '' 17 | const iconArray = args[args.length - 2] 18 | if (iconArray && iconArray.startsWith('fa')) { 19 | icon = `` 20 | args[args.length - 2] = 'icon-padding' 21 | } 22 | 23 | return `
${icon + hexo.render.renderSync({ text: content, engine: 'markdown' })}
` 24 | } 25 | 26 | hexo.extend.tag.register('note', postNote, { ends: true }) 27 | hexo.extend.tag.register('subnote', postNote, { ends: true }) 28 | -------------------------------------------------------------------------------- /layout/includes/third-party/chat/chatra.pug: -------------------------------------------------------------------------------- 1 | //- https://chatra.io/help/api/ 2 | script. 3 | (function(d, w, c) { 4 | w.ChatraID = '#{theme.chatra.id}'; 5 | var s = d.createElement('script'); 6 | w[c] = w[c] || function() { 7 | (w[c].q = w[c].q || []).push(arguments); 8 | }; 9 | s.async = true; 10 | s.src = 'https://call.chatra.io/chatra.js'; 11 | if (d.head) d.head.appendChild(s); 12 | })(document, window, 'Chatra'); 13 | 14 | if (!{theme.chat_btn}) { 15 | var chatBtnFn = () => { 16 | var chatBtn = document.getElementById("chat_btn") 17 | chatBtn.addEventListener("click", function(){ 18 | Chatra('openChat') 19 | }); 20 | } 21 | chatBtnFn() 22 | } else { 23 | if (!{theme.chat_hide_show}) { 24 | function chatBtnHide () { 25 | Chatra('hide') 26 | } 27 | function chatBtnShow () { 28 | Chatra('show') 29 | } 30 | } 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /layout/includes/third-party/newest-comments/index.pug: -------------------------------------------------------------------------------- 1 | - let { use } = theme.comments 2 | 3 | if use 4 | - let forum,apiKey,userRepo 5 | case use[0] 6 | when 'Valine' 7 | include ./valine.pug 8 | when 'Waline' 9 | include ./waline.pug 10 | when 'Twikoo' 11 | include ./twikoo-comment.pug 12 | when 'Disqus' 13 | - forum = theme.disqus.shortname 14 | - apiKey = theme.disqus.apikey 15 | include ./disqus-comment.pug 16 | when 'Disqusjs' 17 | - forum = theme.disqusjs.shortname 18 | - apiKey = theme.disqusjs.apikey 19 | include ./disqus-comment.pug 20 | when 'Gitalk' 21 | - let { repo,owner } = theme.gitalk 22 | - userRepo = owner + '/' + repo 23 | include ./github-issues.pug 24 | when 'Utterances' 25 | - userRepo = theme.utterances.repo 26 | include ./github-issues.pug 27 | when 'Remark42' 28 | include ./remark42.pug 29 | when 'Artalk' 30 | include ./artalk.pug -------------------------------------------------------------------------------- /scripts/tag/gallery.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Butterfly 3 | * galleryGroup and allery 4 | */ 5 | 6 | 'use strict' 7 | 8 | const urlFor = require('hexo-util').url_for.bind(hexo) 9 | 10 | function gallery (args, content) { 11 | return `` 13 | } 14 | 15 | function galleryGroup (args) { 16 | const name = args[0] 17 | const desrc = args[1] 18 | const url = urlFor(args[2]) 19 | const img = urlFor(args[3]) 20 | 21 | return ` 22 | 30 | ` 31 | } 32 | 33 | hexo.extend.tag.register('gallery', gallery, { ends: true }) 34 | hexo.extend.tag.register('galleryGroup', galleryGroup) 35 | -------------------------------------------------------------------------------- /source/css/_highlight/highlight/index.styl: -------------------------------------------------------------------------------- 1 | if $highlight_theme != false 2 | @require 'diff' 3 | 4 | #article-container 5 | figure.highlight 6 | .line 7 | if wordWrap 8 | &:before 9 | display: inline-block 10 | padding: 0 6px 0 0 11 | min-width: 30px 12 | color: var(--hlnumber-color) 13 | content: counter(line) 14 | counter-increment: line 15 | text-align: left 16 | 17 | &.marked 18 | background-color: $highlight-selection 19 | 20 | table 21 | display: block 22 | overflow: auto 23 | border: none 24 | 25 | td 26 | padding: 0 27 | border: none 28 | 29 | .gutter pre 30 | padding-right: 10px 31 | padding-left: 10px 32 | background-color: var(--hlnumber-bg) 33 | color: var(--hlnumber-color) 34 | text-align: right 35 | 36 | .code pre 37 | padding-right: 10px 38 | padding-left: 10px 39 | width: 100% 40 | -------------------------------------------------------------------------------- /layout/includes/widget/index.pug: -------------------------------------------------------------------------------- 1 | #aside-content.aside-content 2 | //- post 3 | if is_post() 4 | - const tocStyle = page.toc_style_simple 5 | - const tocStyleVal = tocStyle === true || tocStyle === false ? tocStyle : theme.toc.style_simple 6 | if showToc && tocStyleVal 7 | .sticky_layout 8 | include ./card_post_toc.pug 9 | else 10 | !=partial('includes/widget/card_author', {}, {cache: true}) 11 | .sticky_layout 12 | if showToc 13 | include ./card_post_toc.pug 14 | else 15 | #card-toc.card-widget 16 | .item-headline 17 | i.dys.categroy 18 | span 抱歉,该文章无目录 19 | hrl.line 20 | !=partial('includes/widget/card_tags', {}, {cache: true}) 21 | else 22 | //- page 23 | !=partial('includes/widget/card_author', {}, {cache: true}) 24 | 25 | .sticky_layout 26 | if showToc 27 | include ./card_post_toc.pug 28 | !=partial('includes/widget/card_tags', {}, {cache: true}) -------------------------------------------------------------------------------- /scripts/events/welcome.js: -------------------------------------------------------------------------------- 1 | hexo.on('ready', () => { 2 | const { version } = require('../../package.json') 3 | hexo.log.info(`╔═════════════════════════════════════════════════════════════════════════════╗ 4 | 5 | ██████╗ ██╗ ██╗ ███══╗ ██║ █████╗ ██████╗ █████████╗ ██╗ ██╗ 6 | ██╔═══██║ ╚██╗ ██╔╝ ██║██║ ██║ ██╔════██║ ██╔════╝ ██╔═══╝ ╚██╗ ██╔╝ 7 | ██║ ██║ ╚████╔╝ ██║██╚╗ ██║ ██║ ██║ ██║ ██║ ╚████╔╝ 8 | ██║ ██║ ╚██╔╝ ██║ ██╚╗██║ █████████║ ███████╗ ██║ ╚██╔╝ 9 | ██║ ██║ ██║ ██║ ██║██║ ██╔════██║ ╚════██║ ██║ ██║ 10 | ██║ ██║ ██║ ██║ ██║██║ ██║ ██║ ██║ ██║ ██║ 11 | ██████╔═╝ ██║ ██║ ███║ ██║ ██║ ██████╔╝ ██║ ██║ 12 | ╚═════╝ ╚═╝ ╚═╝ ╚══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ 13 | ${version} 14 | ╚═════════════════════════════════════════════════════════════════════════════╝`) 15 | }) 16 | -------------------------------------------------------------------------------- /scripts/filters/post_lazyload.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Butterfly 3 | * lazyload 4 | * replace src to data-lazy-src 5 | */ 6 | 7 | 'use strict' 8 | 9 | const urlFor = require('hexo-util').url_for.bind(hexo) 10 | 11 | function lazyload (htmlContent) { 12 | const bg = hexo.theme.config.lazyload.placeholder ? urlFor(hexo.theme.config.lazyload.placeholder) : 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' 13 | return htmlContent.replace(/( { 24 | const config = hexo.theme.config.lazyload 25 | if (!config.enable) return 26 | if (config.field !== 'post') return 27 | data.content = lazyload.call(this, data.content) 28 | return data 29 | }) 30 | -------------------------------------------------------------------------------- /source/css/_search/index.styl: -------------------------------------------------------------------------------- 1 | .search-dialog 2 | position: fixed 3 | top: 0 4 | left: 0 5 | z-index: 1001 6 | display: none 7 | padding: 20px 8 | width: 100% 9 | border-radius: 8px 10 | 11 | hr 12 | margin: 20px auto 13 | 14 | .search-nav 15 | margin: 0 0 14px 16 | color: var(--heo-theme) 17 | font-size: 1.4em 18 | line-height: 1 19 | 20 | .search-dialog-title 21 | margin-right: 10px 22 | 23 | .search-close-button 24 | float: right 25 | color: $grey 26 | transition: color .2s ease-in-out 27 | 28 | &:hover 29 | color: var(--heo-theme) 30 | 31 | #search-mask 32 | position: fixed 33 | top: 0 34 | right: 0 35 | bottom: 0 36 | left: 0 37 | z-index: 1000 38 | display: none 39 | background: #ffffff7a 40 | 41 | [data-theme="dark"] 42 | #search-mask 43 | background: #0000007a 44 | 45 | div#search-mask::after 46 | content: '-- 点击空白处关闭 --' 47 | position: fixed 48 | bottom: 0 49 | font-weight: 100 50 | text-align: center 51 | width: 100% -------------------------------------------------------------------------------- /scripts/tag/folding.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function postFolding(args, content) { 4 | if(/::/g.test(args)){ 5 | args = args.join(' ').split('::'); 6 | } 7 | else{ 8 | args = args.join(' ').split(','); 9 | } 10 | let style = ''; 11 | let title = ''; 12 | if (args.length > 1) { 13 | style = args[0].trim(); 14 | title = args[1].trim(); 15 | } else if (args.length > 0) { 16 | title = args[0].trim(); 17 | } 18 | if (style != undefined) { 19 | return `
${title} 20 |
21 | ${hexo.render.renderSync({text: content, engine: 'markdown'}).split('\n').join('')} 22 |
23 |
`; 24 | } 25 | return `
${title} 26 |
27 | ${hexo.render.renderSync({text: content, engine: 'markdown'}).split('\n').join('')} 28 |
29 |
`; 30 | 31 | 32 | } 33 | 34 | hexo.extend.tag.register('folding', postFolding, {ends: true}); 35 | -------------------------------------------------------------------------------- /layout/includes/third-party/subtitle.pug: -------------------------------------------------------------------------------- 1 | - const { effect,loop,source,sub,startDelay,typeSpeed,backSpeed } = theme.subtitle 2 | - let subContent = sub || new Array() 3 | - subContent = subContent.length ? subContent : new Array(config.subtitle) 4 | //- script. 5 | function subtitleType () { 6 | if (!{effect}) { 7 | window.typed = new Typed("#subtitle", { 8 | strings: !{JSON.stringify(subContent)}, 9 | startDelay: 10, 10 | typeSpeed: 80, 11 | loop: !{loop}, 12 | showCursor: false, 13 | backSpeed: 70 14 | }) 15 | } 16 | } 17 | if (!{effect}) { 18 | if (typeof Typed === 'function') { 19 | subtitleType() 20 | } else { 21 | getScript('!{url_for(theme.asset.typed)}').then(subtitleType) 22 | } 23 | } 24 | 25 | script(src="/js/typed.js") 26 | script. 27 | var typed = new Typed("#subtitle", { 28 | strings: !{JSON.stringify(subContent)}, 29 | startDelay: 10, 30 | typeSpeed: 80, 31 | loop: !{loop}, 32 | showCursor: false, 33 | backSpeed: 70 34 | }); 35 | 36 | //- !{JSON.stringify(subContent)} -------------------------------------------------------------------------------- /source/css/_layout/rightside.styl: -------------------------------------------------------------------------------- 1 | #rightside 2 | position: fixed 3 | right: -48px 4 | bottom: $rightside-bottom 5 | z-index: 100 6 | opacity: 0 7 | transition: all .5s 8 | 9 | #rightside-config-hide 10 | height: 0 11 | opacity: 0 12 | transition: transform .4s 13 | transform: translate(45px, 0) 14 | 15 | &.show 16 | height: auto 17 | opacity: 1 18 | transform: translate(0, 0) 19 | 20 | &.status 21 | height: auto 22 | opacity: 1 23 | 24 | & > div 25 | & > button, 26 | & > a 27 | display: block 28 | margin-bottom: 5px 29 | width: w = 35px 30 | height: w 31 | border-radius: 5px 32 | background-color: var(--btn-bg) 33 | color: var(--btn-color) 34 | text-align: center 35 | font-size: 16px 36 | line-height: w 37 | 38 | &:hover 39 | background-color: var(--btn-hover-color) 40 | 41 | #mobile-toc-button 42 | display: none 43 | 44 | +maxWidth900() 45 | display: block 46 | 47 | +maxWidth900() 48 | #hide-aside-btn 49 | display: none 50 | -------------------------------------------------------------------------------- /layout/includes/widget/card_webinfo.pug: -------------------------------------------------------------------------------- 1 | .card-widget.card-webinfo 2 | .item-headline(style='width:fit-content;margin:auto;') 3 | i.dys.shujukanban(style='font-size:20px;margin-right:5px') 4 | span= _p('aside.card_webinfo.headline') 5 | .webinfo 6 | .webinfo-item 7 | .item-name 8 | i.dys.-disk(style='font-size:20px') 9 | .text 文章总数 10 | .item-count= site.posts.length 11 | .webinfo-item 12 | .item-name 13 | i.dys.view(style='font-size:20px') 14 | .text 总访问量 15 | .item-count#busuanzi_value_site_pv 16 | .webinfo-item 17 | .item-name 18 | i.dys.groupico(style='font-size:20px') 19 | .text 访问人次 20 | .item-count#busuanzi_value_site_uv 21 | .webinfo-item 22 | .item-name 23 | i.dys.postico(style='font-size:20px') 24 | .text 全站字数 25 | .item-count=totalcount(site) 26 | .webinfo-item 27 | .item-name 28 | i.dys.upload(style='font-size:20px') 29 | .text 最后更新 30 | .item-count#last-push-date(data-lastPushDate=date_xml(Date.now())) 31 | i.dys.spinner3.spin.ani 32 | 33 | -------------------------------------------------------------------------------- /layout/includes/head/config_site.pug: -------------------------------------------------------------------------------- 1 | - 2 | const titleVal = pageTitle.replace(/'/ig,"\\'") 3 | 4 | let isHighlightShrink 5 | if (theme.highlight_shrink == 'none') isHighlightShrink = 'undefined' 6 | else if (page.highlight_shrink === true || page.highlight_shrink === false) isHighlightShrink = page.highlight_shrink 7 | else isHighlightShrink = theme.highlight_shrink 8 | 9 | var showToc = false 10 | if (theme.aside.enable && page.aside !== false) { 11 | let tocEnable = false 12 | if (is_post()) { 13 | if (theme.toc.post) tocEnable = true 14 | } else if (is_page()) { 15 | if (theme.toc.page) tocEnable = true 16 | } 17 | const pageToc = page.toc === true || page.toc === false ? page.toc : tocEnable 18 | showToc = pageToc && (toc(page.content) !== '' || page.encrypt == true ) 19 | } 20 | - 21 | 22 | script#config-diff. 23 | var GLOBAL_CONFIG_SITE = { 24 | title: '!{titleVal}', 25 | isPost: !{is_post()}, 26 | isHome: !{is_home()}, 27 | isHighlightShrink: !{isHighlightShrink}, 28 | isToc: !{showToc}, 29 | postUpdate: '!{full_date(page.updated)}' 30 | } 31 | -------------------------------------------------------------------------------- /layout/includes/third-party/chat/crisp.pug: -------------------------------------------------------------------------------- 1 | script. 2 | window.$crisp = []; 3 | window.CRISP_WEBSITE_ID = "!{theme.crisp.website_id}"; 4 | (function () { 5 | d = document; 6 | s = d.createElement("script"); 7 | s.src = "https://client.crisp.chat/l.js"; 8 | s.async = 1; 9 | d.getElementsByTagName("head")[0].appendChild(s); 10 | })(); 11 | $crisp.push(["safe", true]) 12 | 13 | if (!{theme.chat_btn}) { 14 | $crisp.push(["do", "chat:hide"]) 15 | $crisp.push(["on", "chat:closed", function() { 16 | $crisp.push(["do", "chat:hide"]) 17 | }]) 18 | var chatBtnFn = () => { 19 | var chatBtn = document.getElementById("chat_btn") 20 | chatBtn.addEventListener("click", function(){ 21 | $crisp.push(["do", "chat:show"]) 22 | $crisp.push(["do", "chat:open"]) 23 | 24 | }); 25 | } 26 | chatBtnFn() 27 | } else { 28 | if (!{theme.chat_hide_show}) { 29 | function chatBtnHide () { 30 | $crisp.push(["do", "chat:hide"]) 31 | } 32 | function chatBtnShow () { 33 | $crisp.push(["do", "chat:show"]) 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /scripts/tag/btns.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function postBtns(args, content) { 4 | return `
5 | ${content} 6 |
`; 7 | } 8 | 9 | function postCell(args, content) { 10 | args = args.join(' ').split(',') 11 | let text = args[0] || '' 12 | let url = args[1] || '' 13 | text = text.trim() 14 | url = url.trim() 15 | if (url.length > 0) { 16 | url = "href='" + url + "'" 17 | } 18 | let icon = '' 19 | let img = 'https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@3/img/placeholder/d570170f4f12e1ee829ca0e85a7dffeb77343a.svg' 20 | if (args.length > 2) { 21 | if (args[2].indexOf(' fa-') > -1) { 22 | icon = args[2].trim() 23 | } else { 24 | img = args[2].trim() 25 | } 26 | } 27 | if (icon.length > 0) { 28 | return `${text}` 29 | } else { 30 | return `${text}` 31 | } 32 | } 33 | 34 | hexo.extend.tag.register('btns', postBtns, {ends: true}); 35 | hexo.extend.tag.register('cell', postCell); 36 | -------------------------------------------------------------------------------- /source/css/_tags/link.styl: -------------------------------------------------------------------------------- 1 | .link_card 2 | display: flex 3 | margin: 10px 0 4 | color: var(--font-color) !important 5 | text-decoration: none !important 6 | background: var(--reward-pop) 7 | border-radius: 10px 8 | padding: 12px 9 | &:hover 10 | background: #4976f5 11 | color: white !important 12 | .link_icon,.link_content 13 | height: 4rem 14 | .link_icon 15 | img,svg 16 | height: 4rem 17 | width: 4rem 18 | .link_content 19 | margin-left: 1rem 20 | width: calc(100% - 6rem) 21 | overflow: hidden 22 | line-height: 1.5 23 | display: flex 24 | flex-direction: column 25 | justify-content: center 26 | .link_title 27 | font-weight: bold 28 | font-size: 1.2rem 29 | .link_title,.link_desc 30 | word-break: break-all 31 | overflow:hidden 32 | text-overflow: ellipsis 33 | &:not(:has(.link_desc)) .link_title 34 | display:-webkit-box 35 | -webkit-box-orient:vertical 36 | -webkit-line-clamp:2 37 | .link_desc 38 | opacity: .6 39 | .link_desc,&:has(.link_desc) .link_title 40 | white-space: nowrap -------------------------------------------------------------------------------- /layout/includes/third-party/comments/js.pug: -------------------------------------------------------------------------------- 1 | each name in theme.comments.use 2 | case name 3 | when 'Valine' 4 | !=partial('includes/third-party/comments/valine', {}, {cache: true}) 5 | when 'Disqus' 6 | include ./disqus.pug 7 | when 'Disqusjs' 8 | include ./disqusjs.pug 9 | when 'Livere' 10 | !=partial('includes/third-party/comments/livere', {}, {cache: true}) 11 | when 'Gitalk' 12 | include ./gitalk.pug 13 | when 'Utterances' 14 | !=partial('includes/third-party/comments/utterances', {}, {cache: true}) 15 | when 'Twikoo' 16 | !=partial('includes/third-party/comments/twikoo', {}, {cache: true}) 17 | when 'Waline' 18 | !=partial('includes/third-party/comments/waline', {}, {cache: true}) 19 | when 'Giscus' 20 | !=partial('includes/third-party/comments/giscus', {}, {cache: true}) 21 | when 'Facebook Comments' 22 | include ./facebook_comments.pug 23 | when 'Remark42' 24 | !=partial('includes/third-party/comments/remark42', {}, {cache: true}) 25 | when 'Artalk' 26 | !=partial('includes/third-party/comments/artalk', {}, {cache: true}) -------------------------------------------------------------------------------- /layout/includes/mixins/article-sort.pug: -------------------------------------------------------------------------------- 1 | mixin articleSort(posts) 2 | .article-sort 3 | - var year 4 | - posts.each(function (article) { 5 | - let tempYear = date(article.date, 'YYYY') 6 | - let no_cover = article.cover === false || !theme.cover.archives_enable ? 'no-article-cover' : '' 7 | - let title = article.title || _p('no_title') 8 | if tempYear !== year 9 | - year = tempYear 10 | .article-sort-item.year= year 11 | .article-sort-item(class=no_cover) 12 | if article.cover && theme.cover.archives_enable 13 | a.article-sort-item-img(href=url_for(article.path) title=title) 14 | img(src=url_for(article.cover) alt=title onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'`) 15 | .article-sort-item-info 16 | .article-sort-item-time 17 | i.dys.time 18 | time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))= date(article.date, config.date_format) 19 | a.article-sort-item-title(href=url_for(article.path) title=title)= title 20 | - }) -------------------------------------------------------------------------------- /source/css/_custom/tag.styl: -------------------------------------------------------------------------------- 1 | .tag-cloud-list a 2 | color: #fff 3 | width: 47% 4 | border-radius: 10px 5 | padding: 2px 10px 6 | margin-bottom: 10px 7 | font-size: 20px !important 8 | margin-right: 3% 9 | background: var(--heo-theme) 10 | 11 | .card-tag-cloud a 12 | color: var(--heo-font) !important 13 | border-bottom: 2px dashed var(--border) 14 | padding: 3px 10px !important 15 | margin-bottom: 2% 16 | font-size: 16px !important 17 | 18 | .card-tag-cloud, #aside-cat-list, .card-archive-list 19 | max-height: 135px 20 | overflow-y: scroll 21 | font-weight: 600 22 | 23 | .card-tag-cloud, #aside-cat-list, .card-archive-list 24 | &::-webkit-scrollbar 25 | display: none 26 | 27 | li.card-category-list-item, li.card-archive-list-item 28 | width: 48% 29 | border-bottom: 2px dashed var(--border) 30 | margin-bottom: 2% 31 | margin-right: 2% 32 | display: inline-block 33 | 34 | #aside-content .card-archives ul.card-archive-list>.card-archive-list-item a, #aside-content .card-categories ul.card-category-list>.card-category-list-item a 35 | color: var(--heo-font) !important -------------------------------------------------------------------------------- /layout/post.pug: -------------------------------------------------------------------------------- 1 | extends includes/layout.pug 2 | 3 | block content 4 | #post.maininner 5 | if top_img === false 6 | include includes/header/post-info.pug 7 | 8 | article#article-container.post-content!=page.content 9 | include includes/post/post-copyright.pug 10 | .tag_share 11 | if (theme.post_meta.post.tags) 12 | .post-meta__tag-list 13 | each item, index in page.tags.data 14 | a(href=url_for(item.path)).post-meta__tags #[=item.name] 15 | include includes/third-party/share/index.pug 16 | 17 | if theme.reward.enable && theme.reward.QR_code 18 | !=partial('includes/post/reward', {}, {cache: true}) 19 | 20 | //- ad 21 | if theme.ad && theme.ad.post 22 | .ads-wrap!=theme.ad.post 23 | 24 | if theme.post_pagination 25 | include includes/pagination.pug 26 | if theme.related_post && theme.related_post.enable 27 | != related_posts(page,site.posts) 28 | 29 | if page.comments !== false && theme.comments && theme.comments.use 30 | - var commentsJsLoad = true 31 | !=partial('includes/third-party/comments/index', {}, {cache: true}) 32 | -------------------------------------------------------------------------------- /layout/includes/header/menu_item.pug: -------------------------------------------------------------------------------- 1 | if theme.nav.menu 2 | .menus_items#menus-items 3 | each value, label in theme.nav.menu 4 | if typeof value !== 'object' 5 | .menus_item 6 | - const valueArray = value.split('||') 7 | a.site-page(href=url_for(trim(valueArray[0]))) 8 | if valueArray[1] 9 | i(class=trim(valueArray[1])) 10 | span=' '+label 11 | else 12 | .menus_item 13 | - const labelArray = label.split('||') 14 | - const hideClass = labelArray[2] && trim(labelArray[2]) === 'hide' ? 'hide' : '' 15 | a.site-page.group(class=`${hideClass}` href='javascript:void(0);') 16 | if labelArray[1] 17 | i(class=trim(labelArray[1])) 18 | span=' '+ trim(labelArray[0]) 19 | i.dys.arrowdown 20 | ul.menus_item_child 21 | each val,lab in value 22 | - const valArray = val.split('||') 23 | li 24 | a.site-page.child(href=url_for(trim(valArray[0]))) 25 | if valArray[1] 26 | i(class=trim(valArray[1])) 27 | span=' '+ lab -------------------------------------------------------------------------------- /layout/includes/third-party/comments/valine.pug: -------------------------------------------------------------------------------- 1 | - let emojiMaps = '""' 2 | if site.data.valine 3 | - emojiMaps = JSON.stringify(site.data.valine) 4 | 5 | script. 6 | function loadValine () { 7 | function initValine () { 8 | const valine = new Valine(Object.assign({ 9 | el: '#vcomment', 10 | appId: '#{theme.valine.appId}', 11 | appKey: '#{theme.valine.appKey}', 12 | avatar: '#{theme.valine.avatar}', 13 | serverURLs: '#{theme.valine.serverURLs}', 14 | emojiMaps: !{emojiMaps}, 15 | path: window.location.pathname, 16 | visitor: #{theme.valine.visitor} 17 | }, !{JSON.stringify(theme.valine.option)})) 18 | } 19 | 20 | if (typeof Valine === 'function') initValine() 21 | else getScript('!{url_for(theme.asset.valine)}').then(initValine) 22 | } 23 | 24 | if ('!{theme.comments.use[0]}' === 'Valine' || !!{theme.comments.lazyload}) { 25 | if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('vcomment'),loadValine) 26 | else setTimeout(loadValine, 0) 27 | } else { 28 | function loadOtherComment () { 29 | loadValine() 30 | } 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /layout/includes/swiper.pug: -------------------------------------------------------------------------------- 1 | - var fposts = theme.hometop.featured_posts 2 | 3 | .recent-post-item#swiperBar(style='border:none!important;') 4 | #ark-swiper-container 5 | .swiper-wrapper.dht-swiper-wrapper 6 | each item, i in fposts.posts 7 | //- 内容版块 8 | .swiper-slide.dht-swiper-item(onclick=`pjax.loadUrl('${url_for(item.link)}')`) 9 | //- 封面 10 | .dht-swiper-item-cover(onclick=`pjax.loadUrl('${url_for(item.link)}')`) 11 | img.article-cover(src=item.cover title='') 12 | //- 标题和描述 13 | .dht-swiper-item-info(onclick=`pjax.loadUrl('${url_for(item.link)}')`) 14 | a.dht-swiper-item-title 15 | .dht-swiper-item-title-link= item.title 16 | a.dht-swiper-item-description 17 | .dht-swiper-item-description-text=item.descr 18 | .swiper-scrollbar 19 | .swiper-button-prev 20 | .swiper-button-next 21 | 22 | style. 23 | #ark-swiper-container .swiper-scrollbar-drag { 24 | background: linear-gradient(to left, #ff4500, #ffa500, #ffd700, #90ee90, #0ff, #1e90ff, #9370db, #ff69b4, #ff4500); 25 | box-shadow: 0 0 0 2px #fff 26 | } -------------------------------------------------------------------------------- /source/css/_tags/media.styl: -------------------------------------------------------------------------------- 1 | $sp = 4px 2 | 3 | audio,video 4 | border-radius: $border-codeblock 5 | max-width: 100% 6 | video 7 | z-index: 1 8 | trans() 9 | &:hover 10 | box-shadow: 0 4px 8px 0px rgba(0, 0, 0, 0.24), 0 8px 16px 0px rgba(0, 0, 0, 0.24) 11 | 12 | div.video 13 | line-height: 0 14 | text-align: center 15 | 16 | div.videos 17 | max-width: "calc(100% + 2 * %s)" % $sp 18 | display: flex 19 | flex-wrap: wrap 20 | justify-content: flex-start 21 | align-items: flex-end 22 | margin: $gap-p 0 - $sp 23 | .video,iframe 24 | width: 100% 25 | margin: $sp 26 | 27 | iframe 28 | border-radius: $border-codeblock 29 | width: 100% 30 | min-height: 300px 31 | &.left 32 | justify-content: flex-start 33 | &.center 34 | justify-content: center 35 | &.right 36 | justify-content: flex-end 37 | &.stretch 38 | align-items: stretch 39 | &[col='1'] 40 | .video,iframe 41 | width: 100% 42 | &[col='2'] 43 | .video,iframe 44 | width: "calc(50% - 2 * %s)" % $sp 45 | &[col='3'] 46 | .video,iframe 47 | width: "calc(33.33% - 2 * %s)" % $sp 48 | &[col='4'] 49 | .video,iframe 50 | width: "calc(25% - 2 * %s)" % $sp 51 | -------------------------------------------------------------------------------- /source/css/_highlight/prismjs/line-number.styl: -------------------------------------------------------------------------------- 1 | #article-container 2 | pre[class*='language-'] 3 | &.line-numbers 4 | position: relative 5 | padding-left: 3.8em 6 | counter-reset: linenumber 7 | line-height: $line-height-code-block 8 | 9 | > code 10 | position: relative 11 | line-height: $line-height-code-block 12 | 13 | if hexo-config('code_word_wrap') 14 | white-space: pre-wrap 15 | else 16 | white-space: inherit 17 | word-wrap: normal 18 | word-break: normal 19 | overflow-wrap: normal 20 | 21 | .line-numbers-rows 22 | position: absolute 23 | top: 0 24 | left: -3.8em 25 | width: 3em 26 | letter-spacing: -1px 27 | font-size: 100% 28 | pointer-events: none 29 | user-select: none 30 | 31 | & > span 32 | display: block 33 | counter-increment: linenumber 34 | pointer-events: none 35 | 36 | &:before 37 | display: block 38 | padding-right: .8em 39 | color: var(--hlnumber-color) 40 | content: counter(linenumber) 41 | text-align: right 42 | -------------------------------------------------------------------------------- /source/css/_page/common.styl: -------------------------------------------------------------------------------- 1 | #body-wrap 2 | display: flex 3 | flex-direction: column 4 | min-height: 100vh 5 | 6 | .layout 7 | display: flex 8 | flex: 1 auto 9 | margin: 0 auto 10 | padding: 40px 15px 11 | max-width: 1200px 12 | width: 100% 13 | 14 | +maxWidth900() 15 | flex-direction: column 16 | 17 | +maxWidth768() 18 | padding: 20px 15px 19 | 20 | & > div:first-child:not(.recent-posts) 21 | @extend .cardHover 22 | align-self: flex-start 23 | padding: 50px 40px 24 | 25 | +maxWidth768() 26 | padding: 36px 14px 27 | 28 | & > div:first-child 29 | width: 74% 30 | transition: all .3s 31 | 32 | +maxWidth900() 33 | width: 100% !important 34 | 35 | if hexo-config('aside.position') == 'left' 36 | +minWidth900() 37 | order: 2 38 | 39 | // 隱藏aside 40 | &.hide-aside 41 | max-width: 1000px 42 | 43 | +minWidth2000() 44 | max-width: 1300px 45 | 46 | & > div 47 | width: 100% !important 48 | 49 | // for apple device 50 | .apple 51 | #page-header.full_page 52 | background-attachment: scroll !important 53 | 54 | .recent-post-item, 55 | .avatar-img, 56 | .flink-item-icon 57 | transform: translateZ(0) 58 | -------------------------------------------------------------------------------- /layout/includes/third-party/card-post-count/twikoo.pug: -------------------------------------------------------------------------------- 1 | script. 2 | (() => { 3 | const getCommentUrl = () => { 4 | const eleGroup = document.querySelectorAll('#recent-posts .article-title') 5 | let urlArray = [] 6 | eleGroup.forEach(i=>{ 7 | urlArray.push(i.getAttribute('href')) 8 | }) 9 | return urlArray 10 | } 11 | 12 | const getCount = () => { 13 | const runTwikoo = () => { 14 | twikoo.getCommentsCount({ 15 | envId: '!{theme.twikoo.envId}', 16 | region: '!{theme.twikoo.region}', 17 | urls: getCommentUrl(), 18 | includeReply: false 19 | }).then(function (res) { 20 | document.querySelectorAll('#recent-posts .twikoo-count').forEach((item,index) => { 21 | item.innerText = res[index].count 22 | }) 23 | }).catch(function (err) { 24 | console.log(err) 25 | }) 26 | } 27 | 28 | if (typeof twikoo === 'object') { 29 | runTwikoo() 30 | } else { 31 | getScript('!{url_for(theme.asset.twikoo)}').then(runTwikoo) 32 | } 33 | } 34 | 35 | window.pjax ? getCount() : window.addEventListener('load', getCount) 36 | 37 | })() -------------------------------------------------------------------------------- /layout/includes/third-party/chat/gitter.pug: -------------------------------------------------------------------------------- 1 | if theme.chat_btn 2 | script. 3 | ((window.gitter = {}).chat = {}).options = { 4 | disableDefaultChat: true, 5 | }; 6 | document.addEventListener('gitter-sidecar-ready', (e) => { 7 | const GitterChat = e.detail.Chat 8 | let chat 9 | 10 | function initGitter () { 11 | chat = new GitterChat({ 12 | room: '#{theme.gitter.room}', 13 | activationElement: '#chat_btn' 14 | }); 15 | } 16 | 17 | initGitter() 18 | 19 | document.addEventListener('pjax:complete', () => { 20 | chat.destroy() 21 | initGitter() 22 | }) 23 | 24 | }) 25 | else 26 | script. 27 | ((window.gitter = {}).chat = {}).options = { 28 | room: '#{theme.gitter.room}', 29 | }; 30 | 31 | if (!{theme.chat_hide_show}) { 32 | function chatBtnHide () { 33 | document.getElementsByClassName('gitter-open-chat-button')[0].style.display= 'none' 34 | } 35 | 36 | function chatBtnShow () { 37 | document.getElementsByClassName('gitter-open-chat-button')[0].style.display= 'block' 38 | } 39 | } 40 | 41 | script(src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer) 42 | -------------------------------------------------------------------------------- /layout/includes/third-party/math/mermaid.pug: -------------------------------------------------------------------------------- 1 | script. 2 | (() => { 3 | const $mermaidWrap = document.querySelectorAll('#article-container .mermaid-wrap') 4 | if ($mermaidWrap.length) { 5 | window.runMermaid = () => { 6 | window.loadMermaid = true 7 | const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{theme.mermaid.theme.dark}' : '!{theme.mermaid.theme.light}' 8 | 9 | Array.from($mermaidWrap).forEach((item, index) => { 10 | const mermaidSrc = item.firstElementChild 11 | const mermaidThemeConfig = '%%{init:{ \'theme\':\'' + theme + '\'}}%%\n' 12 | const mermaidID = 'mermaid-' + index 13 | const mermaidDefinition = mermaidThemeConfig + mermaidSrc.textContent 14 | mermaid.mermaidAPI.render(mermaidID, mermaidDefinition, (svgCode) => { 15 | mermaidSrc.insertAdjacentHTML('afterend', svgCode) 16 | }) 17 | }) 18 | } 19 | 20 | const loadMermaid = () => { 21 | window.loadMermaid ? runMermaid() : getScript('!{url_for(theme.asset.mermaid)}').then(runMermaid) 22 | } 23 | 24 | window.pjax ? loadMermaid() : document.addEventListener('DOMContentLoaded', loadMermaid) 25 | } 26 | })() -------------------------------------------------------------------------------- /scripts/tag/reference.js: -------------------------------------------------------------------------------- 1 | /* 2 | {% referto 'id','literature' %} 3 | {% referfrom 'id','literature','url' %} 4 | */ 5 | 'use strict' 6 | const urlFor = require('hexo-util').url_for.bind(hexo) 7 | 8 | function referto (args) { 9 | args = args.join(' ').split(',') 10 | let referid = args[0] 11 | let literature = args[1] 12 | return `${referid}${literature}参考资料`; 13 | } 14 | 15 | 16 | function referfrom (args) { 17 | args = args.join(' ').split(',') 18 | let fromid = args[0] 19 | let fromliterature = args[1] 20 | let referurl = args[2] ? urlFor(args[2]) : 'javascript:void' 21 | return `
${fromid}
${fromliterature}
`; 22 | 23 | } 24 | 25 | hexo.extend.tag.register('referto',referto); 26 | hexo.extend.tag.register('referfrom',referfrom); 27 | -------------------------------------------------------------------------------- /layout/includes/third-party/chat/tidio.pug: -------------------------------------------------------------------------------- 1 | script(src=`//code.tidio.co/${theme.tidio.public_key}.js` async) 2 | 3 | if theme.chat_btn 4 | script. 5 | function onTidioChatApiReady() { 6 | window.tidioChatApi.hide(); 7 | window.tidioChatApi.on("close", function() { 8 | window.tidioChatApi.hide(); 9 | }); 10 | } 11 | if (window.tidioChatApi) { 12 | window.tidioChatApi.on("ready", onTidioChatApiReady); 13 | } else { 14 | document.addEventListener("tidioChat-ready", onTidioChatApiReady); 15 | } 16 | 17 | var chatBtnFn = () => { 18 | document.getElementById("chat_btn").addEventListener("click", function(){ 19 | window.tidioChatApi.show(); 20 | window.tidioChatApi.open(); 21 | }); 22 | } 23 | chatBtnFn() 24 | 25 | else if theme.chat_hide_show 26 | script. 27 | function chatBtnHide () { 28 | if (window.tidioChatApi) { 29 | //- window.tidioChatApi.hide(); 30 | document.getElementById('tidio-chat').style.display= 'none' 31 | } 32 | } 33 | 34 | function chatBtnShow () { 35 | if (window.tidioChatApi) { 36 | //- window.tidioChatApi.show(); 37 | document.getElementById('tidio-chat').style.display= 'block' 38 | } 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /layout/includes/loading/index.pug: -------------------------------------------------------------------------------- 1 | if theme.preloader.enable 2 | #loading-box(onclick='document.getElementById("loading-box").classList.add("loaded")') 3 | .loading-bg 4 | div.loading-img 5 | .loading-image-dot 6 | 7 | script. 8 | const preloader = { 9 | endLoading: () => { 10 | document.body.style.overflow = 'auto'; 11 | document.getElementById('loading-box').classList.add("loaded") 12 | new Vue({ 13 | data: function () { 14 | this.$notify({ 15 | title: "请发表合法评论", 16 | message: "在评论发表违法内容者后果自负,站长概不负责,最终解释权归站长所有,发表评论即代表同意上述内容", 17 | position: 'top-left', 18 | offset: 50, 19 | showClose: true, 20 | type: "warning", 21 | duration: 4000 22 | }); 23 | } 24 | }) 25 | }, 26 | initLoading: () => { 27 | document.body.style.overflow = ''; 28 | document.getElementById('loading-box').classList.remove("loaded") 29 | 30 | } 31 | } 32 | window.addEventListener('load',()=> { preloader.endLoading() }) 33 | document.addEventListener('pjax:send', () => { preloader.initLoading() }) 34 | document.addEventListener('pjax:complete', () => { preloader.endLoading() }) -------------------------------------------------------------------------------- /layout/includes/third-party/comments/waline.pug: -------------------------------------------------------------------------------- 1 | - const { serverURL, option, pageview } = theme.waline 2 | - const { lazyload, count, use } = theme.comments 3 | 4 | script. 5 | function loadWaline () { 6 | function insertCSS () { 7 | const link = document.createElement("link") 8 | link.rel = "stylesheet" 9 | link.href = "!{url_for(theme.asset.waline_css)}" 10 | document.head.appendChild(link) 11 | } 12 | 13 | function initWaline () { 14 | const waline = Waline.init(Object.assign({ 15 | el: '#waline-wrap', 16 | serverURL: '!{serverURL}', 17 | pageview: !{lazyload ? false : pageview}, 18 | dark: 'html[data-theme="dark"]', 19 | path: window.location.pathname, 20 | comment: !{lazyload ? false : count}, 21 | }, !{JSON.stringify(option)})) 22 | } 23 | 24 | if (typeof Waline === 'function') initWaline() 25 | else { 26 | insertCSS() 27 | getScript('!{url_for(theme.asset.waline_js)}').then(initWaline) 28 | } 29 | } 30 | 31 | if ('!{use[0]}' === 'Waline' || !!{lazyload}) { 32 | if (!{lazyload}) btf.loadComment(document.getElementById('waline-wrap'),loadWaline) 33 | else setTimeout(loadWaline, 0) 34 | } else { 35 | function loadOtherComment () { 36 | loadWaline() 37 | } 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /layout/includes/widget/card_tags.pug: -------------------------------------------------------------------------------- 1 | if theme.aside.card_tags.enable 2 | if site.tags.length 3 | .card-widget.card-tags 4 | .item-headline 5 | i.dys.tag 6 | span= _p('aside.card_tags') 7 | 8 | - let tagLimit = theme.aside.card_tags.limit === 0 ? 0 : theme.aside.card_tags.limit || 40 9 | if theme.aside.card_tags.color 10 | .card-tag-cloud!= cloudTags({source: site.tags, minfontsize: 1.15, maxfontsize: 1.45, limit: tagLimit, unit: 'em'}) 11 | else 12 | .card-tag-cloud!= tagcloud({min_font: 1.1, max_font: 1.5, amount: tagLimit , color: true, start_color: '#999', end_color: '#99a9bf', unit: 'em'}) 13 | if theme.aside.card_categories.enable 14 | if site.categories.length 15 | .card-widget.card-categories 16 | !=aside_categories({ limit: theme.aside.card_categories.limit === 0 ? 0 : theme.aside.card_categories.limit || 8 , expand: theme.aside.card_categories.expand }) 17 | if theme.aside.card_archives.enable 18 | .card-widget.card-archives 19 | - let type = theme.aside.card_archives.type || 'monthly' 20 | - let format = theme.aside.card_archives.format || 'MMMM YYYY' 21 | - let order = theme.aside.card_archives.order || -1 22 | - let limit = theme.aside.card_archives.limit === 0 ? 0 : theme.aside.card_archives.limit || 8 23 | != aside_archives({ type:type, format: format, order: order, limit: limit }) 24 | 25 | -------------------------------------------------------------------------------- /scripts/tag/flink.js: -------------------------------------------------------------------------------- 1 | /** 2 | * flink 3 | */ 4 | 5 | 'use strict' 6 | 7 | const urlFor = require('hexo-util').url_for.bind(hexo) 8 | 9 | const flinkFn = (args, content) => { 10 | content = hexo.render.renderSync({ text: content, engine: 'yaml' }) 11 | 12 | let result = '' 13 | 14 | content.forEach(i => { 15 | const className = i.class_name ? `` : '' 16 | const classDesc = i.class_desc ? `` : '' 17 | 18 | let listResult = '' 19 | 20 | i.link_list.forEach(j => { 21 | listResult += ` 22 | ` 31 | }) 32 | 33 | result += `${className}${classDesc} ` 34 | }) 35 | 36 | return `` 37 | } 38 | 39 | hexo.extend.tag.register('flink', flinkFn, { ends: true }) 40 | -------------------------------------------------------------------------------- /scripts/filters/random_cover.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Butterfly 3 | * ramdom cover 4 | */ 5 | 6 | 'use strict' 7 | 8 | hexo.extend.filter.register('before_post_render', function (data) { 9 | const { config } = this 10 | if (config.post_asset_folder) { 11 | const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/ 12 | const topImg = data.top_img 13 | const cover = data.cover 14 | if (topImg && topImg.indexOf('/') === -1 && imgTestReg.test(topImg)) data.top_img = data.path + topImg 15 | if (cover && cover.indexOf('/') === -1) data.cover = data.path + cover 16 | } 17 | 18 | if (data.cover === false) { 19 | data.randomcover = randomCover() 20 | return data 21 | } 22 | 23 | data.cover = data.cover || randomCover() 24 | return data 25 | }) 26 | 27 | function randomCover () { 28 | const theme = hexo.theme.config 29 | let cover 30 | let num 31 | 32 | if (theme.cover && theme.cover.default_cover) { 33 | if (!Array.isArray(theme.cover.default_cover)) { 34 | cover = theme.cover.default_cover 35 | return cover 36 | } else { 37 | num = Math.floor(Math.random() * theme.cover.default_cover.length) 38 | cover = theme.cover.default_cover[num] 39 | return cover 40 | } 41 | } else { 42 | cover = theme.default_top_img || 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' 43 | return cover 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /layout/includes/third-party/chat/messenger.pug: -------------------------------------------------------------------------------- 1 | - let { pageID, lang } = theme.messenger 2 | - lang = theme.comments.use && theme.comments.use.includes('Facebook Comments') ? theme.facebook_comments.lang : lang 3 | 4 | #fb-customer-chat.fb-customerchat(page_id=pageID attribution='biz_inbox') 5 | 6 | script. 7 | document.getElementById('fb-root') ? '' : document.body.insertAdjacentHTML('afterend', '
') 8 | 9 | window.fbAsyncInit = function() { 10 | FB.init({ 11 | xfbml: true, 12 | version: 'v15.0' 13 | }); 14 | }; 15 | 16 | (function(d, s, id) { 17 | var js, fjs = d.getElementsByTagName(s)[0]; 18 | if (d.getElementById(id)) return; 19 | js = d.createElement(s); js.id = id; 20 | js.src = 'https://connect.facebook.net/!{lang}/sdk/xfbml.customerchat.js'; 21 | fjs.parentNode.insertBefore(js, fjs); 22 | }(document, 'script', 'facebook-jssdk')); 23 | 24 | if (!{theme.chat_btn}) { 25 | var chatBtnFn = () => { 26 | var chatBtn = document.getElementById("chat_btn") 27 | chatBtn.addEventListener("click", function(){ 28 | FB.CustomerChat.show(); 29 | }); 30 | } 31 | chatBtnFn() 32 | } else { 33 | if (!{theme.chat_hide_show}) { 34 | function chatBtnHide () { 35 | FB.CustomerChat.hide() 36 | } 37 | function chatBtnShow () { 38 | FB.CustomerChat.show(false) 39 | } 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /source/css/_layout/loading.styl: -------------------------------------------------------------------------------- 1 | if hexo-config('preloader') 2 | .loading-bg 3 | display: flex; 4 | width: 100%; 5 | height: 100%; 6 | position: fixed; 7 | background: var(--loading-bg); 8 | backdrop-filter: saturate(180%) blur(20px) 9 | -webkit-backdrop-filter: blur(20px) saturate(180%) 10 | z-index: 99999; 11 | opacity: 1; 12 | transition: .3s; 13 | 14 | #loading-box 15 | .loading-img 16 | background: url(hexo-config('avatar.img')) no-repeat center center 17 | background-size: cover 18 | width: 100px; 19 | height: 100px; 20 | border-radius: 50%; 21 | margin: auto; 22 | border: 4px solid #f0f0f2; 23 | animation-duration: .3s; 24 | animation-name: loadingAction; 25 | animation-iteration-count: infinite; 26 | animation-direction: alternate; 27 | &.loaded 28 | .loading-bg 29 | opacity: 0; 30 | z-index: -1000; 31 | .loading-image-dot 32 | width: 30px; 33 | height: 30px; 34 | display: flex 35 | align-items: center 36 | justify-content: center 37 | position: absolute; 38 | border-radius: 50%; 39 | border: 6px solid #fff; 40 | top: 50%; 41 | left: 50%; 42 | transform: translate(18px, 24px); 43 | img 44 | height: 26px 45 | width: 26px 46 | 47 | @keyframes loadingAction 48 | 0% { 49 | opacity: 1; 50 | } 51 | 52 | 100% { 53 | opacity: .4; 54 | } -------------------------------------------------------------------------------- /layout/includes/head/analytics.pug: -------------------------------------------------------------------------------- 1 | if theme.baidu_analytics 2 | script. 3 | var _hmt = _hmt || []; 4 | (function() { 5 | var hm = document.createElement("script"); 6 | hm.src = "https://hm.baidu.com/hm.js?!{theme.baidu_analytics}"; 7 | var s = document.getElementsByTagName("script")[0]; 8 | s.parentNode.insertBefore(hm, s); 9 | })(); 10 | 11 | if theme.google_analytics 12 | script(async src=`https://www.googletagmanager.com/gtag/js?id=${theme.google_analytics}`) 13 | script. 14 | window.dataLayer = window.dataLayer || []; 15 | function gtag(){dataLayer.push(arguments);} 16 | gtag('js', new Date()); 17 | gtag('config', '!{theme.google_analytics}'); 18 | 19 | if theme.cnzz_analytics 20 | script(async data-pjax src=`https://s4.cnzz.com/z_stat.php?id=${theme.cnzz_analytics}&web_id=${theme.cnzz_analytics}`) 21 | 22 | if theme.cloudflare_analytics 23 | script(defer data-pjax src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon=`{"token": "${theme.cloudflare_analytics}"}`) 24 | 25 | if theme.microsoft_clarity 26 | script. 27 | (function(c,l,a,r,i,t,y){ 28 | c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; 29 | t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; 30 | y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); 31 | })(window, document, "clarity", "script", "!{theme.microsoft_clarity}"); -------------------------------------------------------------------------------- /source/css/_layout/footer.styl: -------------------------------------------------------------------------------- 1 | .footer 2 | padding: 15px 3 | #in 4 | background: var(--footer-bg) 5 | width 100% 6 | padding 0 15px 15px 15px 7 | text-align: center 8 | border: 1px solid var(--border) 9 | max-width: 1200px 10 | margin: 0 auto 20px 11 | border-radius: 18px 12 | @media screen and (max-width: 768px) 13 | margin: auto !important 14 | border-radius: 18px 18px 0 0 15 | .title 16 | display flex 17 | flex-direction: column-reverse 18 | text-align: center 19 | img 20 | position: relative 21 | height: 66px 22 | width 66px 23 | border-radius: 100vh 24 | top: -33px 25 | left: calc(50% - 33px) 26 | .author 27 | margin-top -33px 28 | text-align: center 29 | span.name 30 | font-weight: bolder 31 | font-size: 25px 32 | .links 33 | margin-bottom: 20px 34 | display flex 35 | flex-wrap: wrap 36 | justify-content: center 37 | a 38 | color: var(--heo-font) 39 | font-size: 25px 40 | .frame 41 | margin-top: 20px 42 | font-size: 18px 43 | font-weight: bolder 44 | i 45 | margin: 0 3px 46 | about.about 47 | a.footer-button 48 | padding: 15px 49 | margin: 6px 50 | color: #fff 51 | i 52 | line-height: 2 53 | margin-right: 2px -------------------------------------------------------------------------------- /source/css/_tags/button.styl: -------------------------------------------------------------------------------- 1 | #article-container 2 | .btn-center 3 | margin: 0 0 20px 4 | text-align: center 5 | 6 | .btn-beautify 7 | display: inline-block 8 | margin: 0 4px 6px 9 | padding: 0 15px 10 | background-color: var(--btn-beautify-color, $btn-default-color) 11 | color: $btn-color 12 | line-height: 2 13 | 14 | for $type in $color-types 15 | &.{$type} 16 | --btn-beautify-color: lookup('$tagsP-' + $type + '-color') 17 | 18 | &:hover 19 | background-color: var(--btn-hover-color) 20 | 21 | i + span 22 | margin-left: 6px 23 | 24 | &:not(.block) + .btn-beautify:not(.block) 25 | margin: 0 4px 20px 26 | 27 | &.block 28 | display: block 29 | margin: 0 0 20px 30 | width: fit-content 31 | width: -moz-fit-content 32 | 33 | &.center 34 | margin: 0 auto 20px 35 | 36 | &.right 37 | margin: 0 0 20px auto 38 | 39 | &.larger 40 | padding: 6px 15px 41 | 42 | &:hover 43 | text-decoration: none 44 | 45 | &.outline 46 | border: 1px solid transparent 47 | border-color: var(--btn-beautify-color, $btn-default-color) 48 | background-color: transparent 49 | color: var(--btn-beautify-color, $btn-default-color) 50 | 51 | &:hover 52 | background-color: var(--btn-beautify-color, $btn-default-color) 53 | 54 | &:hover 55 | color: white !important 56 | -------------------------------------------------------------------------------- /scripts/tag/ghcard.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://github.com/anuraghazra/github-readme-stats 3 | */ 4 | 5 | 'use strict'; 6 | 7 | // {% ghcard volantis-x %} 8 | // {% ghcard volantis-x/hexo-theme-volantis %} 9 | hexo.extend.tag.register('ghcard', function(args) { 10 | if(/::/g.test(args)){ 11 | args = args.join(' ').split('::'); 12 | } 13 | else{ 14 | args = args.join(' ').split(','); 15 | } 16 | const path = args[0].trim(); 17 | let card = ''; 18 | card += ''; 19 | let url = ''; 20 | if (path.includes('/')) { 21 | // is repo 22 | const ps = path.split('/'); 23 | url += 'https://github-readme-stats.xaoxuu.com/api/pin/?username=' + ps[0] + '&repo=' + ps[1]; 24 | } else { 25 | // is user 26 | url += 'https://github-readme-stats.xaoxuu.com/api/?username=' + path; 27 | } 28 | if (args.length > 1) { 29 | for (let i = 1; i < args.length; i++) { 30 | const tmp = args[i].trim(); 31 | url += '&' + tmp; 32 | } 33 | } 34 | if (!url.includes('&show_owner=')) { 35 | url += '&show_owner=true'; 36 | } 37 | card += ''; 38 | card += ''; 39 | return card; 40 | }); 41 | 42 | hexo.extend.tag.register('ghcardgroup', function(args, content) { 43 | let ret = ''; 44 | // wrap 45 | ret += '
'; 46 | ret += content; 47 | ret += '
'; 48 | return ret; 49 | }, {ends: true}); 50 | -------------------------------------------------------------------------------- /scripts/tag/timeline.js: -------------------------------------------------------------------------------- 1 | /** 2 | * timeline 3 | * by Jerry 4 | */ 5 | 6 | 'use strict' 7 | 8 | function timeLineFn (args, content) { 9 | const tlBlock = /\n([\w\W\s\S]*?)/g 10 | 11 | let result = '' 12 | let color = '' 13 | if (args.length) { 14 | args = args.join(' ').split(',') 15 | color = args[1] 16 | const mdContent = hexo.render.renderSync({ text: args[0], engine: 'markdown' }) 17 | result += `
${mdContent}
` 18 | } 19 | 20 | const matches = [] 21 | let match 22 | 23 | while ((match = tlBlock.exec(content)) !== null) { 24 | matches.push(match[1]) 25 | matches.push(match[2]) 26 | } 27 | 28 | for (let i = 0; i < matches.length; i += 2) { 29 | const tlChildTitle = hexo.render.renderSync({ text: matches[i], engine: 'markdown' }) 30 | const tlChildContent = hexo.render.renderSync({ text: matches[i + 1], engine: 'markdown' }) 31 | 32 | const tlTitleHtml = `
${tlChildTitle}
` 33 | const tlContentHtml = `
${tlChildContent}
` 34 | 35 | result += `
${tlTitleHtml + tlContentHtml}
` 36 | } 37 | 38 | return `
${result}
` 39 | } 40 | 41 | hexo.extend.tag.register('timeline', timeLineFn, { ends: true }) 42 | -------------------------------------------------------------------------------- /layout/includes/third-party/chat/daovoice.pug: -------------------------------------------------------------------------------- 1 | //- https://guide.daocloud.io/daovoice/javascript-api-5869833.html 2 | script. 3 | (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") 4 | 5 | script. 6 | var isChatBtn = !{theme.chat_btn} 7 | daovoice('init', { 8 | app_id: '!{theme.daovoice.app_id}',},{ 9 | launcher: { 10 | disableLauncherIcon: isChatBtn // 悬浮 ICON 是否显示 11 | }, 12 | }); 13 | daovoice('update'); 14 | 15 | if (isChatBtn) { 16 | var chatBtnFn = () => { 17 | var chatBtn = document.getElementById("chat_btn") 18 | chatBtn.addEventListener("click", function(){ 19 | daovoice('show') 20 | }); 21 | } 22 | chatBtnFn() 23 | } else { 24 | if (!{theme.chat_hide_show}) { 25 | function chatBtnHide () { 26 | daovoice('update', {},{ 27 | launcher: { 28 | disableLauncherIcon: true // 悬浮 ICON 是否显示 29 | }, 30 | }); 31 | } 32 | function chatBtnShow () { 33 | daovoice('update', {},{ 34 | launcher: { 35 | disableLauncherIcon: false // 悬浮 ICON 是否显示 36 | }, 37 | }); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /source/css/_tags/progress.styl: -------------------------------------------------------------------------------- 1 | .progress 2 | display flex 3 | font-size var(--global-font-size) 4 | background-color rgba(88,88,88,0.6) 5 | border-radius .25rem 6 | margin 1rem 0 7 | height 2rem 8 | overflow hidden 9 | p 10 | margin 0 0 0 10px !important 11 | 12 | .progress-bar-animated 13 | background-color #a7b5fd !important 14 | animation progress-bar-stripes 1s linear infinite 15 | 16 | .progress-bar-striped 17 | background-image linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent) 18 | background-size 1rem 1rem 19 | 20 | .progress-bar 21 | display flex 22 | flex-direction column 23 | justify-content center 24 | overflow visible 25 | color #fff 26 | text-align center 27 | white-space nowrap 28 | background-color #0d6efd 29 | transition width .6s ease 30 | 31 | @media (prefers-reduced-motion:reduce) 32 | .progress-bar 33 | transition none 34 | 35 | .bg-green 36 | background-color #28a745 !important 37 | 38 | .bg-yellow 39 | background-color #ffc107 !important 40 | 41 | .bg-red 42 | background-color #dc3545 !important 43 | 44 | .bg-cyan 45 | background-color #17a2b8 !important 46 | 47 | .bg-blue 48 | background-color #0d6efd !important 49 | 50 | .bg-gray 51 | background-color #7f838a !important 52 | 53 | @keyframes progress-bar-stripes 54 | 0% 55 | background-position-x 1rem 56 | -------------------------------------------------------------------------------- /layout/includes/post/post-copyright.pug: -------------------------------------------------------------------------------- 1 | if theme.post_copyright.enable && page.copyright !== false 2 | - let author = page.copyright_author ? page.copyright_author : config.author 3 | - let url = page.copyright_url ? page.copyright_url : page.permalink 4 | .post-copyright 5 | .post-copyright__title 6 | span.post-copyright-info 7 | h #[=page.title] 8 | .post-copyright__type 9 | span.post-copyright-info 10 | a(href=url_for(url))= theme.post_copyright.decode ? decodeURI(url) : url 11 | .post-copyright-m 12 | .post-copyright-m-info 13 | .post-copyright-a(style="display: inline-block;width: 120px") 14 | h 作者 15 | .post-copyright-cc-info 16 | h=author 17 | .post-copyright-c(style="display: inline-block;width: 120px") 18 | h 发布于 19 | .post-copyright-cc-info 20 | h=date(page.date, config.date_format) 21 | .post-copyright-u(style="display: inline-block;width: 120px") 22 | h 更新于 23 | .post-copyright-cc-info 24 | h=date(page.updated, config.date_format) 25 | .post-copyright-c(style="display: inline-block;width: 120px") 26 | h 许可协议 27 | .post-copyright-cc-info 28 | a.icon(rel='noopener' target='_blank' title='Creative Commons' href='https://creativecommons.org/') 29 | i.dys.creativecommons 30 | a(rel='noopener' target='_blank' title='CC BY 4.0' href='https://creativecommons.org/licenses/by/4.0/deed.zh') CC BY 4.0 -------------------------------------------------------------------------------- /layout/includes/third-party/comments/index.pug: -------------------------------------------------------------------------------- 1 | - let defaultComment = theme.comments.use[0] 2 | hr 3 | #post-comment 4 | .comment-head 5 | .comment-headline 6 | i.fas.fa-comments. 7 | span= ' ' + _p('comment') 8 | 9 | if theme.comments.use.length > 1 10 | #comment-switch 11 | span.first-comment=defaultComment 12 | span.switch-btn 13 | span.second-comment=theme.comments.use[1] 14 | 15 | 16 | .comment-wrap 17 | each name in theme.comments.use 18 | div 19 | case name 20 | when 'Disqus' 21 | #disqus_thread 22 | when 'Valine' 23 | #vcomment.vcomment 24 | when 'Disqusjs' 25 | #disqusjs 26 | when 'Livere' 27 | #lv-container(data-id="city" data-uid=theme.livere.uid) 28 | when 'Gitalk' 29 | #gitalk-container 30 | when 'Utterances' 31 | #utterances-wrap 32 | when 'Twikoo' 33 | #twikoo-wrap 34 | when 'Waline' 35 | #waline-wrap 36 | when 'Giscus' 37 | #giscus-wrap 38 | when 'Facebook Comments' 39 | .fb-comments(data-colorscheme = theme.display_mode === 'dark' ? 'dark' : 'light' 40 | data-numposts= theme.facebook_comments.pageSize || 10 41 | data-order-by= theme.facebook_comments.order_by || 'social' 42 | data-width="100%") 43 | when 'Remark42' 44 | #remark42 45 | when 'Artalk' 46 | #artalk-wrap 47 | -------------------------------------------------------------------------------- /layout/includes/third-party/comments/utterances.pug: -------------------------------------------------------------------------------- 1 | script. 2 | function loadUtterances () { 3 | let ele = document.createElement('script') 4 | ele.setAttribute('id', 'utterances_comment') 5 | ele.setAttribute('src', 'https://utteranc.es/client.js') 6 | ele.setAttribute('repo', '!{theme.utterances.repo}') 7 | ele.setAttribute('issue-term', '!{theme.utterances.issue_term}') 8 | let nowTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? '#{theme.utterances.dark_theme}' : '#{theme.utterances.light_theme}' 9 | ele.setAttribute('theme', nowTheme) 10 | ele.setAttribute('crossorigin', 'anonymous') 11 | ele.setAttribute('async', 'true') 12 | document.getElementById('utterances-wrap').insertAdjacentElement('afterbegin',ele) 13 | } 14 | 15 | function utterancesTheme () { 16 | const iframe = document.querySelector('.utterances-frame') 17 | if (iframe) { 18 | const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '#{theme.utterances.dark_theme}' : '#{theme.utterances.light_theme}' 19 | const message = { 20 | type: 'set-theme', 21 | theme: theme 22 | }; 23 | iframe.contentWindow.postMessage(message, 'https://utteranc.es'); 24 | } 25 | } 26 | 27 | if ('!{theme.comments.use[0]}' === 'Utterances' || !!{theme.comments.lazyload}) { 28 | if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('utterances-wrap'), loadUtterances) 29 | else loadUtterances() 30 | } else { 31 | function loadOtherComment () { 32 | loadUtterances() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /layout/includes/third-party/comments/gitalk.pug: -------------------------------------------------------------------------------- 1 | script. 2 | function addGitalkSource () { 3 | const ele = document.createElement('link') 4 | ele.rel = 'stylesheet' 5 | ele.href= '!{url_for(theme.asset.gitalk_css)}' 6 | document.getElementsByTagName('head')[0].appendChild(ele) 7 | } 8 | 9 | function loadGitalk () { 10 | function initGitalk () { 11 | var gitalk = new Gitalk(Object.assign({ 12 | clientID: '!{theme.gitalk.client_id}', 13 | clientSecret: '!{theme.gitalk.client_secret}', 14 | repo: '!{theme.gitalk.repo}', 15 | owner: '!{theme.gitalk.owner}', 16 | admin: ['!{theme.gitalk.admin}'], 17 | id: '!{md5(page.path)}', 18 | updateCountCallback: commentCount 19 | },!{JSON.stringify(theme.gitalk.option)})) 20 | 21 | gitalk.render('gitalk-container') 22 | } 23 | 24 | if (typeof Gitalk === 'function') initGitalk() 25 | else { 26 | addGitalkSource() 27 | getScript('!{url_for(theme.asset.gitalk)}').then(initGitalk) 28 | } 29 | } 30 | 31 | function commentCount(n){ 32 | let isCommentCount = document.querySelector('#post-meta .gitalk-comment-count') 33 | if (isCommentCount) { 34 | isCommentCount.innerHTML= n 35 | } 36 | } 37 | 38 | if ('!{theme.comments.use[0]}' === 'Gitalk' || !!{theme.comments.lazyload}) { 39 | if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('gitalk-container'), loadGitalk) 40 | else loadGitalk() 41 | } else { 42 | function loadOtherComment () { 43 | loadGitalk() 44 | } 45 | } 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /source/css/_custom/snackbar.css: -------------------------------------------------------------------------------- 1 | /* 消息弹窗 */ 2 | .snackbar-container { 3 | background: var(--heo-main) !important; 4 | color: var(--heo-white) !important; 5 | border-radius: 0 !important; 6 | display: flex; 7 | justify-content: center !important; 8 | max-width: none !important; 9 | min-width: 100% !important; 10 | margin: 0px !important; 11 | left: 0px !important; 12 | height: 60px !important; 13 | transform: none !important; 14 | } 15 | .snackbar-container p { 16 | font-weight: 600 !important; 17 | text-align: center !important; 18 | color: var(--heo-font) !important; 19 | font-size: 18px !important; 20 | display: flex !important; 21 | justify-content: center !important; 22 | } 23 | .snackbar-container .action { 24 | color: var(--heo-white) !important; 25 | padding: 4px 6px !important; 26 | font-weight: bold; 27 | border-radius: 8px !important; 28 | transition: 0.3s; 29 | border: var(--style-border) !important; 30 | } 31 | .snackbar-container .action:hover { 32 | color: var(--heo-main) !important; 33 | background: var(--heo-white) !important; 34 | } 35 | .snackbar-container::after { 36 | position: absolute; 37 | width: 0; 38 | height: 100%; 39 | left: 0; 40 | top: 0; 41 | background: var(--heo-white); 42 | opacity: 0.1; 43 | content: ""; 44 | animation: snackbar-progress 2s linear forwards; 45 | pointer-events: none; 46 | } 47 | @keyframes snackbar-progress { 48 | from { 49 | width: 0; 50 | } 51 | to { 52 | width: 100%; 53 | } 54 | } -------------------------------------------------------------------------------- /layout/includes/footer.pug: -------------------------------------------------------------------------------- 1 | .footer 2 | #in 3 | .title 4 | img(src=url_for(theme.footer.footer_logo.url) style='border-radius:100vh;box-shadow:0 8px 12px -3px #4259ef23') 5 | .author 6 | span.name=config.author 7 | .descr=config.subtitle 8 | if theme.footer.footer_icons.enable 9 | .links 10 | each i in theme.footer.footer_icons.icons 11 | if i.class == "in" 12 | a.deal_link(href=`${i.link}`, title=`${i.desrc}`) 13 | i(class=`${i.icon}` style='font-size:25px') 14 | else if i.class == "out" 15 | a.deal_link(target='_blank', rel='noopener external nofollow', href=`${i.link}`, title=`${i.desrc}`) 16 | i(class=`${i.icon}` style='font-size:25px') 17 | else 18 | a.deal_link(href=`${i.link}`, title=`${i.desrc}`) 19 | i(class=`${i.icon}` style='font-size:25px') 20 | about.about 21 | a.footer-button(href="/about/" style='box-shadow:0 8px 12px -3px #ee7d7936;background:#F04A63;border-radius:100vh;') 22 | i.dys.caozuo-wailian 23 | span 了解更多 24 | a.footer-button(href="/cc/" style='box-shadow:0 8px 12px -3px #87ee7936;background:#57BD6A;border-radius:100vh;') 25 | i.dys.creativecommons 26 | span 转载协议 27 | div.frame 28 | span HEXO 29 | i.dys.heart-beat(style='font-size:20px') 30 | span Dynasty 31 | //- p(style="margin:5px 10px 5px 10px;height:20px") 32 | a.active(href="https://cdnnb.cn") 33 | img(src="https://img.shields.io/badge/本站由失控的防御系统提供加速防御支持-green?style=flat&logo=Claris") -------------------------------------------------------------------------------- /scripts/helpers/get_arrays.js: -------------------------------------------------------------------------------- 1 | hexo.extend.helper.register('getarray_bar', function (types) { 2 | if (!types) { 3 | types = "category" 4 | } 5 | const categoriesBar = function (categories) { 6 | if (!categories || !categories.length) return `` 7 | const categoryArr = [] 8 | hexo.locals.get('categories').map(function (category) { 9 | categoryArr.push({ name: category.name, value: category.length }) 10 | }) 11 | categoryArr.sort((a, b) => { return b.value - a.value }) 12 | let strCategoriesBar = `` 13 | for (let i = 0; i < categories.length; i++) { 14 | strTemp=` 15 |
16 | ${categoryArr[i].name} 17 |
` 18 | strCategoriesBar+=strTemp 19 | } 20 | return strCategoriesBar 21 | } 22 | const tagsBar = function(tags) { 23 | if (!tags || !tags.length) return `` 24 | const tagArr = [] 25 | hexo.locals.get('tags').map(function (tag) { 26 | tagArr.push({ name: tag.name, value: tag.length }) 27 | }) 28 | tagArr.sort((a, b) => { return b.value - a.value }) 29 | let strTagsBar = `` 30 | for (let i = 0; i < tags.length; i++) { 31 | strTemp=` 32 |
33 | ${tagArr[i].name} 34 |
` 35 | strTagsBar+=strTemp 36 | } 37 | return strTagsBar 38 | } 39 | if (types == "category"){ 40 | return categoriesBar(this.site.categories) 41 | } 42 | if (types == "tag"){ 43 | return tagsBar(this.site.tags) 44 | } 45 | }) -------------------------------------------------------------------------------- /scripts/tag/card.js: -------------------------------------------------------------------------------- 1 | /** 2 | * card 3 | * {% card name,url,bg,star,text,icon,tag,w,h %} 4 | * {% card 标题,链接,背景,评分,评价,图标,标签,宽度,高度 %} 5 | */ 6 | 7 | 'use strict' 8 | 9 | // 分数转成星星 10 | function tostar(num) { 11 | let tmp = '' 12 | for (let i = 0; i < Math.floor(num); i++) { tmp += '' } // 整数部分加实心星星 13 | if (num - Math.floor(num) != 0) tmp += '' // 小数部分转成半星 14 | for (let i = 0; i < 5 - Math.ceil(num); i++) { tmp += '' } // 不够5个补空心星星 15 | return tmp 16 | } 17 | 18 | function card(args) { 19 | args = args.join(' ').split(',') 20 | 21 | // 获取参数 22 | let name = (args[0] || '未知').trim() 23 | let url = (args[1] || '').trim() 24 | let bg = (args[2] ? `background-image: url(${args[2]});` : 'background-color: #333;').trim() 25 | let star = tostar(Number(args[3]) || 0) 26 | let text = (args[4] || '此作品博主暂未作出评价').trim() 27 | let icon = (args[5] || '').trim() 28 | let tag = (args[6] || '').trim() 29 | let w = args[7] || '200px' 30 | let h = args[8] || '275px' 31 | 32 | return `
33 |
34 | ${text} 35 | ${url?'查看详情':''} 36 |
37 |
38 | 39 | ${tag} 40 |
41 |
42 | ${name} 43 |
${star}
44 |
45 |
` 46 | } 47 | 48 | hexo.extend.tag.register('card', card, { ends: false }) -------------------------------------------------------------------------------- /layout/includes/third-party/comments/artalk.pug: -------------------------------------------------------------------------------- 1 | - const { server, site, option } = theme.artalk 2 | 3 | script. 4 | function addArtalkSource () { 5 | const ele = document.createElement('link') 6 | ele.rel = 'stylesheet' 7 | ele.href= '!{theme.asset.artalk_css}' 8 | document.getElementsByTagName('head')[0].appendChild(ele) 9 | } 10 | 11 | function loadArtalk () { 12 | function initArtalk () { 13 | window.artalkItem = new Artalk(Object.assign({ 14 | el: '#artalk-wrap', 15 | server: '!{server}', 16 | site: '!{site}', 17 | pageKey: location.pathname, 18 | darkMode: document.documentElement.getAttribute('data-theme') === 'dark', 19 | countEl: '.artalk-count' 20 | },!{JSON.stringify(option)})) 21 | } 22 | 23 | if (typeof window.artalkItem === 'object') setTimeout(()=>{initArtalk()},200) 24 | else { 25 | addArtalkSource() 26 | typeof Artalk !== 'function' ? getScript('!{theme.asset.artalk_js}').then(initArtalk) 27 | : setTimeout(()=>{initArtalk()},200) 28 | } 29 | } 30 | 31 | document.getElementById('darkmode').addEventListener('click',()=> { 32 | if (typeof window.artalkItem !== 'object') return 33 | let isDark = document.documentElement.getAttribute('data-theme') === 'dark' 34 | window.artalkItem.setDarkMode(!isDark) 35 | }) 36 | 37 | 38 | if ('!{theme.comments.use[0]}' === 'Artalk' || !!{theme.comments.lazyload}) { 39 | if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('artalk-wrap'), loadArtalk) 40 | else loadArtalk() 41 | } else { 42 | function loadOtherComment () { 43 | loadArtalk() 44 | } 45 | } -------------------------------------------------------------------------------- /source/css/_layout/comments.styl: -------------------------------------------------------------------------------- 1 | #post-comment 2 | .comment-head 3 | margin-bottom: 20px 4 | 5 | .comment-headline 6 | display: inline-block 7 | vertical-align: middle 8 | font-weight: 700 9 | font-size: 1.43em 10 | 11 | #comment-switch 12 | display: inline-block 13 | 14 | if hexo-config('comments.text') 15 | float: right 16 | margin: 2px auto 0 17 | padding: 4px 16px 18 | width: max-content 19 | border-radius: 8px 20 | background: $comments-switch-bg 21 | else 22 | vertical-align: middle 23 | 24 | > span 25 | display: none 26 | 27 | .first-comment 28 | color: $comments-switch-first-text 29 | 30 | .second-comment 31 | color: $comments-switch-second-text 32 | 33 | .switch-btn 34 | position: relative 35 | display: inline-block 36 | margin: -4px 8px 0 37 | width: 42px 38 | height: 22px 39 | border-radius: 34px 40 | background-color: $comments-switch-first-text 41 | vertical-align: middle 42 | cursor: pointer 43 | transition: .4s 44 | 45 | &:before 46 | position: absolute 47 | bottom: 4px 48 | left: 4px 49 | width: 14px 50 | height: 14px 51 | border-radius: 50% 52 | background-color: $comments-switch-round 53 | content: '' 54 | transition: .4s 55 | 56 | &.move 57 | background-color: $comments-switch-second-text 58 | 59 | &:before 60 | transform: translateX(20px) 61 | 62 | .comment-wrap 63 | > div:nth-child(2) 64 | display: none -------------------------------------------------------------------------------- /layout/includes/third-party/comments/twikoo.pug: -------------------------------------------------------------------------------- 1 | - const { envId, region, option } = theme.twikoo 2 | - const { use, lazyload, count } = theme.comments 3 | 4 | script. 5 | (()=>{ 6 | const init = () => { 7 | twikoo.init(Object.assign({ 8 | el: '#twikoo-wrap', 9 | envId: '!{envId}', 10 | region: '!{region}', 11 | onCommentLoaded: function () { 12 | btf.loadLightbox(document.querySelectorAll('#twikoo .tk-content img:not(.tk-owo-emotion)')) 13 | } 14 | }, !{JSON.stringify(option)})) 15 | } 16 | 17 | const getCount = () => { 18 | const countELement = document.getElementById('twikoo-count') 19 | if(!countELement) return 20 | twikoo.getCommentsCount({ 21 | envId: '!{envId}', 22 | region: '!{region}', 23 | urls: [window.location.pathname], 24 | includeReply: false 25 | }).then(function (res) { 26 | countELement.innerText = res[0].count 27 | }).catch(function (err) { 28 | console.error(err); 29 | }); 30 | } 31 | 32 | const runFn = () => { 33 | init() 34 | !{count ? 'GLOBAL_CONFIG_SITE.isPost && getCount()' : ''} 35 | } 36 | 37 | const loadTwikoo = () => { 38 | if (typeof twikoo === 'object') { 39 | setTimeout(runFn,0) 40 | return 41 | } 42 | getScript('!{url_for(theme.asset.twikoo)}').then(runFn) 43 | } 44 | 45 | if ('!{use[0]}' === 'Twikoo' || !!{lazyload}) { 46 | if (!{lazyload}) btf.loadComment(document.getElementById('twikoo-wrap'), loadTwikoo) 47 | else loadTwikoo() 48 | } else { 49 | window.loadOtherComment = () => { 50 | loadTwikoo() 51 | } 52 | } 53 | })() -------------------------------------------------------------------------------- /source/css/_search/local-search.styl: -------------------------------------------------------------------------------- 1 | #local-search 2 | .search-dialog 3 | .local-search-box 4 | margin: 0 auto 5 | max-width: 100% 6 | width: 100% 7 | 8 | input 9 | padding: 15px 10 | width: 100% 11 | outline: none 12 | border: 1px solid var(--search-border-color) 13 | border-radius: 100vh 14 | background: transparent 15 | font-size: 27px 16 | text-align: center 17 | font-weight: 600 18 | color: var(--search-input-color) 19 | -webkit-appearance: none 20 | 21 | .search-wrap 22 | display: none 23 | 24 | .local-search__hit-item 25 | position: relative 26 | padding: 15px 27 | line-height: 1.7 28 | 29 | a 30 | display: block 31 | font-weight: 800 32 | cursor: pointer 33 | font-size: 20px 34 | color: var(--search-border-color) 35 | 36 | .search-result 37 | margin: 0 8px 8px 0 38 | word-break: break-all 39 | font-size: 17px !important 40 | 41 | .search-keyword 42 | color: $search-keyword-highlight 43 | font-weight: bold 44 | 45 | .search-result-list 46 | overflow-y: auto 47 | max-height: calc(80vh - 130px) 48 | 49 | +maxWidth768() 50 | padding-bottom: 40px 51 | max-height: 75vh !important 52 | 53 | .local-search__hit-item 54 | height: 90px 55 | text-align: center 56 | overflow: hidden 57 | transition: all .5s 58 | border-bottom: 1px dashed var(--search-border-color) 59 | 60 | &:hover 61 | background: var(--search-border-color) 62 | color: var(--global-bg) 63 | 64 | a 65 | color: var(--global-bg) !important -------------------------------------------------------------------------------- /source/css/_tags/card.styl: -------------------------------------------------------------------------------- 1 | .card_box 2 | display: flex 3 | justify-content: space-between 4 | flex-direction: column 5 | background-position: center 6 | background-size: cover 7 | border-radius: 12px 8 | position: relative 9 | overflow: hidden 10 | padding: 10px 11 | color: #fff !important 12 | margin: 10px auto 13 | &::after 14 | content: '' 15 | position: absolute 16 | height: 100% 17 | width: 100% 18 | left: 0 19 | top: 0 20 | background: rgba(0,0,0,0.1) 21 | transition: .5s 22 | z-index: 0 23 | &:hover 24 | .card_mask 25 | opacity: 1 26 | pointer-events: auto 27 | .card_top 28 | display: flex 29 | z-index: 1 30 | align-items: center 31 | justify-content: space-between 32 | .card_mask 33 | position: absolute 34 | pointer-events: none 35 | z-index: 2 36 | transition: .5s 37 | opacity: 0 38 | width: 100% 39 | height: 100% 40 | left: 0 41 | top: 0 42 | padding: 20px 43 | background: #333 44 | span 45 | display: block 46 | height: calc(100% - 40px) 47 | overflow: auto 48 | a 49 | text-align: center 50 | background: #fff 51 | color: #333 !important 52 | border-radius: 5px 53 | position: absolute 54 | width: calc(100% - 40px) 55 | bottom: 20px 56 | left: 20px 57 | &:hover 58 | text-decoration: none !important 59 | color: white !important 60 | background: #71e5ff 61 | 62 | .card_content 63 | z-index: 1 64 | span 65 | font-size: 18px 66 | font-weight: bold 67 | 68 | [data-theme='dark'] 69 | .card_box 70 | color: #ddd !important 71 | &::after 72 | background: rgba(0,0,0,0.4) -------------------------------------------------------------------------------- /source/css/_highlight/highlight/diff.styl: -------------------------------------------------------------------------------- 1 | figure.highlight 2 | table 3 | scrollbar-color: var(--hlscrollbar-bg) transparent 4 | 5 | &::-webkit-scrollbar-thumb 6 | background: var(--hlscrollbar-bg) 7 | 8 | pre .deletion 9 | color: $highlight-deletion 10 | 11 | pre .addition 12 | color: $highlight-addition 13 | 14 | pre .meta 15 | color: $highlight-purple 16 | 17 | pre 18 | .comment 19 | color: $highlight-comment 20 | 21 | .variable, 22 | .attribute, 23 | .regexp, 24 | .ruby .constant, 25 | .xml .tag .title, 26 | .xml .pi, 27 | .xml .doctype, 28 | .html .doctype, 29 | .css .id, 30 | .tag .name, 31 | .css .class, 32 | .css .pseudo 33 | color: $highlight-red 34 | 35 | .tag 36 | color: $highlight-aqua 37 | 38 | .number, 39 | .preprocessor, 40 | .literal, 41 | .params, 42 | .constant, 43 | .command 44 | color: $highlight-orange 45 | 46 | .built_in 47 | color: $highlight-yellow 48 | 49 | .ruby .class .title, 50 | .css .rules .attribute, 51 | .string, 52 | .value, 53 | .inheritance, 54 | .header, 55 | .ruby .symbol, 56 | .xml .cdata, 57 | .special, 58 | .number, 59 | .formula 60 | color: $highlight-green 61 | 62 | .keyword, 63 | .title, 64 | .css .hexcolor 65 | color: $highlight-aqua 66 | 67 | .function, 68 | .python .decorator, 69 | .python .title, 70 | .ruby .function .title, 71 | .ruby .title .keyword, 72 | .perl .sub, 73 | .javascript .title, 74 | .coffeescript .title 75 | color: $highlight-blue 76 | 77 | .tag .attr, 78 | .javascript .function 79 | color: $highlight-purple 80 | -------------------------------------------------------------------------------- /layout/includes/header/nav.pug: -------------------------------------------------------------------------------- 1 | - const { darkmode } = theme 2 | 3 | nav#nav 4 | #navbar 5 | if theme.nav.title.type === text 6 | span#blog_name 7 | a#site-name(href=url_for('/')) 8 | .title #[=theme.nav.title.title] 9 | i.dys.home 10 | else 11 | span#blog_name(style="margin-left:-5px;height:30px;width:30px") 12 | a#site-name(href=url_for('/')) 13 | img(src=url_for(theme.nav.title.title) style="width:30px;height:30px;border-radius:100vh;") 14 | 15 | .nav-menus#nav-menus 16 | #toggle-menu(style='margin:0 10px 0 5px;') 17 | a.site-page(style='display:flex; align-items:center; height:35px;') 18 | i.dys.apps(style='font-size: 25px;') 19 | | 菜单 20 | 21 | !=partial('includes/header/menu_item', {}, {cache: true}) 22 | 23 | .notebar#notebar 24 | 25 | a.link(href="https://travellings.cn/go.html" style='margin-right:10px') 26 | i.dys.tower(style='font-size: 22px;') 27 | 28 | if (theme.algolia_search.enable || theme.local_search.enable) 29 | div.nav-button#search-button 30 | a.site-page.social-icon.search 31 | .search-button-text 32 | i.dys.searchico(style='font-size:25px') 33 | //- span 搜索 34 | else 35 | div.nav-button 36 | a.site-page.social-icon.search 37 | .search-button-text 38 | i.dys.searchico(style='font-size:25px') 39 | span 未开启 40 | //- div.nav-button 41 | a.link(onclick='showconsolebtn()') 42 | i.dys.apps(style='font-size: 26px;') 43 | 44 | #buttons.conbtn(onclick='btf.scrollToDest(0,500)') 45 | a.link 46 | i.dys.arrowup(style='font-size: 26px;') 47 | span#percent 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /layout/includes/third-party/math/mathjax.pug: -------------------------------------------------------------------------------- 1 | //- Mathjax 3 2 | script. 3 | if (!window.MathJax) { 4 | window.MathJax = { 5 | tex: { 6 | inlineMath: [ ['$','$'], ["\\(","\\)"]], 7 | tags: 'ams' 8 | }, 9 | chtml: { 10 | scale: 1.1 11 | }, 12 | options: { 13 | renderActions: { 14 | findScript: [10, doc => { 15 | for (const node of document.querySelectorAll('script[type^="math/tex"]')) { 16 | const display = !!node.type.match(/; *mode=display/) 17 | const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display) 18 | const text = document.createTextNode('') 19 | node.parentNode.replaceChild(text, node) 20 | math.start = {node: text, delim: '', n: 0} 21 | math.end = {node: text, delim: '', n: 0} 22 | doc.math.push(math) 23 | } 24 | }, ''], 25 | insertScript: [200, () => { 26 | document.querySelectorAll('mjx-container').forEach(node => { 27 | if (node.hasAttribute('display')) { 28 | btf.wrap(node, 'div', { class: 'mathjax-overflow' }) 29 | } else { 30 | btf.wrap(node, 'span', { class: 'mathjax-overflow' }) 31 | } 32 | }); 33 | }, '', false] 34 | } 35 | } 36 | } 37 | 38 | const script = document.createElement('script') 39 | script.src = '!{url_for(theme.asset.mathjax)}' 40 | script.id = 'MathJax-script' 41 | script.async = true 42 | document.head.appendChild(script) 43 | } else { 44 | MathJax.startup.document.state(0) 45 | MathJax.texReset() 46 | MathJax.typeset() 47 | } -------------------------------------------------------------------------------- /source/css/_layout/reward.styl: -------------------------------------------------------------------------------- 1 | .post-reward 2 | position: relative 3 | margin-top: 80px 4 | width: 100% 5 | text-align: center 6 | pointer-events: none 7 | 8 | & > * 9 | pointer-events: auto 10 | 11 | .reward-button 12 | display: inline-block 13 | padding: 4px 24px 14 | background: var(--btn-bg) 15 | color: var(--btn-color) 16 | cursor: pointer 17 | 18 | &:hover 19 | .reward-button 20 | background: var(--btn-hover-color) 21 | 22 | & > .reward-main 23 | display: block 24 | 25 | .reward-main 26 | position: absolute 27 | bottom: 40px 28 | left: 0 29 | z-index: 100 30 | display: none 31 | padding: 0 0 15px 32 | width: 100% 33 | 34 | .reward-all 35 | display: inline-block 36 | margin: 0 37 | padding: 20px 10px 38 | border-radius: 4px 39 | background: var(--reward-pop) 40 | 41 | &:before 42 | position: absolute 43 | bottom: -10px 44 | left: 0 45 | width: 100% 46 | height: 20px 47 | content: '' 48 | 49 | &:after 50 | position: absolute 51 | right: 0 52 | bottom: 2px 53 | left: 0 54 | margin: 0 auto 55 | width: 0 56 | height: 0 57 | border-top: 13px solid var(--reward-pop) 58 | border-right: 13px solid transparent 59 | border-left: 13px solid transparent 60 | content: '' 61 | 62 | .reward-item 63 | display: inline-block 64 | padding: 0 8px 65 | list-style-type: none 66 | vertical-align: top 67 | 68 | img 69 | width: 130px 70 | height: 130px 71 | 72 | .post-qr-code-desc 73 | width: 130px 74 | color: $reward-pop-up-color 75 | -------------------------------------------------------------------------------- /source/css/_page/404.styl: -------------------------------------------------------------------------------- 1 | if hexo-config('error_404.enable') 2 | .error404 3 | #error-wrap 4 | position: absolute 5 | top: 50% 6 | right: 0 7 | left: 0 8 | margin: 0 auto 9 | padding: 60px 20px 0 10 | max-width: 1000px 11 | transform: translate(0, -50%) 12 | 13 | .error-content 14 | @extend .cardHover 15 | overflow: hidden 16 | margin: 0 20px 17 | height: 360px 18 | 19 | +maxWidth768() 20 | margin: 0 21 | height: 500px 22 | 23 | .error-img 24 | display: inline-block 25 | overflow: hidden 26 | width: 50% 27 | height: 100% 28 | 29 | +maxWidth768() 30 | width: 100% 31 | height: 45% 32 | 33 | img 34 | @extend .imgHover 35 | background-color: $theme-color 36 | 37 | .error-info 38 | display: inline-flex 39 | flex-direction: column 40 | justify-content: center 41 | align-content: center 42 | width: 50% 43 | height: 100% 44 | vertical-align: top 45 | text-align: center 46 | 47 | if $site-name-font 48 | font-family: $site-name-font 49 | 50 | +maxWidth768() 51 | width: 100% 52 | height: 55% 53 | 54 | .error_title 55 | margin-top: -.6em 56 | font-size: 9em 57 | 58 | +maxWidth768() 59 | font-size: 8em 60 | 61 | .error_subtitle 62 | @extend .limit-more-line 63 | margin-top: -3em 64 | word-break: break-word 65 | font-size: 1.6em 66 | -webkit-line-clamp: 2 67 | 68 | & + #rightside 69 | display: none -------------------------------------------------------------------------------- /source/css/_layout/sidebar.styl: -------------------------------------------------------------------------------- 1 | #sidebar 2 | #menu-mask 3 | position: fixed 4 | z-index: 102 5 | display: none 6 | width: 100% 7 | height: 100% 8 | background: #ffffff7a 9 | backdrop-filter: blur(20px) saturate(180%) 10 | -webkit-backdrop-filter: blur(20px) saturate(180%) 11 | 12 | #sidebar-menus 13 | position: fixed 14 | top: 0 15 | right: -($sidebar-width) 16 | z-index: 100000 17 | border: 1.5px solid #e3e8f7 18 | border-radius: 20px 0 0 20px 19 | overflow-x: hidden 20 | overflow-y: auto 21 | width: $sidebar-width 22 | height: 100% 23 | background: var(--sidebar-bg) 24 | transition: all .5s 25 | 26 | &.open 27 | transform: translate3d(-100%, 0, 0) 28 | 29 | & > .avatar-img 30 | margin: 20px auto 31 | 32 | .sidebar-site-data 33 | padding: 0 10px 34 | 35 | hr 36 | margin: 20px auto 37 | 38 | .menus_items 39 | padding: 0 10px 40px 40 | 41 | .site-page 42 | @extend .limit-one-line 43 | position: relative 44 | display: block 45 | padding: 6px 30px 6px 22px 46 | color: var(--font-color) 47 | font-size: 1.15em 48 | 49 | &:hover 50 | background: var(--text-bg-hover) 51 | 52 | i:first-child 53 | font-size: 20px 54 | text-align: left 55 | 56 | &.group 57 | & > i:last-child 58 | position: absolute 59 | top: .78em 60 | right: 18px 61 | transition: transform .3s 62 | 63 | &.hide 64 | & > i:last-child 65 | transform: rotate(90deg) 66 | 67 | & + .menus_item_child 68 | display: none 69 | 70 | .menus_item_child 71 | margin: 0 72 | list-style: none -------------------------------------------------------------------------------- /layout/includes/third-party/comments/disqus.pug: -------------------------------------------------------------------------------- 1 | - let disqusPageTitle = page.title.replace(/'/ig,"\\'") 2 | 3 | script. 4 | function loadDisqus () { 5 | var disqus_config = function () { 6 | this.page.url = '!{ page.permalink }' 7 | this.page.identifier = '!{ url_for(page.path) }' 8 | this.page.title = '!{ disqusPageTitle }' 9 | }; 10 | 11 | window.disqusReset = () => { 12 | DISQUS.reset({ 13 | reload: true, 14 | config: disqus_config 15 | }) 16 | } 17 | 18 | if (window.DISQUS) disqusReset() 19 | else { 20 | (function() { 21 | var d = document, s = d.createElement('script'); 22 | s.src = 'https://!{theme.disqus.shortname}.disqus.com/embed.js'; 23 | s.setAttribute('data-timestamp', +new Date()); 24 | (d.head || d.body).appendChild(s); 25 | })(); 26 | } 27 | 28 | document.getElementById('darkmode').addEventListener('click', () => { 29 | setTimeout(() => window.disqusReset(), 200) 30 | }) 31 | } 32 | 33 | if ('!{theme.comments.use[0]}' === 'Disqus' || !!{theme.comments.lazyload}) { 34 | if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('disqus_thread'), loadDisqus) 35 | else loadDisqus() 36 | } else { 37 | function loadOtherComment () { 38 | loadDisqus() 39 | } 40 | } 41 | 42 | if is_post() && !theme.comments.lazyload && theme.comments.count && theme.comments.use[0] === 'Disqus' 43 | script. 44 | if (window.DISQUSWIDGETS === undefined) { 45 | var d = document, s = d.createElement('script'); 46 | s.src = 'https://!{theme.disqus.shortname}.disqus.com/count.js'; 47 | s.id = 'dsq-count-scr'; 48 | (d.head || d.body).appendChild(s); 49 | } else { 50 | DISQUSWIDGETS.getCount({reset: true}); 51 | } 52 | -------------------------------------------------------------------------------- /layout/includes/third-party/comments/facebook_comments.pug: -------------------------------------------------------------------------------- 1 | - const fbSDKVer = 'v15.0' 2 | - 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}` 3 | 4 | script. 5 | function loadFBComment () { 6 | document.getElementById('fb-root') ? '' : document.body.insertAdjacentHTML('afterend', '
') 7 | 8 | const themeNow = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' 9 | const $fbComment = document.getElementsByClassName('fb-comments')[0] 10 | $fbComment.setAttribute('data-colorscheme',themeNow) 11 | $fbComment.setAttribute('data-href', '!{urlNoIndex(page.permalink)}') 12 | 13 | if (typeof FB === 'object') { 14 | FB.XFBML.parse(document.getElementsByClassName('post-meta-commentcount')[0]) 15 | FB.XFBML.parse(document.getElementById('post-comment')) 16 | } 17 | else { 18 | let ele = document.createElement('script') 19 | ele.setAttribute('src','!{fbSDK}') 20 | ele.setAttribute('async', 'true') 21 | ele.setAttribute('defer', 'true') 22 | ele.setAttribute('crossorigin', 'anonymous') 23 | ele.setAttribute('id', 'facebook-jssdk') 24 | document.getElementById('fb-root').insertAdjacentElement('afterbegin',ele) 25 | } 26 | } 27 | 28 | if ('!{theme.comments.use[0]}' === 'Facebook Comments' || !!{theme.comments.lazyload}) { 29 | if (!{theme.comments.lazyload}) btf.loadComment(document.querySelector('#post-comment .fb-comments'), loadFBComment) 30 | else loadFBComment() 31 | } else { 32 | function loadOtherComment () { 33 | loadFBComment() 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /layout/includes/third-party/comments/giscus.pug: -------------------------------------------------------------------------------- 1 | - const { repo, repo_id, category_id, option } = theme.giscus 2 | - const themes = theme.giscus.theme 3 | script. 4 | function loadGiscus () { 5 | let nowTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{themes.dark}' : '!{themes.light}' 6 | 7 | const config = Object.assign({ 8 | src: 'https://giscus.app/client.js', 9 | 'data-repo': '!{repo}', 10 | 'data-repo-id': '!{repo_id}', 11 | 'data-category-id': '!{category_id}', 12 | 'data-mapping': 'pathname', 13 | 'data-theme': nowTheme, 14 | 'data-reactions-enabled': '1', 15 | crossorigin: 'anonymous', 16 | async: true 17 | },!{JSON.stringify(option)}) 18 | 19 | let ele = document.createElement('script') 20 | for (let key in config) { 21 | ele.setAttribute(key, config[key]) 22 | } 23 | document.getElementById('giscus-wrap').insertAdjacentElement('afterbegin',ele) 24 | } 25 | 26 | function changeGiscusTheme () { 27 | const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{themes.dark}' : '!{themes.light}' 28 | 29 | function sendMessage(message) { 30 | const iframe = document.querySelector('iframe.giscus-frame'); 31 | if (!iframe) return; 32 | iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app'); 33 | } 34 | 35 | sendMessage({ 36 | setConfig: { 37 | theme: theme 38 | } 39 | }); 40 | } 41 | 42 | if ('!{theme.comments.use[0]}' === 'Giscus' || !!{theme.comments.lazyload}) { 43 | if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('giscus-wrap'), loadGiscus) 44 | else loadGiscus() 45 | } else { 46 | function loadOtherComment () { 47 | loadGiscus() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /scripts/tag/msgbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | {% msgbox %} 3 | {% msgguest name,avatar %} 4 | 对话内容 5 | {% endmsgguest %} 6 | {% msgadmin name,avatar %} 7 | 对话内容 8 | {% endmsgadmin %} 9 | {% endmsgbox %} 10 | */ 11 | 12 | 'use strict' 13 | 14 | const urlFor = require('hexo-util').url_for.bind(hexo) 15 | 16 | function msgbox (args, content) { 17 | return `
${hexo.render.renderSync({ text: content, engine: 'markdown' }).split('\n').join('')} 18 |
` 19 | } 20 | 21 | function msgguest (args, content) { 22 | args = args.join(' ').split(',') 23 | let guestname = args[0]?args[0].trim():'noname' //默认无名 24 | let guestavatar = args[1]?args[1].trim():hexo.theme.config.error_img.flink //默认友链错误头像 25 | 26 | return `
${guestname}
${hexo.render.renderSync({ text: content, engine: 'markdown' }).split('\n').join('')}
` 27 | } 28 | function msgadmin (args, content) { 29 | args = args.join(' ').split(',') 30 | let adminname = args[0]?args[0].trim():hexo.config.author //默认作者 31 | let adminavatar = args[1]?args[1].trim():hexo.theme.config.avatar.img //默认作者头像 32 | 33 | return `
${adminname}
${hexo.render.renderSync({ text: content, engine: 'markdown' }).split('\n').join('')}
` 34 | } 35 | 36 | 37 | hexo.extend.tag.register('msgbox', msgbox, { ends: true }) 38 | hexo.extend.tag.register('msgguest', msgguest, { ends: true }) 39 | hexo.extend.tag.register('msgadmin', msgadmin, { ends: true }) -------------------------------------------------------------------------------- /source/js/scroll.js: -------------------------------------------------------------------------------- 1 | PostActive() 2 | topPostScroll() 3 | 4 | //分类条 5 | function PostActive(){ 6 | var urlinfo = window.location.pathname; 7 | urlinfo = decodeURIComponent(urlinfo) 8 | console.log(urlinfo); 9 | } 10 | 11 | //鼠标控制横向滚动 12 | function topPostScroll(){ 13 | if (document.getElementById("recent-post-top")){ 14 | let xscroll = document.getElementById("recent-post-top"); 15 | xscroll.addEventListener("mousewheel", function (e) { 16 | //计算鼠标滚轮滚动的距离 17 | let v = -e.wheelDelta / 2; 18 | xscroll.scrollLeft += v; 19 | //阻止浏览器默认方法 20 | e.preventDefault(); 21 | }, false); 22 | } 23 | } 24 | 25 | tagBarActive() 26 | toptagBarScroll() 27 | 28 | //分类条 29 | function tagBarActive(){ 30 | var urlinfo = window.location.pathname; 31 | urlinfo = decodeURIComponent(urlinfo) 32 | console.log(urlinfo); 33 | } 34 | 35 | //鼠标控制横向滚动 36 | function toptagBarScroll(){ 37 | if (document.getElementById("tag-bar-items")){ 38 | let xscroll = document.getElementById("tag-bar-items"); 39 | xscroll.addEventListener("mousewheel", function (e) { 40 | //计算鼠标滚轮滚动的距离 41 | let v = -e.wheelDelta / 2; 42 | xscroll.scrollLeft += v; 43 | //阻止浏览器默认方法 44 | e.preventDefault(); 45 | }, false); 46 | } 47 | } 48 | 49 | categoryBarActive() 50 | topcategoryBarScroll() 51 | 52 | //分类条 53 | function categoryBarActive(){ 54 | var urlinfo = window.location.pathname; 55 | urlinfo = decodeURIComponent(urlinfo) 56 | console.log(urlinfo); 57 | } 58 | 59 | //鼠标控制横向滚动 60 | function topcategoryBarScroll(){ 61 | if (document.getElementById("category-bar-items")){ 62 | let xscroll = document.getElementById("category-bar-items"); 63 | xscroll.addEventListener("mousewheel", function (e) { 64 | //计算鼠标滚轮滚动的距离 65 | let v = -e.wheelDelta / 2; 66 | xscroll.scrollLeft += v; 67 | //阻止浏览器默认方法 68 | e.preventDefault(); 69 | }, false); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /source/css/_layout/pagination.styl: -------------------------------------------------------------------------------- 1 | #pagination 2 | .pagination 3 | margin-top: 20px 4 | text-align: center 5 | 6 | .page-number 7 | box-shadow: none !important 8 | border: 1px solid #e3e8f7 9 | &.current 10 | background: var(--heo-theme) right 11 | color: var(--heo-font) 12 | 13 | .pagination-info 14 | position: absolute 15 | top: 50% 16 | padding: 20px 40px 17 | width: 100% 18 | transform: translate(0, -50%) 19 | 20 | .prev_info, 21 | .next_info 22 | @extend .limit-one-line 23 | color: var(--white) 24 | font-weight: 500 25 | 26 | .next-post 27 | .pagination-info 28 | text-align: right 29 | 30 | .pull-full 31 | width: 100% !important 32 | 33 | .prev-post .label, 34 | .next-post .label 35 | color: var(--light-grey) 36 | text-transform: uppercase 37 | font-size: 90% 38 | 39 | .prev-post, 40 | .next-post 41 | @extend .postImgHover 42 | width: 50% 43 | 44 | +maxWidth768() 45 | width: 100% 46 | 47 | a 48 | position: relative 49 | display: block 50 | overflow: hidden 51 | height: 150px 52 | 53 | .layout 54 | & > .recent-posts 55 | .pagination 56 | & > * 57 | display: inline-block 58 | margin: 0 6px 59 | width: w = 2.5em 60 | height: w 61 | line-height: w 62 | 63 | & > *:not(.space) 64 | @extend .cardHover 65 | 66 | &:hover 67 | background: var(--btn-hover-color) 68 | color: var(--btn-color) 69 | 70 | & > div:not(.recent-posts) 71 | .pagination 72 | .page-number 73 | display: inline-block 74 | margin: 0 4px 75 | min-width: w = 24px 76 | height: w 77 | text-align: center 78 | line-height: w 79 | cursor: pointer 80 | 81 | .extend 82 | &.prev, &.next 83 | box-shadow: none !important 84 | border: 1px solid #e3e8f7 -------------------------------------------------------------------------------- /layout/includes/header/index.pug: -------------------------------------------------------------------------------- 1 | if !theme.disable_top_img && page.top_img !== false 2 | if is_post() 3 | - var top_img = page.top_img || page.cover || page.randomcover 4 | else if is_page() 5 | - var top_img = false 6 | else if is_tag() 7 | - var top_img = false 8 | else if is_category() 9 | - var top_img = false 10 | else if is_home() 11 | - var top_img = false 12 | else if is_archive() 13 | - var top_img = false 14 | else 15 | - var top_img = page.top_img || theme.default_top_img 16 | 17 | if top_img !== false 18 | - var imgSource = top_img && top_img.indexOf('/') !== -1 ? `background-image: url('${url_for(top_img)}')` : `background: ${top_img}` 19 | - var bg_img = top_img ? imgSource : '' 20 | - var site_title = page.title || page.tag || page.category || config.title 21 | - var isHomeClass = is_home() ? 'full_page nav-fixed nav-visible' : 'not-home-page' 22 | - is_post() ? isHomeClass = 'post-bg' : isHomeClass 23 | else 24 | - var isHomeClass = 'not-top-img' 25 | else 26 | - var top_img = false 27 | - var isHomeClass = 'not-top-img' 28 | 29 | header#page-header(class=isHomeClass style=bg_img) 30 | !=partial('includes/header/nav', {}, {cache: true}) 31 | if is_post() 32 | include ./post-info.pug 33 | section.main-hero-waves-area.waves-area 34 | 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') 35 | defs 36 | 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') 37 | g.parallax 38 | use(href='#gentle-wave', x='48', y='0') 39 | use(href='#gentle-wave', x='48', y='3') 40 | use(href='#gentle-wave', x='48', y='5') 41 | use(href='#gentle-wave', x='48', y='7') 42 | else if is_home() 43 | else 44 | #page-site-info 45 | h1#site-title=site_title -------------------------------------------------------------------------------- /source/css/_tags/tabs.styl: -------------------------------------------------------------------------------- 1 | 2 | #article-container 3 | .tabs 4 | position: relative 5 | margin: 0 0 20px 6 | border-right: 1px solid var(--tab-border-color) 7 | border-bottom: 1px solid var(--tab-border-color) 8 | border-left: 1px solid var(--tab-border-color) 9 | 10 | > .nav-tabs 11 | display: flex 12 | flex-wrap: wrap 13 | margin: 0 14 | padding: 0 15 | background: var(--tab-botton-bg) 16 | 17 | > .tab 18 | margin: 0 19 | padding: 0 20 | list-style: none 21 | 22 | +maxWidth768() 23 | flex-grow: 1 24 | 25 | button 26 | display: block 27 | padding: 8px 18px 28 | width: 100% 29 | border-top: 2px solid var(--tab-border-color) 30 | background: var(--tab-botton-bg) 31 | color: var(--tab-botton-color) 32 | line-height: 2 33 | transition: all .4s 34 | 35 | i 36 | width: 1.5em 37 | 38 | &.active 39 | button 40 | border-top: 2px solid $tab-active-border-color 41 | background: var(--tab-button-active-bg) 42 | cursor: default 43 | 44 | &:not(.active) 45 | button 46 | &:hover 47 | border-top: 2px solid var(--tab-button-hover-bg) 48 | background: var(--tab-button-hover-bg) 49 | 50 | > .tab-contents 51 | .tab-item-content 52 | position: relative 53 | display: none 54 | padding: 36px 24px 55 | 56 | +maxWidth768() 57 | padding: 24px 14px 58 | 59 | &.active 60 | display: block 61 | animation: tabshow .5s 62 | 63 | .tab-to-top 64 | position: relative 65 | display: block 66 | margin: 0 0 0 auto 67 | color: $tab-to-top-color 68 | 69 | @keyframes tabshow 70 | 0% 71 | transform: translateY(15px) 72 | 73 | 100% 74 | transform: translateY(0) 75 | -------------------------------------------------------------------------------- /scripts/tag/media.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function postAudio(args) { 4 | const src = args[0].trim(); 5 | return `
`; 6 | } 7 | 8 | function postVideo(args) { 9 | const {config} = hexo; 10 | const src = args[0].trim(); 11 | // m3u8 https://github.com/volantis-x/hexo-theme-volantis/issues/606 12 | // 文件扩展名为 .m3u8 13 | if (hexo.getType(src) === "m3u8") { 14 | let video_id = `video-${hexo.createUuid()}` 15 | return `
16 | `; 28 | } 29 | return `
`; 30 | } 31 | 32 | function postVideos(args, content) { 33 | if(/::/g.test(args)){ 34 | args = args.join(' ').split('::'); 35 | } 36 | else{ 37 | args = args.join(' ').split(','); 38 | } 39 | var cls = args[0]; 40 | if (cls.length > 0) { 41 | cls = ' ' + cls; 42 | } 43 | var col = Number(args[1]) || 0; 44 | if (col > 0) { 45 | return `
${content}
`; 46 | } 47 | return `
${content}
`; 48 | 49 | } 50 | 51 | hexo.extend.tag.register('audio', postAudio); 52 | hexo.extend.tag.register('video', postVideo); 53 | hexo.extend.tag.register('videos', postVideos, {ends: true}); 54 | -------------------------------------------------------------------------------- /source/css/post-double-row.css: -------------------------------------------------------------------------------- 1 | #recent-posts{ 2 | align-content:flex-start; 3 | display: flex; 4 | flex-wrap: wrap; /*规定灵活的项目在必要的时候拆行或拆列。*/ 5 | justify-content: space-between; /*。*/ 6 | } 7 | #recent-posts > .recent-post-item { 8 | /*max-height:324px;*/ /*文章容器最大高度*/ 9 | margin-top: 1rem; /*最小间距*/ 10 | display: inline-block; 11 | height:auto; /*高度自动*/ 12 | width:49%;/*文章容器容器宽度*/ 13 | } 14 | #recent-posts > .recent-post-item .post_cover { 15 | width: 100%; /*图片封面宽度*/ 16 | height: 200px;/*图片封面高度*/ 17 | } 18 | #recent-posts > .recent-post-item .post_cover img.post_bg { 19 | width: 100%;/*图片宽度*/ 20 | height: 100%;/*图片高度*/ 21 | } 22 | 23 | 24 | #recent-posts > .recent-post-item >.recent-post-info > .content { 25 | display:none;/*隐藏文章详情*/ 26 | } 27 | #recent-posts > .recent-post-item { 28 | 29 | -webkit-flex-direction: column; /*容器内部纵向排列*/ 30 | -ms-flex-direction: column; /*容器内部纵向排列*/ 31 | flex-direction: column; /*容器内部纵向排列*/ 32 | 33 | } 34 | #recent-posts > .recent-post-item .left_radius { 35 | border-radius: 8px 8px 0 0;/*圆角修改*/ 36 | } 37 | #recent-posts > .recent-post-item .right_radius { 38 | border-radius: 8px 8px 0 0;/*圆角修改*/ 39 | } 40 | .recent-post-item{ 41 | height:auto !important;/*容器高度自动*/ 42 | } 43 | 44 | .recent-post-info { 45 | 46 | padding: 0 40px;/*容器内部文字左右间距*/ 47 | margin-top: 1em;/*容器内部文字上间距*/ 48 | width: 100%!important;/*容器宽度*/ 49 | } 50 | #recent-posts > .recent-post-item > .recent-post-info > .article-title { 51 | -webkit-line-clamp: 1;/*控制标题的行数*/ 52 | margin-top: 0.3rem; /*控制标题的上间距*/ 53 | margin-bottom: 0.3rem;/*控制标题的下间距*/ 54 | color: var(--text-highlight-color); 55 | font-size: 1.2em; /*控制标题的字体大小*/ 56 | line-height: 1.4;/*控制标题的行高*/ 57 | 58 | } 59 | #recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap { 60 | margin-bottom: 1rem;/*控制标题meta信息的底部间距*/ 61 | } 62 | @media screen and (max-width: 768px) { 63 | #recent-posts > .recent-post-item { 64 | width:100%;/*控制手机自适应*/ 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /source/css/_custom/animations.css: -------------------------------------------------------------------------------- 1 | /* 波浪css */ 2 | .main-hero-waves-area { 3 | width: 100%; 4 | left: 0; 5 | position: relative; 6 | bottom: -11px; 7 | top: 12px; 8 | z-index: 0; 9 | } 10 | .waves-area .waves-svg { 11 | width: 100%; 12 | height: 5rem; 13 | } 14 | /* Animation */ 15 | 16 | .parallax > use { 17 | animation: move-forever 25s cubic-bezier(0.55, 0.5, 0.45, 0.5) infinite; 18 | } 19 | .parallax > use:nth-child(1) { 20 | animation-delay: -2s; 21 | animation-duration: 7s; 22 | fill: #f7f9febd; 23 | } 24 | .parallax > use:nth-child(2) { 25 | animation-delay: -3s; 26 | animation-duration: 10s; 27 | fill: #f7f9fe82; 28 | } 29 | .parallax > use:nth-child(3) { 30 | animation-delay: -4s; 31 | animation-duration: 13s; 32 | fill: #f7f9fe36; 33 | } 34 | .parallax > use:nth-child(4) { 35 | animation-delay: -5s; 36 | animation-duration: 20s; 37 | fill: #f7f9fe; 38 | } 39 | /* 黑色模式背景 */ 40 | [data-theme="dark"] .parallax > use:nth-child(1) { 41 | animation-delay: -2s; 42 | animation-duration: 7s; 43 | fill: #18171dc8; 44 | } 45 | [data-theme="dark"] .parallax > use:nth-child(2) { 46 | animation-delay: -3s; 47 | animation-duration: 10s; 48 | fill: #18171d80; 49 | } 50 | [data-theme="dark"] .parallax > use:nth-child(3) { 51 | animation-delay: -4s; 52 | animation-duration: 13s; 53 | fill: #18171d3e; 54 | } 55 | [data-theme="dark"] .parallax > use:nth-child(4) { 56 | animation-delay: -5s; 57 | animation-duration: 20s; 58 | fill: #18171d; 59 | } 60 | 61 | @keyframes move-forever { 62 | 0% { 63 | transform: translate3d(-90px, 0, 0); 64 | } 65 | 100% { 66 | transform: translate3d(85px, 0, 0); 67 | } 68 | } 69 | 70 | .post-bg .main-hero-waves-area { 71 | top: 470px !important; 72 | } 73 | 74 | /* 旋转动画-class-spin */ 75 | @keyframes rotate { 76 | 0% { 77 | transform: rotate(0deg); 78 | } 79 | 100% { 80 | transform: rotate(1turn); 81 | } 82 | } 83 | 84 | .spin { 85 | display: block; 86 | animation: rotate 2s linear infinite; 87 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: Create a report to help us improve 3 | title: '[Bug]: ' 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | 重要:請依照該模板來提交 10 | Please follow the template to create a new issue 11 | - type: input 12 | id: butterfly-ver 13 | attributes: 14 | label: 使用的 Butterfly 版本? | What version of Butterfly are you use? 15 | description: 檢視主題的 package.json | Check the theme's package.json 16 | validations: 17 | required: true 18 | 19 | - type: dropdown 20 | id: modify 21 | attributes: 22 | label: 是否修改过主题文件? || Has the theme files been modified? 23 | options: 24 | - 是 (Yes) 25 | - 不是 (No) 26 | validations: 27 | required: true 28 | 29 | - type: dropdown 30 | id: browser 31 | attributes: 32 | label: 使用的瀏覽器? || What browse are you using? 33 | options: 34 | - Chrome 35 | - Edge 36 | - Safari 37 | - Opera 38 | - Other 39 | validations: 40 | required: true 41 | 42 | - type: dropdown 43 | id: platform 44 | attributes: 45 | label: 使用的系統? || What operating system are you using? 46 | options: 47 | - Windows 48 | - macOS 49 | - Linux 50 | - Android 51 | - iOS 52 | - Other 53 | validations: 54 | required: true 55 | 56 | - type: textarea 57 | id: description 58 | attributes: 59 | label: 問題描述 | Describe the bug 60 | description: 請描述你的問題現象 | A clear and concise description of what the bug is. 61 | placeholder: 請儘量提供截圖來定位問題 | If applicable, add screenshots to help explain your problem 62 | value: 63 | validations: 64 | required: true 65 | 66 | - type: input 67 | id: website 68 | attributes: 69 | label: 出現問題網站 | Website 70 | description: 請提供下可復現網站地址 | Please supply a website url which can reproduce problem. 71 | placeholder: 72 | validations: 73 | required: true 74 | -------------------------------------------------------------------------------- /source/css/_tags/timeline.styl: -------------------------------------------------------------------------------- 1 | #article-container 2 | .timeline 3 | margin: 0 0 20px 10px 4 | padding: 14px 20px 5px 5 | border-left: 2px solid var(--timeline-color, $theme-color) 6 | 7 | for $type in $color-types 8 | &.{$type} 9 | --timeline-color: lookup('$tagsP-' + $type + '-color') 10 | --timeline-bg: s('rgba(%s,%s,%s, 0.2)', red(lookup('$tagsP-' + $type + '-color')), green(lookup('$tagsP-' + $type + '-color')), blue(lookup('$tagsP-' + $type + '-color'))) 11 | 12 | .timeline-item 13 | margin: 0 0 15px 14 | 15 | &:hover 16 | .item-circle 17 | &:before 18 | border-color: var(--timeline-color, $theme-color) 19 | 20 | &.headline 21 | .timeline-item-title 22 | .item-circle 23 | > p 24 | font-weight: 600 25 | font-size: 1.2em 26 | 27 | &:before 28 | left: -28px 29 | border: 4px solid var(--timeline-color, $theme-color) 30 | 31 | &:hover 32 | .item-circle 33 | &:before 34 | border-color: var(--pseudo-hover) 35 | 36 | .timeline-item-title 37 | position: relative 38 | 39 | .item-circle 40 | &:before 41 | position: absolute 42 | top: 50% 43 | left: -27px 44 | width: 6px 45 | height: 6px 46 | border: 3px solid var(--pseudo-hover) 47 | border-radius: 50% 48 | background: var(--card-bg) 49 | content: '' 50 | transition: all .3s 51 | transform: translate(0, -50%) 52 | 53 | > p 54 | margin: 0 0 8px 55 | font-weight: 500 56 | 57 | .timeline-item-content 58 | position: relative 59 | padding: 12px 15px 60 | border-radius: 8px 61 | background: var(--timeline-bg, lighten($theme-color, 85%)) 62 | font-size: .93em 63 | 64 | & > :last-child 65 | margin-bottom: 0 66 | 67 | & + .timeline 68 | margin-top: -20px -------------------------------------------------------------------------------- /scripts/helpers/findArchiveLength.js: -------------------------------------------------------------------------------- 1 | hexo.extend.helper.register('findArchiveLength', function (func) { 2 | const allPostsLength = this.site.posts.length; 3 | if (hexo.config.archive_generator && hexo.config.archive_generator.enable === false ) return allPostsLength 4 | const { yearly, monthly, daily } = hexo.config.archive_generator 5 | const { year, month, day } = this.page 6 | if (yearly === false || !year) return allPostsLength 7 | 8 | const posts = this.site.posts.sort('date') 9 | 10 | const compareFunc = (type,y1,m1,d1,y2,m2,d2) => { 11 | if (type === 'year') { 12 | return y1 === y2 13 | } else if (type === 'month') { 14 | return y1 === y2 && m1 === m2 15 | } else if (type === 'day') { 16 | return y1 === y2 && m1 === m2 && d1 === d2 17 | } 18 | } 19 | 20 | const generateDateObj = (type) => { 21 | let dateObj = [] 22 | let length = 0 23 | 24 | posts.forEach(post => { 25 | let date = post.date.clone() 26 | const year = date.year() 27 | const month = date.month() + 1 28 | const day = date.date() 29 | let lastData = dateObj[length - 1] 30 | 31 | if (!lastData || !compareFunc(type, lastData.year, lastData.month, lastData.day, year, month, day)) { 32 | const name = type === 'year' ? year : type === 'month' ? `${year}-${month}` : `${year}-${month}-${day}` 33 | length = dateObj.push({ 34 | name, 35 | year, 36 | month, 37 | day, 38 | count: 1 39 | }) 40 | } else { 41 | lastData.count++ 42 | } 43 | }); 44 | 45 | return dateObj 46 | } 47 | 48 | const data = func('createArchiveObj', ()=> { 49 | const yearObj = yearly ? generateDateObj('year') : [] 50 | const monthObj = monthly ? generateDateObj('month') : [] 51 | const dayObj = daily ? generateDateObj('day') : [] 52 | const fullObj = [...yearObj, ...monthObj, ...dayObj] 53 | return fullObj 54 | }) 55 | 56 | const name = month ? day ? `${year}-${month}-${day}` : `${year}-${month}` : year 57 | return data.find(item => item.name === name).count 58 | }) -------------------------------------------------------------------------------- /source/css/_search/algolia.styl: -------------------------------------------------------------------------------- 1 | #algolia-search 2 | .search-dialog 3 | .ais-SearchBox 4 | input 5 | padding: 5px 14px 6 | width: 100% 7 | outline: none 8 | border: 2px solid var(--heo-theme) 9 | border-radius: 40px 10 | background: var(--search-bg) 11 | color: var(--search-input-color) 12 | 13 | .ais-Hits-list 14 | margin: 0 15 | padding: 0 16 | @extend .list-beauty 17 | 18 | a 19 | color: var(--search-result-title) 20 | 21 | &:hover 22 | color: var(--heo-theme) 23 | 24 | mark 25 | background: transparent 26 | color: $search-keyword-highlight 27 | font-weight: bold 28 | 29 | .algolia-hit-item-content 30 | margin: 0 0 8px 31 | word-break: break-all 32 | 33 | .ais-Pagination 34 | margin: 20px 0 0 35 | padding: 0 36 | text-align: center 37 | 38 | .ais-Pagination-list 39 | margin: 0 40 | padding: 0 41 | list-style: none 42 | 43 | .ais-Pagination-item 44 | display: inline 45 | margin: 0 4px 46 | padding: 0 47 | 48 | .ais-Pagination-link 49 | display: inline-block 50 | min-width: 24px 51 | height: 24px 52 | text-align: center 53 | line-height: 24px 54 | 55 | .ais-Pagination-item--selected 56 | a 57 | background: $theme-paginator-color 58 | color: #eee 59 | cursor: default 60 | 61 | .ais-Pagination-item--disabled 62 | visibility: hidden 63 | 64 | .algolia-logo 65 | padding-top: 2px 66 | width: 80px 67 | height: 30px 68 | 69 | #algolia-hits 70 | > div 71 | overflow-y: scroll 72 | 73 | +minWidth768() 74 | max-height: calc(80vh - 240px) 75 | 76 | +maxWidth768() 77 | height: calc(100vh - 260px) 78 | 79 | #algolia-info 80 | div 81 | display: inline 82 | 83 | .algolia-poweredBy 84 | float: right 85 | 86 | .apple 87 | #algolia-search 88 | #algolia-hits 89 | > div 90 | +maxWidth768() 91 | height: calc(90vh - 260px) 92 | -------------------------------------------------------------------------------- /layout/includes/third-party/comments/remark42.pug: -------------------------------------------------------------------------------- 1 | - const { host, siteId, option } = theme.remark42 2 | script. 3 | var remark_config = Object.assign({ 4 | host: '!{host}', 5 | site_id: '!{siteId}', 6 | components: ['embed'], 7 | theme: document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' 8 | },!{JSON.stringify(option)}) 9 | 10 | function addRemark42(){ 11 | for (let i = 0; i < remark_config.components.length; i++) { 12 | const s = document.createElement('script') 13 | s.src = remark_config.host + '/web/' + remark_config.components[i] + '.js' 14 | s.defer = true 15 | document.head.appendChild(s) 16 | } 17 | } 18 | 19 | function initRemark42() { 20 | if (window.REMARK42) { 21 | if (this.remark42Instance) { 22 | this.remark42Instance.destroy() 23 | } 24 | 25 | this.remark42Instance = window.REMARK42.createInstance({ 26 | ...remark_config 27 | }) 28 | } 29 | } 30 | 31 | function getCount () { 32 | const ele = document.querySelector('.remark42__counter') 33 | if (ele) { 34 | const s = document.createElement('script') 35 | s.src = remark_config.host + '/web/counter.js' 36 | s.defer = true 37 | document.head.appendChild(s) 38 | } 39 | } 40 | 41 | function loadRemark42 () { 42 | if (window.REMARK42) { 43 | this.initRemark42() 44 | getCount() 45 | } else { 46 | addRemark42() 47 | window.addEventListener('REMARK42::ready', () => { 48 | this.initRemark42() 49 | getCount() 50 | }) 51 | } 52 | } 53 | 54 | document.getElementById('darkmode').addEventListener('click',()=>{ 55 | if (!window.REMARK42) return 56 | let theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark' 57 | window.REMARK42.changeTheme(theme) 58 | }) 59 | 60 | if ('!{theme.comments.use[0]}' === 'Remark42' || !!{theme.comments.lazyload}) { 61 | if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('remark42'), loadRemark42) 62 | else loadRemark42() 63 | } else { 64 | function loadOtherComment () { 65 | loadRemark42() 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /layout/includes/additional-js.pug: -------------------------------------------------------------------------------- 1 | div 2 | script(src=url_for(theme.asset.utils)) 3 | script(src=url_for(theme.asset.main)) 4 | 5 | if theme.translate.enable 6 | script(src=url_for(theme.asset.translate)) 7 | 8 | if theme.medium_zoom 9 | script(src=url_for(theme.asset.medium_zoom)) 10 | else if theme.fancybox 11 | script(src=url_for(theme.asset.fancybox_v4)) 12 | 13 | if theme.instantpage 14 | script(src=url_for(theme.asset.instantpage), type='module') 15 | 16 | if theme.lazyload.enable 17 | script(src=url_for(theme.asset.lazyload)) 18 | 19 | if theme.snackbar.enable 20 | script(src=url_for(theme.asset.snackbar)) 21 | 22 | if theme.pangu.enable 23 | != partial("includes/third-party/pangu.pug", {}, { cache: true }) 24 | 25 | //- search 26 | if theme.algolia_search.enable 27 | script(src=url_for(theme.asset.algolia_search_v4)) 28 | script(src=url_for(theme.asset.instantsearch_v4)) 29 | script(src=url_for(theme.asset.algolia_js)) 30 | else if theme.local_search.enable 31 | script(src=url_for(theme.asset.local_search)) 32 | 33 | .js-pjax 34 | if needLoadCountJs 35 | != partial("includes/third-party/card-post-count/index", {}, { cache: true }) 36 | 37 | if loadSubJs 38 | include ./third-party/subtitle.pug 39 | 40 | include ./third-party/math/index.pug 41 | 42 | if commentsJsLoad 43 | include ./third-party/comments/js.pug 44 | 45 | != partial("includes/third-party/prismjs", {}, { cache: true }) 46 | 47 | != fragment_cache('injectBottom', function(){return injectHtml(theme.inject.bottom)}) 48 | 49 | != partial("includes/third-party/effect", {}, { cache: true }) 50 | 51 | != partial("includes/third-party/chat/index", {}, { cache: true }) 52 | 53 | if theme.aplayerInject && theme.aplayerInject.enable 54 | if theme.aplayerInject.per_page 55 | include ./third-party/aplayer.pug 56 | else if page.aplayer 57 | include ./third-party/aplayer.pug 58 | 59 | != partial("includes/third-party/pjax", {}, { cache: true }) 60 | 61 | if theme.busuanzi.site_uv || theme.busuanzi.site_pv || theme.busuanzi.page_pv 62 | script(async data-pjax src='//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js') 63 | -------------------------------------------------------------------------------- /layout/includes/third-party/comments/disqusjs.pug: -------------------------------------------------------------------------------- 1 | - let disqusjsPageTitle = page.title.replace(/'/ig,"\\'") 2 | 3 | script. 4 | function loadDisqusjs () { 5 | function addDisqusjsCSS () { 6 | const ele = document.createElement('link') 7 | ele.rel = 'stylesheet' 8 | ele.href= '!{url_for(theme.asset.disqusjs_css)}' 9 | document.getElementsByTagName('head')[0].appendChild(ele) 10 | } 11 | 12 | function initDisqusjs () { 13 | window.disqusjs = null 14 | disqusjs = new DisqusJS(Object.assign({ 15 | shortname: '!{theme.disqusjs.shortname}', 16 | identifier: '!{ url_for(page.path) }', 17 | url: '!{ page.permalink }', 18 | title: '!{ disqusjsPageTitle }', 19 | apikey: '!{theme.disqusjs.apikey}', 20 | },!{JSON.stringify(theme.disqusjs.option)})) 21 | 22 | disqusjs.render(document.getElementById('disqusjs')) 23 | } 24 | 25 | const themeChange = () => { 26 | const ele = document.getElementById('disqus_thread') 27 | if(!ele) return 28 | disqusjs.destroy() 29 | initDisqusjs() 30 | } 31 | 32 | 33 | document.getElementById('darkmode').addEventListener('click', themeChange) 34 | 35 | if (window.disqusJsLoad) initDisqusjs() 36 | else { 37 | addDisqusjsCSS() 38 | getScript('!{url_for(theme.asset.disqusjs)}').then(initDisqusjs) 39 | window.disqusJsLoad = true 40 | } 41 | } 42 | 43 | if ('!{theme.comments.use[0]}' === 'Disqusjs' || !!{theme.comments.lazyload}) { 44 | if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('disqusjs'), loadDisqusjs) 45 | else loadDisqusjs() 46 | } 47 | else { 48 | function loadOtherComment () { 49 | loadDisqusjs() 50 | } 51 | } 52 | 53 | 54 | if is_post() && !theme.comments.lazyload && theme.comments.count && theme.comments.use[0] === 'Disqusjs' 55 | script. 56 | if (window.DISQUSWIDGETS === undefined) { 57 | var d = document, s = d.createElement('script'); 58 | s.src = 'https://!{theme.disqus.shortname}.disqus.com/count.js'; 59 | s.id = 'dsq-count-scr'; 60 | (d.head || d.body).appendChild(s); 61 | } else { 62 | DISQUSWIDGETS.getCount({reset: true}); 63 | } 64 | 65 | -------------------------------------------------------------------------------- /source/css/_page/flink.styl: -------------------------------------------------------------------------------- 1 | #article-container 2 | .flink 3 | margin-bottom: 20px 4 | 5 | .flink-list 6 | overflow: auto 7 | padding: 10px 10px 0 8 | text-align: center 9 | 10 | & > .flink-list-item 11 | position: relative 12 | float: left 13 | overflow: hidden 14 | margin: 15px 7px 15 | width: calc(100% / 3 - 15px) 16 | height: 90px 17 | border-radius: 8px 18 | line-height: 17px 19 | -webkit-transform: translateZ(0) 20 | 21 | +maxWidth1024() 22 | width: calc(50% - 15px) !important 23 | 24 | +maxWidth600() 25 | width: calc(100% - 15px) !important 26 | 27 | &:hover 28 | .flink-item-icon 29 | margin-left: -10px 30 | width: 0 31 | 32 | &:before 33 | position: absolute 34 | top: 0 35 | right: 0 36 | bottom: 0 37 | left: 0 38 | z-index: -1 39 | background: var(--text-bg-hover) 40 | content: '' 41 | transition: transform .3s ease-out 42 | transform: scale(0) 43 | 44 | &:hover:before, 45 | &:focus:before, 46 | &:active:before 47 | transform: scale(1) 48 | 49 | a 50 | color: var(--font-color) 51 | text-decoration: none 52 | 53 | .flink-item-icon 54 | float: left 55 | overflow: hidden 56 | margin: 15px 10px 57 | width: 60px 58 | height: 60px 59 | border-radius: 35px 60 | transition: width .3s ease-out 61 | 62 | img 63 | width: 100% 64 | height: 100% 65 | transition: filter 375ms ease-in .2s, transform .3s 66 | object-fit: cover 67 | 68 | .img-alt 69 | display: none 70 | 71 | .flink-item-name 72 | @extend .limit-one-line 73 | padding: 16px 10px 0 0 74 | height: 40px 75 | font-weight: bold 76 | font-size: 1.43em 77 | 78 | .flink-item-desc 79 | @extend .limit-one-line 80 | padding: 16px 10px 16px 0 81 | height: 50px 82 | font-size: .93em 83 | 84 | .flink-name 85 | margin-bottom: 5px 86 | font-weight: bold 87 | font-size: 1.5em -------------------------------------------------------------------------------- /scripts/tag/hide.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Butterfly 3 | * @example 4 | * hideInline 5 | * {% hideInline content,display,bg,color %} 6 | * content不能包含當引號,可用 ' 7 | * hideBlock 8 | * {% hideBlock display,bg,color %} 9 | * content 10 | * {% endhideBlock %} 11 | * hideToggle 12 | * {% hideToggle display,bg,color %} 13 | * content 14 | * {% endhideToggle %} 15 | */ 16 | 17 | 'use strict' 18 | 19 | function hideInline (args) { 20 | args = args.join(' ').split(',') 21 | const content = args[0] 22 | const display = args[1] || 'Click' 23 | const bg = args[2] || false 24 | const color = args[3] || false 25 | let group = 'style="' 26 | 27 | if (bg) group += `background-color: ${bg};` 28 | if (color) group += `color: ${color}` 29 | group += '"' 30 | 31 | return `${content}` 33 | } 34 | 35 | function hideBlock (args, content) { 36 | args = args.join(' ').split(',') 37 | const display = args[0] || 'Click' 38 | const bg = args[1] || false 39 | const color = args[2] || false 40 | let group = 'style="' 41 | 42 | if (bg) group += `background-color: ${bg};` 43 | if (color) group += `color: ${color}` 44 | group += '"' 45 | 46 | return `
${hexo.render.renderSync({ text: content, engine: 'markdown' })}
` 48 | } 49 | 50 | function hideToggle (args, content) { 51 | args = args.join(' ').split(',') 52 | const display = args[0] 53 | const bg = args[1] || false 54 | const color = args[2] || false 55 | let group = 'style="' 56 | let border = '' 57 | 58 | if (bg) { 59 | border = `style="border: 1px solid ${bg}"` 60 | group += `background-color: ${bg};` 61 | } 62 | if (color) group += `color: ${color}` 63 | group += '"' 64 | 65 | return `
${display}
${hexo.render.renderSync({ text: content, engine: 'markdown' })}
` 66 | } 67 | 68 | hexo.extend.tag.register('hideInline', hideInline) 69 | hexo.extend.tag.register('hideBlock', hideBlock, { ends: true }) 70 | hexo.extend.tag.register('hideToggle', hideToggle, { ends: true }) 71 | -------------------------------------------------------------------------------- /scripts/tag/tabs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tabs 3 | * transplant from hexo-theme-next 4 | * modify by Jerry 5 | */ 6 | 7 | 'use strict' 8 | 9 | function postTabs (args, content) { 10 | const tabBlock = /\n([\w\W\s\S]*?)/g 11 | 12 | args = args.join(' ').split(',') 13 | const tabName = args[0] 14 | const tabActive = Number(args[1]) || 0 15 | 16 | const matches = [] 17 | let match 18 | let tabId = 0 19 | let tabNav = '' 20 | let tabContent = '' 21 | 22 | !tabName && hexo.log.warn('Tabs block must have unique name!') 23 | 24 | while ((match = tabBlock.exec(content)) !== null) { 25 | matches.push(match[1]) 26 | matches.push(match[2]) 27 | } 28 | 29 | for (let i = 0; i < matches.length; i += 2) { 30 | const tabParameters = matches[i].split('@') 31 | let postContent = matches[i + 1] 32 | let tabCaption = tabParameters[0] || '' 33 | let tabIcon = tabParameters[1] || '' 34 | let tabHref = '' 35 | 36 | postContent = hexo.render.renderSync({ text: postContent, engine: 'markdown' }).trim() 37 | 38 | tabId += 1 39 | tabHref = (tabName + ' ' + tabId).toLowerCase().split(' ').join('-'); 40 | 41 | ((tabCaption.length === 0) && (tabIcon.length === 0)) && (tabCaption = tabName + ' ' + tabId) 42 | 43 | const isOnlyicon = tabIcon.length > 0 && tabCaption.length === 0 ? ' style="text-align: center;"' : '' 44 | const icon = tabIcon.trim() 45 | tabIcon.length > 0 && (tabIcon = ``) 46 | 47 | const toTop = '' 48 | 49 | const isActive = (tabActive > 0 && tabActive === tabId) || (tabActive === 0 && tabId === 1) ? ' active' : '' 50 | tabNav += `
  • ` 51 | tabContent += `
    ${postContent + toTop}
    ` 52 | } 53 | 54 | tabNav = `` 55 | tabContent = `
    ${tabContent}
    ` 56 | 57 | return `
    ${tabNav + tabContent}
    ` 58 | } 59 | 60 | hexo.extend.tag.register('tabs', postTabs, { ends: true }) 61 | hexo.extend.tag.register('subtabs', postTabs, { ends: true }) 62 | hexo.extend.tag.register('subsubtabs', postTabs, { ends: true }) 63 | -------------------------------------------------------------------------------- /layout/includes/rightside.pug: -------------------------------------------------------------------------------- 1 | - const { readmode, translate, darkmode, aside, chat_btn } = theme 2 | mixin rightsideItem(array) 3 | each item in array 4 | case item 5 | //-when 'readmode' 6 | if is_post() && readmode 7 | button#readmode(type="button" title=_p('rightside.readmode_title')) 8 | i.fas.fa-book-open 9 | //-when 'translate' 10 | if translate.enable 11 | button#translateLink(type="button" title=_p('rightside.translate_title'))= translate.default 12 | //-when 'darkmode' 13 | if darkmode.enable && darkmode.button 14 | button#darkmode(type="button" title=_p('rightside.night_mode_title')) 15 | i.fas.fa-adjust 16 | //-when 'hideAside' 17 | if aside.enable && aside.button && page.aside !== false 18 | button#hide-aside-btn(type="button" title=_p('rightside.aside')) 19 | i.fas.fa-arrows-alt-h 20 | when 'toc' 21 | if showToc 22 | button#mobile-toc-button.close(type="button" title=_p("rightside.toc")) 23 | i.dys.shujuwj 24 | //-when 'chat' 25 | if chat_btn 26 | button#chat_btn(type="button" title=_p("rightside.chat")) 27 | i.fas.fa-sms 28 | //-when 'comment' 29 | if commentsJsLoad 30 | a#to_comment(href="#post-comment" title=_p("rightside.scroll_to_comment")) 31 | i.fas.fa-comments 32 | 33 | #rightside 34 | - const { enable, hide, show } = theme.rightside_item_order 35 | - const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode','hideAside'] 36 | - const showArray = enable ? show && show.split(',') : ['toc','chat','comment'] 37 | 38 | 39 | #rightside-config-hide 40 | if hideArray 41 | +rightsideItem(hideArray) 42 | //-#rightside-config-show 43 | if enable 44 | if hide 45 | button#rightside_config(type="button" title=_p("rightside.setting")) 46 | i.fas.fa-cog.fa-spin 47 | else 48 | if is_post() 49 | if (readmode || translate.enable || (darkmode.enable && darkmode.button)) 50 | button#rightside_config(type="button" title=_p("rightside.setting")) 51 | i.fas.fa-cog.fa-spin 52 | else if translate.enable || (darkmode.enable && darkmode.button) 53 | button#rightside_config(type="button" title=_p("rightside.setting")) 54 | i.fas.fa-cog.fa-spin 55 | 56 | if showArray 57 | +rightsideItem(showArray) 58 | 59 | //-button#go-up(type="button" title=_p("rightside.back_to_top")) 60 | i.fas.fa-arrow-up -------------------------------------------------------------------------------- /source/css/_layout/third-party.styl: -------------------------------------------------------------------------------- 1 | #vcomment 2 | font-size: 1.1em 3 | 4 | .vbtn 5 | border: none 6 | background: var(--btn-bg) 7 | color: var(--btn-color) 8 | 9 | &:hover 10 | background: var(--btn-hover-color) 11 | 12 | .vimg 13 | transition: all .3s 14 | 15 | &:hover 16 | transform: rotate(360deg) 17 | 18 | .vcards .vcard .vcontent.expand 19 | &:before, 20 | &:after 21 | z-index: 22 22 | 23 | #waline-wrap 24 | --waline-font-size: 1.1em 25 | --waline-theme-color: $button-bg 26 | --waline-active-color: $button-hover-color 27 | 28 | .wl-comment-actions > button:not(last-child) 29 | padding-right: 4px 30 | 31 | if hexo-config('valine.bg') 32 | #vcomment 33 | textarea 34 | background: url(hexo-config('valine.bg')) 100% 100% no-repeat 35 | 36 | &:focus 37 | background-image: none 38 | 39 | if hexo-config('waline.bg') 40 | #waline-wrap 41 | textarea 42 | background: url(hexo-config('waline.bg')) 100% 100% no-repeat 43 | 44 | &:focus 45 | background-image: none 46 | 47 | .fireworks 48 | position: fixed 49 | top: 0 50 | left: 0 51 | z-index: $fireworks-zIndex 52 | pointer-events: none 53 | 54 | .medium-zoom-image--opened 55 | z-index: 99999 !important 56 | margin: 0 !important 57 | 58 | .medium-zoom-overlay 59 | z-index: 99999 !important 60 | 61 | .mermaid-wrap 62 | margin: 0 0 20px 63 | text-align: center 64 | 65 | & > svg 66 | height: 100% 67 | 68 | .utterances, 69 | .fb-comments iframe 70 | width: 100% !important 71 | 72 | #gitalk-container 73 | .gt-meta 74 | margin: 0 0 .8em 75 | padding: 6px 0 16px 76 | 77 | .katex-wrap 78 | overflow: auto 79 | 80 | if hexo-config('katex') && hexo-config('katex.hide_scrollbar') 81 | &::-webkit-scrollbar 82 | display: none 83 | 84 | // Mathjax 85 | .mathjax-overflow 86 | overflow-x: auto 87 | overflow-y: hidden 88 | 89 | span.mathjax-overflow 90 | display: inline-block 91 | padding: 0 2px 92 | max-width: 100% 93 | vertical-align: bottom 94 | 95 | .aplayer 96 | color: $font-black 97 | 98 | #article-container 99 | .aplayer 100 | margin: 0 0 20px 101 | 102 | if hexo-config('beautify.enable') 103 | ol, 104 | ul 105 | margin: 0 106 | padding: 0 107 | 108 | li 109 | margin: 0 110 | padding: 0 15px 111 | 112 | &:before 113 | content: none 114 | 115 | .snackbar-css 116 | border-radius: 5px !important -------------------------------------------------------------------------------- /languages/zh-CN.yml: -------------------------------------------------------------------------------- 1 | footer: 2 | framework: 框架 3 | theme: 主题 4 | 5 | copy: 6 | success: 复制成功 7 | error: 复制错误 8 | noSupport: 浏览器不支持 9 | 10 | page: 11 | articles: 文章总览 12 | tag: 标签 13 | category: 分类 14 | archives: 归档 15 | 16 | card_post_count: 条评论 17 | 18 | sticky: 置顶 19 | no_title: 无题 20 | 21 | post: 22 | created: 发表于 23 | updated: 更新于 24 | wordcount: 字数总计 25 | min2read: 阅读时长 26 | min2read_unit: 分钟 27 | page_pv: 阅读量 28 | comments: 评论数 29 | copyright: 30 | author: 文章作者 31 | link: 文章链接 32 | copyright_notice: 版权声明 33 | copyright_content: '本博客所有文章除特别声明外,均采用 34 | %s 许可协议。转载请注明来自 %s!' 35 | recommend: 相关推荐 36 | edit: 编辑 37 | 38 | search: 39 | title: 搜索 40 | load_data: 数据库加载中 41 | algolia_search: 42 | input_placeholder: 搜索文章 43 | hits_empty: '找不到您查询的内容:${query}' 44 | hits_stats: '找到 ${hits} 条结果,用时 ${time} 毫秒' 45 | 46 | local_search: 47 | input_placeholder: 搜索文章 48 | hits_empty: '找不到您查询的内容:${query}' 49 | 50 | pagination: 51 | prev: 上一篇 52 | next: 下一篇 53 | 54 | comment: 评论 55 | 56 | aside: 57 | articles: 文章 58 | tags: 标签 59 | categories: 分类 60 | card_announcement: 公告 61 | card_categories: 分类 62 | card_tags: 标签 63 | card_archives: 归档 64 | card_recent_post: 最新文章 65 | card_webinfo: 66 | headline: 网站资讯 67 | article_name: 文章数目 68 | runtime: 69 | name: 已运行时间 70 | unit: 天 71 | last_push_date: 72 | name: 最后更新时间 73 | site_wordcount: 本站总字数 74 | site_uv_name: 本站访客数 75 | site_pv_name: 本站总访问量 76 | more_button: 查看更多 77 | card_newest_comments: 78 | headline: 最新评论 79 | loading_text: 正在加载中... 80 | error: 无法获取评论,请确认相关配置是否正确 81 | zero: 没有评论 82 | image: 图片 83 | link: 链接 84 | code: 代码 85 | card_toc: 目录 86 | 87 | date_suffix: 88 | just: 刚刚 89 | min: 分钟前 90 | hour: 小时前 91 | day: 天前 92 | month: 个月前 93 | 94 | donate: 打赏 95 | share: 分享 96 | 97 | rightside: 98 | readmode_title: 阅读模式 99 | translate_title: 简繁转换 100 | night_mode_title: 浅色和深色模式转换 101 | back_to_top: 回到顶部 102 | toc: 目录 103 | scroll_to_comment: 直达评论 104 | setting: 设置 105 | aside: 单栏和双栏切换 106 | chat: 聊天 107 | 108 | copy_copyright: 109 | author: 作者 110 | link: 链接 111 | source: 来源 112 | info: 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 113 | 114 | Snackbar: 115 | chs_to_cht: 你已切换为繁体 116 | cht_to_chs: 你已切换为简体 117 | day_to_night: 你已切换为深色模式 118 | night_to_day: 你已切换为浅色模式 119 | 120 | loading: 加载中... 121 | 122 | error404: 页面没有找到 123 | -------------------------------------------------------------------------------- /languages/zh-TW.yml: -------------------------------------------------------------------------------- 1 | footer: 2 | framework: 框架 3 | theme: 主題 4 | 5 | copy: 6 | success: 複製成功 7 | error: 複製錯誤 8 | noSupport: 瀏覽器不支援 9 | 10 | page: 11 | articles: 文章總覽 12 | tag: 標籤 13 | category: 分類 14 | archives: 歸檔 15 | 16 | card_post_count: 條評論 17 | 18 | sticky: 置頂 19 | no_title: 無題 20 | 21 | post: 22 | created: 發表於 23 | updated: 更新於 24 | wordcount: 字數總計 25 | min2read: 閱讀時長 26 | min2read_unit: 分鐘 27 | page_pv: 閱讀量 28 | comments: 評論數 29 | copyright: 30 | author: 文章作者 31 | link: 文章連結 32 | copyright_notice: 版權聲明 33 | copyright_content: '本部落格所有文章除特別聲明外,均採用 34 | %s 許可協議。轉載請註明來自 %s!' 35 | recommend: 相關推薦 36 | edit: 編輯 37 | 38 | search: 39 | title: 搜尋 40 | load_data: 資料庫載入中 41 | algolia_search: 42 | input_placeholder: 搜尋文章 43 | hits_empty: '找不到您查詢的內容:${query}' 44 | hits_stats: '找到 ${hits} 條結果,用時 ${time} 毫秒' 45 | 46 | local_search: 47 | input_placeholder: 搜尋文章 48 | hits_empty: '找不到您查詢的內容:${query}' 49 | 50 | pagination: 51 | prev: 上一篇 52 | next: 下一篇 53 | 54 | comment: 評論 55 | 56 | aside: 57 | articles: 文章 58 | tags: 標籤 59 | categories: 分類 60 | card_announcement: 公告 61 | card_categories: 分類 62 | card_tags: 標籤 63 | card_archives: 歸檔 64 | card_recent_post: 最新文章 65 | card_webinfo: 66 | headline: 網站資訊 67 | article_name: 文章數目 68 | runtime: 69 | name: 已執行時間 70 | unit: 天 71 | last_push_date: 72 | name: 最後更新時間 73 | site_wordcount: 本站總字數 74 | site_uv_name: 本站訪客數 75 | site_pv_name: 本站總訪問量 76 | more_button: 檢視更多 77 | card_newest_comments: 78 | headline: 最新評論 79 | loading_text: 正在載入中... 80 | error: 無法獲取評論,請確認相關配置是否正確 81 | zero: 沒有評論 82 | image: 圖片 83 | link: 連結 84 | code: 程式碼 85 | card_toc: 目錄 86 | 87 | date_suffix: 88 | just: 剛剛 89 | min: 分鐘前 90 | hour: 小時前 91 | day: 天前 92 | month: 個月前 93 | 94 | donate: 打賞 95 | share: 分享 96 | 97 | rightside: 98 | readmode_title: 閱讀模式 99 | translate_title: 簡繁轉換 100 | night_mode_title: 淺色和深色模式轉換 101 | back_to_top: 回到頂部 102 | toc: 目錄 103 | scroll_to_comment: 直達評論 104 | setting: 設定 105 | aside: 單欄和雙欄切換 106 | chat: 聊天 107 | 108 | copy_copyright: 109 | author: 作者 110 | link: 連結 111 | source: 來源 112 | info: 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。 113 | 114 | Snackbar: 115 | chs_to_cht: 你已切換為繁體 116 | cht_to_chs: 你已切換為簡體 117 | day_to_night: 你已切換為深色模式 118 | night_to_day: 你已切換為淺色模式 119 | 120 | loading: 載入中... 121 | 122 | error404: 頁面沒有找到 123 | -------------------------------------------------------------------------------- /scripts/helpers/page.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Butterfly 3 | * @example 4 | * page_description() 5 | * cloudTags(source, minfontsize, maxfontsize, limit) 6 | */ 7 | 8 | 'use strict' 9 | 10 | const { stripHTML, escapeHTML, prettyUrls } = require('hexo-util') 11 | const crypto = require('crypto') 12 | 13 | hexo.extend.helper.register('page_description', function () { 14 | const { config, page } = this 15 | let description = page.description || page.content || page.title || config.description 16 | 17 | if (description) { 18 | description = escapeHTML(stripHTML(description).substring(0, 150) 19 | .trim() 20 | ).replace(/\n/g, ' ') 21 | return description 22 | } 23 | }) 24 | 25 | hexo.extend.helper.register('cloudTags', function (options = {}) { 26 | const env = this 27 | let source = options.source 28 | const limit = options.limit 29 | 30 | let result = '' 31 | if (limit > 0) { 32 | source = source.limit(limit) 33 | } 34 | 35 | const sizes = [] 36 | source.sort('length').forEach(tag => { 37 | const { length } = tag 38 | if (sizes.includes(length)) return 39 | sizes.push(length) 40 | }) 41 | 42 | source.forEach(tag => { 43 | let style = `20px;` 44 | style 45 | result += `${tag.name}` 46 | }) 47 | return result 48 | }) 49 | 50 | hexo.extend.helper.register('urlNoIndex', function (url = null) { 51 | return prettyUrls(url || this.url, { trailing_index: false, trailing_html: false }) 52 | }) 53 | 54 | hexo.extend.helper.register('md5', function (path) { 55 | return crypto.createHash('md5').update(decodeURI(this.url_for(path))).digest('hex') 56 | }) 57 | 58 | hexo.extend.helper.register('injectHtml', function (data) { 59 | let result = '' 60 | if (!data) return '' 61 | for (let i = 0; i < data.length; i++) { 62 | result += data[i] 63 | } 64 | return result 65 | }) 66 | 67 | hexo.extend.helper.register('findArchivesTitle', function (page, menu, date) { 68 | if (page.year) { 69 | const dateStr = page.month ? `${page.year}-${page.month}` : `${page.year}` 70 | const date_format = page.month ? hexo.theme.config.aside.card_archives.format : 'YYYY' 71 | return date(dateStr, date_format) 72 | } 73 | 74 | const defaultTitle = this._p('page.archives') 75 | if (!menu) return defaultTitle 76 | 77 | const loop = (m) => { 78 | for (const key in m) { 79 | if (typeof m[key] === 'object') { 80 | loop(m[key]) 81 | } 82 | 83 | if (/\/archives\//.test(m[key])) { 84 | return key 85 | } 86 | } 87 | } 88 | 89 | return loop(menu) || defaultTitle 90 | }) 91 | -------------------------------------------------------------------------------- /source/css/_tags/gallery.styl: -------------------------------------------------------------------------------- 1 | #article-container 2 | figure.gallery-group 3 | position: relative 4 | float: left 5 | overflow: hidden 6 | margin: 6px 4px 7 | width: calc(50% - 8px) 8 | height: 250px 9 | border-radius: 8px 10 | background: $dark-black 11 | -webkit-transform: translate3d(0, 0, 0) 12 | 13 | +maxWidth600() 14 | width: calc(100% - 8px) 15 | 16 | &:hover 17 | img 18 | opacity: .4 19 | transform: translate3d(0, 0, 0) 20 | 21 | .gallery-group-name::after 22 | transform: translate3d(0, 0, 0) 23 | 24 | p 25 | opacity: 1 26 | transform: translate3d(0, 0, 0) 27 | 28 | img 29 | position: relative 30 | margin: 0 31 | max-width: none 32 | width: calc(100% + 20px) 33 | height: 250px 34 | backface-visibility: hidden 35 | opacity: .8 36 | transition: all .3s, filter 375ms ease-in .2s 37 | transform: translate3d(-10px, 0, 0) 38 | object-fit: cover 39 | 40 | figcaption 41 | position: absolute 42 | top: 0 43 | left: 0 44 | padding: 30px 45 | width: 100% 46 | height: 100% 47 | color: $gallery-color 48 | text-transform: uppercase 49 | backface-visibility: hidden 50 | 51 | & > a 52 | position: absolute 53 | top: 0 54 | right: 0 55 | bottom: 0 56 | left: 0 57 | z-index: 1000 58 | opacity: 0 59 | 60 | p 61 | @extend .limit-more-line 62 | margin: 0 63 | padding: 8px 0 0 64 | letter-spacing: 1px 65 | font-size: 1.1em 66 | line-height: 1.5 67 | opacity: 0 68 | transition: opacity .35s, transform .35s 69 | transform: translate3d(100%, 0, 0) 70 | -webkit-line-clamp: 4 71 | 72 | .gallery-group-name 73 | @extend .limit-more-line 74 | position: relative 75 | margin: 0 76 | padding: 8px 0 77 | font-weight: bold 78 | font-size: 1.65em 79 | line-height: 1.5 80 | -webkit-line-clamp: 2 81 | 82 | &:after 83 | position: absolute 84 | bottom: 0 85 | left: 0 86 | width: 100% 87 | height: 2px 88 | background: $gallery-color 89 | content: '' 90 | transition: transform .35s 91 | transform: translate3d(-100%, 0, 0) 92 | 93 | .gallery-group-main 94 | overflow: auto 95 | padding: 0 0 16px 96 | 97 | .fj-gallery 98 | margin: 0 0 16px 99 | opacity: 0 100 | 101 | .img-alt 102 | display: none -------------------------------------------------------------------------------- /source/css/_page/archives.styl: -------------------------------------------------------------------------------- 1 | .article-sort 2 | margin-left: 10px 3 | padding-left: 20px 4 | border-left: 2px solid lighten($light-blue, 20) 5 | 6 | &-title 7 | position: relative 8 | margin-left: 10px 9 | padding-bottom: 20px 10 | padding-left: 20px 11 | font-size: 1.72em 12 | 13 | &:hover 14 | &:before 15 | border-color: var(--pseudo-hover) 16 | 17 | &:before 18 | position: absolute 19 | top: calc(((100% - 36px) / 2)) 20 | left: -9px 21 | z-index: 1 22 | width: w = 10px 23 | height: h = w 24 | border: .5 * w solid $light-blue 25 | border-radius: w 26 | background: var(--card-bg) 27 | content: '' 28 | line-height: h 29 | transition: all .2s ease-in-out 30 | 31 | &:after 32 | position: absolute 33 | bottom: 0 34 | left: 0 35 | z-index: 0 36 | width: 2px 37 | height: 1.5em 38 | background: lighten($light-blue, 20) 39 | content: '' 40 | 41 | &-item 42 | position: relative 43 | display: flex 44 | align-items: center 45 | margin: 0 0 20px 10px 46 | transition: all .2s ease-in-out 47 | 48 | &:hover 49 | &:before 50 | border-color: var(--pseudo-hover) 51 | 52 | &:before 53 | $w = 6px 54 | position: absolute 55 | left: calc(-20px - 17px) 56 | width: w = $w 57 | height: h = w 58 | border: .5 * w solid $light-blue 59 | border-radius: w 60 | background: var(--card-bg) 61 | content: '' 62 | transition: all .2s ease-in-out 63 | 64 | &.no-article-cover 65 | height: 80px 66 | 67 | .article-sort-item-info 68 | padding: 0 69 | 70 | &.year 71 | font-size: 1.43em 72 | 73 | &:hover 74 | &:before 75 | border-color: $light-blue 76 | 77 | &:before 78 | border-color: var(--pseudo-hover) 79 | 80 | &-time 81 | color: $theme-meta-color 82 | font-size: 95% 83 | 84 | time 85 | padding-left: 6px 86 | cursor: default 87 | 88 | &-title 89 | @extend .limit-more-line 90 | color: var(--font-color) 91 | font-size: 1.1em 92 | transition: all .3s 93 | -webkit-line-clamp: 2 94 | 95 | &:hover 96 | color: $text-hover 97 | transform: translateX(10px) 98 | 99 | &-img 100 | overflow: hidden 101 | width: 80px 102 | height: 80px 103 | 104 | img 105 | @extend .imgHover 106 | 107 | &-info 108 | flex: 1 109 | padding: 0 16px 110 | -------------------------------------------------------------------------------- /source/css/_tags/folding.styl: -------------------------------------------------------------------------------- 1 | details 2 | display: block 3 | padding: 10px 4 | margin: 10px-p 0 5 | border-radius: 15px 6 | background: var(--color-card) 7 | font-size: $fontsize-list 8 | trans() 9 | summary 10 | cursor: pointer 11 | padding: 10px 12 | margin: 0 - 10px 13 | border-radius: 15px 14 | color: black 15 | font-size: 1rem 16 | font-weight: bold 17 | position: relative 18 | line-height: normal 19 | > 20 | p,h1,h2,h3,h4,h5,h6 21 | display: inline 22 | border-bottom: none !important 23 | &:hover 24 | color: var(--color-p) 25 | &:after 26 | position: absolute 27 | content: '+' 28 | text-align: center 29 | top: 50% 30 | transform: translateY(-50%) 31 | right: 10px 32 | 33 | border: 1px solid var(--color-block) 34 | >summary 35 | background: var(--color-block) 36 | &[blue] 37 | border-color: #2196f3 38 | >summary 39 | background: #2196f3 40 | &[cyan] 41 | border-color: #1bcdfc 42 | >summary 43 | background: #1bcdfc 44 | &[green] 45 | border-color: #3dc550 46 | >summary 47 | background: #3dc550 48 | &[yellow] 49 | border-color: #ffbd2b 50 | >summary 51 | background: #ffbd2b 52 | &[red] 53 | border-color: #fe5f58 54 | >summary 55 | background: #fe5f58 56 | 57 | details[open] 58 | border-color: alpha(blue, .2) 59 | >summary 60 | border-bottom: 1px solid alpha(blue, .2) 61 | border-bottom-left-radius: 0 62 | border-bottom-right-radius: 0 63 | &[blue] 64 | border-color: #2196f3 65 | >summary 66 | border-bottom-color: #2196f3 67 | &[cyan] 68 | border-color: #1bcdfc 69 | >summary 70 | border-bottom-color: #1bcdfc 71 | &[green] 72 | border-color: #3dc550 73 | >summary 74 | border-bottom-color: #3dc550 75 | &[yellow] 76 | border-color: #ffbd2b 77 | >summary 78 | border-bottom-color: #ffbd2b 79 | &[red] 80 | border-color: #fe5f58 81 | >summary 82 | border-bottom-color: #fe5f58 83 | >summary 84 | color: black 85 | margin-bottom: 0 86 | &:hover 87 | &:after 88 | content: '-' 89 | >div.content 90 | padding: 10px 91 | margin: 0 - 10px 92 | margin-top: 0 93 | p>a:hover 94 | text-decoration: underline 95 | > 96 | p,.tabs,ul,ol,.highlight,.note,details 97 | &:first-child 98 | margin-top: 0 99 | &:last-child 100 | margin-bottom: 0 101 | 102 | details 103 | margin-bottom 20px 104 | box-shadow 0 0 0 1px #aaa -------------------------------------------------------------------------------- /source/css/_custom/comment.styl: -------------------------------------------------------------------------------- 1 | if hexo-config('envelope_comment.enable') 2 | $hoverHeight = hexo-config('envelope_comment.height') ? convert(hexo-config('envelope_comment.height')) : 1050px 3 | @media screen and (max-width: 600px) 4 | #beforeimg, 5 | #afterimg 6 | display none !important 7 | 8 | @media screen and (min-width: 600px) 9 | #article-container 10 | img 11 | margin 0 auto 0rem 12 | #form-wrap 13 | overflow hidden 14 | height 447px 15 | position relative 16 | top 0px 17 | transition all 1s ease-in-out .3s 18 | z-index 0 19 | &:hover 20 | height $hoverHeight 21 | top -200px 22 | #maincontent 23 | width 530px 24 | margin 20px auto 0 25 | #beforeimg 26 | position absolute 27 | bottom 126px 28 | left 0px 29 | background-repeat no-repeat 30 | width 530px 31 | height 317px 32 | z-index -100 33 | pointer-events none 34 | #afterimg 35 | position absolute 36 | bottom -2px 37 | left 0 38 | background-repeat no-repeat 39 | width 530px 40 | height 259px 41 | z-index 100 42 | pointer-events none 43 | #envelope 44 | position relative 45 | overflow visible 46 | width 500px 47 | margin 0px auto 48 | transition all 1s ease-in-out .3s 49 | padding-top 200px 50 | 51 | .headerimg 52 | width 100% 53 | overflow hidden 54 | pointer-events none 55 | 56 | .formmain 57 | background white 58 | width 95% 59 | max-width 800px 60 | margin auto auto 61 | border-radius 5px 62 | border 1px solid 63 | overflow hidden 64 | -webkit-box-shadow 0px 0px 20px 0px rgba(0, 0, 0, 0.12) 65 | box-shadow 0px 0px 20px 0px rgba(0, 0, 0, 0.18) 66 | .comments-main 67 | padding 5px 20px 68 | .title3 69 | text-decoration none 70 | color $theme-color 71 | text-align center 72 | .comments 73 | text-align center 74 | border-bottom #ddd 1px solid 75 | border-left #ddd 1px solid 76 | padding-bottom 20px 77 | background-color #eee 78 | margin 15px 0px 79 | padding-left 20px 80 | padding-right 20px 81 | border-top #ddd 1px solid 82 | border-right #ddd 1px solid 83 | padding-top 20px 84 | 85 | .bottomcontent 86 | text-align center 87 | margin-top 40px 88 | 89 | .bottomimg 90 | width 100% 91 | margin 5px auto 5px auto 92 | display block 93 | pointer-events none 94 | 95 | .bottomhr 96 | font-size 12px 97 | text-align center 98 | color #999 99 | 100 | [data-theme='dark'] 101 | .formmain 102 | background rgb(50, 50, 50) 103 | .comments 104 | background rgba(90, 90, 90, 0.8) -------------------------------------------------------------------------------- /source/css/_custom/bar.css: -------------------------------------------------------------------------------- 1 | /* 首页分类条展示 */ 2 | #tag-bar{ 3 | padding: 0.4rem 1rem 0.4rem 0.5rem; 4 | background: var(--heo-card-bg); 5 | border-radius: 12px; 6 | display: flex; 7 | white-space: nowrap; 8 | overflow: hidden; 9 | margin-bottom: 1rem; 10 | border: var(--style-border); 11 | } 12 | 13 | @media screen and (max-width: 768px){ 14 | #tag-bar{ 15 | border-radius: 0; 16 | } 17 | } 18 | 19 | #tag #tag-bar{ 20 | padding: 0; 21 | border: none; 22 | } 23 | 24 | #tag a.tag-bar-item.select a{ 25 | display: none; 26 | } 27 | 28 | .tag-in-bar{ 29 | display: flex; 30 | white-space: nowrap; 31 | } 32 | 33 | .tag-in-bar-tips{ 34 | margin-right: 1rem; 35 | } 36 | 37 | .tag-bar-items{ 38 | white-space: nowrap; 39 | overflow-x: scroll; 40 | display: flex; 41 | } 42 | 43 | .tag-bar-items::-webkit-scrollbar{ 44 | display: none; 45 | } 46 | 47 | .tag-bar-item a{ 48 | padding: 0.1rem 0.5rem; 49 | margin: 0 0.25rem; 50 | font-weight: bold; 51 | border-radius: 12px; 52 | } 53 | 54 | .tag-bar-item:hover a{ 55 | background: var(--heo-main); 56 | color: var(--heo-white); 57 | } 58 | 59 | .tag-bar-item.select a { 60 | background: var(--heo-main); 61 | color: var(--heo-white); 62 | border-radius: 12px; 63 | } 64 | 65 | .tag-bar-more{ 66 | margin-left: 1rem; 67 | font-weight: bold; 68 | } 69 | 70 | /* 首页分类条展示 */ 71 | #category-bar{ 72 | padding: 0.4rem 1rem 0.4rem 0.5rem; 73 | background: var(--heo-card-bg); 74 | border-radius: 12px; 75 | display: flex; 76 | white-space: nowrap; 77 | overflow: hidden; 78 | margin-bottom: 1rem; 79 | border: var(--style-border); 80 | } 81 | 82 | @media screen and (max-width: 768px){ 83 | #category-bar{ 84 | border-radius: 0; 85 | } 86 | } 87 | 88 | #category #category-bar{ 89 | padding: 0; 90 | border: none; 91 | } 92 | 93 | #category a.category-bar-item.select a{ 94 | display: none; 95 | } 96 | 97 | .category-in-bar{ 98 | display: flex; 99 | white-space: nowrap; 100 | } 101 | 102 | .category-in-bar-tips{ 103 | margin-right: 1rem; 104 | } 105 | 106 | .category-bar-items{ 107 | white-space: nowrap; 108 | overflow-x: scroll; 109 | display: flex; 110 | } 111 | 112 | 113 | 114 | .category-bar-items::-webkit-scrollbar{ 115 | display: none; 116 | } 117 | 118 | .category-bar-item a{ 119 | padding: 0.1rem 0.5rem; 120 | margin: 0 0.25rem; 121 | font-weight: bold; 122 | border-radius: 12px; 123 | } 124 | 125 | .category-bar-item:hover a{ 126 | background: var(--heo-main); 127 | color: var(--heo-white); 128 | } 129 | 130 | .category-bar-item.select a { 131 | background: var(--heo-main); 132 | color: var(--heo-white); 133 | border-radius: 12px; 134 | } 135 | 136 | .category-bar-more{ 137 | margin-left: 1rem; 138 | font-weight: bold; 139 | } -------------------------------------------------------------------------------- /scripts/events/cdn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Butterfly 3 | * Merge CDN 4 | */ 5 | 6 | 'use strict' 7 | 8 | const { version } = require('../../package.json') 9 | const path = require('path') 10 | 11 | hexo.extend.filter.register('before_generate', () => { 12 | const themeConfig = hexo.theme.config 13 | const { CDN } = themeConfig 14 | 15 | const thirdPartySrc = hexo.render.renderSync({ path: path.join(hexo.theme_dir,'/plugins.yml'), engine: 'yaml'}) 16 | const internalSrc = { 17 | main: { 18 | name: 'hexo-theme-butterfly', 19 | file: 'js/main.js', 20 | version 21 | }, 22 | utils: { 23 | name: 'hexo-theme-butterfly', 24 | file: 'js/utils.js', 25 | version 26 | }, 27 | translate: { 28 | name: 'hexo-theme-butterfly', 29 | file: 'js/tw_cn.js', 30 | version 31 | }, 32 | local_search: { 33 | name: 'hexo-theme-butterfly', 34 | file: 'js/search/local-search.js', 35 | version 36 | }, 37 | algolia_js: { 38 | name: 'hexo-theme-butterfly', 39 | file: 'js/search/algolia.js', 40 | version 41 | } 42 | } 43 | 44 | const minFile = (file) => { 45 | return file.replace(/(? '.min' + ext) 46 | } 47 | 48 | const createCDNLink = (data, type, cond = '') => { 49 | Object.keys(data).map(key => { 50 | let { name, version, file, other_name } = data[key] 51 | 52 | const min_file = minFile(file) 53 | const cdnjs_name = other_name || name 54 | const cdnjs_file = file.replace(/^[lib|dist]*\/|browser\//g, '') 55 | const min_cdnjs_file = minFile(cdnjs_file) 56 | if (cond === 'internal') file = `source/${file}` 57 | const verType = CDN.version ? `@${version}` : '' 58 | 59 | const value = { 60 | version, 61 | name, 62 | file, 63 | cdnjs_file, 64 | min_file, 65 | min_cdnjs_file, 66 | cdnjs_name 67 | } 68 | const cdnSource = { 69 | local: cond === 'internal' ? cdnjs_file : `/pluginsSrc/${name}/${file}`, 70 | jsdelivr: `https://cdn.jsdelivr.net/npm/${name}${verType}/${min_file}`, 71 | unpkg: `https://unpkg.com/${name}${verType}/${file}`, 72 | cdnjs: `https://cdnjs.cloudflare.com/ajax/libs/${cdnjs_name}/${version}/${min_cdnjs_file}`, 73 | custom: (CDN.custom_format || '').replace(/\$\{(.+?)\}/g, (match, $1) => value[$1]) 74 | } 75 | 76 | data[key] = cdnSource[type] 77 | }) 78 | 79 | if (cond === 'internal') data['main_css'] = 'css/index.css' 80 | return data 81 | } 82 | 83 | // delete null value 84 | const deleteNullValue = obj => { 85 | if (!obj) return 86 | for (const i in obj) { 87 | obj[i] === null && delete obj[i] 88 | } 89 | return obj 90 | } 91 | 92 | themeConfig.asset = Object.assign(createCDNLink(internalSrc,CDN.internal_provider,'internal'), 93 | createCDNLink(thirdPartySrc,CDN.third_party_provider), deleteNullValue(CDN.option)) 94 | }) 95 | -------------------------------------------------------------------------------- /source/css/_page/homepage.styl: -------------------------------------------------------------------------------- 1 | #recent-posts 2 | & > .recent-post-item 3 | margin-top: 20px 4 | 5 | & > .recent-post-item 6 | @extend .cardHover 7 | display: flex 8 | flex-direction: row 9 | align-items: center 10 | overflow: hidden 11 | height: 18em 12 | 13 | if hexo-config('post_double_row') == false 14 | &::after 15 | position: relative 16 | height: 100% 17 | width: 4px 18 | background: #909DF3 19 | content: '' 20 | bottom: 0 21 | border-radius: 100vh 22 | left: 0 23 | right: -99% 24 | animation: glow 10s linear infinite 25 | 26 | +maxWidth768() 27 | height: 4px 28 | width: 100% 29 | 30 | +maxWidth768() 31 | flex-direction: column 32 | height: 350px !important 33 | 34 | &:hover 35 | img.post_bg 36 | transform: scale(1.1) 37 | 38 | &.ads-wrap 39 | display: block !important 40 | height: auto !important 41 | 42 | .post_cover 43 | overflow: hidden 44 | width: 50% 45 | height: 100% 46 | 47 | +maxWidth768() 48 | width: 100% 49 | height: 230px 50 | 51 | img.post_bg 52 | @extend .imgHover 53 | 54 | &.right 55 | order: 1 56 | 57 | +maxWidth768() 58 | order: 0 59 | 60 | & >.recent-post-info 61 | padding: 0 40px 62 | width: 57% 63 | height 100% 64 | max-height: 150px 65 | 66 | +maxWidth768() 67 | padding: 20px 20px 30px 68 | width: 100% 69 | 70 | &.no-cover 71 | width: 100% 72 | 73 | +maxWidth768() 74 | padding: 30px 20px 75 | 76 | & > .article-title 77 | @extend .limit-more-line 78 | color: var(--text-highlight-color) 79 | font-size: 1.72em 80 | line-height: 1.4 81 | transition: all .2s ease-in-out 82 | -webkit-line-clamp: 2 83 | 84 | +maxWidth768() 85 | font-size: 1.43em 86 | 87 | &:hover 88 | color: $text-hover 89 | 90 | & > .article-meta-wrap 91 | margin: 6px 0 92 | color: $theme-meta-color 93 | font-size: 90% 94 | 95 | & > .post-meta-date 96 | cursor: default 97 | 98 | .sticky 99 | color: $sticky-color 100 | 101 | i 102 | margin: 0 4px 0 0 103 | 104 | .fa-spinner 105 | margin: 0 106 | 107 | .article-meta-separator 108 | margin: 0 6px 109 | 110 | .article-meta-link 111 | margin: 0 4px 112 | 113 | if hexo-config('post_meta.page.date_format') == 'relative' 114 | time 115 | display: none 116 | 117 | a 118 | color: $theme-meta-color 119 | 120 | &:hover 121 | color: $text-hover 122 | text-decoration: underline 123 | 124 | & > .content 125 | @extend .limit-more-line 126 | -webkit-line-clamp: 2 --------------------------------------------------------------------------------