由於整合了多個設定並更改了部分設定名稱,升級到 5.0 版本時,請重新設定 `_config.yml` 文件。

1. 新增 macstyle 設定,取消 mac / mac light 主題設定
2. 整合搜索相關設定
3. 修改程式碼區塊設定
4. 主頁文章新增多種版面配置
5. 新增說說頁面
6. 適配 hexo-blog-encrypt 加密插件
7. 改善手機端目錄的開啟效果
8. 新增平滑滾動功能
9. 支持以程式碼區塊方式撰寫 mermaid 圖表
10. 可自訂文章標題位置
11. 新增程式碼全螢幕按鈕
12. 友情連結頭像改為圓角設計
13. 優化程式碼,使用 hexo-util 的參數和 hexo 內建參數
14. 可自訂搜索框提示文字
15. 未設定選單時,不顯示側邊欄目錄和按鈕
16. 螢幕寬度超過 2000px 時,增加卡片高度
17. 根據語言設定調整字體:簡體中文使用雅黑,其他使用正黑體
18. 更新 plugins.yml
19. 全新的側邊欄界面設計
20. 新增 giscus 的 js 設定
21. 調整 utterances js 的設定位置
22. 新增 utterances option 設定
23. 修改 giscus 的主題設定
24. 多個界面元素改為圓角設計
25. 可選擇圓角或直角界面風格
26. 圖庫加載按鈕新增圖標
27. 改善標籤頁面的滑鼠懸停效果
28. 調整側邊欄的滑鼠懸停效果
29. 微調部分界面元素

1. 修復 Hexo 新版本下 Prism.js 無法正確高亮的問題
2. 修復文章標籤為空時可能出現的錯誤
3. 修正 mermaid 圖表可能出現的錯誤
4. 解決未設定選單時控制台報錯的問題
5. 修復 Algolia 搜索的每頁顯示數量設定無效的問題
6. 解決 Algolia 搜索結果出現滾動條的問題
7. 修正滾動條出現上下按鈕的問題
8. 修復圖庫遠程連結未加前綴的問題
9. 修正 label 標籤外掛右側多餘空格的問題
10. 解決 APlayer 報告內存洩漏的問題

1. 優化 PJAX 下的函數調用
2. 整體代碼優化
3. 提升兼容性
4. 改善 Lighthouse 評分
5. 在 PJAX 關閉時減少不必要的全局變量
6. 優化 Waline 的 import 兼容性
7. 改善頁面進入效果
8. 優化程式碼區塊工具列顯示邏輯
9. 改善不同螢幕寬度下文章標題位置的顯示
10. 優化標籤顏色生成算法,避免過暗或過亮
11. 調整 Artalk 和 Waline 在夜間模式下的字體顏色,與主題保持一致
12. 調整 Algolia 搜索加載動畫位置,避免換行
13. 優化 Algolia 搜索結果為空時的處理
14. 改善系列文章的滑鼠懸停效果
15. 優化 404 頁面代碼
16. 解決搜索和側邊欄開啟時窗口抖動的問題
17. 優化 tabs 標籤外掛的代碼和效能
18. 改善 tabs 中使用 gallery 標籤外掛時的圖片加載邏輯
19. 優化目錄滾動效果,使當前標題保持在中間
20. 調整螢幕寬度超過 1024px 時 gallerygroup 的顯示數量
pull/1550/head
Jerry 2 months ago
parent 0d52505331
commit 06f543ed96

@ -7,11 +7,12 @@ body:
attributes:
value: |
重要:請依照該模板來提交
Please follow the template to create a new issue
Important: Please follow the template to create a new issue
- type: input
id: butterfly-ver
attributes:
label: 使用的 Butterfly 版本? | What version of Butterfly are you use?
label: 使用的 Butterfly 版本? | What version of Butterfly are you using?
description: 檢視主題的 package.json | Check the theme's package.json
validations:
required: true
@ -19,17 +20,17 @@ body:
- type: dropdown
id: modify
attributes:
label: 是否修改过主题文件? || Has the theme files been modified?
label: 是否修改過主題文件? | Has the theme files been modified?
options:
- 是 (Yes)
- 不是 (No)
- (No)
validations:
required: true
- type: dropdown
id: browser
attributes:
label: 使用的瀏覽器? || What browse are you using?
label: 使用的瀏覽器? | What browser are you using?
options:
- Chrome
- Edge
@ -42,7 +43,7 @@ body:
- type: dropdown
id: platform
attributes:
label: 使用的系統? || What operating system are you using?
label: 使用的系統? | What operating system are you using?
options:
- Windows
- macOS
@ -56,8 +57,8 @@ body:
- type: textarea
id: dependencies
attributes:
label: 依賴插件 | Package dependencies Information
description: 在 Hexo 根目錄下執行`npm ls --depth 0` | Run `npm ls --depth 0` in Hexo root directory
label: 依賴插件 | Package dependencies information
description: 在 Hexo 根目錄下執行 `npm ls --depth 0` | Run `npm ls --depth 0` in Hexo root directory
render: Text
validations:
required: true
@ -75,8 +76,8 @@ body:
- type: input
id: website
attributes:
label: 出現問題網站 | Website
description: 請提供下可復現網站地址 | Please supply a website url which can reproduce problem.
placeholder:
label: 出現問題網站 | Website with the issue
description: 請提供可復現問題的網站地址 | Please provide a website URL where the problem can be reproduced.
placeholder: 請填寫具體的網址,不要填寫 localhost 網站 | Please provide a specific URL, do not use localhost.
validations:
required: true
required: true

@ -2,6 +2,10 @@
<a title="Chinese" href="/README_CN.md">中文</a>
</div>
<div align="center">
<img src="./source/img/butterfly-icon.png" width="150" height="150" />
# hexo-theme-butterfly
![master version](https://img.shields.io/github/package-json/v/jerryc127/hexo-theme-butterfly/master?color=%231ab1ad&label=master)
@ -10,13 +14,15 @@
![hexo version](https://img.shields.io/badge/hexo-5.3.0+-0e83c)
![license](https://img.shields.io/github/license/jerryc127/hexo-theme-butterfly?color=FF5531)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png)
📢 Demo: [Butterfly](https://butterfly.js.org/) / [CrazyWong](https://blog.crazywong.com/)
📢 Demo: [Butterfly](https://butterfly.js.org/) || [CrazyWong](https://blog.crazywong.com/)
📖 Docs: [English](https://butterfly.js.org/en/posts/butterfly-docs-en-get-started/) / [Chinese](https://butterfly.js.org/posts/21cfbf15/)
📖 Docs: [English](https://butterfly.js.org/en/posts/butterfly-docs-en-get-started/) || [Chinese](https://butterfly.js.org/posts/21cfbf15/)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png)
</div>
Based on [hexo-theme-melody](https://github.com/Molunerfinn/hexo-theme-melody) theme.
---
## 💻 Installation
@ -59,6 +65,7 @@ npm i hexo-theme-butterfly
## 🎉 Features
- [x] Card UI Design
- [x] Rounded Design/Squared Design
- [X] Support sub-menu
- [x] Two-column layout
- [x] Responsive Web Design

@ -2,6 +2,10 @@
<a title="English" href="/README.md">English</a>
</div>
<div align="center">
<img src="./source/img/butterfly-icon.png" width="150" height="150" />
# hexo-theme-butterfly
![master version](https://img.shields.io/github/package-json/v/jerryc127/hexo-theme-butterfly/master?color=%231ab1ad&label=master)
@ -10,13 +14,15 @@
![hexo version](https://img.shields.io/badge/hexo-5.3.0+-0e83c)
![license](https://img.shields.io/github/license/jerryc127/hexo-theme-butterfly?color=FF5531)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png)
📢 預覽: [Butterfly](https://butterfly.js.org/) / [CrazyWong](https://blog.crazywong.com/)
📢 預覽: [Butterfly](https://butterfly.js.org/) || [CrazyWong](https://blog.crazywong.com/)
📖 文檔: [中文](https://butterfly.js.org/posts/21cfbf15/) / [English](https://butterfly.js.org/en/posts/butterfly-docs-en-get-started/)
📖 文檔: [中文](https://butterfly.js.org/posts/21cfbf15/) || [English](https://butterfly.js.org/en/posts/butterfly-docs-en-get-started/)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png)
</div>
一款基於[hexo-theme-melody](https://github.com/Molunerfinn/hexo-theme-melody)修改的主題
---
## 💻 安裝
@ -59,6 +65,7 @@ theme: butterfly
## 🎉 特色
- [x] 卡片化設計
- [x] 圓角化設計/直角化設計
- [X] 支持二級目錄
- [x] 雙欄設計
- [x] 響應式主題

File diff suppressed because it is too large Load Diff

@ -36,13 +36,11 @@ post:
search:
title: Search
load_data: Loading the Database
input_placeholder: Search for Posts
algolia_search:
input_placeholder: Search for Posts
hits_empty: "We didn't find any results for the search: ${query}."
hits_stats: '${hits} results found in ${time} ms'
local_search:
input_placeholder: Search for Posts
hits_empty: "We didn't find any results for the search: ${query}"
hits_stats: '${hits} results found'

@ -36,13 +36,11 @@ post:
search:
title: Search
load_data: Loading the Database
input_placeholder: Search for Posts
algolia_search:
input_placeholder: Search for Posts
hits_empty: "We didn't find any results for the search: ${query}."
hits_stats: '${hits} results found in ${time} ms'
local_search:
input_placeholder: Search for Posts
hits_empty: "We didn't find any results for the search: ${query}"
hits_stats: '${hits} results found'

@ -37,13 +37,11 @@ post:
search:
title: 搜索
load_data: 数据库加载中
input_placeholder: 搜索文章
algolia_search:
input_placeholder: 搜索文章
hits_empty: '找不到您查询的内容:${query}'
hits_stats: '找到 ${hits} 条结果,用时 ${time} 毫秒'
local_search:
input_placeholder: 搜索文章
hits_empty: '找不到您查询的内容:${query}'
hits_stats: '共找到 ${hits} 篇文章'

@ -15,7 +15,7 @@ page:
card_post_count: 條評論
no_title:
no_title:
post:
created: 發表於
@ -28,8 +28,8 @@ post:
copyright:
author: 文章作者
link: 文章連結
copyright_notice: 版權聲明
copyright_content: '本部落格所有文章除特別聲明外,均採用
copyright_notice: 版權宣告
copyright_content: '本部落格所有文章除特別宣告外,均採用
<a href="%s" target="_blank">%s</a> 許可協議。轉載請註明來自 <a href="%s" target="_blank">%s</a>'
recommend: 相關推薦
edit: 編輯
@ -37,16 +37,14 @@ post:
search:
title: 搜尋
load_data: 資料庫載入中
input_placeholder: 搜尋文章
algolia_search:
input_placeholder: 搜尋文章
hits_empty: '找不到您查詢的內容:${query}'
hits_stats: '找到 ${hits} 條結果,用時 ${time} 毫秒'
local_search:
input_placeholder: 搜尋文章
hits_empty: '找不到您查詢的內容:${query}'
hits_stats: '共找到 ${hits} 篇文章'
pagination:
prev: 上一篇
next: 下一篇
@ -83,7 +81,7 @@ aside:
link: 連結
code: 程式碼
card_toc: 目錄
card_post_series: 文章系列
card_post_series: 系列文章
date_suffix:
just: 剛剛
@ -99,7 +97,7 @@ rightside:
readmode_title: 閱讀模式
translate_title: 簡繁轉換
night_mode_title: 淺色和深色模式轉換
back_to_top: 回頂部
back_to_top: 頂部
toc: 目錄
scroll_to_comment: 直達評論
setting: 設定
@ -110,7 +108,7 @@ copy_copyright:
author: 作者
link: 連結
source: 來源
info: 著作權歸作者所有。商業轉載請聯作者獲得授權,非商業轉載請註明出處。
info: 著作權歸作者所有。商業轉載請聯作者獲得授權,非商業轉載請註明出處。
Snackbar:
chs_to_cht: 你已切換為繁體中文

@ -2,10 +2,8 @@ extends includes/layout.pug
block content
if theme.category_ui == 'index'
include ./includes/mixins/post-ui.pug
#recent-posts.recent-posts.category_ui
+postUI
include includes/pagination.pug
include ./includes/mixins/indexPostUI.pug
+indexPostUI
else
include ./includes/mixins/article-sort.pug
#category

@ -1,12 +0,0 @@
- var top_img_404 = theme.error_404.background || theme.default_top_img
#body-wrap.error404
include ./header/index.pug
#error-wrap
.error-content
.error-img
img(src=url_for(top_img_404) alt='Page not found')
.error-info
h1.error_title= '404'
.error_subtitle= theme.error_404.subtitle || _p('error404')

@ -5,9 +5,9 @@ div
if theme.translate.enable
script(src=url_for(theme.asset.translate))
if theme.medium_zoom
if theme.lightbox === 'medium_zoom'
script(src=url_for(theme.asset.medium_zoom))
else if theme.fancybox
else if theme.lightbox === 'fancybox'
script(src=url_for(theme.asset.fancybox))
if theme.instantpage
@ -38,7 +38,7 @@ div
!= partial("includes/third-party/prismjs", {}, { cache: true })
if theme.aside.enable && theme.newest_comments.enable
if theme.aside.enable && theme.aside.card_newest_comments.enable
if theme.pjax.enable
!= partial("includes/third-party/newest-comments/index", {}, { cache: true })
else if (!is_post() && page.aside !== false)

@ -45,7 +45,7 @@ link(rel='stylesheet', href=url_for(theme.asset.fontawesome))
if (theme.snackbar && theme.snackbar.enable)
link(rel='stylesheet', href=url_for(theme.asset.snackbar_css) media="print" onload="this.media='all'")
if theme.fancybox
if theme.lightbox === 'fancybox'
link(rel='stylesheet' href=url_for(theme.asset.fancybox_css) media="print" onload="this.media='all'")
!=fragment_cache('injectHeadJs', function(){return inject_head_js()})

@ -10,5 +10,7 @@ if theme.Open_Graph_meta.enable
-
!= open_graph(ogOption)
else
meta(name="description" content=page_description())
- const description = page.description || page.content || page.title || config.description
if description
meta(name="description" content=truncate(description, 150))

@ -1,28 +1,30 @@
-
let algolia = 'undefined';
let env = process.env;
if (theme.algolia_search.enable) {
let algolia = 'undefined'
if (theme.search.use === 'algolia_search') {
const { ALGOLIA_APP_ID, ALGOLIA_API_KEY, ALGOLIA_INDEX_NAME } = process.env
const { appId, applicationID, apiKey, indexName } = config.algolia
algolia = JSON.stringify({
appId: env.ALGOLIA_APP_ID || config.algolia.appId || config.algolia.applicationID,
apiKey: env.ALGOLIA_API_KEY || config.algolia.apiKey,
indexName: env.ALGOLIA_INDEX_NAME || config.algolia.indexName,
hits: theme.algolia_search.hits,
appId: ALGOLIA_APP_ID || appId || applicationID,
apiKey: ALGOLIA_API_KEY || apiKey,
indexName: ALGOLIA_INDEX_NAME || indexName,
hitsPerPage: theme.search.algolia_search.hitsPerPage,
// search languages
languages: {
input_placeholder: _p("search.algolia_search.input_placeholder"),
input_placeholder: theme.search.placeholder || _p("search.input_placeholder"),
hits_empty: _p("search.algolia_search.hits_empty"),
hits_stats: _p("search.algolia_search.hits_stats"),
}
})
}
let localSearch = 'undefined';
if (theme.local_search && theme.local_search.enable) {
let localSearch = 'undefined'
if (theme.search.use === 'local_search') {
const { CDN, preload, top_n_per_article, unescape } = theme.search.local_search
localSearch = JSON.stringify({
path: theme.local_search.CDN ? theme.local_search.CDN : config.root + config.search.path,
preload: theme.local_search.preload,
top_n_per_article: theme.local_search.top_n_per_article,
unescape: theme.local_search.unescape,
path: CDN || config.root + config.search.path,
preload,
top_n_per_article,
unescape,
languages: {
// search languages
hits_empty: _p("search.local_search.hits_empty"),
@ -31,7 +33,7 @@
})
}
let translate = 'undefined';
let translate = 'undefined'
if (theme.translate && theme.translate.enable){
translate = JSON.stringify({
defaultEncoding: theme.translate.defaultEncoding,
@ -41,7 +43,7 @@
})
}
let copyright = 'undefined';
let copyright = 'undefined'
if (theme.copy.enable && theme.copy.copyright.enable){
copyright = JSON.stringify({
limitCount: theme.copy.copyright.limit_count,
@ -54,7 +56,7 @@
})
}
let Snackbar = 'undefined';
let Snackbar = 'undefined'
if (theme.snackbar && theme.snackbar.enable) {
Snackbar = JSON.stringify({
chs_to_cht: _p("Snackbar.chs_to_cht"),
@ -67,7 +69,7 @@
})
}
let noticeOutdate = 'undefined';
let noticeOutdate = 'undefined'
if (theme.noticeOutdate && theme.noticeOutdate.enable) {
noticeOutdate = JSON.stringify({
limitDay: theme.noticeOutdate.limit_day,
@ -77,17 +79,18 @@
})
}
let highlight = 'undefined';
let syntaxHighlighter = config.syntax_highlighter;
let highlightEnable = syntaxHighlighter ? ['highlight.js', 'prismjs'].includes(syntaxHighlighter) : (config.highlight.enable || config.prismjs.enable);
let highlight = 'undefined'
let syntaxHighlighter = config.syntax_highlighter
let highlightEnable = syntaxHighlighter ? ['highlight.js', 'prismjs'].includes(syntaxHighlighter) : (config.highlight.enable || config.prismjs.enable)
if (highlightEnable) {
const { copy, language, height_limit, fullpage, macStyle } = theme.code_blocks
highlight = JSON.stringify({
plugin: syntaxHighlighter ? syntaxHighlighter : config.highlight.enable ? 'highlight.js' : 'prismjs',
highlightCopy: theme.highlight_copy,
highlightLang: theme.highlight_lang,
highlightHeightLimit: theme.highlight_height_limit,
highlightFullpage: theme.highlight_fullpage,
highlightMacStyle: theme.highlight_theme_macStyle
highlightCopy: copy,
highlightLang: language,
highlightHeightLimit: height_limit,
highlightFullpage: fullpage,
highlightMacStyle: macStyle
})
}
@ -108,7 +111,7 @@ script.
homepage: !{theme.post_meta.page.date_format === 'relative'},
post: !{theme.post_meta.post.date_format === 'relative'}
},
runtime: '!{theme.runtimeshow.enable ? _p("aside.card_webinfo.runtime.unit") : ""}',
runtime: '!{theme.aside.card_webinfo.runtime_date ? _p("aside.card_webinfo.runtime.unit") : ""}',
dateSuffix: {
just: '!{_p("date_suffix.just")}',
min: '!{_p("date_suffix.min")}',
@ -117,7 +120,7 @@ script.
month: '!{_p("date_suffix.month")}'
},
copyright: !{copyright},
lightbox: '!{ theme.medium_zoom ? "mediumZoom" : (theme.fancybox ? "fancybox" : "null" )}',
lightbox: '!{ theme.lightbox || 'null' }',
Snackbar: !{Snackbar},
infinitegrid: {
js: '!{url_for(theme.asset.egjs_infinitegrid)}',

@ -2,20 +2,17 @@
const titleVal = pageTitle.replace(/'/ig,"\\'")
let isHighlightShrink
if (theme.highlight_shrink == 'none') isHighlightShrink = 'undefined'
else if (page.highlight_shrink === true || page.highlight_shrink === false) isHighlightShrink = page.highlight_shrink
else isHighlightShrink = theme.highlight_shrink
if (theme.code_blocks.shrink == 'none') isHighlightShrink = 'undefined'
else if (typeof page.highlight_shrink == 'boolean') isHighlightShrink = page.highlight_shrink
else isHighlightShrink = theme.code_blocks.shrink
var showToc = false
if (theme.aside.enable && page.aside !== false) {
let tocEnable = false
if (is_post()) {
if (theme.toc.post) tocEnable = true
} else if (is_page()) {
if (theme.toc.page) tocEnable = true
}
const pageToc = page.toc === true || page.toc === false ? page.toc : tocEnable
showToc = pageToc && (toc(page.content) !== '' || page.encrypt == true )
if (is_post() && theme.toc.post) tocEnable = true
else if (is_page() && theme.toc.page) tocEnable = true
const pageToc = typeof page.toc === 'boolean' ? page.toc : tocEnable
showToc = pageToc && (toc(page.content) !== '' || page.encrypt === true)
}
-

@ -4,7 +4,7 @@ if !theme.disable_top_img && page.top_img !== false
else if is_page()
- var top_img = page.top_img || theme.default_top_img
else if is_tag()
- var top_img = theme.tag_per_img && theme.tag_per_img[page.tag]
- var top_img = theme.tag_per_img && theme.tag_per_img[page.tag]
- top_img = top_img ? top_img : (theme.tag_img !== false ? theme.tag_img || theme.default_top_img : false)
else if is_category()
- var top_img = theme.category_per_img && theme.category_per_img[page.category]

@ -5,17 +5,18 @@ nav#nav
img.site-icon(src=url_for(theme.nav.logo) alt='Logo')
if theme.nav.display_title
span.site-name=config.title
#menus
if (theme.algolia_search.enable || theme.local_search.enable || theme.docsearch.enable)
if (theme.search.use)
#search-button
span.site-page.social-icon.search
i.fas.fa-search.fa-fw
span=' '+_p('search.title')
!=partial('includes/header/menu_item', {}, {cache: true})
if theme.menu
!=partial('includes/header/menu_item', {}, {cache: true})
#toggle-menu
span.site-page
i.fas.fa-bars.fa-fw
#toggle-menu
span.site-page
i.fas.fa-bars.fa-fw

@ -2,6 +2,7 @@
- page.aside = is_archive() ? theme.aside.display.archive: is_category() ? theme.aside.display.category : is_tag() ? theme.aside.display.tag : page.aside
- var hideAside = !theme.aside.enable || page.aside === false ? 'hide-aside' : ''
- var pageType = is_post() ? 'post' : 'page'
- pageType = page.type ? pageType + ' type-' + page.type : pageType
doctype html
html(lang=config.language data-theme=theme.display_mode class=htmlClassHideAside)
@ -16,32 +17,28 @@ html(lang=config.language data-theme=theme.display_mode class=htmlClassHideAside
!=partial('includes/sidebar', {}, {cache: true})
if page.type !== '404'
#body-wrap(class=pageType)
include ./header/index.pug
#body-wrap(class=pageType)
include ./header/index.pug
main#content-inner.layout(class=hideAside)
if body
div!= body
else
block content
if theme.aside.enable && page.aside !== false
include widget/index.pug
- var footerBg = theme.footer_bg
if (footerBg)
if (footerBg === true)
- var footer_bg = bg_img
else
- var footer_bg = isImgOrUrl(theme.footer_bg) ? `background-image: url('${url_for(footerBg)}')` : `background: ${footerBg}`
main#content-inner.layout(class=hideAside)
if body
div!= body
else
- var footer_bg = ''
footer#footer(style=footer_bg)
!=partial('includes/footer', {}, {cache: true})
block content
if theme.aside.enable && page.aside !== false
include widget/index.pug
- var footerBg = theme.footer_img
if (footerBg)
if (footerBg === true)
- var footer_bg = bg_img
else
- var footer_bg = isImgOrUrl(theme.footer_bg) ? `background-image: url('${url_for(footerBg)}')` : `background: ${footerBg}`
else
- var footer_bg = ''
else
include ./404.pug
footer#footer(style=footer_bg)
!=partial('includes/footer', {}, {cache: true})
include ./rightside.pug
include ./additional-js.pug

@ -0,0 +1,125 @@
mixin indexPostUI()
- let indexLayout = theme.index_layout
- let masonryLayoutClass = (indexLayout === 6 || indexLayout === 7) ? 'masonry' : ''
#recent-posts.recent-posts.nc(class=masonryLayoutClass)
.recent-post-items
each article , index in page.posts.data
.recent-post-item
-
let link = article.link || article.path
let title = article.title || _p('no_title')
let leftOrRight = indexLayout === 3
? index%2 == 0 ? 'left' : 'right'
: indexLayout === 2 ? 'right' : ''
let post_cover = article.cover
let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : ''
-
if post_cover && theme.cover.index_enable
.post_cover(class=leftOrRight)
a(href=url_for(link) title=title)
if article.cover_type === 'img'
img.post-bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'` alt=title)
else
div.post-bg(style=`background: ${post_cover}`)
.recent-post-info(class=no_cover)
a.article-title(href=url_for(link) title=title)
if (is_home() && (article.top || article.sticky > 0))
i.fas.fa-thumbtack.sticky
= title
.article-meta-wrap
if (theme.post_meta.page.date_type)
span.post-meta-date
if (theme.post_meta.page.date_type === 'both')
i.far.fa-calendar-alt
span.article-meta-label=_p('post.created')
time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format)
span.article-meta-separator |
i.fas.fa-history
span.article-meta-label=_p('post.updated')
time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format)
else
- let data_type_updated = theme.post_meta.page.date_type === 'updated'
- let date_type = data_type_updated ? 'updated' : 'date'
- let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt'
- let date_title = data_type_updated ? _p('post.updated') : _p('post.created')
i(class=date_icon)
span.article-meta-label=date_title
time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format)
if (theme.post_meta.page.categories && article.categories.data.length > 0)
span.article-meta
span.article-meta-separator |
each item, index in article.categories.data
i.fas.fa-inbox
a(href=url_for(item.path)).article-meta__categories #[=item.name]
if (index < article.categories.data.length - 1)
i.fas.fa-angle-right.article-meta-link
if (theme.post_meta.page.tags && article.tags.length > 0)
span.article-meta.tags
span.article-meta-separator |
each item, index in article.tags.data
i.fas.fa-tag
a(href=url_for(item.path)).article-meta__tags #[=item.name]
if (index < article.tags.data.length - 1)
span.article-meta-link #[='•']
mixin countBlockInIndex
- needLoadCountJs = true
span.article-meta
span.article-meta-separator |
i.fas.fa-comments
if block
block
span.article-meta-label= ' ' + _p('card_post_count')
if theme.comments.card_post_count && theme.comments.use
case theme.comments.use[0]
when 'Disqus'
when 'Disqusjs'
+countBlockInIndex
a.disqus-count(href=full_url_for(link) + '#post-comment')
i.fa-solid.fa-spinner.fa-spin
when 'Valine'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.valine-comment-count(data-xid=url_for(link))
i.fa-solid.fa-spinner.fa-spin
when 'Waline'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.waline-comment-count(data-path=url_for(link))
i.fa-solid.fa-spinner.fa-spin
when 'Twikoo'
+countBlockInIndex
a.twikoo-count(href=url_for(link) + '#post-comment')
i.fa-solid.fa-spinner.fa-spin
when 'Facebook Comments'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.fb-comments-count(data-href=urlNoIndex(article.permalink))
when 'Remark42'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.remark42__counter(data-url=urlNoIndex(article.permalink))
i.fa-solid.fa-spinner.fa-spin
when 'Artalk'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.artalk-count(data-page-key=url_for(link))
i.fa-solid.fa-spinner.fa-spin
//- Display the article introduction on homepage
case theme.index_post_content.method
when false
- break
when 1
.content!= article.description
when 2
.content!= article.description || truncate(article.content, theme.index_post_content.length)
default
.content!= truncate(article.content, theme.index_post_content.length)
if theme.ad && theme.ad.index
if (index + 1) % 3 == 0
.recent-post-item.ads-wrap!=theme.ad.index
include ../pagination.pug

@ -1,129 +0,0 @@
mixin postUI(posts)
each article , index in page.posts.data
.recent-post-item
-
let link = article.link || article.path
let title = article.title || _p('no_title')
const position = theme.cover.position
let leftOrRight = position === 'both'
? index%2 == 0 ? 'left' : 'right'
: position === 'left' ? 'left' : 'right'
let post_cover = article.cover
let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : ''
-
if post_cover && theme.cover.index_enable
.post_cover(class=leftOrRight)
a(href=url_for(link) title=title)
if article.cover_type === 'img'
img.post-bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'` alt=title)
else
div.post-bg(style=`background: ${post_cover}`)
.recent-post-info(class=no_cover)
a.article-title(href=url_for(link) title=title)
if (is_home() && (article.top || article.sticky > 0))
i.fas.fa-thumbtack.sticky
= title
.article-meta-wrap
if (theme.post_meta.page.date_type)
span.post-meta-date
if (theme.post_meta.page.date_type === 'both')
i.far.fa-calendar-alt
span.article-meta-label=_p('post.created')
time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format)
span.article-meta-separator |
i.fas.fa-history
span.article-meta-label=_p('post.updated')
time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format)
else
- let data_type_updated = theme.post_meta.page.date_type === 'updated'
- let date_type = data_type_updated ? 'updated' : 'date'
- let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt'
- let date_title = data_type_updated ? _p('post.updated') : _p('post.created')
i(class=date_icon)
span.article-meta-label=date_title
time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format)
if (theme.post_meta.page.categories && article.categories.data.length > 0)
span.article-meta
span.article-meta-separator |
each item, index in article.categories.data
i.fas.fa-inbox
a(href=url_for(item.path)).article-meta__categories #[=item.name]
if (index < article.categories.data.length - 1)
i.fas.fa-angle-right.article-meta-link
if (theme.post_meta.page.tags && article.tags.data.length > 0)
span.article-meta.tags
span.article-meta-separator |
each item, index in article.tags.data
i.fas.fa-tag
a(href=url_for(item.path)).article-meta__tags #[=item.name]
if (index < article.tags.data.length - 1)
span.article-meta-link #[='•']
mixin countBlockInIndex
- needLoadCountJs = true
span.article-meta
span.article-meta-separator |
i.fas.fa-comments
if block
block
span.article-meta-label= ' ' + _p('card_post_count')
if theme.comments.card_post_count && theme.comments.use
case theme.comments.use[0]
when 'Disqus'
when 'Disqusjs'
+countBlockInIndex
a.disqus-count(href=full_url_for(link) + '#post-comment')
i.fa-solid.fa-spinner.fa-spin
when 'Valine'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.valine-comment-count(data-xid=url_for(link))
i.fa-solid.fa-spinner.fa-spin
when 'Waline'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.waline-comment-count(data-path=url_for(link))
i.fa-solid.fa-spinner.fa-spin
when 'Twikoo'
+countBlockInIndex
a.twikoo-count(href=url_for(link) + '#post-comment')
i.fa-solid.fa-spinner.fa-spin
when 'Facebook Comments'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.fb-comments-count(data-href=urlNoIndex(article.permalink))
when 'Remark42'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.remark42__counter(data-url=urlNoIndex(article.permalink))
i.fa-solid.fa-spinner.fa-spin
when 'Artalk'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.artalk-count(data-page-key=url_for(link))
i.fa-solid.fa-spinner.fa-spin
//- Display the article introduction on homepage
case theme.index_post_content.method
when false
- break
when 1
.content!= article.description
when 2
if article.description
.content!= article.description
else
- const content = strip_html(article.content)
- let expert = content.substring(0, theme.index_post_content.length)
- content.length > theme.index_post_content.length ? expert += ' ...' : ''
.content!= expert
default
- const content = strip_html(article.content)
- let expert = content.substring(0, theme.index_post_content.length)
- content.length > theme.index_post_content.length ? expert += ' ...' : ''
.content!= expert
if theme.ad && theme.ad.index
if (index + 1) % 3 == 0
.recent-post-item.ads-wrap!=theme.ad.index

@ -0,0 +1,8 @@
- var top_img_404 = theme.error_404.background || theme.default_top_img
.error-content
.error-img
img(src=url_for(top_img_404) alt='Page not found')
.error-info
h1.error_title= '404'
.error_subtitle= theme.error_404.subtitle || _p('error404')

@ -0,0 +1,103 @@
//- - author:
//- avatar:
//- date:
//- content:
//- tags:
//- - tag1
//- - tag2
- page.comments = false
- page.toc = false
#article-container
if page.shuoshuo_url
script.
(() => {
const loadShuoshuo = async () => {
try {
const fetchContent = await fetch('!{url_for(page.shuoshuo_url)}')
const shuoshuo = await fetchContent.json()
let start = 0
const container = document.getElementById('article-container')
const addData = data => {
const cLength = data.length
const end = start + 10 > cLength ? cLength : start + 10
let result = ''
data.slice(start, end).forEach((item) => {
result += `
<div class="shuoshuo-item">
<div class="shuoshuo-item-header">
<div class="shuoshuo-avatar">
<img class="no-lightbox" src="${item.avatar || '!{url_for(theme.avatar.img)}'}">
</div>
<div class="shuoshuo-info">
<div class="shuoshuo-author">${item.author || '!{config.author}'}</div>
<div class="shuoshuo-date">${btf.diffDate(item.date, true)}</div>
</div>
</div>
<div class="shuoshuo-content">
${item.content}
</div>
<div class="shuoshuo-footer">
<div class="shuoshuo-tags">
${item.tags.map(tag => `<span class="shuoshuo-tag">${tag}</span>`).join('')}
</div>
</div>
</div>
`
})
start = end
container.insertAdjacentHTML('beforeend', result)
if (start >= cLength) {
observer.disconnect()
} else {
setTimeout(() => observer.observe(container.lastElementChild), 100)
}
window.lazyLoadInstance.update()
btf.loadLightbox(document.querySelectorAll('#article-container img:not(.no-lightbox)'))
}
addData(shuoshuo)
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
observer.unobserve(entries[0].target)
addData(shuoshuo)
}
}, {
root: null,
rootMargin: '0px',
threshold: 1.0
})
if (container.lastElementChild) {
observer.observe(container.lastElementChild)
}
} catch (e) {
console.error(e)
}
}
window.pjax ? loadShuoshuo() : window.addEventListener('load', loadShuoshuo)
})()
else
if site.data.shuoshuo
each i in site.data.shuoshuo
.shuoshuo-item
.shuoshuo-item-header
.shuoshuo-avatar
img.no-lightbox(src=i.avatar || url_for(theme.avatar.img))
.shuoshuo-info
.shuoshuo-author=i.author || config.author
.shuoshuo-date=relative_date(i.date)
.shuoshuo-content
!=markdown(i.content)
.shuoshuo-footer
.shuoshuo-tags
each tag in i.tags
span.shuoshuo-tag=tag

@ -1,2 +1,2 @@
.tag-cloud-list.is-center
!=cloudTags({source: site.tags, orderby: page.orderby || 'random', order: page.order || 1, minfontsize: 1.2, maxfontsize: 2.1, limit: 0, unit: 'em'})
!=cloudTags({source: site.tags, orderby: page.orderby || 'random', order: page.order || 1, minfontsize: 1.2, maxfontsize: 1.5, limit: 0, unit: 'em'})

@ -12,27 +12,25 @@ if is_post()
nav#pagination.pagination-post
if(prev)
- var hasPageNext = next ? 'pull-left' : 'pull-full'
.prev-post(class=hasPageNext)
a(href=url_for(prev.path) title=prev.title)
if prev.cover_type === 'img'
img.cover(src=url_for(prev.cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of previous post')
else
.cover(style=`background: ${prev.cover || 'var(--default-bg-color)'}`)
.pagination-info
.label=_p('pagination.prev')
.prev_info=prev.title
a.prev-post(class=hasPageNext href=url_for(prev.path) title=prev.title)
if prev.cover_type === 'img'
img.cover(src=url_for(prev.cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of previous post')
else
.cover(style=`background: ${prev.cover || 'var(--default-bg-color)'}`)
.pagination-info
.label=_p('pagination.prev')
.prev_info=prev.title
if(next)
- var hasPagePrev = prev ? 'pull-right' : 'pull-full'
.next-post(class=hasPagePrev)
a(href=url_for(next.path) title=next.title)
if next.cover_type === 'img'
img.cover(src=url_for(next.cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of next post')
else
.cover(style=`background: ${next.cover || 'var(--default-bg-color)'}`)
.pagination-info
.label=_p('pagination.next')
.next_info=next.title
a.next-post(class=hasPagePrev href=url_for(next.path) title=next.title)
if next.cover_type === 'img'
img.cover(src=url_for(next.cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of next post')
else
.cover(style=`background: ${next.cover || 'var(--default-bg-color)'}`)
.pagination-info
.label=_p('pagination.next')
.next_info=next.title
else
nav#pagination
.pagination

@ -1,4 +1,4 @@
- const { readmode, translate, darkmode, aside, chat_btn } = theme
- const { readmode, translate, darkmode, aside, chat } = theme
mixin rightsideItem(array)
each item in array
case item
@ -22,9 +22,9 @@ mixin rightsideItem(array)
button#mobile-toc-button.close(type="button" title=_p("rightside.toc"))
i.fas.fa-list-ul
when 'chat'
if chat_btn
if chat.rightside_button && chat.use
button#chat-btn(type="button" title=_p("rightside.chat"))
i.fas.fa-sms
i.fas.fa-message
when 'comment'
if commentsJsLoad
a#to_comment(href="#post-comment" title=_p("rightside.scroll_to_comment"))

@ -1,18 +1,18 @@
#sidebar
#menu-mask
#sidebar-menus
.avatar-img.is-center
img(src=url_for(theme.avatar.img) onerror=`onerror=null;src='${theme.error_img.flink}'` alt="avatar")
.sidebar-site-data.site-data.is-center
a(href=url_for(config.archive_dir) + '/')
.headline= _p('aside.articles')
.length-num= site.posts.length
a(href=url_for(config.tag_dir) + '/' )
.headline= _p('aside.tags')
.length-num= site.tags.length
a(href=url_for(config.category_dir) + '/')
.headline= _p('aside.categories')
.length-num= site.categories.length
if theme.menu
#sidebar
#menu-mask
#sidebar-menus
.avatar-img.is-center
img(src=url_for(theme.avatar.img) onerror=`onerror=null;src='${theme.error_img.flink}'` alt="avatar")
.site-data.is-center
a(href=url_for(config.archive_dir) + '/')
.headline= _p('aside.articles')
.length-num= site.posts.length
a(href=url_for(config.tag_dir) + '/' )
.headline= _p('aside.tags')
.length-num= site.tags.length
a(href=url_for(config.category_dir) + '/')
.headline= _p('aside.categories')
.length-num= site.categories.length
hr.custom-hr
!=partial('includes/header/menu_item', {}, {cache: true})
!=partial('includes/header/menu_item', {}, {cache: true})

@ -14,10 +14,10 @@ if theme.pjax.enable
}
}
const loadMeting = () => {
const runMetingJS = () => {
typeof loadMeting === 'function' && document.getElementsByClassName('aplayer').length && loadMeting()
}
btf.addGlobalFn('pjaxSend', destroyAplayer, 'destroyAplayer')
btf.addGlobalFn('pjaxComplete', loadMeting, 'loadMeting')
btf.addGlobalFn('pjaxComplete', loadMeting, 'runMetingJS')
})()

@ -1,5 +1,5 @@
- const fbSDKVer = 'v16.0'
- const fbSDK = theme.messenger.enable ? `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk/xfbml.customerchat.js#xfbml=1&version=${fbSDKVer}` : `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk.js#xfbml=1&version=${fbSDKVer}`
- const fbSDK = theme.chat.use === 'messenger' ? `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk/xfbml.customerchat.js#xfbml=1&version=${fbSDKVer}` : `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk.js#xfbml=1&version=${fbSDKVer}`
script.
(()=>{

@ -1,8 +1,8 @@
//- https://chatra.io/help/api/
script.
(() => {
const isChatBtn = !{theme.chat_btn}
const isChatHideShow = !{theme.chat_hide_show}
const isChatBtn = !{theme.chat.rightside_button}
const isChatHideShow = !{theme.chat.button_hide_show}
if (isChatBtn) {
const close = () => {

@ -11,8 +11,8 @@ script.
})();
$crisp.push(["safe", true])
const isChatBtn = !{theme.chat_btn}
const isChatHideShow = !{theme.chat_hide_show}
const isChatBtn = !{theme.chat.rightside_button}
const isChatHideShow = !{theme.chat.button_hide_show}
if (isChatBtn) {
const open = () => {

@ -3,8 +3,8 @@ script.
(() => {
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/!{theme.daovoice.app_id}.js","daovoice")
const isChatBtn = !{theme.chat_btn}
const isChatHideShow = !{theme.chat_hide_show}
const isChatBtn = !{theme.chat.rightside_button}
const isChatHideShow = !{theme.chat.button_hide_show}
daovoice('init', {
app_id: '!{theme.daovoice.app_id}',},{

@ -1,10 +1,11 @@
if theme.chatra && theme.chatra.enable
include ./chatra.pug
else if theme.tidio && theme.tidio.enable
include ./tidio.pug
else if theme.daovoice && theme.daovoice.enable
include ./daovoice.pug
else if theme.crisp && theme.crisp.enable
include ./crisp.pug
else if theme.messenger && theme.messenger.enable
include ./messenger.pug
case theme.chat.use
when 'chatra'
include ./chatra.pug
when 'tidio'
include ./tidio.pug
when 'daovoice'
include ./daovoice.pug
when 'crisp'
include ./crisp.pug
when 'messenger'
include ./messenger.pug

@ -22,8 +22,8 @@ script.
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
const isChatBtn = !{theme.chat_btn}
const isChatHideShow = !{theme.chat_hide_show}
const isChatBtn = !{theme.chat.rightside_button}
const isChatHideShow = !{theme.chat.button_hide_show}
if (isChatBtn) {
window.chatBtnFn = () => {

@ -1,8 +1,8 @@
script(src=`//code.tidio.co/${theme.tidio.public_key}.js` async)
script.
(() => {
const isChatBtn = !{theme.chat_btn}
const isChatHideShow = !{theme.chat_hide_show}
const isChatBtn = !{theme.chat.rightside_button}
const isChatHideShow = !{theme.chat.button_hide_show}
if (isChatBtn) {
let isShow = false

@ -25,7 +25,7 @@ script.
artalkItem.destroy()
}
btf.addGlobalFn('pjax', destroyArtalk, 'destroyArtalk')
btf.addGlobalFn('pjaxSendOnce', destroyArtalk, 'destroyArtalk')
}
const loadArtalk = async () => {

@ -1,5 +1,5 @@
- const fbSDKVer = 'v16.0'
- const fbSDK = theme.messenger.enable ? `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk/xfbml.customerchat.js#xfbml=1&version=${fbSDKVer}` : `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk.js#xfbml=1&version=${fbSDKVer}`
- const fbSDK = theme.chat.use === 'messenger' ? `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk/xfbml.customerchat.js#xfbml=1&version=${fbSDKVer}` : `https://connect.facebook.net/${theme.facebook_comments.lang}/sdk.js#xfbml=1&version=${fbSDKVer}`
script.
(()=>{

@ -1,13 +1,11 @@
- const { repo, repo_id, category_id, theme:themes, option } = theme.giscus
- const giscusUrl = theme.asset.giscus || 'https://giscus.app/client.js'
- const giscusOriginUrl = new URL(giscusUrl).origin
- const { use, lazyload } = theme.comments
- const { repo, repo_id, category_id, light_theme, dark_theme, js, option } = theme.giscus
- const giscusUrl = js || 'https://giscus.app/client.js'
- const giscusOriginUrl = new URL(giscusUrl).origin
script.
(()=>{
const getGiscusTheme = theme => {
return theme === 'dark' ? '!{themes.dark}' : '!{themes.light}'
}
const getGiscusTheme = theme => theme === 'dark' ? '!{dark_theme}' : '!{light_theme}'
const loadGiscus = () => {
const config = Object.assign({
@ -30,17 +28,17 @@ script.
}
const changeGiscusTheme = theme => {
const sendMessage = message => {
const iframe = document.querySelector('iframe.giscus-frame')
if (!iframe) return
iframe.contentWindow.postMessage({ giscus: message }, '!{giscusOriginUrl}')
}
sendMessage({
setConfig: {
theme: getGiscusTheme(theme)
const iframe = document.querySelector('#giscus-wrap iframe')
if (iframe) {
const message = {
giscus: {
setConfig: {
theme: getGiscusTheme(theme)
}
}
}
});
iframe.contentWindow.postMessage(message, '!{giscusOriginUrl}')
}
}
btf.addGlobalFn('themeChange', changeGiscusTheme, 'giscus')

@ -1,34 +1,42 @@
- const { use, lazyload } = theme.comments
- const { repo, issue_term, light_theme, dark_theme } = theme.utterances
- const { repo, issue_term, light_theme, dark_theme, js, option } = theme.utterances
- const utterancesUrl = js || 'https://utteranc.es/client.js'
- const utterancesOriginUrl = new URL(utterancesUrl).origin
script.
(() => {
const getUtterancesTheme = theme => theme === 'dark' ? '#{dark_theme}' : '#{light_theme}'
const loadUtterances = () => {
let ele = document.createElement('script')
ele.id = 'utterances_comment'
ele.src = 'https://utteranc.es/client.js'
ele.setAttribute('repo', '!{repo}')
ele.setAttribute('issue-term', '!{issue_term}')
const nowTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? '#{dark_theme}' : '#{light_theme}'
ele.setAttribute('theme', nowTheme)
ele.crossOrigin = 'anonymous'
ele.async = true
const config = Object.assign({
id: 'utterances_comment',
src: '!{utterancesUrl}',
repo: '!{repo}',
'issue-term': '!{issue_term}',
theme: getUtterancesTheme(document.documentElement.getAttribute('data-theme')),
crossorigin: 'anonymous',
async: true
},!{JSON.stringify(option)})
const ele = document.createElement('script')
for (let key in config) {
ele.setAttribute(key, config[key])
}
document.getElementById('utterances-wrap').appendChild(ele)
}
const utterancesTheme = theme => {
const iframe = document.querySelector('.utterances-frame')
const changeUtterancesTheme = theme => {
const iframe = document.querySelector('#utterances-wrap iframe')
if (iframe) {
const theme = theme === 'dark' ? '#{dark_theme}' : '#{light_theme}'
const message = {
type: 'set-theme',
theme: theme
theme: getUtterancesTheme(theme)
};
iframe.contentWindow.postMessage(message, 'https://utteranc.es');
iframe.contentWindow.postMessage(message, '!{utterancesOriginUrl}')
}
}
btf.addGlobalFn('themeChange', utterancesTheme, 'utterances')
btf.addGlobalFn('themeChange', changeUtterancesTheme, 'utterances')
if ('!{use[0]}' === 'Utterances' || !!{lazyload}) {
if (!{lazyload}) btf.loadComment(document.getElementById('utterances-wrap'), loadUtterances)

@ -19,7 +19,7 @@ script.
waline.destroy()
}
btf.addGlobalFn('pjax', destroyWaline, 'destroyWaline')
btf.addGlobalFn('pjaxSendOnce', destroyWaline, 'destroyWaline')
}
const loadWaline = () => {

@ -1,18 +1,19 @@
if theme.mathjax && theme.mathjax.enable
if theme.mathjax.per_page
if is_post() || is_page()
include ./mathjax.pug
else
if page.mathjax
include ./mathjax.pug
case theme.math.use
when 'mathjax'
if theme.math.per_page
if is_post() || is_page()
include ./mathjax.pug
else
if page.mathjax
include ./mathjax.pug
if theme.katex && theme.katex.enable
if theme.katex.per_page
if is_post() || is_page()
include ./katex.pug
else
if page.katex
include ./katex.pug
when 'katex'
if theme.math.per_page
if is_post() || is_page()
include ./katex.pug
else
if page.katex
include ./katex.pug
if theme.mermaid.enable
include ./mermaid.pug

@ -1,2 +1,16 @@
link(rel="stylesheet" type="text/css" href=url_for(theme.asset.katex))
script(src=url_for(theme.asset.katex_copytex))
script.
(async () => {
const showKatex = () => {
const mathElements = document.querySelectorAll('#article-container .katex')
mathElements.length && mathElements.forEach((el) => {
el.classList.add('katex-show')
})
}
if (!window.katex_js_css) {
window.katex_js_css = true
await btf.getCSS('!{url_for(theme.asset.katex)}')
if (!{theme.math.katex.copy_tex}) await btf.getScript('!{url_for(theme.asset.katex_copytex)}')
}
showKatex()
})()

@ -1,4 +1,5 @@
//- Mathjax 3
- const { tags, enableMenu } = theme.math.mathjax
script.
(() => {
const loadMathjax = () => {
@ -6,12 +7,13 @@ script.
window.MathJax = {
tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']],
tags: 'ams'
tags: '!{tags}',
},
chtml: {
scale: 1.1
},
options: {
enableMenu: !{enableMenu},
renderActions: {
findScript: [10, doc => {
for (const node of document.querySelectorAll('script[type^="math/tex"]')) {

@ -11,18 +11,12 @@ script.
const mermaidDefinition = mermaidThemeConfig + mermaidSrc.textContent
const renderFn = mermaid.render(mermaidID, mermaidDefinition)
const renderV10 = () => {
renderFn.then(({svg}) => {
mermaidSrc.insertAdjacentHTML('afterend', svg)
})
}
const renderV9 = svg => {
const renderMermaid = svg => {
mermaidSrc.insertAdjacentHTML('afterend', svg)
}
typeof renderFn === 'string' ? renderV9(renderFn) : renderV10()
// mermaid v9 and v10 compatibility
typeof renderFn === 'string' ? renderMermaid(renderFn) : renderFn.then(({svg}) => renderMermaid(svg))
})
}
@ -31,9 +25,13 @@ script.
if (codeMermaidEle.length === 0) return
codeMermaidEle.forEach(ele => {
const preEle = document.createElement('pre')
preEle.className = 'mermaid-src'
preEle.hidden = true
preEle.textContent = ele.textContent
const newEle = document.createElement('div')
newEle.className = 'mermaid-wrap'
newEle.innerHTML = `<pre class="mermaid-src" hidden>${ele.textContent}</pre>`
newEle.appendChild(preEle)
ele.parentNode.replaceWith(newEle)
})
}

@ -1,6 +1,6 @@
- const { server, site, option } = theme.artalk
- const avatarCdn = option !== null && option.gravatar && option.gravatar.mirror
- const avatarDefault = option !== null && option.gravatar && (option.gravatar.params || option.gravatar.default)
- const avatarCdn = (option !== null && option.gravatar && option.gravatar.mirror) || ''
- const avatarDefault = (option !== null && option.gravatar && (option.gravatar.params || option.gravatar.default)) || ''
script.
window.addEventListener('load', () => {
@ -25,7 +25,7 @@ script.
for (let i = 0; i < array.length; i++) {
result += '<div class=\'aside-list-item\'>'
if (!{theme.newest_comments.avatar}) {
if (!{theme.aside.card_newest_comments.avatar}) {
const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}'
result += `<a href='${array[i].url}' class='thumbnail'><img ${name}='${array[i].avatar}' alt='${array[i].nick}'></a>`
}
@ -60,7 +60,7 @@ script.
const searchParams = new URLSearchParams({
'site_name': '!{site}',
'limit': '!{theme.newest_comments.limit}',
'limit': '!{theme.aside.card_newest_comments.limit}',
})
const getComment = async () => {
@ -69,8 +69,8 @@ script.
const result = await res.json()
const avatarStr = await getSetting()
const { mirror, params, default:defaults } = avatarStr.frontend_conf.gravatar
const avatarCdn = !{avatarCdn} || mirror
let avatarDefault = !{avatarDefault} || params || defaults
const avatarCdn = '!{avatarCdn}' || mirror
let avatarDefault = '!{avatarDefault}' || params || defaults
avatarDefault = avatarDefault.startsWith('d=') ? avatarDefault : `d=${avatarDefault}`
const artalk = result.data.map(function (e) {
return {
@ -81,7 +81,7 @@ script.
'date': e.date,
}
})
btf.saveToLocal.set('artalk-newest-comments', JSON.stringify(artalk), !{theme.newest_comments.storage}/(60*24))
btf.saveToLocal.set('artalk-newest-comments', JSON.stringify(artalk), !{theme.aside.card_newest_comments.storage}/(60*24))
generateHtml(artalk)
} catch (e) {
console.log(e)

@ -15,7 +15,7 @@ script.
}
const getComment = () => {
fetch('https://disqus.com/api/3.0/forums/listPosts.json?forum=!{forum}&related=thread&limit=!{theme.newest_comments.limit}&api_key=!{apiKey}')
fetch('https://disqus.com/api/3.0/forums/listPosts.json?forum=!{forum}&related=thread&limit=!{theme.aside.card_newest_comments.limit}&api_key=!{apiKey}')
.then(response => response.json())
.then(data => {
const disqusArray = data.response.map(item => {
@ -28,7 +28,7 @@ script.
}
})
btf.saveToLocal.set('disqus-newest-comments', JSON.stringify(disqusArray), !{theme.newest_comments.storage}/(60*24))
btf.saveToLocal.set('disqus-newest-comments', JSON.stringify(disqusArray), !{theme.aside.card_newest_comments.storage}/(60*24))
generateHtml(disqusArray)
}).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list')
@ -43,7 +43,7 @@ script.
for (let i = 0; i < array.length; i++) {
result += '<div class=\'aside-list-item\'>'
if (!{theme.newest_comments.avatar}) {
if (!{theme.aside.card_newest_comments.avatar}) {
const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}'
result += `<a href='${array[i].url}' class='thumbnail'><img ${name}='${array[i].avatar}' alt='${array[i].nick}'></a>`
}

@ -35,13 +35,13 @@ script.
}
})
btf.saveToLocal.set('github-newest-comments', JSON.stringify(array), !{theme.newest_comments.storage}/(60*24))
btf.saveToLocal.set('github-newest-comments', JSON.stringify(array), !{theme.aside.card_newest_comments.storage}/(60*24))
generateHtml(array)
});
}
const getComment = () => {
fetch('https://api.github.com/repos/!{userRepo}/issues/comments?sort=updated&direction=desc&per_page=!{theme.newest_comments.limit}&page=1',{
fetch('https://api.github.com/repos/!{userRepo}/issues/comments?sort=updated&direction=desc&per_page=!{theme.aside.card_newest_comments.limit}&page=1',{
"headers": {
Accept: 'application/vnd.github.v3.html+json'
}
@ -72,7 +72,7 @@ script.
for (let i = 0; i < array.length; i++) {
result += '<div class=\'aside-list-item\'>'
if (!{theme.newest_comments.avatar}) {
if (!{theme.aside.card_newest_comments.avatar}) {
const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}'
result += `<a href='${array[i].url}' class='thumbnail'><img ${name}='${array[i].avatar}' alt='${array[i].nick}'></a>`
}

@ -23,7 +23,7 @@ script.
for (let i = 0; i < array.length; i++) {
result += '<div class=\'aside-list-item\'>'
if (!{theme.newest_comments.avatar}) {
if (!{theme.aside.card_newest_comments.avatar}) {
const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}'
result += `<a href='${array[i].url}' class='thumbnail'><img ${name}='${array[i].avatar}' alt='${array[i].nick}'></a>`
}
@ -44,7 +44,7 @@ script.
}
const getComment = () => {
fetch('!{host}/api/v1/last/!{theme.newest_comments.limit}?site=!{siteId}')
fetch('!{host}/api/v1/last/!{theme.aside.card_newest_comments.limit}?site=!{siteId}')
.then(response => response.json())
.then(data => {
const remark42 = data.map(function (e) {
@ -56,7 +56,7 @@ script.
'date': e.time,
}
})
btf.saveToLocal.set('remark42-newest-comments', JSON.stringify(remark42), !{theme.newest_comments.storage}/(60*24))
btf.saveToLocal.set('remark42-newest-comments', JSON.stringify(remark42), !{theme.aside.card_newest_comments.storage}/(60*24))
generateHtml(remark42)
}).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list')

@ -5,7 +5,7 @@ script.
content = content.replace(/<img.*?src="(.*?)"?[^\>]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link
content = content.replace(/<a[^>]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[!{_p("aside.card_newest_comments.link")}]') // replace url
content = content.replace(/<pre><code>.*?<\/pre>/gi, '[!{_p("aside.card_newest_comments.code")}]') // replace code
content = content.replace(/<pre><code>.*?<\/pre>/gi, '[!{_p("aside.card_aside.card_aside.card_newest_comments.code")}]') // replace code
content = content.replace(/<[^>]+>/g,"") // remove html tag
if (content.length > 150) {
@ -19,7 +19,7 @@ script.
twikoo.getRecentComments({
envId: '!{theme.twikoo.envId}',
region: '!{theme.twikoo.region}',
pageSize: !{theme.newest_comments.limit},
pageSize: !{theme.aside.card_newest_comments.limit},
includeReply: true
}).then(function (res) {
const twikooArray = res.map(e => {
@ -32,7 +32,7 @@ script.
}
})
btf.saveToLocal.set('twikoo-newest-comments', JSON.stringify(twikooArray), !{theme.newest_comments.storage}/(60*24))
btf.saveToLocal.set('twikoo-newest-comments', JSON.stringify(twikooArray), !{theme.aside.card_newest_comments.storage}/(60*24))
generateHtml(twikooArray)
}).catch(function (err) {
const $dom = document.querySelector('#card-newest-comments .aside-list')
@ -54,7 +54,7 @@ script.
for (let i = 0; i < array.length; i++) {
result += '<div class=\'aside-list-item\'>'
if (!{theme.newest_comments.avatar}) {
if (!{theme.aside.card_newest_comments.avatar}) {
const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}'
result += `<a href='${array[i].url}' class='thumbnail'><img ${name}='${array[i].avatar}' alt='${array[i].nick}'></a>`
}

@ -31,7 +31,7 @@ script.
for (let i = 0; i < array.length; i++) {
result += '<div class=\'aside-list-item\'>'
if (!{theme.newest_comments.avatar}) {
if (!{theme.aside.card_newest_comments.avatar}) {
const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}'
result += `<a href='${array[i].url}' class='thumbnail'><img ${name}='${array[i].avatar}' alt='${array[i].nick}'></a>`
}
@ -63,7 +63,7 @@ script.
},
}
fetch(`${serverURL}/1.1/classes/Comment?limit=!{theme.newest_comments.limit}&order=-createdAt`,settings)
fetch(`${serverURL}/1.1/classes/Comment?limit=!{theme.aside.card_newest_comments.limit}&order=-createdAt`,settings)
.then(response => response.json())
.then(data => {
const valineArray = data.results.map(function (e) {
@ -75,7 +75,7 @@ script.
'date': e.updatedAt,
}
})
btf.saveToLocal.set('valine-newest-comments', JSON.stringify(valineArray), !{theme.newest_comments.storage}/(60*24))
btf.saveToLocal.set('valine-newest-comments', JSON.stringify(valineArray), !{theme.aside.card_newest_comments.storage}/(60*24))
generateHtml(valineArray)
}).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list')

@ -23,7 +23,7 @@ script.
for (let i = 0; i < array.length; i++) {
result += '<div class=\'aside-list-item\'>'
if (!{theme.newest_comments.avatar}) {
if (!{theme.aside.card_newest_comments.avatar}) {
const name = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}'
result += `<a href='${array[i].url}' class='thumbnail'><img ${name}='${array[i].avatar}' alt='${array[i].nick}'></a>`
}
@ -45,7 +45,7 @@ script.
const getComment = async () => {
try {
const res = await fetch('!{serverURL}/api/comment?type=recent&count=!{theme.newest_comments.limit}', { method: 'GET' })
const res = await fetch('!{serverURL}/api/comment?type=recent&count=!{theme.aside.card_newest_comments.limit}', { method: 'GET' })
const result = await res.json()
const walineArray = result.data.map(e => {
return {
@ -56,7 +56,7 @@ script.
'date': e.time || e.insertedAt
}
})
btf.saveToLocal.set('waline-newest-comments', JSON.stringify(walineArray), !{theme.newest_comments.storage}/(60*24))
btf.saveToLocal.set('waline-newest-comments', JSON.stringify(walineArray), !{theme.aside.card_newest_comments.storage}/(60*24))
generateHtml(walineArray)
} catch (err) {
console.error(err)

@ -32,7 +32,7 @@ script.
document.addEventListener('pjax:send', function () {
// removeEventListener
btf.removeGlobalFnEvent('pjax')
btf.removeGlobalFnEvent('pjaxSendOnce')
btf.removeGlobalFnEvent('themeChange')
//reset readmode
@ -43,6 +43,7 @@ script.
})
document.addEventListener('pjax:complete', () => {
btf.removeGlobalFnEvent('pjaxCompleteOnce')
document.querySelectorAll('script[data-pjax]').forEach(item => {
const newScript = document.createElement('script')
const content = item.text || item.textContent || item.innerHTML || ""

@ -1,4 +1,4 @@
- const { appId, apiKey, indexName, option } = theme.docsearch
- const { placeholder, docsearch: { appId, apiKey, indexName, option } } = theme.search
.docsearch-wrap
#docsearch(style="display:none")
@ -11,6 +11,7 @@
apiKey: '!{apiKey}',
indexName: '!{indexName}',
container: '#docsearch',
placeholder: '!{ placeholder || _p("search.input_placeholder")}',
}, !{JSON.stringify(option)}))
const handleClick = () => {

@ -1,6 +1,7 @@
if theme.algolia_search.enable
include ./algolia.pug
else if theme.local_search.enable
include ./local-search.pug
else if theme.docsearch.enable
include ./docsearch.pug
case theme.search.use
when 'algolia_search'
include ./algolia.pug
when 'local_search'
include ./local-search.pug
when 'docsearch'
include ./docsearch.pug

@ -13,7 +13,7 @@
.search-wrap
#local-search-input
.local-search-box
input(placeholder=_p("search.local_search.input_placeholder") type="text").local-search-box--input
input(placeholder=theme.search.placeholder || _p("search.input_placeholder") type="text").local-search-box--input
hr
#local-search-results
#local-search-stats-wrap

@ -1,5 +1,9 @@
.post_share
if theme.sharejs.enable
include ./share-js.pug
else if theme.addtoany.enable
!=partial('includes/third-party/share/addtoany', {}, {cache: true})
- const { use } = theme.share
if use
.post-share
case use
when 'addtoany'
!=partial('includes/third-party/share/addtoany', {}, {cache: true})
when 'sharejs'
include ./share-js.pug

@ -1,4 +1,4 @@
- const coverVal = page.cover_type === 'img' ? page.cover : theme.avatar.img
.social-share(data-image=url_for(coverVal) data-sites= theme.sharejs.sites)
.social-share(data-image=url_for(coverVal) data-sites= theme.share.sharejs.sites)
link(rel='stylesheet' href=url_for(theme.asset.sharejs_css) media="print" onload="this.media='all'")
script(src=url_for(theme.asset.sharejs) defer)

@ -3,7 +3,7 @@
script.
window.typedJSFn = {
init: (str) => {
init: str => {
window.typed = new Typed('#subtitle', Object.assign({
strings: str,
startDelay: 300,
@ -12,7 +12,7 @@ script.
backSpeed: 50,
}, !{JSON.stringify(typed_option)}))
},
run: (subtitleType) => {
run: subtitleType => {
if (!{effect}) {
if (typeof Typed === 'function') {
subtitleType()
@ -24,7 +24,7 @@ script.
}
}
}
btf.addGlobalFn('pjaxSend', () => { typed.destroy() }, 'typedDestroy')
btf.addGlobalFn('pjaxSendOnce', () => { typed.destroy() }, 'typedDestroy')
case source
when 1

@ -1,12 +1,11 @@
if theme.aside.card_author.enable
.card-widget.card-info
.is-center
.avatar-img
img(src=url_for(theme.avatar.img) onerror=`this.onerror=null;this.src='` + url_for(theme.error_img.flink) + `'` alt="avatar")
.author-info__name= config.author
.author-info__description!= theme.aside.card_author.description || config.description
.card-widget.card-info.is-center
.avatar-img
img(src=url_for(theme.avatar.img) onerror=`this.onerror=null;this.src='` + url_for(theme.error_img.flink) + `'` alt="avatar")
.author-info-name= config.author
.author-info-description!= theme.aside.card_author.description || config.description
.card-info-data.site-data.is-center
.site-data
a(href=url_for(config.archive_dir) + '/')
.headline= _p('aside.articles')
.length-num= site.posts.length
@ -23,5 +22,5 @@ if theme.aside.card_author.enable
span=theme.aside.card_author.button.text
if(theme.social)
.card-info-social-icons.is-center
!=partial('includes/header/social', {}, {cache: true})
.card-info-social-icons
!=partial('includes/header/social', {}, {cache: true})

@ -1,4 +1,4 @@
if theme.newest_comments.enable && theme.comments.use && !['Livere','Facebook Comments','Giscus'].includes(theme.comments.use[0])
if theme.aside.card_newest_comments.enable && theme.comments.use && !['Livere','Facebook Comments','Giscus'].includes(theme.comments.use[0])
.card-widget#card-newest-comments
.item-headline
i.fas.fa-comment-dots

@ -8,10 +8,10 @@ if theme.aside.card_webinfo.enable
.webinfo-item
.item-name= _p('aside.card_webinfo.article_name') + " :"
.item-count= site.posts.length
if theme.runtimeshow.enable
if theme.aside.card_webinfo.runtime_date
.webinfo-item
.item-name= _p('aside.card_webinfo.runtime.name') + " :"
.item-count#runtimeshow(data-publishDate=date_xml(theme.runtimeshow.publish_date))
.item-count#runtimeshow(data-publishDate=date_xml(theme.aside.card_webinfo.runtime_date))
i.fa-solid.fa-spinner.fa-spin
if theme.wordcount.enable && theme.wordcount.total_wordcount
.webinfo-item

@ -1,7 +1,5 @@
extends includes/layout.pug
block content
include ./includes/mixins/post-ui.pug
#recent-posts.recent-posts
+postUI
include includes/pagination.pug
include ./includes/mixins/indexPostUI.pug
+indexPostUI

@ -1,20 +1,32 @@
extends includes/layout.pug
block content
#page
if top_img === false
- const noCardLayout = ['shuoshuo', '404'].includes(page.type) ? 'nc' : ''
- var commentsJsLoad = false
mixin commentLoad
if page.comments !== false && theme.comments.use
- commentsJsLoad = true
!=partial('includes/third-party/comments/index', {}, {cache: true})
#page(class=noCardLayout)
if top_img === false && page.title
h1.page-title= page.title
case page.type
when 'tags'
include includes/page/tags.pug
+commentLoad
when 'link'
include includes/page/flink.pug
+commentLoad
when 'categories'
include includes/page/categories.pug
+commentLoad
when '404'
include includes/page/404.pug
when 'shuoshuo'
include includes/page/shuoshuo.pug
default
include includes/page/default-page.pug
if page.comments !== false && theme.comments && theme.comments.use
- var commentsJsLoad = true
!=partial('includes/third-party/comments/index', {}, {cache: true})
+commentLoad

@ -8,7 +8,7 @@ block content
article#article-container.post-content!=page.content
include includes/post/post-copyright.pug
.tag_share
if (theme.post_meta.post.tags)
if (page.tags.length > 0 && theme.post_meta.post.tags)
.post-meta__tag-list
each item, index in page.tags.data
a(href=url_for(item.path)).post-meta__tags #[=item.name]
@ -26,7 +26,7 @@ block content
if theme.related_post && theme.related_post.enable
!= related_posts(page,site.posts)
if page.comments !== false && theme.comments && theme.comments.use
if page.comments !== false && theme.comments.use
- var commentsJsLoad = true
!=partial('includes/third-party/comments/index', {}, {cache: true})

@ -2,10 +2,8 @@ extends includes/layout.pug
block content
if theme.tag_ui == 'index'
include ./includes/mixins/post-ui.pug
#recent-posts.recent-posts
+postUI
include includes/pagination.pug
include ./includes/mixins/indexPostUI.pug
+indexPostUI
else
include ./includes/mixins/article-sort.pug
#tag

@ -1,6 +1,6 @@
{
"name": "hexo-theme-butterfly",
"version": "4.14.0-b3",
"version": "5.0.0-b1",
"description": "A Simple and Card UI Design theme for Hexo",
"main": "package.json",
"scripts": {

@ -1,7 +1,7 @@
abcjs_basic_js:
name: abcjs
file: dist/abcjs-basic-min.js
version: 6.3.0
version: 6.4.1
activate_power_mode:
name: butterfly-extsrc
file: dist/activate-power-mode.min.js
@ -9,7 +9,7 @@ activate_power_mode:
algolia_search:
name: algoliasearch
file: dist/algoliasearch-lite.umd.js
version: 4.23.2
version: 4.24.0
aplayer_css:
name: aplayer
file: dist/APlayer.min.css
@ -21,11 +21,11 @@ aplayer_js:
artalk_css:
name: artalk
file: dist/Artalk.css
version: 2.8.3
version: 2.8.7
artalk_js:
name: artalk
file: dist/Artalk.js
version: 2.8.3
version: 2.8.7
blueimp_md5:
name: blueimp-md5
file: js/md5.min.js
@ -62,26 +62,26 @@ docsearch_css:
name: '@docsearch/css'
other_name: docsearch-css
file: dist/style.css
version: 3.6.0
version: 3.6.1
docsearch_js:
name: '@docsearch/js'
other_name: docsearch-js
file: dist/umd/index.js
version: 3.6.0
version: 3.6.1
egjs_infinitegrid:
name: '@egjs/infinitegrid'
other_name: egjs-infinitegrid
file: dist/infinitegrid.min.js
version: 4.11.1
version: 4.12.0
fancybox:
name: '@fancyapps/ui'
file: dist/fancybox/fancybox.umd.js
version: 5.0.35
version: 5.0.36
other_name: fancyapps-ui
fancybox_css:
name: '@fancyapps/ui'
file: dist/fancybox/fancybox.css
version: 5.0.35
version: 5.0.36
other_name: fancyapps-ui
fireworks:
name: butterfly-extsrc
@ -91,7 +91,7 @@ fontawesome:
name: '@fortawesome/fontawesome-free'
file: css/all.min.css
other_name: font-awesome
version: 6.5.1
version: 6.6.0
gitalk:
name: gitalk
file: dist/gitalk.min.js
@ -107,21 +107,21 @@ instantpage:
instantsearch:
name: instantsearch.js
file: dist/instantsearch.production.min.js
version: 4.66.1
version: 4.73.3
katex:
name: katex
file: dist/katex.min.css
other_name: KaTeX
version: 0.16.10
version: 0.16.11
katex_copytex:
name: katex
file: dist/contrib/copy-tex.min.js
other_name: KaTeX
version: 0.16.10
version: 0.16.11
lazyload:
name: vanilla-lazyload
file: dist/lazyload.iife.min.js
version: 19.0.5
version: 19.1.3
mathjax:
name: mathjax
file: es5/tex-mml-chtml.js
@ -133,7 +133,7 @@ medium_zoom:
mermaid:
name: mermaid
file: dist/mermaid.min.js
version: 10.9.0
version: 10.9.1
meting_js:
name: butterfly-extsrc
file: metingjs/dist/Meting.min.js
@ -190,7 +190,7 @@ snackbar_css:
twikoo:
name: twikoo
file: dist/twikoo.all.min.js
version: 1.6.32
version: 1.6.38
typed:
name: typed.js
file: dist/typed.umd.js
@ -198,14 +198,14 @@ typed:
valine:
name: valine
file: dist/Valine.min.js
version: 1.5.1
version: 1.5.2
waline_css:
name: '@waline/client'
file: dist/waline.css
other_name: waline
version: 3.1.3
version: 3.3.0
waline_js:
name: '@waline/client'
file: dist/waline.js
other_name: waline
version: 3.1.3
version: 3.3.0

@ -12,7 +12,9 @@ hexo.extend.generator.register('404', function (locals) {
layout: ['page'],
data: {
type: '404',
top_img: false
top_img: false,
comments: false,
aside: false
}
}
})

@ -1,3 +1,5 @@
const { deepMerge } = require('hexo-util')
hexo.extend.filter.register('before_generate', () => {
const defaultConfig = {
nav: {
@ -6,33 +8,36 @@ hexo.extend.filter.register('before_generate', () => {
fixed: false
},
menu: null,
highlight_theme: 'light',
highlight_theme_macStyle: false,
highlight_copy: true,
highlight_lang: true,
highlight_shrink: false,
highlight_fullpage: true,
highlight_height_limit: false,
code_word_wrap: false,
code_blocks: {
theme: 'light',
macStyle: false,
height_limit: false,
word_wrap: false,
copy: true,
language: true,
shrink: false,
fullpage: false
},
social: null,
favicon: '/img/favicon.png',
avatar: {
img: 'https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png',
img: '/img/butterfly-icon.png',
effect: false
},
disable_top_img: false,
index_img: null,
default_top_img: null,
index_img: null,
archive_img: null,
tag_img: null,
tag_per_img: null,
category_img: null,
category_per_img: null,
footer_img: false,
background: null,
cover: {
index_enable: true,
aside_enable: true,
archives_enable: true,
position: 'both',
default_cover: null
},
error_img: {
@ -42,7 +47,7 @@ hexo.extend.filter.register('before_generate', () => {
error_404: {
enable: false,
subtitle: 'Page Not Found',
background: 'https://i.loli.net/2020/05/19/aKOcLiyPl2JQdFD.png'
background: '/img/error-page.png'
},
post_meta: {
page: {
@ -61,22 +66,20 @@ hexo.extend.filter.register('before_generate', () => {
label: true
}
},
index_site_info_top: null,
index_top_img_height: null,
subtitle: {
enable: false,
effect: true,
typed_option: null,
source: false,
sub: null
},
index_layout: 3,
index_post_content: {
method: 3,
length: 500
},
anchor: {
auto_update: false,
click_to_scroll: false
},
photofigcaption: false,
copy: {
enable: true,
copyright: {
enable: false,
limit_count: 50
}
},
toc: {
post: true,
page: false,
@ -110,7 +113,7 @@ hexo.extend.filter.register('before_generate', () => {
noticeOutdate: {
enable: false,
style: 'flat',
limit_day: 500,
limit_day: 365,
position: 'top',
message_prev: 'It has been',
message_next: 'days since the last update, the content of the article may be outdated.'
@ -118,7 +121,7 @@ hexo.extend.filter.register('before_generate', () => {
footer: {
owner: {
enable: true,
since: 2020
since: 2019
},
custom_text: null,
copyright: true
@ -154,6 +157,13 @@ hexo.extend.filter.register('before_generate', () => {
sort: 'date',
sort_order: null
},
card_newest_comments: {
enable: false,
sort_order: null,
limit: 6,
storage: 10,
avatar: true
},
card_categories: {
enable: true,
limit: 8,
@ -176,35 +186,21 @@ hexo.extend.filter.register('before_generate', () => {
limit: 8,
sort_order: null
},
card_webinfo: {
enable: true,
post_count: true,
last_push_date: true,
sort_order: null
},
card_post_series: {
enable: true,
series_title: false,
orderBy: 'date',
order: -1
},
card_webinfo: {
enable: true,
post_count: true,
last_push_date: true,
sort_order: null,
runtime_date: null
}
},
busuanzi: {
site_uv: true,
site_pv: true,
page_pv: true
},
runtimeshow: {
enable: false,
publish_date: null
},
newest_comments: {
enable: false,
sort_order: null,
limit: 6,
storage: 10,
avatar: true
},
rightside_bottom: null,
translate: {
enable: false,
default: '繁',
@ -227,42 +223,68 @@ hexo.extend.filter.register('before_generate', () => {
hide: null,
show: null
},
mathjax: {
enable: false,
per_page: false
},
katex: {
enable: false,
per_page: false,
hide_scrollbar: true
anchor: {
auto_update: false,
click_to_scroll: false
},
algolia_search: {
enable: false,
hits: {
per_page: 6
photofigcaption: false,
copy: {
enable: true,
copyright: {
enable: false,
limit_count: 150
}
},
local_search: {
wordcount: {
enable: false,
preload: false,
top_n_per_article: 1,
unescape: false,
CDN: null
post_wordcount: true,
min2read: true,
total_wordcount: true
},
docsearch: {
enable: false,
appId: null,
apiKey: null,
indexName: null,
option: null
busuanzi: {
site_uv: true,
site_pv: true,
page_pv: true
},
sharejs: {
enable: true,
sites: 'facebook,twitter,wechat,weibo,qq'
math: {
use: null,
per_page: true,
hide_scrollbar: false,
mathjax: {
enableMenu: true,
tags: 'none'
},
katex: {
copy_tex: false
}
},
addtoany: {
enable: false,
item: 'facebook,twitter,wechat,sina_weibo,facebook_messenger,email,copy_link'
search: {
use: null,
placeholder: null,
algolia_search: {
hitsPerPage: 6
},
local_search: {
preload: false,
top_n_per_article: 1,
unescape: false,
CDN: null
},
docsearch: {
appId: null,
apiKey: null,
indexName: null,
option: null
}
},
share: {
use: 'sharejs',
sharejs: {
sites: 'facebook,twitter,wechat,weibo,qq'
},
addtoany: {
item: 'facebook,twitter,wechat,sina_weibo,facebook_messenger,email,copy_link'
}
},
comments: {
use: null,
@ -310,7 +332,9 @@ hexo.extend.filter.register('before_generate', () => {
repo: null,
issue_term: 'pathname',
light_theme: 'github-light',
dark_theme: 'photon-dark'
dark_theme: 'photon-dark',
js: null,
option: null
},
facebook_comments: {
app_id: null,
@ -329,10 +353,9 @@ hexo.extend.filter.register('before_generate', () => {
repo: null,
repo_id: null,
category_id: null,
theme: {
light: 'light',
dark: 'dark'
},
light_theme: 'light',
dark_theme: 'dark',
js: null,
option: null
},
remark42: {
@ -346,26 +369,24 @@ hexo.extend.filter.register('before_generate', () => {
visitor: false,
option: null
},
chat_btn: false,
chat_hide_show: false,
chat: {
use: null,
rightside_button: false,
button_hide_show: false
},
chatra: {
enable: false,
id: null
},
tidio: {
enable: false,
public_key: null
},
daovoice: {
enable: false,
app_id: null
},
crisp: {
enable: false,
website_id: null
},
messenger: {
enable: false,
pageID: null,
lang: 'zh_TW'
},
@ -380,20 +401,48 @@ hexo.extend.filter.register('before_generate', () => {
client: null,
enable_page_level_ads: true
},
ad: {
index: null,
aside: null,
post: null
},
site_verification: null,
index_site_info_top: null,
index_top_img_height: null,
category_ui: null,
tag_ui: null,
rounded_corners_ui: true,
text_align_justify: false,
background: null,
footer_bg: false,
mask: {
header: true,
footer: true
},
rightside_bottom: null,
preloader: {
enable: false,
source: 1,
pace_css_url: null
},
enter_transitions: true,
display_mode: 'light',
beautify: {
enable: false,
field: 'post',
'title-prefix-icon': null,
'title-prefix-icon-color': null
},
font: {
'global-font-size': null,
'code-font-size': null,
'font-family': null,
'code-font-family': null
},
blog_title_font: {
font_link: null,
'font-family': null
},
hr_icon: {
enable: true,
icon: null,
'icon-top': null
},
activate_power_mode: {
enable: false,
colorful: true,
@ -436,50 +485,9 @@ hexo.extend.filter.register('before_generate', () => {
random: false,
mobile: false
},
display_mode: 'light',
beautify: {
enable: false,
field: 'post',
'title-prefix-icon': null,
'title-prefix-icon-color': null
},
font: {
'global-font-size': null,
'code-font-size': null,
'font-family': null,
'code-font-family': null
},
blog_title_font: {
font_link: null,
'font-family': null
},
hr_icon: {
enable: true,
icon: null,
'icon-top': null
},
subtitle: {
enable: false,
effect: true,
typed_option: null,
source: false,
sub: null
},
preloader: {
enable: false,
source: 1,
pace_css_url: null
},
wordcount: {
enable: false,
post_wordcount: true,
min2read: true,
total_wordcount: true
},
medium_zoom: false,
fancybox: true,
lightbox: null,
series: {
enable: true,
enable: false,
orderBy: 'title',
order: 1,
number: true
@ -527,6 +535,14 @@ hexo.extend.filter.register('before_generate', () => {
placeholder: null,
blur: false
},
pwa: {
enable: false,
manifest: null,
apple_touch_icon: null,
favicon_32_32: null,
favicon_16_16: null,
mask_icon: null
},
Open_Graph_meta: {
enable: true,
option: null
@ -539,11 +555,11 @@ hexo.extend.filter.register('before_generate', () => {
CDN: {
internal_provider: 'local',
third_party_provider: 'jsdelivr',
version: true,
version: false,
custom_format: null,
option: null
}
}
hexo.theme.config = Object.assign(defaultConfig, hexo.theme.config)
hexo.theme.config = deepMerge(defaultConfig, hexo.theme.config)
}, 1)

@ -19,5 +19,6 @@ hexo.extend.filter.register('stylus:renderer', style => {
.define('$highlight_line_number', highlightLineNumber)
.define('$prismjs_enable', prismjsEnable)
.define('$prismjs_line_number', prismjsLineNumber)
.define('$language', hexo.config.language)
// .import(`${this.source_dir.replace(/\\/g, '/')}_data/css/*`)
})

@ -1,58 +0,0 @@
hexo.extend.helper.register('getArchiveLength', function () {
const { archive_generator: archiveGenerator } = hexo.config
if (archiveGenerator && archiveGenerator.enable === false) return this.site.posts.length
const { yearly, monthly, daily } = archiveGenerator
const { year, month, day } = this.page
if (yearly === false || !year) return this.site.posts.length
const posts = this.site.posts.sort('date')
const compareFunc = (type, y1, m1, d1, y2, m2, d2) => {
switch (type) {
case 'year':
return y1 === y2
case 'month':
return y1 === y2 && m1 === m2
case 'day':
return y1 === y2 && m1 === m2 && d1 === d2
default:
return false
}
}
const generateDateObj = (type) => {
return posts.reduce((dateObj, post) => {
const date = post.date.clone()
const year = date.year()
const month = date.month() + 1
const day = date.date()
const lastData = dateObj[dateObj.length - 1]
if (!lastData || !compareFunc(type, lastData.year, lastData.month, lastData.day, year, month, day)) {
const name = type === 'year' ? year : type === 'month' ? `${year}-${month}` : `${year}-${month}-${day}`
dateObj.push({
name,
year,
month,
day,
count: 1
})
} else {
lastData.count++
}
return dateObj
}, [])
}
const data = this.fragment_cache('createArchiveObj', () => {
const dateObjs = []
if (yearly) dateObjs.push(...generateDateObj('year'))
if (monthly) dateObjs.push(...generateDateObj('month'))
if (daily) dateObjs.push(...generateDateObj('day'))
return dateObjs
})
const name = month ? (day ? `${year}-${month}-${day}` : `${year}-${month}`) : year
return data.find(item => item.name === name).count
})

@ -0,0 +1,45 @@
hexo.extend.helper.register('getArchiveLength', function () {
const archiveGenerator = hexo.config.archive_generator
const posts = this.site.posts
const { yearly, monthly, daily } = archiveGenerator
const { year, month, day } = this.page
// Archives Page
if (!year) return posts.length
// Function to generate a unique key based on the granularity
const getKey = (post, type) => {
const date = post.date.clone()
const y = date.year()
const m = date.month() + 1
const d = date.date()
if (type === 'year') return `${y}`
if (type === 'month') return `${y}-${m}`
if (type === 'day') return `${y}-${m}-${d}`
}
// Create a map to count posts per period
const mapData = this.fragment_cache('createArchiveObj', () => {
const map = new Map()
posts.forEach(post => {
const keyYear = getKey(post, 'year')
const keyMonth = getKey(post, 'month')
const keyDay = getKey(post, 'day')
if (yearly) map.set(keyYear, (map.get(keyYear) || 0) + 1)
if (monthly) map.set(keyMonth, (map.get(keyMonth) || 0) + 1)
if (daily) map.set(keyDay, (map.get(keyDay) || 0) + 1)
})
return map
})
// Determine the appropriate key to fetch based on current page context
let key
if (yearly && year) key = `${year}`
if (monthly && month) key = `${year}-${month}`
if (daily && day) key = `${year}-${month}-${day}`
// Return the count for the current period or default to the total posts
return mapData.get(key) || posts.length
})

@ -1,6 +1,12 @@
/**
* Butterfly
* inject js to head
*
* addGlobalFn
* pjaxSendOnce - remove in pjaxSend
* pjaxCompleteOnce - remove in pjaxComplete
* pjaxSend - run in pjaxSend
* pjaxComplete - run in pjaxComplete
*/
'use strict'

@ -1,18 +1,10 @@
'use strict'
const { stripHTML, escapeHTML, prettyUrls } = require('hexo-util')
const { stripHTML, prettyUrls, truncate } = require('hexo-util')
const crypto = require('crypto')
hexo.extend.helper.register('page_description', function () {
const { config, page } = this
let description = page.description || page.content || page.title || config.description
if (description) {
description = escapeHTML(stripHTML(description).substring(0, 150)
.trim()
).replace(/\n/g, ' ')
return description
}
hexo.extend.helper.register('truncate', (content, length) => {
return truncate(stripHTML(content), { length, separator: ' ' }).replace(/\n/g, ' ')
})
hexo.extend.helper.register('cloudTags', function (options = {}) {
@ -32,13 +24,26 @@ hexo.extend.helper.register('cloudTags', function (options = {}) {
sizes.push(length)
})
const getRandomColor = () => {
const randomColor = () => Math.floor(Math.random() * 201)
const r = randomColor()
const g = randomColor()
const b = randomColor()
// 確保顏色不是太暗,通過增加一個最低值
return `rgb(${Math.max(r, 50)}, ${Math.max(g, 50)}, ${Math.max(b, 50)})`
}
const generateStyle = (size, unit) => {
const fontSize = parseFloat(size.toFixed(2)) + unit
const color = getRandomColor()
return `font-size: ${fontSize}; color: ${color};`
}
const length = sizes.length - 1
source.sort(orderby, order).forEach(tag => {
const ratio = length ? sizes.indexOf(tag.length) / length : 0
const size = minfontsize + ((maxfontsize - minfontsize) * ratio)
let style = `font-size: ${parseFloat(size.toFixed(2))}${unit};`
const color = 'rgb(' + Math.floor(Math.random() * 201) + ', ' + Math.floor(Math.random() * 201) + ', ' + Math.floor(Math.random() * 201) + ')' // 0,0,0 -> 200,200,200
style += ` color: ${color}`
const style = generateStyle(size, unit)
result += `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}</a>`
})
return result
@ -84,5 +89,5 @@ hexo.extend.helper.register('findArchivesTitle', function (page, menu, date) {
hexo.extend.helper.register('isImgOrUrl', function (path) {
const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/i
return path.indexOf('//') !== -1 || imgTestReg.test(path)
return path.includes('//') || imgTestReg.test(path)
})

@ -8,9 +8,10 @@
hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
let relatedPosts = []
currentPost.tags.forEach(function (tag) {
const tagsData = currentPost.tags
tagsData.length && tagsData.forEach(function (tag) {
allPosts.forEach(function (post) {
if (isTagRelated(tag.name, post.tags)) {
if (currentPost.path !== post.path && isTagRelated(tag.name, post.tags)) {
const relatedPost = {
title: post.title,
path: post.path,
@ -24,13 +25,12 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
if (index !== -1) {
relatedPosts[index].weight += 1
} else {
if (currentPost.path !== post.path) {
relatedPosts.push(relatedPost)
}
relatedPosts.push(relatedPost)
}
}
})
})
if (relatedPosts.length === 0) {
return ''
}
@ -52,7 +52,7 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
for (let i = 0; i < Math.min(relatedPosts.length, limitNum); i++) {
const cover = relatedPosts[i].cover || 'var(--default-bg-color)'
const title = this.escape_html(relatedPosts[i].title)
result += `<div><a href="${this.url_for(relatedPosts[i].path)}" title="${title}">`
result += `<a href="${this.url_for(relatedPosts[i].path)}" title="${title}">`
if (relatedPosts[i].cover_type === 'img') {
result += `<img class="cover" src="${this.url_for(cover)}" alt="cover">`
} else {
@ -64,7 +64,7 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
result += `<div class="content is-center"><div class="date"><i class="fas fa-history fa-fw"></i> ${this.date(relatedPosts[i].updated, hexoConfig.date_format)}</div>`
}
result += `<div class="title">${title}</div>`
result += '</div></a></div>'
result += '</div></a>'
}
result += '</div></div>'
@ -72,29 +72,14 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
}
})
function isTagRelated (tagName, TBDtags) {
let result = false
TBDtags.forEach(function (tag) {
if (tagName === tag.name) {
result = true
}
})
return result
function isTagRelated (tagName, tags) {
return tags.some(tag => tag.name === tagName)
}
function findItem (arrayToSearch, attr, val) {
for (let i = 0; i < arrayToSearch.length; i++) {
if (arrayToSearch[i][attr] === val) {
return i
}
}
return -1
return arrayToSearch.findIndex(item => item[attr] === val)
}
function compare (attr) {
return function (a, b) {
const val1 = a[attr]
const val2 = b[attr]
return val2 - val1
}
return (a, b) => b[attr] - a[attr]
}

@ -19,6 +19,7 @@ const gallery = (args, content) => {
if (args[0] === 'url') {
[type, dataStr, button] = args // url,[link],[lazyload]
dataStr = urlFor(dataStr)
} else {
[button] = args // [lazyload]
const regex = /!\[(.*?)\]\(([^\s]*)\s*(?:["'](.*?)["']?)?\s*\)/g
@ -39,9 +40,7 @@ const gallery = (args, content) => {
}
return `<div class="gallery-container" data-type="${type}" data-button="${button}">
<div class="gallery-data">${dataStr}</div>
<div class="gallery-items">
</div>
<div class="gallery-items">${dataStr}</div>
</div>`
}

@ -8,7 +8,7 @@
const addLabel = args => {
const [text, className = 'default'] = args
return `<mark class="hl-label ${className}">${text}</mark> `
return `<mark class="hl-label ${className}">${text}</mark>`
}
hexo.extend.tag.register('label', addLabel, { ends: false })

@ -63,7 +63,7 @@ function series (args) {
result += `<li><a href="${urlFor(ele.path)}" title="${ele.title}">${ele.title}</a></li>`
})
return series.number ? `<ol>${result}</ol>` : `<ul>${result}</ul>`
return series.number ? `<ol class="series-items">${result}</ol>` : `<ul class="series-items">${result}</ul>`
}
hexo.extend.tag.register('series', series, { ends: false })

@ -9,7 +9,7 @@
const postTabs = (args, content) => {
const tabBlock = /<!--\s*tab (.*?)\s*-->\n([\w\W\s\S]*?)<!--\s*endtab\s*-->/g
args = args.join(' ').split(',')
const tabName = args[0]
const tabName = args[0] || 'tab'
const tabActive = Number(args[1]) || 0
const matches = []
let match
@ -18,8 +18,6 @@ const postTabs = (args, content) => {
let tabContent = ''
let noDefault = true
!tabName && hexo.log.warn('Tabs block must have unique name!')
while ((match = tabBlock.exec(content)) !== null) {
matches.push(match[1], match[2])
}
@ -29,34 +27,31 @@ const postTabs = (args, content) => {
let postContent = matches[i + 1]
let tabCaption = tabParameters[0] || ''
let tabIcon = tabParameters[1] || ''
let tabHref = ''
postContent = hexo.render.renderSync({ text: postContent, engine: 'markdown' }).trim()
tabId += 1
tabHref = (tabName + ' ' + tabId).toLowerCase().split(' ').join('-');
((tabCaption.length === 0) && (tabIcon.length === 0)) && (tabCaption = tabName + ' ' + tabId)
if (tabCaption.length === 0 && tabIcon.length === 0) tabCaption = tabName + ' ' + tabId
const isOnlyicon = tabIcon.length > 0 && tabCaption.length === 0 ? ' style="text-align: center;"' : ''
const icon = tabIcon.trim()
tabIcon.length > 0 && (tabIcon = `<i class="${icon}"${isOnlyicon}></i>`)
tabIcon.length > 0 && (tabIcon = `<i class="${icon}"></i>`)
let isActive = ''
if ((tabActive > 0 && tabActive === tabId) || (tabActive === 0 && tabId === 1)) {
isActive = ' active'
noDefault = false
}
tabNav += `<button type="button" class="tab ${isActive}" data-href="${tabHref}">${tabIcon + tabCaption.trim()}</button>`
tabContent += `<div class="tab-item-content${isActive}" id="${tabHref}">${postContent}</div>`
tabNav += `<button type="button" class="tab${isActive}">${tabIcon + tabCaption.trim()}</button>`
tabContent += `<div class="tab-item-content${isActive}">${postContent}</div>`
}
const toTop = '<div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div>'
tabNav = `<ul class="nav-tabs${noDefault ? ' no-default' : ''}">${tabNav}</ul>`
tabNav = `<div class="nav-tabs${noDefault ? ' no-default' : ''}">${tabNav}</div>`
tabContent = `<div class="tab-contents">${tabContent}</div>`
return `<div class="tabs" id="${tabName.toLowerCase().split(' ').join('-')}">${tabNav + tabContent + toTop}</div>`
return `<div class="tabs">${tabNav + tabContent + toTop}</div>`
}
hexo.extend.tag.register('tabs', postTabs, { ends: true })

@ -15,12 +15,16 @@
text-rendering: auto
-webkit-font-smoothing: antialiased
addBorderRadius(x = 6)
if hexo-config('rounded_corners_ui')
border-radius: unit(x, 'px')
// card hover
.cardHover
border-radius: 8px
background: var(--card-bg)
box-shadow: var(--card-box-shadow)
transition: all .3s
addBorderRadius(8)
&:hover
box-shadow: var(--card-hover-box-shadow)
@ -37,11 +41,10 @@
.postImgHover
&:hover
.cover
opacity: .8
opacity: .7
transform: scale(1.1)
.cover
position: absolute
width: 100%
height: 100%
opacity: .4
@ -96,6 +99,12 @@
transition: all 1s ease-in-out
@extend .fontawesomeIcon
.verticalCenter
position: absolute
top: 50%
width: 100%
transform: translate(0, -50%)
maxWidth600()
@media screen and (max-width: 600px)
{block}
@ -112,6 +121,10 @@ maxWidth1024()
@media screen and (max-width: 1024px)
{block}
minWidth1024()
@media screen and (min-width: 1024px)
{block}
maxWidth900()
@media screen and (max-width: 900px)
{block}
@ -261,4 +274,4 @@ if hexo-config('avatar.effect') == true
transform: translateX(200px)
100%
transform: translateX(0)
transform: translateX(0)

@ -15,7 +15,9 @@
--tab-button-hover-bg: $tab-button-hover-bg
--tab-button-active-bg: $tab-button-active-bg
--card-bg: $card-bg
--card-meta: $theme-meta-color
--sidebar-bg: $sidebar-background
--sidebar-menu-bg: $white
--btn-hover-color: $button-hover-color
--btn-color: $button-color
--btn-bg: $button-bg
@ -39,6 +41,7 @@
body
position: relative
overflow-y: scroll
min-height: 100%
background: var(--global-bg)
color: var(--font-color)
@ -52,6 +55,12 @@ body
user-select: none
-webkit-user-select: none
// scrollbar - firefox
@-moz-document url-prefix()
*
scrollbar-width: thin
scrollbar-color: var(--scrollbar-color) transparent
// scrollbar - chrome/safari
*::-webkit-scrollbar
width: 5px
@ -63,11 +72,6 @@ body
*::-webkit-scrollbar-track
background-color: transparent
// scrollbar - firefox
*
scrollbar-width: thin
scrollbar-color: var(--scrollbar-color) transparent
input::placeholder
color: var(--font-color)
@ -104,11 +108,34 @@ h6
overflow-x: scroll
margin: 0 0 20px
if hexo-config('rounded_corners_ui')
$borderRadius = 5px
border-radius: $borderRadius
table
border-radius: $borderRadius
thead > tr:first-child
th:first-child
border-top-left-radius: $borderRadius
th:last-child
border-top-right-radius: $borderRadius
tbody > tr:last-child
td:first-child
border-bottom-left-radius: $borderRadius
td:last-child
border-bottom-right-radius: $borderRadius
table
display: table
width: 100%
border-spacing: 0
border-collapse: collapse
border-collapse: separate
border-top: 1px solid var(--light-grey)
border-left: 1px solid var(--light-grey)
empty-cells: show
thead
@ -118,6 +145,8 @@ table
td
padding: 6px 12px
border: 1px solid var(--light-grey)
border-top: none
border-left: none
vertical-align: middle
*::selection
@ -147,8 +176,8 @@ if $site-name-font
#site-title,
#site-subtitle,
.site-name,
#aside-content .author-info__name,
#aside-content .author-info__description
#aside-content .author-info-name,
#aside-content .author-info-description
font-family: $site-name-font
.is-center
@ -183,10 +212,11 @@ if hexo-config('lazyload.enable') && hexo-config('lazyload.blur') && !hexo-confi
blockquote
margin: 0 0 20px
padding: 12px 15px
border-left: 3px solid $blockquote-padding-color
padding: 7px 15px
border-left: 4px solid $blockquote-padding-color
background-color: var(--blockquote-bg)
color: var(--blockquote-color)
addBorderRadius()
footer
cite

@ -1,6 +1,6 @@
$highlight_theme = hexo-config('highlight_theme')
$highlight_macstyle = hexo-config('highlight_theme_macStyle')
wordWrap = $highlight_enable && !$highlight_line_number && hexo-config('code_word_wrap')
$highlight_theme = hexo-config('code_blocks.theme')
$highlight_macstyle = hexo-config('code_blocks.macStyle')
wordWrap = $highlight_enable && !$highlight_line_number && hexo-config('code_blocks.word_wrap')
@require 'theme'
@ -47,9 +47,10 @@ $code-block
code
font-size: $code-font-size
font-family: $code-font-family !important
addBorderRadius()
code
padding: 2px 4px
padding: 2px 5px
background: $code-background
color: $code-foreground
@ -66,6 +67,7 @@ $code-block
figure.highlight
@extend $code-block
position: relative
addBorderRadius()
pre
margin: 0
@ -104,9 +106,10 @@ $code-block
background: var(--hltools-bg)
color: var(--hltools-color)
font-size: $code-font-size
overflow: hidden
& > *
margin: 0 3px
padding: 5px
i
cursor: pointer
@ -124,7 +127,7 @@ $code-block
if !$highlight_macstyle
& > .macStyle
margin: 0
padding: 0
.code-lang
flex: 1
@ -133,16 +136,17 @@ $code-block
font-size: 1.15em
user-select: none
-webkit-user-select: none
padding 2px
.copy-notice
padding-right: 2px
opacity: 0
transition: opacity .4s
if hexo-config('highlight_lang')
if hexo-config('code_blocks.language')
.code-lang
flex: 1
else if (!$highlight_macstyle && hexo-config('highlight_shrink') != 'none')
else if (!$highlight_macstyle && hexo-config('code_blocks.shrink') != 'none')
& > div:nth-child(2)
flex: 1
else
@ -168,8 +172,6 @@ if $highlight_macstyle
-webkit-transform: translateZ(0)
.highlight-tools
padding: 0 10px
.macStyle
display: flex
@ -191,15 +193,15 @@ if $highlight_macstyle
.mac-maximize
background: #35cd4b
if hexo-config('highlight_shrink') != 'none'
& > div:nth-child(2)
if hexo-config('code_blocks.shrink') != 'none'
& > :nth-child(2)
order: 8
&.closed
.expand
transform: rotate(90deg)
if hexo-config('highlight_height_limit')
if hexo-config('code_blocks.height_limit')
#article-container
.code-expand-btn
position: absolute
@ -228,7 +230,7 @@ if hexo-config('highlight_height_limit')
& ~ table,
& ~ pre
overflow: hidden
height: unit(hexo-config('highlight_height_limit'), px)
height: unit(hexo-config('code_blocks.height_limit'), px)
@keyframes code-expand-key
0%
@ -240,7 +242,7 @@ if hexo-config('highlight_height_limit')
100%
opacity: .6
if hexo-config('highlight_fullpage')
if hexo-config('code_blocks.fullpage')
#article-container
figure.highlight.code-fullpage
position: fixed

@ -1,6 +1,8 @@
figure.highlight
table
scrollbar-color: var(--hlscrollbar-bg) transparent
// scrollbar - firefox
@-moz-document url-prefix()
scrollbar-color: var(--hlscrollbar-bg) transparent
&::-webkit-scrollbar-thumb
background: var(--hlscrollbar-bg)

@ -6,7 +6,9 @@ if $highlight_theme != false
#article-container
pre[class*='language-']
scrollbar-color: var(--hlscrollbar-bg) transparent
// scrollbar - firefox
@-moz-document url-prefix()
scrollbar-color: var(--hlscrollbar-bg) transparent
&::-webkit-scrollbar-thumb
background: var(--hlscrollbar-bg)

@ -10,7 +10,7 @@
position: relative
line-height: $line-height-code-block
if hexo-config('code_word_wrap')
if hexo-config('code_blocks.word_wrap')
white-space: pre-wrap
else
white-space: inherit

@ -8,19 +8,14 @@
padding-right: 15px
+maxWidth900()
margin-top: 20px
width: 100%
> .card-widget:first-child
margin-top: 0
+maxWidth900()
margin-top: 20px
.card-widget
@extend .cardHover
position: relative
overflow: hidden
margin-top: 20px
margin-bottom: 20px
padding: 20px 24px
if hexo-config('aside.mobile') == false
@ -28,16 +23,19 @@
&:not(#card-toc)
display: none
&:last-child
margin-bottom: 0
.card-info
.author-info
&__name
&-name
font-weight: 500
font-size: 1.57em
&__description
&-description
margin-top: -.42em
.card-info-data
.site-data
margin: 14px 0 4px
.card-info-social-icons
@ -61,6 +59,7 @@
color: var(--btn-color)
text-align: center
line-height: 2.4
addBorderRadius(7)
&:hover
background-color: var(--btn-hover-color)
@ -86,6 +85,7 @@
a
display: inline-block
padding: 0 4px
line-height: 1.8
&:hover
color: $text-hover !important
@ -112,8 +112,9 @@
.thumbnail
overflow: hidden
width: w = 4.2em
width: w = 4em
height: w
addBorderRadius()
:first-child
@extend .imgHover
@ -130,14 +131,14 @@
& > time,
& > .name
display: block
color: $theme-meta-color
font-size: 85%
color: var(--card-meta)
font-size: .85em
& > .title,
& > .comment
@extend .limit-more-line
color: var(--font-color)
font-size: 95%
// font-size: 95%
line-height: 1.5
-webkit-line-clamp: 2
@ -158,13 +159,16 @@
a
display: flex
flex-direction: row
padding: 3px 10px
padding: 2px 8px
margin: 2px 0
color: var(--font-color)
transition: all .4s
transition: all .3s
addBorderRadius()
&:hover
padding: 3px 17px
padding: 2px 12px
background-color: var(--text-bg-hover)
color: var(--white)
span
@extend .limit-one-line
@ -288,9 +292,10 @@
.toc-link
display: block
margin: 4px 0
padding: 1px 6px
padding: 1px 8px
color: var(--toc-link-color)
transition: all .2s ease-in-out
addBorderRadius()
&:hover
color: $theme-color
@ -397,9 +402,9 @@
.card-recent-post
order: hexo-config('aside.card_recent_post.sort_order')
if hexo-config('newest_comments.sort_order')
if hexo-config('aside.card_newest_comments.sort_order')
#card-newest-comments
order: hexo-config('newest_comments.sort_order')
order: hexo-config('aside.card_newest_comments.sort_order')
if hexo-config('aside.card_categories.sort_order')
.card-categories

@ -1,17 +1,18 @@
// chat
if hexo-config('chat_btn') == true && hexo-config('chatra.enable')
#chatra:not(.chatra--expanded)
visibility: hidden !important
width: 1px !important
height: 1px !important
opacity: 0 !important
pointer-events: none
if hexo-config('chat.rightside_button') == true
if hexo-config('chat.use') == 'chatra'
#chatra:not(.chatra--expanded)
visibility: hidden !important
width: 1px !important
height: 1px !important
opacity: 0 !important
pointer-events: none
if hexo-config('chat_btn') == true && hexo-config('messenger.enable')
.fb_dialog,
.fb-customerchat
visibility: hidden !important
width: 1px !important
height: 1px !important
opacity: 0 !important
pointer-events: none
if hexo-config('chat.use') == 'messenger'
.fb_dialog,
.fb-customerchat
visibility: hidden !important
width: 1px !important
height: 1px !important
opacity: 0 !important
pointer-events: none

@ -5,7 +5,7 @@
background-position: bottom
background-size: cover
if hexo-config('footer_bg') != false && hexo-config('mask.footer')
if hexo-config('footer_img') != false && hexo-config('mask.footer')
&:before
position: absolute
width: 100%

@ -146,6 +146,7 @@
background: rgba(255, 255, 255, .8)
box-shadow: 0 5px 6px -5px alpha($grey, .6)
transition: transform .2s ease-in-out, opacity .2s ease-in-out
will-change: transform
#blog-info
color: var(--font-color)
@ -345,10 +346,10 @@
margin-top: 8px
padding: 0
width: max-content
border-radius: 5px
background-color: var(--sidebar-bg)
box-shadow: 0 5px 20px -4px rgba($dark-black, .5)
animation: sub_menus .3s .1s ease both
addBorderRadius(5)
&:before
position: absolute
@ -364,13 +365,14 @@
&:hover
background: var(--text-bg-hover)
&:first-child
border-top-left-radius: 5px
border-top-right-radius: 5px
if hexo-config('rounded_corners_ui')
&:first-child
border-top-left-radius: 5px
border-top-right-radius: 5px
&:last-child
border-bottom-right-radius: 5px
border-bottom-left-radius: 5px
&:last-child
border-bottom-right-radius: 5px
border-bottom-left-radius: 5px
a
display: inline-block

@ -37,47 +37,40 @@
.prev-post,
.next-post
@extend .postImgHover
position: relative
overflow: hidden
width: 50%
height: 150px
+maxWidth768()
width: 100%
a
position: relative
display: block
overflow: hidden
height: 150px
&.pagination-post
overflow: hidden
margin-top: 40px
width: 100%
background: $dark-black
addBorderRadius()
.layout
& > .recent-posts
.pagination
& > *
display: inline-block
margin: 0 6px
width: w = 2.5em
height: w
line-height: w
.pagination
& > *
display: inline-block
margin: 0 6px
width: w = 2.5em
height: w
line-height: w
& > *:not(.space)
@extend .cardHover
& > *:not(.space)
@extend .cardHover
&:hover
background: var(--btn-hover-color)
color: var(--btn-color)
&:hover
background: var(--btn-hover-color)
color: var(--btn-color)
#archive
.pagination
margin-top: 30px
& > div:not(.recent-posts)
.pagination
.page-number
display: inline-block
margin: 0 4px
min-width: w = 24px
height: w
text-align: center
line-height: w
cursor: pointer
& > *:not(.space)
box-shadow: none

@ -87,6 +87,7 @@ beautify()
margin: 0 auto 20px
max-width: 100%
transition: filter 375ms ease-in .2s
addBorderRadius()
p
margin: 0 0 16px
@ -98,7 +99,6 @@ beautify()
margin: 0 3px
padding: 3px 5px
border: 1px solid #b4b4b4
border-radius: 3px
background-color: #f8f8f8
box-shadow: 0 1px 3px rgba(0, 0, 0, .25), 0 2px 1px 0 rgba(255, 255, 255, .6) inset
color: #34495e
@ -107,6 +107,7 @@ beautify()
font-size: .9em
font-family: Monaco, 'Ubuntu Mono', monospace
line-height: 1em
addBorderRadius(3)
if hexo-config('anchor.click_to_scroll')
h1,
@ -181,7 +182,7 @@ beautify()
background: $light-blue
color: var(--white)
.post_share
.post-share
display: inline-block
float: right
margin: 8px 0 0
@ -203,6 +204,7 @@ beautify()
padding: 10px 16px
border: 1px solid var(--light-grey)
transition: box-shadow .3s ease-in-out
addBorderRadius()
&:before
@extend .fontawesomeIcon
@ -238,9 +240,9 @@ beautify()
position: relative
margin: 0 0 20px
padding: .5em 1.2em
border-radius: 3px
background-color: $noticeOutdate-bg
color: $noticeOutdate-color
addBorderRadius(3)
if hexo-config('noticeOutdate.style') == 'flat'
padding: .5em 1em .5em 2.6em

@ -7,7 +7,7 @@
font-size: 1.43em
& > .relatedPosts-list
& > div
& > a
position: relative
display: inline-block
overflow: hidden
@ -17,6 +17,7 @@
background: $dark-black
vertical-align: bottom
@extend .postImgHover
addBorderRadius()
+maxWidth768()
margin: 2px
@ -27,11 +28,8 @@
width: calc(100% - 4px)
.content
position: absolute
top: 50%
padding: 0 20px
width: 100%
transform: translate(0, -50%)
@extend .verticalCenter
.date
color: var(--light-grey)

@ -14,6 +14,7 @@
background: var(--btn-bg)
color: var(--btn-color)
cursor: pointer
addBorderRadius()
i
margin-right: 5px
@ -33,12 +34,12 @@
display: none
padding: 0 0 15px
width: 100%
addBorderRadius()
.reward-all
display: inline-block
margin: 0
padding: 20px 10px
border-radius: 4px
background: var(--reward-pop)
&:before

@ -32,12 +32,12 @@
margin-bottom: 5px
width: w = 35px
height: w
border-radius: 5px
background-color: var(--btn-bg)
color: var(--btn-color)
text-align: center
font-size: 16px
line-height: w
addBorderRadius(5)
&:hover
background-color: var(--btn-hover-color)

@ -26,27 +26,33 @@
& > .avatar-img
margin: 20px auto
.sidebar-site-data
.site-data
padding: 0 10px
hr
margin: 20px auto
.menus_items
padding: 0 10px
margin: 20px
padding: 15px
background: var(--sidebar-menu-bg)
box-shadow: 0 0 1px 1px rgba(7, 17, 27, .05)
addBorderRadius(10)
.site-page
@extend .limit-one-line
position: relative
display: block
padding: 3px 28px 3px 20px
border-radius: 6px
margin: 4px 0
padding: 2px 23px 2px 15px
color: var(--font-color)
font-size: 1.15em
cursor: pointer
addBorderRadius(6)
&:hover
background: var(--text-bg-hover)
color: var(--white)
i:first-child
width: 15%
@ -55,8 +61,8 @@
&.group
& > i:last-child
position: absolute
top: .78em
right: 13px
top: .6em
right: 10px
transition: transform .3s
&.hide

@ -79,31 +79,45 @@ if hexo-config('mermaid.enable')
margin: 0 0 .8em
padding: 6px 0 16px
.katex-display
overflow: auto hidden
padding: 5px
if hexo-config('math.use')
.katex-display
overflow: auto hidden
padding: 5px
if hexo-config('katex') && hexo-config('katex.hide_scrollbar')
&::-webkit-scrollbar
display: none
.katex-show
display: block
.katex
display: none
&.katex-show
display: inline
if hexo-config('math.hide_scrollbar')
.katex-display,
mjx-container
scrollbar-width: none
&::-webkit-scrollbar
display: none
// Mathjax
mjx-container
overflow-x: auto
overflow-y: hidden
padding-bottom: 4px
max-width: 100%
// Mathjax
mjx-container
overflow-x: auto
overflow-y: hidden
padding-bottom: 4px
max-width: 100%
&[display]
display: block !important
min-width: auto !important
&[display]
display: block !important
min-width: auto !important
&:not([display])
display: inline-grid !important
&:not([display])
display: inline-grid !important
mjx-assistive-mml
right: 0
bottom: 0
mjx-assistive-mml
right: 0
bottom: 0
.aplayer
color: $font-black

@ -16,6 +16,7 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
--tab-button-active-bg: #121212
--card-bg: #121212
--sidebar-bg: #121212
--sidebar-menu-bg: lighten(#121212, 5)
--btn-hover-color: lighten(#121212, 40)
--btn-color: alpha(#FFFFFF, .7)
--btn-bg: lighten(#121212, 5)
@ -139,4 +140,21 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
#card-toc
+maxWidth900()
background: lighten(#121212, 5)
background: lighten(#121212, 5)
// artalk
.artalk.atk-dark-mode,
.atk-layer-wrap.atk-dark-mode
--at-color-font: alpha(#FFFFFF, .7)
--at-color-meta: alpha(#FFFFFF, .7)
--at-color-grey: alpha(#FFFFFF, .7)
.atk-send-btn,
.atk-badge
color: alpha(#FFFFFF, .7) !important
// waline
#waline-wrap
--waline-color: alpha(#FFFFFF, .7)
--waline-dark-grey: alpha(#FFFFFF, .7)
--waline-info-color: alpha(#FFFFFF, .5)

@ -37,11 +37,11 @@ if hexo-config('readmode')
z-index: 100
width: 40px
height: 40px
border-radius: 8px
background: var(--exit-btn-bg)
color: var(--exit-btn-color)
font-size: 16px
transition: background .3s
addBorderRadius(8)
+maxWidth768()
top: initial

@ -1,69 +1,66 @@
if hexo-config('error_404.enable')
.error404
#error-wrap
position: absolute
top: 50%
right: 0
left: 0
margin: 0 auto
padding: 60px 20px 0
max-width: 1000px
transform: translate(0, -50%)
.type-404
.error-content
@extend .cardHover
overflow: hidden
margin: 0 20px
height: 360px
.error-content
@extend .cardHover
+maxWidth768()
margin: 0
height: 500px
.error-img
display: inline-block
overflow: hidden
margin: 0 20px
height: 360px
width: 50%
height: 100%
+maxWidth768()
margin: 0
height: 500px
width: 100%
height: 45%
.error-img
display: inline-block
overflow: hidden
width: 50%
height: 100%
img
@extend .imgHover
background-color: $theme-color
+maxWidth768()
width: 100%
height: 45%
.error-info
display: inline-flex
flex-direction: column
justify-content: center
align-content: center
width: 50%
height: 100%
vertical-align: top
text-align: center
img
@extend .imgHover
background-color: $theme-color
if $site-name-font
font-family: $site-name-font
.error-info
display: inline-flex
flex-direction: column
justify-content: center
align-content: center
width: 50%
height: 100%
vertical-align: top
text-align: center
+maxWidth768()
width: 100%
height: 55%
if $site-name-font
font-family: $site-name-font
.error_title
margin-top: -.6em
font-size: 9em
+maxWidth768()
width: 100%
height: 55%
font-size: 8em
.error_title
margin-top: -.6em
font-size: 9em
.error_subtitle
@extend .limit-more-line
margin-top: -3em
word-break: break-word
font-size: 1.6em
-webkit-line-clamp: 2
+maxWidth768()
font-size: 8em
.nc
margin-top: 5%
padding: 0 20px
.error_subtitle
@extend .limit-more-line
margin-top: -3em
word-break: break-word
font-size: 1.6em
-webkit-line-clamp: 2
#footer
display: none
& + #rightside
display: none

@ -78,8 +78,8 @@
border-color: var(--pseudo-hover)
&-time
color: $theme-meta-color
font-size: 95%
color: var(--card-meta)
font-size: .85em
time
padding-left: 6px
@ -88,7 +88,7 @@
&-title
@extend .limit-more-line
color: var(--font-color)
font-size: 1.1em
font-size: 1.05em
transition: all .3s
-webkit-line-clamp: 2
@ -98,8 +98,13 @@
&-img
overflow: hidden
width: 80px
height: 80px
width: 100px
height: 70px
addBorderRadius()
+maxWidth768()
width: 70px
height: 70px
:first-child
@extend .imgHover

@ -16,7 +16,7 @@
.category-list-count
margin-left: 8px
color: $theme-meta-color
color: var(--card-meta)
&:before
content: '('

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save