Compare commits

..

20 Commits
4.8.0 ... 4.9.0

64 changed files with 675 additions and 565 deletions

View File

@@ -1,7 +1,5 @@
<div align="right"> <div align="right">
Language: <a title="Chinese" href="/README_CN.md">中文</a>
🇺🇸
<a title="Chinese" href="/README_CN.md">🇨🇳</a>
</div> </div>
# hexo-theme-butterfly # hexo-theme-butterfly
@@ -14,7 +12,7 @@
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png) ![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png)
Demo: 👍 [Butterfly](https://butterfly.js.org/) || 🤞 [CrazyWong](https://crazywong.com/) Demo: 👍 [Butterfly](https://butterfly.js.org/) || 🤞 [CrazyWong](https://blog.crazywong.com/)
Docs: 📖 [Butterfly Docs](https://butterfly.js.org/posts/21cfbf15/) Docs: 📖 [Butterfly Docs](https://butterfly.js.org/posts/21cfbf15/)
@@ -62,17 +60,17 @@ npm i hexo-theme-butterfly
- [x] Card UI Design - [x] Card UI Design
- [X] Support sub-menu - [X] Support sub-menu
- [x] Two Column designs - [x] Two-column layout
- [x] Responsive Web Design - [x] Responsive Web Design
- [x] Dark Mode - [x] Dark Mode
- [x] Pjax - [x] Pjax
- [x] Read Mode - [x] Read Mode
- [x] Conversion between Traditional and Simplified Chinese - [x] Conversion between Traditional and Simplified Chinese
- [X] TOC catalog is available for both computers and mobile phones - [X] TOC catalog is available for both computers and mobile phones
- [X] Color themes (darker/pale night/light/ocean/mac/mac light), support custom colors - [X] Built-in Syntax Highlighting Themes (darker/pale night/light/ocean/mac/mac light), also support customization
- [X] Code Blocks (Display code language/close or expand Code Blocks/Copy Button/word wrap) - [X] Code Blocks (Display code language/close or expand Code Blocks/Copy Button/word wrap)
- [X] Disable copy/Add a Copyright Notice to the Copied Text - [X] Disable copy/Add a Copyright Notice to the Copied Text
- [X] Search (Algolia SearchZ/Local Search) - [X] Search (Algolia Search/Local Search)
- [x] Mathjax and Katex - [x] Mathjax and Katex
- [x] Built-in 404 page - [x] Built-in 404 page
- [x] WordCount - [x] WordCount

View File

@@ -1,7 +1,5 @@
<div align="right"> <div align="right">
語言: <a title="English" href="/README.md">English</a>
中文
<a title="English" href="/README.md">英文</a>
</div> </div>
# hexo-theme-butterfly # hexo-theme-butterfly
@@ -14,7 +12,7 @@
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png) ![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png)
預覽: 👍 [Butterfly](https://butterfly.js.org/) || 🤞 [CrazyWong](https://crazywong.com/) 預覽: 👍 [Butterfly](https://butterfly.js.org/) || 🤞 [CrazyWong](https://blog.crazywong.com/)
文檔: 📖 [Butterfly Docs](https://butterfly.js.org/posts/21cfbf15/) 文檔: 📖 [Butterfly Docs](https://butterfly.js.org/posts/21cfbf15/)
@@ -72,7 +70,7 @@ theme: butterfly
- [X] 內置多種代碼配色darker/pale night/light/ocean/mac/mac light可自定義代碼配色 - [X] 內置多種代碼配色darker/pale night/light/ocean/mac/mac light可自定義代碼配色
- [X] 代碼塊顯示代碼語言/關閉或展開代碼塊/代碼複製/代碼自動換行 - [X] 代碼塊顯示代碼語言/關閉或展開代碼塊/代碼複製/代碼自動換行
- [X] 可關閉文字複製/可開啟內容複製增加版權信息) - [X] 可關閉文字複製/可開啟內容複製增加版權信息)
- [X] 兩種搜索Algolia搜索和本地搜索 - [X] 兩種搜索( Algolia 搜索和本地搜索)
- [x] Mathjax 和 Katex - [x] Mathjax 和 Katex
- [x] 內置404頁面 - [x] 內置404頁面
- [x] 顯示字數統計 - [x] 顯示字數統計

View File

@@ -645,6 +645,11 @@ background:
# Footer Background # Footer Background
footer_bg: false footer_bg: false
# Add mask to header or footer (为 header 或 footer 添加黑色半透遮罩)
mask:
header: true
footer: true
# the position of bottom right button/default unit: px (右下角按鈕距離底部的距離/默認單位為px) # the position of bottom right button/default unit: px (右下角按鈕距離底部的距離/默認單位為px)
rightside-bottom: rightside-bottom:

View File

@@ -127,5 +127,6 @@ script.
percent: { percent: {
toc: !{theme.toc.scroll_percent}, toc: !{theme.toc.scroll_percent},
rightside: !{theme.rightside_scroll_percent}, rightside: !{theme.rightside_scroll_percent},
} },
autoDarkmode: !{theme.darkmode.enable && theme.darkmode.autoChangeMode === 1}
} }

View File

@@ -44,7 +44,7 @@ header#page-header(class=`${isHomeClass+isFixedClass}` style=bg_img)
span#subtitle span#subtitle
if(theme.social) if(theme.social)
#site_social_icons #site_social_icons
!=fragment_cache('social', function(){return partial('includes/header/social')}) !=partial('includes/header/social', {}, {cache: true})
#scroll-down #scroll-down
i.fas.fa-angle-down.scroll-down-effects i.fas.fa-angle-down.scroll-down-effects
else else

View File

@@ -9,21 +9,25 @@
.loading-word= _p('loading') .loading-word= _p('loading')
script. script.
const preloader = { (()=>{
endLoading: () => { const $loadingBox = document.getElementById('loading-box')
document.body.style.overflow = ''; const $body = document.body
document.getElementById('loading-box').classList.add("loaded") const preloader = {
}, endLoading: () => {
initLoading: () => { $body.style.overflow = ''
document.body.style.overflow = 'hidden'; $loadingBox.classList.add('loaded')
document.getElementById('loading-box').classList.remove("loaded") },
initLoading: () => {
$body.style.overflow = 'hidden'
$loadingBox.classList.remove('loaded')
}
} }
}
preloader.initLoading() preloader.initLoading()
window.addEventListener('load',()=> { preloader.endLoading() }) window.addEventListener('load',() => { preloader.endLoading() })
if (!{theme.pjax && theme.pjax.enable}) { if (!{theme.pjax && theme.pjax.enable}) {
document.addEventListener('pjax:send', () => { preloader.initLoading() }) document.addEventListener('pjax:send', () => { preloader.initLoading() })
document.addEventListener('pjax:complete', () => { preloader.endLoading() }) document.addEventListener('pjax:complete', () => { preloader.endLoading() })
} }
})()

View File

@@ -70,7 +70,7 @@ mixin postUI(posts)
block block
span.article-meta-label= ' ' + _p('card_post_count') span.article-meta-label= ' ' + _p('card_post_count')
if theme.comments.card_post_count if theme.comments.card_post_count && theme.comments.use
case theme.comments.use[0] case theme.comments.use[0]
when 'Disqus' when 'Disqus'
+countBlockInIndex +countBlockInIndex
@@ -89,7 +89,7 @@ mixin postUI(posts)
when 'Waline' when 'Waline'
+countBlockInIndex +countBlockInIndex
a(href=url_for(link) + '#post-comment') a(href=url_for(link) + '#post-comment')
span.waline-comment-count(id=url_for(link)) span.waline-comment-count(data-path=url_for(link))
i.fa-solid.fa-spinner.fa-spin i.fa-solid.fa-spinner.fa-spin
when 'Twikoo' when 'Twikoo'
+countBlockInIndex +countBlockInIndex

View File

@@ -1,7 +1,10 @@
#article-container #article-container
.flink .flink
- let pageContent = page.content - let { content, random, flink_url } = page
if page.flink_url - let pageContent = content
if flink_url || random
- const linkData = flink_url ? false : site.data.link || false
script. script.
(()=>{ (()=>{
const replaceSymbol = (str) => { const replaceSymbol = (str) => {
@@ -9,35 +12,45 @@
} }
let result = "" let result = ""
fetch("!{url_for(page.flink_url)}") const add = (str) => {
.then(response => response.json()) for(let i = 0; i < str.length; i++){
.then(str => { const replaceClassName = replaceSymbol(str[i].class_name)
for(let i = 0; i < str.length; i++){ const className = str[i].class_name ? `<h2 id="${replaceClassName}"><a href="#${replaceClassName}" class="headerlink" title="${str[i].class_name}"></a>${str[i].class_name}</h2>` : ""
const replaceClassName = replaceSymbol(str[i].class_name) const classDesc = str[i].class_desc ? `<div class="flink-desc">${str[i].class_desc}</div>` : ""
const className = str[i].class_name ? `<h2 id="${replaceClassName}"><a href="#${replaceClassName}" class="headerlink" title="${str[i].class_name}"></a>${str[i].class_name}</h2>` : ""
const classDesc = str[i].class_desc ? `<div class="flink-desc">${str[i].class_desc}</div>` : ""
let listResult = "" let listResult = ""
const lists = str[i].link_list const lists = str[i].link_list
for(let j = 0; j < lists.length; j++){ if (!{random === true}) {
listResult += ` lists.sort(() => Math.random() - 0.5)
<div class="flink-list-item"> }
<a href="${lists[j].link}" title="${lists[j].name}" target="_blank"> for(let j = 0; j < lists.length; j++){
<div class="flink-item-icon"> listResult += `
<img class="no-lightbox" src="${lists[j].avatar}" onerror='this.onerror=null;this.src="!{url_for(theme.error_img.flink)}"' alt="${lists[j].name}" /> <div class="flink-list-item">
</div> <a href="${lists[j].link}" title="${lists[j].name}" target="_blank">
<div class="flink-item-name">${lists[j].name}</div> <div class="flink-item-icon">
<div class="flink-item-desc" title="${lists[j].descr}">${lists[j].descr}</div> <img class="no-lightbox" src="${lists[j].avatar}" onerror='this.onerror=null;this.src="!{url_for(theme.error_img.flink)}"' alt="${lists[j].name}" />
</a> </div>
</div>` <div class="flink-item-name">${lists[j].name}</div>
} <div class="flink-item-desc" title="${lists[j].descr}">${lists[j].descr}</div>
</a>
result += `${className}${classDesc} <div class="flink-list">${listResult}</div>` </div>`
} }
document.querySelector(".flink").insertAdjacentHTML("afterbegin", result) result += `${className}${classDesc} <div class="flink-list">${listResult}</div>`
window.lazyLoadInstance && window.lazyLoadInstance.update() }
})
document.querySelector(".flink").insertAdjacentHTML("afterbegin", result)
window.lazyLoadInstance && window.lazyLoadInstance.update()
}
const linkData = !{JSON.stringify(linkData)}
if (!{Boolean(flink_url)}) {
fetch("!{url_for(flink_url)}")
.then(response => response.json())
.then(add)
} else if (linkData) {
add(linkData)
}
})() })()
else else
@@ -67,4 +80,3 @@
- pageContent = result + pageContent - pageContent = result + pageContent
!= pageContent != pageContent

View File

@@ -23,7 +23,7 @@ mixin rightsideItem(array)
i.fas.fa-list-ul i.fas.fa-list-ul
when 'chat' when 'chat'
if chat_btn if chat_btn
button#chat_btn(type="button" title=_p("rightside.chat")) button#chat-btn(type="button" title=_p("rightside.chat"))
i.fas.fa-sms i.fas.fa-sms
when 'comment' when 'comment'
if commentsJsLoad if commentsJsLoad

View File

@@ -14,5 +14,5 @@
.headline= _p('aside.categories') .headline= _p('aside.categories')
.length-num= site.categories.length .length-num= site.categories.length
hr hr.custom-hr
!=partial('includes/header/menu_item', {}, {cache: true}) !=partial('includes/header/menu_item', {}, {cache: true})

View File

@@ -1,4 +1,4 @@
if theme.abcjs.enable if theme.abcjs && theme.abcjs.enable
if theme.abcjs.per_page if theme.abcjs.per_page
if is_post() || is_page() if is_post() || is_page()
include ./abcjs.pug include ./abcjs.pug

View File

@@ -2,19 +2,34 @@
script. script.
(() => { (() => {
const getArtalkCount = () => { const getArtalkCount = async() => {
const runWidget = () => { try {
Artalk.LoadCountWidget({ const eleGroup = document.querySelectorAll('#recent-posts .artalk-count')
server: '!{server}', const keyArray = Array.from(eleGroup).map(i => i.getAttribute('data-page-key'))
site: '!{site}',
countEl: '.artalk-count' const headerList = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': window.location.origin
},
body: new URLSearchParams({
'site_name': '!{site}',
'type':'page_comment',
'page_keys': keyArray
})
}
const res = await fetch('!{server}/api/stat', headerList)
const result = await res.json()
keyArray.forEach((key, index) => {
eleGroup[index].textContent = result.data[key] || 0
}) })
} catch (err) {
console.error(err)
} }
if (typeof Artalk === 'function') runWidget()
else getScript('!{theme.asset.artalk_js}').then(runWidget)
} }
window.pjax ? getArtalkCount() : window.addEventListener('load', getArtalkCount) window.pjax ? getArtalkCount() : window.addEventListener('load', getArtalkCount)
})() })()

View File

@@ -18,7 +18,7 @@ script.
includeReply: false includeReply: false
}).then(function (res) { }).then(function (res) {
document.querySelectorAll('#recent-posts .twikoo-count').forEach((item,index) => { document.querySelectorAll('#recent-posts .twikoo-count').forEach((item,index) => {
item.innerText = res[index].count item.textContent = res[index].count
}) })
}).catch(function (err) { }).catch(function (err) {
console.log(err) console.log(err)

View File

@@ -1,17 +1,19 @@
script. script.
(() => { (() => {
function loadWaline () { async function loadWaline () {
function initWaline () { try {
let initData = { const eleGroup = document.querySelectorAll('#recent-posts .waline-comment-count')
el: null, const keyArray = Array.from(eleGroup).map(i => i.getAttribute('data-path'))
serverURL: '!{theme.waline.serverURL}',
comment: true
}
const waline = Waline.init(initData)
}
if (typeof Waline === 'object') initWaline() const res = await fetch(`!{theme.waline.serverURL}/api/comment?type=count&url=${keyArray}`, { method: 'GET' })
else getScript('!{url_for(theme.asset.waline_js)}').then(initWaline) const result = await res.json()
result.data.forEach((count, index) => {
eleGroup[index].textContent = count
})
} catch (err) {
console.error(err)
}
} }
window.pjax ? loadWaline() : window.addEventListener('load', loadWaline) window.pjax ? loadWaline() : window.addEventListener('load', loadWaline)

View File

@@ -1,33 +1,50 @@
//- https://chatra.io/help/api/ //- https://chatra.io/help/api/
script. script.
(function(d, w, c) { (() => {
w.ChatraID = '#{theme.chatra.id}'; const isChatBtn = !{theme.chat_btn}
var s = d.createElement('script'); const isChatHideShow = !{theme.chat_hide_show}
w[c] = w[c] || function() {
(w[c].q = w[c].q || []).push(arguments);
};
s.async = true;
s.src = 'https://call.chatra.io/chatra.js';
if (d.head) d.head.appendChild(s);
})(document, window, 'Chatra');
if (!{theme.chat_btn}) { if (isChatBtn) {
var chatBtnFn = () => { const close = () => {
var chatBtn = document.getElementById("chat_btn") Chatra('minimizeWidget')
chatBtn.addEventListener("click", function(){
Chatra('openChat')
});
}
chatBtnFn()
} else {
if (!{theme.chat_hide_show}) {
function chatBtnHide () {
Chatra('hide') Chatra('hide')
} }
function chatBtnShow () {
const open = () => {
Chatra('openChat', true)
Chatra('show') Chatra('show')
} }
window.ChatraSetup = {
startHidden: true
}
window.chatBtnFn = () => {
const isShow = document.getElementById('chatra').classList.contains('chatra--expanded')
isShow ? close() : open()
}
} else if (isChatHideShow) {
window.chatBtn = {
hide: () => {
Chatra('hide')
},
show: () => {
Chatra('show')
}
}
} }
}
(function(d, w, c) {
w.ChatraID = '#{theme.chatra.id}'
var s = d.createElement('script')
w[c] = w[c] || function() {
(w[c].q = w[c].q || []).push(arguments)
}
s.async = true
s.src = 'https://call.chatra.io/chatra.js'
if (d.head) d.head.appendChild(s)
})(document, window, 'Chatra')
})()

View File

@@ -1,36 +1,45 @@
script. script.
window.$crisp = []; (() => {
window.CRISP_WEBSITE_ID = "!{theme.crisp.website_id}"; window.$crisp = [];
(function () { window.CRISP_WEBSITE_ID = "!{theme.crisp.website_id}";
d = document; (function () {
s = d.createElement("script"); d = document;
s.src = "https://client.crisp.chat/l.js"; s = d.createElement("script");
s.async = 1; s.src = "https://client.crisp.chat/l.js";
d.getElementsByTagName("head")[0].appendChild(s); s.async = 1;
})(); d.getElementsByTagName("head")[0].appendChild(s);
$crisp.push(["safe", true]) })();
$crisp.push(["safe", true])
if (!{theme.chat_btn}) { const isChatBtn = !{theme.chat_btn}
$crisp.push(["do", "chat:hide"]) const isChatHideShow = !{theme.chat_hide_show}
$crisp.push(["on", "chat:closed", function() {
$crisp.push(["do", "chat:hide"]) if (isChatBtn) {
}]) const open = () => {
var chatBtnFn = () => {
var chatBtn = document.getElementById("chat_btn")
chatBtn.addEventListener("click", function(){
$crisp.push(["do", "chat:show"]) $crisp.push(["do", "chat:show"])
$crisp.push(["do", "chat:open"]) $crisp.push(["do", "chat:open"])
}
}); const close = () => {
}
chatBtnFn()
} else {
if (!{theme.chat_hide_show}) {
function chatBtnHide () {
$crisp.push(["do", "chat:hide"]) $crisp.push(["do", "chat:hide"])
} }
function chatBtnShow () {
$crisp.push(["do", "chat:show"]) close()
$crisp.push(["on", "chat:closed", function() {
close()
}])
window.chatBtnFn = () => {
$crisp.is("chat:visible") ? close() : open()
}
} else if (isChatHideShow) {
window.chatBtn = {
hide: () => {
$crisp.push(["do", "chat:hide"])
},
show: () => {
$crisp.push(["do", "chat:show"])
}
} }
} }
} })()

View File

@@ -1,40 +1,40 @@
//- https://guide.daocloud.io/daovoice/javascript-api-5869833.html //- https://guide.daocloud.io/daovoice/javascript-api-5869833.html
script. 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") (() => {
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/!{theme.daovoice.app_id}.js","daovoice")
script. const isChatBtn = !{theme.chat_btn}
var isChatBtn = !{theme.chat_btn} const isChatHideShow = !{theme.chat_hide_show}
daovoice('init', {
app_id: '!{theme.daovoice.app_id}',},{
launcher: {
disableLauncherIcon: isChatBtn // 悬浮 ICON 是否显示
},
});
daovoice('update');
if (isChatBtn) { daovoice('init', {
var chatBtnFn = () => { app_id: '!{theme.daovoice.app_id}',},{
var chatBtn = document.getElementById("chat_btn") launcher: {
chatBtn.addEventListener("click", function(){ disableLauncherIcon: isChatBtn
daovoice('show') },
}); });
} daovoice('update');
chatBtnFn()
} else { if (isChatBtn) {
if (!{theme.chat_hide_show}) { window.chatBtnFn = () => {
function chatBtnHide () { const isShow = document.getElementById('daodream-messenger').classList.contains('daodream-messenger-active')
daovoice('update', {},{ isShow ? daovoice('hide') : daovoice('show')
launcher: {
disableLauncherIcon: true // 悬浮 ICON 是否显示
},
});
} }
function chatBtnShow () { } else if (isChatHideShow) {
daovoice('update', {},{ window.chatBtn = {
launcher: { hide: () => {
disableLauncherIcon: false // 悬浮 ICON 是否显示 daovoice('update', {},{
}, launcher: {
}); disableLauncherIcon: true
}
})
},
show: () => {
daovoice('update', {}, {
launcher: {
disableLauncherIcon: false
}
})
}
} }
} }
} })()

View File

@@ -4,39 +4,41 @@
#fb-customer-chat.fb-customerchat(page_id=pageID attribution='biz_inbox') #fb-customer-chat.fb-customerchat(page_id=pageID attribution='biz_inbox')
script. script.
document.getElementById('fb-root') ? '' : document.body.insertAdjacentHTML('afterend', '<div id="fb-root"></div>') (() => {
document.getElementById('fb-root') ? '' : document.body.insertAdjacentHTML('afterend', '<div id="fb-root"></div>')
window.fbAsyncInit = function() { window.fbAsyncInit = function() {
FB.init({ FB.init({
xfbml: true, xfbml: true,
version: 'v16.0' version: 'v16.0'
});
};
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = 'https://connect.facebook.net/!{lang}/sdk/xfbml.customerchat.js';
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
if (!{theme.chat_btn}) {
var chatBtnFn = () => {
var chatBtn = document.getElementById("chat_btn")
chatBtn.addEventListener("click", function(){
FB.CustomerChat.show();
}); });
} };
chatBtnFn()
} else { (function(d, s, id) {
if (!{theme.chat_hide_show}) { var js, fjs = d.getElementsByTagName(s)[0];
function chatBtnHide () { if (d.getElementById(id)) return;
FB.CustomerChat.hide() js = d.createElement(s); js.id = id;
} js.src = 'https://connect.facebook.net/!{lang}/sdk/xfbml.customerchat.js';
function chatBtnShow () { fjs.parentNode.insertBefore(js, fjs);
FB.CustomerChat.show(false) }(document, 'script', 'facebook-jssdk'));
}
} const isChatBtn = !{theme.chat_btn}
} const isChatHideShow = !{theme.chat_hide_show}
if (isChatBtn) {
window.chatBtnFn = () => {
const isShow = document.querySelector('.fb_customer_chat_bounce_in_v2')
isShow ? FB.CustomerChat.hide() : FB.CustomerChat.show()
}
} else if (isChatHideShow) {
window.chatBtn = {
hide: () => {
FB.CustomerChat.hide()
},
show: () => {
FB.CustomerChat.show(false)
}
}
}
})()

View File

@@ -1,41 +1,45 @@
script(src=`//code.tidio.co/${theme.tidio.public_key}.js` async) script(src=`//code.tidio.co/${theme.tidio.public_key}.js` async)
script.
(() => {
const isChatBtn = !{theme.chat_btn}
const isChatHideShow = !{theme.chat_hide_show}
if theme.chat_btn if (isChatBtn) {
script. let isShow = false
function onTidioChatApiReady() { const close = () => {
window.tidioChatApi.hide(); window.tidioChatApi.hide()
window.tidioChatApi.on("close", function() { isShow = false
window.tidioChatApi.hide(); }
});
}
if (window.tidioChatApi) {
window.tidioChatApi.on("ready", onTidioChatApiReady);
} else {
document.addEventListener("tidioChat-ready", onTidioChatApiReady);
}
var chatBtnFn = () => { const open = () => {
document.getElementById("chat_btn").addEventListener("click", function(){ window.tidioChatApi.open()
window.tidioChatApi.show(); window.tidioChatApi.show()
window.tidioChatApi.open(); isShow = true
}); }
}
chatBtnFn()
else if theme.chat_hide_show const onTidioChatApiReady = () => {
script. window.tidioChatApi.hide()
function chatBtnHide () { window.tidioChatApi.on("close", close)
}
if (window.tidioChatApi) { if (window.tidioChatApi) {
//- window.tidioChatApi.hide(); window.tidioChatApi.on("ready", onTidioChatApiReady)
document.getElementById('tidio-chat').style.display= 'none' } else {
document.addEventListener("tidioChat-ready", onTidioChatApiReady)
}
window.chatBtnFn = () => {
if (!window.tidioChatApi) return
isShow ? close() : open()
}
} else if (isChatHideShow) {
window.chatBtn = {
hide: () => {
window.tidioChatApi && window.tidioChatApi.hide()
},
show: () => {
window.tidioChatApi && window.tidioChatApi.show()
}
} }
} }
})()
function chatBtnShow () {
if (window.tidioChatApi) {
//- window.tidioChatApi.show();
document.getElementById('tidio-chat').style.display= 'block'
}
}

View File

@@ -11,22 +11,34 @@ script.
darkMode: document.documentElement.getAttribute('data-theme') === 'dark', darkMode: document.documentElement.getAttribute('data-theme') === 'dark',
countEl: '.artalk-count' countEl: '.artalk-count'
},!{JSON.stringify(option)})) },!{JSON.stringify(option)}))
if (GLOBAL_CONFIG.lightbox === 'null') return
window.artalkItem.use(ctx => {
ctx.on('list-loaded', () => {
ctx.getCommentList().forEach(comment => {
const $content = comment.getRender().$content
btf.loadLightbox($content.querySelectorAll('img:not([atk-emoticon])'))
})
})
})
} }
if (typeof window.artalkItem === 'object') setTimeout(()=>{initArtalk()},200) if (typeof window.artalkItem === 'object') initArtalk()
else { else {
getCSS('!{theme.asset.artalk_css}') getCSS('!{theme.asset.artalk_css}').then(()=>{
typeof Artalk !== 'function' ? getScript('!{theme.asset.artalk_js}').then(initArtalk) getScript('!{theme.asset.artalk_js}').then(initArtalk)
: setTimeout(()=>{initArtalk()},200) })
} }
} }
document.getElementById('darkmode').addEventListener('click',()=> { function artalkChangeMode (theme) {
if (typeof window.artalkItem !== 'object') return const artalkWrap = document.getElementById('artalk-wrap')
let isDark = document.documentElement.getAttribute('data-theme') === 'dark' if (!(artalkWrap && artalkWrap.children.length)) return
window.artalkItem.setDarkMode(!isDark) const isDark = theme === 'dark'
}) window.artalkItem.setDarkMode(isDark)
}
btf.addModeChange('artalk', artalkChangeMode)
if ('!{theme.comments.use[0]}' === 'Artalk' || !!{theme.comments.lazyload}) { if ('!{theme.comments.use[0]}' === 'Artalk' || !!{theme.comments.lazyload}) {
if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('artalk-wrap'), loadArtalk) if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('artalk-wrap'), loadArtalk)

View File

@@ -2,19 +2,21 @@
script. script.
function loadDisqus () { function loadDisqus () {
var disqus_config = function () { const disqus_config = function () {
this.page.url = '!{ page.permalink }' this.page.url = '!{ page.permalink }'
this.page.identifier = '!{ url_for(page.path) }' this.page.identifier = '!{ url_for(page.path) }'
this.page.title = '!{ disqusPageTitle }' this.page.title = '!{ disqusPageTitle }'
}; }
window.disqusReset = () => { const disqusReset = () => {
DISQUS.reset({ DISQUS.reset({
reload: true, reload: true,
config: disqus_config config: disqus_config
}) })
} }
btf.addModeChange('disqus', disqusReset)
if (window.DISQUS) disqusReset() if (window.DISQUS) disqusReset()
else { else {
(function() { (function() {
@@ -24,10 +26,6 @@ script.
(d.head || d.body).appendChild(s); (d.head || d.body).appendChild(s);
})(); })();
} }
document.getElementById('darkmode').addEventListener('click', () => {
setTimeout(() => window.disqusReset(), 200)
})
} }
if ('!{theme.comments.use[0]}' === 'Disqus' || !!{theme.comments.lazyload}) { if ('!{theme.comments.use[0]}' === 'Disqus' || !!{theme.comments.lazyload}) {

View File

@@ -23,7 +23,7 @@ script.
} }
document.getElementById('darkmode').addEventListener('click', themeChange) btf.addModeChange('disqusjs', themeChange)
if (window.disqusJsLoad) initDisqusjs() if (window.disqusJsLoad) initDisqusjs()
else { else {

View File

@@ -25,6 +25,16 @@ script.
} }
} }
function fbModeChange (theme) {
const $fbComment = document.getElementsByClassName('fb-comments')[0]
if ($fbComment && typeof FB === 'object') {
$fbComment.setAttribute('data-colorscheme',theme)
FB.XFBML.parse(document.getElementById('post-comment'))
}
}
btf.addModeChange('facebook_comments', fbModeChange)
if ('!{theme.comments.use[0]}' === 'Facebook Comments' || !!{theme.comments.lazyload}) { if ('!{theme.comments.use[0]}' === 'Facebook Comments' || !!{theme.comments.lazyload}) {
if (!{theme.comments.lazyload}) btf.loadComment(document.querySelector('#post-comment .fb-comments'), loadFBComment) if (!{theme.comments.lazyload}) btf.loadComment(document.querySelector('#post-comment .fb-comments'), loadFBComment)
else loadFBComment() else loadFBComment()

View File

@@ -3,8 +3,8 @@
- const giscusOriginUrl = new URL(giscusUrl).origin - const giscusOriginUrl = new URL(giscusUrl).origin
script. script.
function getGiscusTheme () { function getGiscusTheme (theme) {
return document.documentElement.getAttribute('data-theme') === 'dark' ? '!{themes.dark}' : '!{themes.light}' return theme === 'dark' ? '!{themes.dark}' : '!{themes.light}'
} }
function loadGiscus () { function loadGiscus () {
@@ -14,7 +14,7 @@ script.
'data-repo-id': '!{repo_id}', 'data-repo-id': '!{repo_id}',
'data-category-id': '!{category_id}', 'data-category-id': '!{category_id}',
'data-mapping': 'pathname', 'data-mapping': 'pathname',
'data-theme': getGiscusTheme(), 'data-theme': getGiscusTheme(document.documentElement.getAttribute('data-theme')),
'data-reactions-enabled': '1', 'data-reactions-enabled': '1',
crossorigin: 'anonymous', crossorigin: 'anonymous',
async: true async: true
@@ -27,7 +27,7 @@ script.
document.getElementById('giscus-wrap').insertAdjacentElement('afterbegin',ele) document.getElementById('giscus-wrap').insertAdjacentElement('afterbegin',ele)
} }
function changeGiscusTheme () { function changeGiscusTheme (theme) {
function sendMessage(message) { function sendMessage(message) {
const iframe = document.querySelector('iframe.giscus-frame') const iframe = document.querySelector('iframe.giscus-frame')
if (!iframe) return if (!iframe) return
@@ -36,11 +36,13 @@ script.
sendMessage({ sendMessage({
setConfig: { setConfig: {
theme: getGiscusTheme() theme: getGiscusTheme(theme)
} }
}); });
} }
btf.addModeChange('giscus', changeGiscusTheme)
if ('!{theme.comments.use[0]}' === 'Giscus' || !!{theme.comments.lazyload}) { if ('!{theme.comments.use[0]}' === 'Giscus' || !!{theme.comments.lazyload}) {
if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('giscus-wrap'), loadGiscus) if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('giscus-wrap'), loadGiscus)
else loadGiscus() else loadGiscus()

View File

@@ -24,7 +24,7 @@ script.
function commentCount(n){ function commentCount(n){
let isCommentCount = document.querySelector('#post-meta .gitalk-comment-count') let isCommentCount = document.querySelector('#post-meta .gitalk-comment-count')
if (isCommentCount) { if (isCommentCount) {
isCommentCount.innerHTML= n isCommentCount.textContent= n
} }
} }

View File

@@ -1,5 +1,5 @@
- let defaultComment = theme.comments.use[0] - let defaultComment = theme.comments.use[0]
hr hr.custom-hr
#post-comment #post-comment
.comment-head .comment-head
.comment-headline .comment-headline

View File

@@ -51,11 +51,12 @@ script.
} }
} }
document.getElementById('darkmode').addEventListener('click',()=>{ function remarkChangeMode (theme) {
if (!window.REMARK42) return if (!window.REMARK42) return
let theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'
window.REMARK42.changeTheme(theme) window.REMARK42.changeTheme(theme)
}) }
btf.addModeChange('remark42', remarkChangeMode)
if ('!{theme.comments.use[0]}' === 'Remark42' || !!{theme.comments.lazyload}) { if ('!{theme.comments.use[0]}' === 'Remark42' || !!{theme.comments.lazyload}) {
if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('remark42'), loadRemark42) if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('remark42'), loadRemark42)

View File

@@ -23,7 +23,7 @@ script.
urls: [window.location.pathname], urls: [window.location.pathname],
includeReply: false includeReply: false
}).then(function (res) { }).then(function (res) {
countELement.innerText = res[0].count countELement.textContent = res[0].count
}).catch(function (err) { }).catch(function (err) {
console.error(err); console.error(err);
}); });

View File

@@ -12,10 +12,10 @@ script.
document.getElementById('utterances-wrap').insertAdjacentElement('afterbegin',ele) document.getElementById('utterances-wrap').insertAdjacentElement('afterbegin',ele)
} }
function utterancesTheme () { function utterancesTheme (theme) {
const iframe = document.querySelector('.utterances-frame') const iframe = document.querySelector('.utterances-frame')
if (iframe) { if (iframe) {
const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '#{theme.utterances.dark_theme}' : '#{theme.utterances.light_theme}' const theme = theme === 'dark' ? '#{theme.utterances.dark_theme}' : '#{theme.utterances.light_theme}'
const message = { const message = {
type: 'set-theme', type: 'set-theme',
theme: theme theme: theme
@@ -24,6 +24,8 @@ script.
} }
} }
btf.addModeChange('utterances', utterancesTheme)
if ('!{theme.comments.use[0]}' === 'Utterances' || !!{theme.comments.lazyload}) { if ('!{theme.comments.use[0]}' === 'Utterances' || !!{theme.comments.lazyload}) {
if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('utterances-wrap'), loadUtterances) if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('utterances-wrap'), loadUtterances)
else loadUtterances() else loadUtterances()

View File

@@ -14,13 +14,9 @@ script.
}, !{JSON.stringify(option)})) }, !{JSON.stringify(option)}))
} }
const walineCSSLoad = document.getElementById('waline-css') if (typeof Waline === 'object') initWaline()
if (typeof Waline === 'object') {
walineCSSLoad ? initWaline() : getCSS('!{url_for(theme.asset.waline_css)}','waline-css').then(initWaline)
}
else { else {
getCSS('!{url_for(theme.asset.waline_css)}','waline-css').then(() => { getCSS('!{url_for(theme.asset.waline_css)}').then(() => {
getScript('!{url_for(theme.asset.waline_js)}').then(initWaline) getScript('!{url_for(theme.asset.waline_js)}').then(initWaline)
}) })
} }

View File

@@ -3,7 +3,7 @@ script.
if (!window.MathJax) { if (!window.MathJax) {
window.MathJax = { window.MathJax = {
tex: { tex: {
inlineMath: [ ['$','$'], ["\\(","\\)"]], inlineMath: [['$', '$'], ['\\(', '\\)']],
tags: 'ams' tags: 'ams'
}, },
chtml: { chtml: {
@@ -21,16 +21,7 @@ script.
math.end = {node: text, delim: '', n: 0} math.end = {node: text, delim: '', n: 0}
doc.math.push(math) doc.math.push(math)
} }
}, ''], }, '']
insertScript: [200, () => {
document.querySelectorAll('mjx-container').forEach(node => {
if (node.hasAttribute('display')) {
btf.wrap(node, 'div', { class: 'mathjax-overflow' })
} else {
btf.wrap(node, 'span', { class: 'mathjax-overflow' })
}
});
}, '', false]
} }
} }
} }

View File

@@ -1,26 +1,38 @@
script. script.
(() => { (() => {
const $mermaidWrap = document.querySelectorAll('#article-container .mermaid-wrap') const $mermaid = document.querySelectorAll('#article-container .mermaid-wrap')
if ($mermaidWrap.length) { if ($mermaid.length === 0) return
window.runMermaid = () => { const runMermaid = () => {
window.loadMermaid = true window.loadMermaid = true
const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{theme.mermaid.theme.dark}' : '!{theme.mermaid.theme.light}' const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? '!{theme.mermaid.theme.dark}' : '!{theme.mermaid.theme.light}'
Array.from($mermaidWrap).forEach((item, index) => { Array.from($mermaid).forEach((item, index) => {
const mermaidSrc = item.firstElementChild const mermaidSrc = item.firstElementChild
const mermaidThemeConfig = '%%{init:{ \'theme\':\'' + theme + '\'}}%%\n' const mermaidThemeConfig = '%%{init:{ \'theme\':\'' + theme + '\'}}%%\n'
const mermaidID = 'mermaid-' + index const mermaidID = 'mermaid-' + index
const mermaidDefinition = mermaidThemeConfig + mermaidSrc.textContent const mermaidDefinition = mermaidThemeConfig + mermaidSrc.textContent
mermaid.mermaidAPI.render(mermaidID, mermaidDefinition, (svgCode) => {
mermaidSrc.insertAdjacentHTML('afterend', svgCode) const renderFn = mermaid.render(mermaidID, mermaidDefinition)
const renderV10 = () => {
renderFn.then(({svg}) => {
mermaidSrc.insertAdjacentHTML('afterend', svg)
}) })
}) }
}
const loadMermaid = () => { const renderV9 = svg => {
window.loadMermaid ? runMermaid() : getScript('!{url_for(theme.asset.mermaid)}').then(runMermaid) mermaidSrc.insertAdjacentHTML('afterend', svg)
} }
window.pjax ? loadMermaid() : document.addEventListener('DOMContentLoaded', loadMermaid) typeof renderFn === 'string' ? renderV9(renderFn) : renderV10()
})
} }
const loadMermaid = () => {
window.loadMermaid ? runMermaid() : getScript('!{url_for(theme.asset.mermaid)}').then(runMermaid)
}
btf.addModeChange('mermaid', runMermaid)
window.pjax ? loadMermaid() : document.addEventListener('DOMContentLoaded', loadMermaid)
})() })()

View File

@@ -1,6 +1,6 @@
- const { server, site, option } = theme.artalk - const { server, site, option } = theme.artalk
- const avatarCdn = option !== null && option.gravatar ? option.gravatar.mirror : 'https://sdn.geekzu.org/avatar/' - const avatarCdn = option !== null && option.gravatar && option.gravatar.mirror
- const avatarDefault = option !== null && option.gravatar ? option.gravatar.default : 'mp' - const avatarDefault = option !== null && option.gravatar && (option.gravatar.params || option.gravatar.default)
script. script.
window.addEventListener('load', () => { window.addEventListener('load', () => {
@@ -45,32 +45,53 @@ script.
window.pjax && window.pjax.refresh($dom) window.pjax && window.pjax.refresh($dom)
} }
const headerList = { const getSetting = async () => {
method: 'POST', try {
headers: { const res = await fetch('!{server}/api/conf', { method: 'GET' })
'Origin': window.location.origin return await res.json()
} catch (e) {
console.log(e)
} }
} }
const getComment = () => { const headerList = {
fetch('!{server}/api/stat?type=latest_comments&limit=!{theme.newest_comments.limit}&site_name=!{site}', headerList) method: 'POST',
.then(response => response.json()) headers: {
.then(d => { 'Content-Type': 'application/x-www-form-urlencoded',
const artalk = d.data.map(function (e) { 'Origin': window.location.origin
return { },
'avatar': '!{avatarCdn}' + e.email_encrypted + '?d=!{avatarDefault}', body: new URLSearchParams({
'content': changeContent(e.content_marked), 'site_name': '!{site}',
'nick': e.nick, 'limit': '!{theme.newest_comments.limit}',
'url': e.page_url, 'type':'latest_comments'
'date': e.date, })
} }
})
saveToLocal.set('artalk-newest-comments', JSON.stringify(artalk), !{theme.newest_comments.storage}/(60*24)) const getComment = async () => {
generateHtml(artalk) try {
}).catch(e => { const res = await fetch('!{server}/api/stat', headerList)
const $dom = document.querySelector('#card-newest-comments .aside-list') const result = await res.json()
$dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" const avatarStr = await getSetting()
const { mirror, params, default:defaults } = avatarStr.data.frontend_conf.gravatar
const avatarCdn = !{avatarCdn} || mirror
let avatarDefault = !{avatarDefault} || params || defaults
avatarDefault = avatarDefault.startsWith('d=') ? avatarDefault : `d=${avatarDefault}`
const artalk = result.data.map(function (e) {
return {
'avatar': `${avatarCdn}${e.email_encrypted}?${avatarDefault}`,
'content': changeContent(e.content_marked),
'nick': e.nick,
'url': e.page_url,
'date': e.date,
}
}) })
saveToLocal.set('artalk-newest-comments', JSON.stringify(artalk), !{theme.newest_comments.storage}/(60*24))
generateHtml(artalk)
} catch (e) {
console.log(e)
const $dom = document.querySelector('#card-newest-comments .aside-list')
$dom.innerHTML= "!{_p('aside.card_newest_comments.error')}"
}
} }
const newestCommentInit = () => { const newestCommentInit = () => {

View File

@@ -32,7 +32,7 @@ script.
generateHtml(disqusArray) generateHtml(disqusArray)
}).catch(e => { }).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list') const $dom = document.querySelector('#card-newest-comments .aside-list')
$dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" $dom.textContent= "!{_p('aside.card_newest_comments.error')}"
}) })
} }

View File

@@ -58,7 +58,7 @@ script.
findTrueUrl(githubArray) findTrueUrl(githubArray)
}).catch(e => { }).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list') const $dom = document.querySelector('#card-newest-comments .aside-list')
$dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" $dom.textContent= "!{_p('aside.card_newest_comments.error')}"
}) })
} }

View File

@@ -60,7 +60,7 @@ script.
generateHtml(remark42) generateHtml(remark42)
}).catch(e => { }).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list') const $dom = document.querySelector('#card-newest-comments .aside-list')
$dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" $dom.textContent= "!{_p('aside.card_newest_comments.error')}"
}) })
} }

View File

@@ -36,7 +36,7 @@ script.
generateHtml(twikooArray) generateHtml(twikooArray)
}).catch(function (err) { }).catch(function (err) {
const $dom = document.querySelector('#card-newest-comments .aside-list') const $dom = document.querySelector('#card-newest-comments .aside-list')
$dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" $dom.textContent= "!{_p('aside.card_newest_comments.error')}"
}) })
} }

View File

@@ -79,7 +79,7 @@ script.
generateHtml(valineArray) generateHtml(valineArray)
}).catch(e => { }).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list') const $dom = document.querySelector('#card-newest-comments .aside-list')
$dom.innerHTML= "!{_p('aside.card_newest_comments.error')}" $dom.textContent= "!{_p('aside.card_newest_comments.error')}"
}) })
} }

View File

@@ -1,6 +1,6 @@
script. script.
window.addEventListener('load', () => { window.addEventListener('load', () => {
const changeContent = (content) => { const changeContent = content => {
if (content === '') return content if (content === '') return content
content = content.replace(/<img.*?src="(.*?)"?[^\>]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link content = content.replace(/<img.*?src="(.*?)"?[^\>]+>/ig, '[!{_p("aside.card_newest_comments.image")}]') // replace image link
@@ -41,31 +41,26 @@ script.
window.pjax && window.pjax.refresh($dom) window.pjax && window.pjax.refresh($dom)
} }
const getComment = () => { const getComment = async () => {
const loadWaline = () => { try {
Waline.RecentComments({ const res = await fetch('!{theme.waline.serverURL}/api/comment?type=recent&count=!{theme.newest_comments.limit}', { method: 'GET' })
serverURL: '!{theme.waline.serverURL}', const result = await res.json()
count: !{theme.newest_comments.limit} const walineArray = result.data.map(e => {
}).then(({comments}) => { return {
const walineArray = comments.map(e => { 'content': changeContent(e.comment),
return { 'avatar': e.avatar,
'content': changeContent(e.comment), 'nick': e.nick,
'avatar': e.avatar, 'url': e.url + '#' + e.objectId,
'nick': e.nick, 'date': e.time || e.insertedAt
'url': e.url + '#' + e.objectId, }
'date': e.insertedAt,
}
})
saveToLocal.set('waline-newest-comments', JSON.stringify(walineArray), !{theme.newest_comments.storage}/(60*24))
generateHtml(walineArray)
}).catch(e => {
const $dom = document.querySelector('#card-newest-comments .aside-list')
$dom.innerHTML= "!{_p('aside.card_newest_comments.error')}"
}) })
saveToLocal.set('waline-newest-comments', JSON.stringify(walineArray), !{theme.newest_comments.storage}/(60*24))
generateHtml(walineArray)
} catch (err) {
console.error(err)
const $dom = document.querySelector('#card-newest-comments .aside-list')
$dom.textContent= "!{_p('aside.card_newest_comments.error')}"
} }
if (typeof Waline === 'object') loadWaline()
else getScript('!{url_for(theme.asset.waline_js)}').then(loadWaline)
} }
const newestCommentInit = () => { const newestCommentInit = () => {

View File

@@ -62,7 +62,6 @@ script.
GLOBAL_CONFIG.islazyload && window.lazyLoadInstance.update() GLOBAL_CONFIG.islazyload && window.lazyLoadInstance.update()
typeof chatBtnFn === 'function' && chatBtnFn()
typeof panguInit === 'function' && panguInit() typeof panguInit === 'function' && panguInit()
// google analytics // google analytics

View File

@@ -38,7 +38,7 @@ case source
sub.unshift(data.hitokoto, from) sub.unshift(data.hitokoto, from)
typedJSFn.init(sub) typedJSFn.init(sub)
} else { } else {
document.getElementById('subtitle').innerHTML = data.hitokoto document.getElementById('subtitle').textContent = data.hitokoto
} }
}) })
} }
@@ -55,7 +55,7 @@ case source
sub.unshift(con, from) sub.unshift(con, from)
typedJSFn.init(sub) typedJSFn.init(sub)
} else { } else {
document.getElementById('subtitle').innerHTML = con document.getElementById('subtitle').textContent = con
} }
}) })
} }
@@ -72,7 +72,7 @@ case source
sub.unshift(content) sub.unshift(content)
typedJSFn.init(sub) typedJSFn.init(sub)
} else { } else {
document.getElementById('subtitle').innerHTML = result.data.content document.getElementById('subtitle').textContent = result.data.content
} }
}) })
}) })
@@ -86,7 +86,7 @@ case source
if (!{effect}) { if (!{effect}) {
typedJSFn.init(!{JSON.stringify(subContent)}) typedJSFn.init(!{JSON.stringify(subContent)})
} else { } else {
document.getElementById("subtitle").innerHTML = '!{subContent[0]}' document.getElementById("subtitle").textContent = !{JSON.stringify(subContent[0])}
} }
} }
typedJSFn.run(subtitleType) typedJSFn.run(subtitleType)

View File

@@ -24,4 +24,4 @@ if theme.aside.card_author.enable
if(theme.social) if(theme.social)
.card-info-social-icons.is-center .card-info-social-icons.is-center
!=fragment_cache('social', function(){return partial('includes/header/social')}) !=partial('includes/header/social', {}, {cache: true})

View File

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

View File

@@ -1,6 +1,6 @@
{ {
"name": "hexo-theme-butterfly", "name": "hexo-theme-butterfly",
"version": "4.8.0", "version": "4.9.0",
"description": "A Simple and Card UI Design theme for Hexo", "description": "A Simple and Card UI Design theme for Hexo",
"main": "package.json", "main": "package.json",
"scripts": { "scripts": {
@@ -23,7 +23,7 @@
"email": "my@crazywong.com" "email": "my@crazywong.com"
}, },
"dependencies": { "dependencies": {
"hexo-renderer-stylus": "^2.1.0", "hexo-renderer-stylus": "^3.0.0",
"hexo-renderer-pug": "^3.0.0" "hexo-renderer-pug": "^3.0.0"
}, },
"homepage": "https://butterfly.js.org/", "homepage": "https://butterfly.js.org/",

View File

@@ -1,11 +1,11 @@
algolia_search: algolia_search:
name: algoliasearch name: algoliasearch
file: dist/algoliasearch-lite.umd.js file: dist/algoliasearch-lite.umd.js
version: 4.17.0 version: 4.17.1
instantsearch: instantsearch:
name: instantsearch.js name: instantsearch.js
file: dist/instantsearch.production.min.js file: dist/instantsearch.production.min.js
version: 4.54.0 version: 4.56.1
pjax: pjax:
name: pjax name: pjax
file: pjax.min.js file: pjax.min.js
@@ -37,17 +37,17 @@ disqusjs_css:
twikoo: twikoo:
name: twikoo name: twikoo
file: dist/twikoo.all.min.js file: dist/twikoo.all.min.js
version: 1.6.14 version: 1.6.16
waline_js: waline_js:
name: '@waline/client' name: '@waline/client'
file: dist/waline.js file: dist/waline.js
other_name: waline other_name: waline
version: 2.14.9 version: 2.15.5
waline_css: waline_css:
name: '@waline/client' name: '@waline/client'
file: dist/waline.css file: dist/waline.css
other_name: waline other_name: waline
version: 2.14.9 version: 2.15.5
sharejs: sharejs:
name: butterfly-extsrc name: butterfly-extsrc
file: sharejs/dist/js/social-share.min.js file: sharejs/dist/js/social-share.min.js
@@ -64,16 +64,16 @@ katex:
name: katex name: katex
file: dist/katex.min.css file: dist/katex.min.css
other_name: KaTeX other_name: KaTeX
version: 0.16.4 version: 0.16.7
katex_copytex: katex_copytex:
name: katex name: katex
file: dist/contrib/copy-tex.min.js file: dist/contrib/copy-tex.min.js
other_name: KaTeX other_name: KaTeX
version: 0.16.4 version: 0.16.7
mermaid: mermaid:
name: mermaid name: mermaid
file: dist/mermaid.min.js file: dist/mermaid.min.js
version: 9.4.3 version: 10.2.2
canvas_ribbon: canvas_ribbon:
name: butterfly-extsrc name: butterfly-extsrc
file: dist/canvas-ribbon.min.js file: dist/canvas-ribbon.min.js
@@ -113,7 +113,7 @@ instantpage:
typed: typed:
name: typed.js name: typed.js
file: dist/typed.umd.js file: dist/typed.umd.js
version: 2.0.15 version: 2.0.16
pangu: pangu:
name: pangu name: pangu
file: dist/browser/pangu.min.js file: dist/browser/pangu.min.js
@@ -121,12 +121,12 @@ pangu:
fancybox_css: fancybox_css:
name: '@fancyapps/ui' name: '@fancyapps/ui'
file: dist/fancybox/fancybox.css file: dist/fancybox/fancybox.css
version: 5.0.15 version: 5.0.19
other_name: fancyapps-ui other_name: fancyapps-ui
fancybox: fancybox:
name: '@fancyapps/ui' name: '@fancyapps/ui'
file: dist/fancybox/fancybox.umd.js file: dist/fancybox/fancybox.umd.js
version: 5.0.15 version: 5.0.19
other_name: fancyapps-ui other_name: fancyapps-ui
medium_zoom: medium_zoom:
name: medium-zoom name: medium-zoom
@@ -183,11 +183,11 @@ prismjs_autoloader:
artalk_js: artalk_js:
name: artalk name: artalk
file: dist/Artalk.js file: dist/Artalk.js
version: 2.5.4 version: 2.5.5
artalk_css: artalk_css:
name: artalk name: artalk
file: dist/Artalk.css file: dist/Artalk.css
version: 2.5.4 version: 2.5.5
pace_js: pace_js:
name: pace-js name: pace-js
other_name: pace other_name: pace
@@ -202,13 +202,13 @@ docsearch_js:
name: '@docsearch/js' name: '@docsearch/js'
other_name: docsearch-js other_name: docsearch-js
file: dist/umd/index.js file: dist/umd/index.js
version: 3.3.3 version: 3.4.0
docsearch_css: docsearch_css:
name: '@docsearch/css' name: '@docsearch/css'
other_name: docsearch-css other_name: docsearch-css
file: dist/style.css file: dist/style.css
version: 3.3.3 version: 3.4.0
abcjs_basic_js: abcjs_basic_js:
name: abcjs name: abcjs
file: dist/abcjs-basic-min.js file: dist/abcjs-basic-min.js
version: 6.2.0 version: 6.2.2

View File

@@ -48,12 +48,11 @@ hexo.extend.filter.register('before_generate', () => {
const createCDNLink = (data, type, cond = '') => { const createCDNLink = (data, type, cond = '') => {
Object.keys(data).forEach(key => { Object.keys(data).forEach(key => {
let { name, version, file, other_name } = data[key] let { name, version, file, other_name } = data[key]
const min_file = minFile(file)
const cdnjs_name = other_name || name const cdnjs_name = other_name || name
const cdnjs_file = file.replace(/^[lib|dist]*\/|browser\//g, '') const cdnjs_file = file.replace(/^[lib|dist]*\/|browser\//g, '')
const min_cdnjs_file = minFile(cdnjs_file) const min_cdnjs_file = minFile(cdnjs_file)
if (cond === 'internal') file = `source/${file}` if (cond === 'internal') file = `source/${file}`
const min_file = minFile(file)
const verType = CDN.version ? (type === 'local' ? `?v=${version}` : `@${version}`) : '' const verType = CDN.version ? (type === 'local' ? `?v=${version}` : `@${version}`) : ''
const value = { const value = {

View File

@@ -1,21 +1,19 @@
hexo.extend.filter.register('before_generate', () => { hexo.extend.filter.register('before_generate', () => {
// Get first two digits of the Hexo version number // Get first two digits of the Hexo version number
const hexoVer = hexo.version.replace(/(^.*\..*)\..*/, '$1') const { version, log, locals } = hexo
const logger = hexo.log const hexoVer = version.replace(/(^.*\..*)\..*/, '$1')
if (hexoVer < 5.3) { if (hexoVer < 5.3) {
logger.error('Please update Hexo to V5.3.0 or higher!') log.error('Please update Hexo to V5.3.0 or higher!')
logger.error('請把 Hexo 升級到 V5.3.0 或更高的版本!') log.error('請把 Hexo 升級到 V5.3.0 或更高的版本!')
process.exit(-1) process.exit(-1)
} }
if (hexo.locals.get) { if (locals.get) {
const data = hexo.locals.get('data') const data = locals.get('data')
if (data && data.butterfly) { if (data && data.butterfly) {
logger.error( log.error("'butterfly.yml' is deprecated. Please use '_config.butterfly.yml'")
" 'butterfly.yml' is deprecated. Please use '_config.butterfly.yml' " log.error("'butterfly.yml' 已經棄用,請使用 '_config.butterfly.yml'")
)
logger.error(" 'butterfly.yml' 已經棄用,請使用 '_config.butterfly.yml' ")
process.exit(-1) process.exit(-1)
} }
} }

View File

@@ -72,6 +72,30 @@
cursor: pointer cursor: pointer
transition: all .3s ease-out transition: all .3s ease-out
.custom-hr
position: relative
margin: 40px auto
border: 2px dashed var(--hr-border)
if hexo-config('hr_icon.enable')
width: calc(100% - 4px)
&:hover
&:before
left: calc(95% - 20px)
&:before
position: absolute
top: $hr-icon-top
left: 5%
z-index: 1
color: var(--hr-before-color)
content: $hr-icon
font-size: 20px
line-height: 1
transition: all 1s ease-in-out
@extend .fontawesomeIcon
maxWidth600() maxWidth600()
@media screen and (max-width: 600px) @media screen and (max-width: 600px)
{block} {block}

View File

@@ -34,6 +34,8 @@
--headline-presudo: #a0a0a0 --headline-presudo: #a0a0a0
--scrollbar-color: $scrollbar-color --scrollbar-color: $scrollbar-color
--default-bg-color: $theme-color --default-bg-color: $theme-color
--zoom-bg: #fff
--mark-bg: alpha($dark-black, .3)
body body
position: relative position: relative
@@ -96,30 +98,6 @@ h6
* *
box-sizing: border-box box-sizing: border-box
hr
position: relative
margin: 40px auto
border: 2px dashed var(--hr-border)
if hexo-config('hr_icon.enable')
width: calc(100% - 4px)
&:hover
&:before
left: calc(95% - 20px)
&:before
position: absolute
top: $hr-icon-top
left: 5%
z-index: 1
color: var(--hr-before-color)
content: $hr-icon
font-size: 20px
line-height: 1
transition: all 1s ease-in-out
@extend .fontawesomeIcon
.table-wrap .table-wrap
overflow-x: scroll overflow-x: scroll
margin: 0 0 20px margin: 0 0 20px
@@ -174,9 +152,6 @@ if $site-name-font
.is-center .is-center
text-align: center text-align: center
.copy-true
user-select: all
.pull-left .pull-left
float: left float: left

View File

@@ -75,6 +75,14 @@ $code-block
&:hover &:hover
border-bottom-color: var(--hl-color) border-bottom-color: var(--hl-color)
&.copy-true
user-select: all
& > table,
& > pre
display: block !important
opacity: 0
.highlight-tools .highlight-tools
position: relative position: relative
display: flex display: flex

View File

@@ -5,12 +5,12 @@
background-position: bottom background-position: bottom
background-size: cover background-size: cover
if hexo-config('footer_bg') != false if hexo-config('footer_bg') != false && hexo-config('mask.footer')
&:before &:before
position: absolute position: absolute
width: 100% width: 100%
height: 100% height: 100%
background-color: alpha($dark-black, .5) background-color: var(--mark-bg)
content: '' content: ''
#footer-wrap #footer-wrap

View File

@@ -7,12 +7,13 @@
background-repeat: no-repeat background-repeat: no-repeat
transition: all .5s transition: all .5s
&:not(.not-top-img):before if hexo-config('mask.header')
position: absolute &:not(.not-top-img):before
width: 100% position: absolute
height: 100% width: 100%
background-color: alpha($dark-black, .3) height: 100%
content: '' background-color: var(--mark-bg)
content: ''
// index // index
&.full_page &.full_page
@@ -97,9 +98,6 @@
+maxWidth768() +maxWidth768()
height: 360px height: 360px
&:before
background-color: alpha($dark-black, .5)
#post-info #post-info
position: absolute position: absolute
bottom: 100px bottom: 100px

View File

@@ -66,6 +66,9 @@ beautify()
ul > li ul > li
list-style-type: circle list-style-type: circle
hr
@extend .custom-hr
#article-container #article-container
word-wrap: break-word word-wrap: break-word
overflow-wrap: break-word overflow-wrap: break-word
@@ -156,14 +159,6 @@ beautify()
else if hexo-config('beautify.field') == 'post' else if hexo-config('beautify.field') == 'post'
&.post-content &.post-content
beautify() beautify()
else
hr
margin: 20px 0
border: 1px inset
width 100%
&:before
content: none
#post #post
.tag_share .tag_share

View File

@@ -82,15 +82,22 @@ if hexo-config('waline.bg')
display: none display: none
// Mathjax // Mathjax
.mathjax-overflow mjx-container
overflow-x: auto overflow-x: auto
overflow-y: hidden overflow-y: hidden
padding-bottom: 4px
span.mathjax-overflow
display: inline-block
padding: 0 2px
max-width: 100% max-width: 100%
vertical-align: bottom
&[display]
display: block !important
min-width: auto !important
&:not([display])
display: inline-grid !important
mjx-assistive-mml
right: 0
bottom: 0
.aplayer .aplayer
color: $font-black color: $font-black

View File

@@ -38,10 +38,10 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
--hlexpand-bg: linear-gradient(180deg, rgba(lighten(#121212, 2), .6), rgba(lighten(#121212, 2), .9)) --hlexpand-bg: linear-gradient(180deg, rgba(lighten(#121212, 2), .6), rgba(lighten(#121212, 2), .9))
--scrollbar-color: lighten(#121212, 5) --scrollbar-color: lighten(#121212, 5)
--timeline-bg: lighten(#121212, 5) --timeline-bg: lighten(#121212, 5)
--zoom-bg: #121212
--mark-bg: alpha($dark-black, .6)
#web_bg:before, #web_bg:before
#footer:before,
#page-header:before
position: absolute position: absolute
width: 100% width: 100%
height: 100% height: 100%

View File

@@ -54,8 +54,7 @@ if hexo-config('readmode')
display: none display: none
#page-header.post-bg #page-header.post-bg
background-color: transparent background: none !important
background-image: none !important
&:before &:before
opacity: 0 opacity: 0

View File

@@ -18,7 +18,7 @@
padding: 20px 5px padding: 20px 5px
+minWidth2000() +minWidth2000()
max-width: 1700px max-width: 70%
& > div:first-child:not(.recent-posts) & > div:first-child:not(.recent-posts)
@extend .cardHover @extend .cardHover

View File

@@ -8,7 +8,7 @@
flex-direction: row flex-direction: row
align-items: center align-items: center
overflow: hidden overflow: hidden
height: 18em height: 16.8em
+maxWidth768() +maxWidth768()
flex-direction: column flex-direction: column
@@ -24,7 +24,7 @@
.post_cover .post_cover
overflow: hidden overflow: hidden
width: 44% width: 42%
height: 100% height: 100%
+maxWidth768() +maxWidth768()
@@ -42,7 +42,7 @@
& >.recent-post-info & >.recent-post-info
padding: 0 40px padding: 0 40px
width: 57% width: 58%
+maxWidth768() +maxWidth768()
padding: 20px 20px 30px padding: 20px 20px 30px
@@ -57,7 +57,7 @@
& > .article-title & > .article-title
@extend .limit-more-line @extend .limit-more-line
color: var(--text-highlight-color) color: var(--text-highlight-color)
font-size: 1.72em font-size: 1.55em
line-height: 1.4 line-height: 1.4
transition: all .2s ease-in-out transition: all .2s ease-in-out
-webkit-line-clamp: 2 -webkit-line-clamp: 2
@@ -71,7 +71,7 @@
& > .article-meta-wrap & > .article-meta-wrap
margin: 6px 0 margin: 6px 0
color: $theme-meta-color color: $theme-meta-color
font-size: 90% font-size: .9em
& > .post-meta-date & > .post-meta-date
cursor: default cursor: default

View File

@@ -39,6 +39,10 @@
&:hover &:hover
color: $search-color color: $search-color
hr
margin: 20px auto
@extend .custom-hr
#search-mask #search-mask
position: fixed position: fixed
top: 0 top: 0
@@ -48,3 +52,9 @@
z-index: 1000 z-index: 1000
display: none display: none
background: rgba($dark-black, .6) background: rgba($dark-black, .6)
if hexo-config('algolia_search.enable')
@require 'algolia'
if hexo-config('local_search.enable')
@require 'local-search'

View File

@@ -12,10 +12,4 @@ if hexo-config('css_prefix')
@import '_mode/*' @import '_mode/*'
// search // search
if hexo-config('algolia_search.enable') @import '_search/index'
@import '_search/index'
@import '_search/algolia'
if hexo-config('local_search') && hexo-config('local_search.enable')
@import '_search/index'
@import '_search/local-search'

View File

@@ -70,28 +70,17 @@ document.addEventListener('DOMContentLoaded', function () {
const highLight = GLOBAL_CONFIG.highlight const highLight = GLOBAL_CONFIG.highlight
if (!highLight) return if (!highLight) return
const isHighlightCopy = highLight.highlightCopy const { highlightCopy, highlightLang, highlightHeightLimit, plugin } = highLight
const isHighlightLang = highLight.highlightLang
const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink
const highlightHeightLimit = highLight.highlightHeightLimit const isShowTool = highlightCopy || highlightLang || isHighlightShrink !== undefined
const isShowTool = isHighlightCopy || isHighlightLang || isHighlightShrink !== undefined const $figureHighlight = plugin === 'highlighjs' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]')
const $figureHighlight = highLight.plugin === 'highlighjs' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]')
if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return
const isPrismjs = highLight.plugin === 'prismjs' const isPrismjs = plugin === 'prismjs'
let highlightShrinkEle = ''
let highlightCopyEle = ''
const highlightShrinkClass = isHighlightShrink === true ? 'closed' : '' const highlightShrinkClass = isHighlightShrink === true ? 'closed' : ''
const highlightShrinkEle = isHighlightShrink !== undefined ? `<i class="fas fa-angle-down expand ${highlightShrinkClass}"></i>` : ''
if (isHighlightShrink !== undefined) { const highlightCopyEle = highlightCopy ? '<div class="copy-notice"></div><i class="fas fa-paste copy-button"></i>' : ''
highlightShrinkEle = `<i class="fas fa-angle-down expand ${highlightShrinkClass}"></i>`
}
if (isHighlightCopy) {
highlightCopyEle = '<div class="copy-notice"></div><i class="fas fa-paste copy-button"></i>'
}
const copy = (text, ctx) => { const copy = (text, ctx) => {
if (document.queryCommandSupported && document.queryCommandSupported('copy')) { if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
@@ -100,7 +89,7 @@ document.addEventListener('DOMContentLoaded', function () {
btf.snackbarShow(GLOBAL_CONFIG.copy.success) btf.snackbarShow(GLOBAL_CONFIG.copy.success)
} else { } else {
const prevEle = ctx.previousElementSibling const prevEle = ctx.previousElementSibling
prevEle.innerText = GLOBAL_CONFIG.copy.success prevEle.textContent = GLOBAL_CONFIG.copy.success
prevEle.style.opacity = 1 prevEle.style.opacity = 1
setTimeout(() => { prevEle.style.opacity = 0 }, 700) setTimeout(() => { prevEle.style.opacity = 0 }, 700)
} }
@@ -108,7 +97,7 @@ document.addEventListener('DOMContentLoaded', function () {
if (GLOBAL_CONFIG.Snackbar !== undefined) { if (GLOBAL_CONFIG.Snackbar !== undefined) {
btf.snackbarShow(GLOBAL_CONFIG.copy.noSupport) btf.snackbarShow(GLOBAL_CONFIG.copy.noSupport)
} else { } else {
ctx.previousElementSibling.innerText = GLOBAL_CONFIG.copy.noSupport ctx.previousElementSibling.textContent = GLOBAL_CONFIG.copy.noSupport
} }
} }
} }
@@ -119,8 +108,8 @@ document.addEventListener('DOMContentLoaded', function () {
$buttonParent.classList.add('copy-true') $buttonParent.classList.add('copy-true')
const selection = window.getSelection() const selection = window.getSelection()
const range = document.createRange() const range = document.createRange()
if (isPrismjs) range.selectNodeContents($buttonParent.querySelectorAll('pre code')[0]) const preCodeSelector = isPrismjs ? 'pre code' : 'table .code pre'
else range.selectNodeContents($buttonParent.querySelectorAll('table .code pre')[0]) range.selectNodeContents($buttonParent.querySelectorAll(`${preCodeSelector}`)[0])
selection.removeAllRanges() selection.removeAllRanges()
selection.addRange(range) selection.addRange(range)
const text = selection.toString() const text = selection.toString()
@@ -175,33 +164,29 @@ document.addEventListener('DOMContentLoaded', function () {
} }
} }
if (isHighlightLang) { if (isPrismjs) {
if (isPrismjs) { $figureHighlight.forEach(item => {
$figureHighlight.forEach(function (item) { if (highlightLang) {
const langName = item.getAttribute('data-language') ? item.getAttribute('data-language') : 'Code' const langName = item.getAttribute('data-language') || 'Code'
const highlightLangEle = `<div class="code-lang">${langName}</div>` const highlightLangEle = `<div class="code-lang">${langName}</div>`
btf.wrap(item, 'figure', { class: 'highlight' }) btf.wrap(item, 'figure', { class: 'highlight' })
createEle(highlightLangEle, item) createEle(highlightLangEle, item)
}) } else {
} else { btf.wrap(item, 'figure', { class: 'highlight' })
$figureHighlight.forEach(function (item) { createEle('', item)
}
})
} else {
$figureHighlight.forEach(function (item) {
if (highlightLang) {
let langName = item.getAttribute('class').split(' ')[1] let langName = item.getAttribute('class').split(' ')[1]
if (langName === 'plain' || langName === undefined) langName = 'Code' if (langName === 'plain' || langName === undefined) langName = 'Code'
const highlightLangEle = `<div class="code-lang">${langName}</div>` const highlightLangEle = `<div class="code-lang">${langName}</div>`
createEle(highlightLangEle, item, 'hl') createEle(highlightLangEle, item, 'hl')
}) } else {
}
} else {
if (isPrismjs) {
$figureHighlight.forEach(function (item) {
btf.wrap(item, 'figure', { class: 'highlight' })
createEle('', item)
})
} else {
$figureHighlight.forEach(function (item) {
createEle('', item, 'hl') createEle('', item, 'hl')
}) }
} })
} }
} }
@@ -313,6 +298,11 @@ document.addEventListener('DOMContentLoaded', function () {
const scrollFn = function () { const scrollFn = function () {
const $rightside = document.getElementById('rightside') const $rightside = document.getElementById('rightside')
const innerHeight = window.innerHeight + 56 const innerHeight = window.innerHeight + 56
let initTop = 0
let isChatShow = true
const $header = document.getElementById('page-header')
const isChatBtn = typeof chatBtn !== 'undefined'
const isShowPercent = GLOBAL_CONFIG.percent.rightside
// 當滾動條小于 56 的時候 // 當滾動條小于 56 的時候
if (document.body.scrollHeight <= innerHeight) { if (document.body.scrollHeight <= innerHeight) {
@@ -321,33 +311,26 @@ document.addEventListener('DOMContentLoaded', function () {
} }
// find the scroll direction // find the scroll direction
function scrollDirection (currentTop) { const scrollDirection = currentTop => {
const result = currentTop > initTop // true is down & false is up const result = currentTop > initTop // true is down & false is up
initTop = currentTop initTop = currentTop
return result return result
} }
let initTop = 0
let isChatShow = true
const $header = document.getElementById('page-header')
const isChatBtnHide = typeof chatBtnHide === 'function'
const isChatBtnShow = typeof chatBtnShow === 'function'
const isShowPercent = GLOBAL_CONFIG.percent.rightside
const scrollTask = btf.throttle(() => { const scrollTask = btf.throttle(() => {
const currentTop = window.scrollY || document.documentElement.scrollTop const currentTop = window.scrollY || document.documentElement.scrollTop
const isDown = scrollDirection(currentTop) const isDown = scrollDirection(currentTop)
if (currentTop > 56) { if (currentTop > 56) {
if (isDown) { if (isDown) {
if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible') if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
if (isChatBtnShow && isChatShow === true) { if (isChatBtn && isChatShow === true) {
chatBtnHide() window.chatBtn.hide()
isChatShow = false isChatShow = false
} }
} else { } else {
if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible') if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
if (isChatBtnHide && isChatShow === false) { if (isChatBtn && isChatShow === false) {
chatBtnShow() window.chatBtn.show()
isChatShow = true isChatShow = true
} }
} }
@@ -492,6 +475,22 @@ document.addEventListener('DOMContentLoaded', function () {
window.addEventListener('scroll', tocScrollFn) window.addEventListener('scroll', tocScrollFn)
} }
const modeChangeFn = mode => {
if (!window.themeChange) {
return
}
const turnMode = item => window.themeChange[item](mode)
Object.keys(window.themeChange).forEach(item => {
if (['disqus', 'disqusjs'].includes(item)) {
setTimeout(() => turnMode(item), 300)
} else {
turnMode(item)
}
})
}
/** /**
* Rightside * Rightside
*/ */
@@ -504,7 +503,7 @@ document.addEventListener('DOMContentLoaded', function () {
newEle.className = 'fas fa-sign-out-alt exit-readmode' newEle.className = 'fas fa-sign-out-alt exit-readmode'
$body.appendChild(newEle) $body.appendChild(newEle)
function clickFn () { const clickFn = () => {
$body.classList.remove('read-mode') $body.classList.remove('read-mode')
newEle.remove() newEle.remove()
newEle.removeEventListener('click', clickFn) newEle.removeEventListener('click', clickFn)
@@ -513,8 +512,8 @@ document.addEventListener('DOMContentLoaded', function () {
newEle.addEventListener('click', clickFn) newEle.addEventListener('click', clickFn)
}, },
switchDarkMode: () => { // Switch Between Light And Dark Mode switchDarkMode: () => { // Switch Between Light And Dark Mode
const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' const willChangeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'
if (nowMode === 'light') { if (willChangeMode === 'dark') {
activateDarkMode() activateDarkMode()
saveToLocal.set('theme', 'dark', 2) saveToLocal.set('theme', 'dark', 2)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night) GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
@@ -523,11 +522,7 @@ document.addEventListener('DOMContentLoaded', function () {
saveToLocal.set('theme', 'light', 2) saveToLocal.set('theme', 'light', 2)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day) GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day)
} }
// handle some cases modeChangeFn(willChangeMode)
typeof utterancesTheme === 'function' && utterancesTheme()
typeof changeGiscusTheme === 'function' && changeGiscusTheme()
typeof FB === 'object' && window.loadFBComment && window.loadFBComment()
typeof runMermaid === 'function' && window.runMermaid()
}, },
showOrHideBtn: (e) => { // rightside 點擊設置 按鈕 展開 showOrHideBtn: (e) => { // rightside 點擊設置 按鈕 展開
const rightsideHideClassList = document.getElementById('rightside-config-hide').classList const rightsideHideClassList = document.getElementById('rightside-config-hide').classList
@@ -545,15 +540,16 @@ document.addEventListener('DOMContentLoaded', function () {
}, },
hideAsideBtn: () => { // Hide aside hideAsideBtn: () => { // Hide aside
const $htmlDom = document.documentElement.classList const $htmlDom = document.documentElement.classList
$htmlDom.contains('hide-aside') const saveStatus = $htmlDom.contains('hide-aside') ? 'show' : 'hide'
? saveToLocal.set('aside-status', 'show', 2) saveToLocal.set('aside-status', saveStatus, 2)
: saveToLocal.set('aside-status', 'hide', 2)
$htmlDom.toggle('hide-aside') $htmlDom.toggle('hide-aside')
}, },
runMobileToc: () => { runMobileToc: () => {
if (window.getComputedStyle(document.getElementById('card-toc')).getPropertyValue('opacity') === '0') window.mobileToc.open() if (window.getComputedStyle(document.getElementById('card-toc')).getPropertyValue('opacity') === '0') window.mobileToc.open()
else window.mobileToc.close() else window.mobileToc.close()
},
toggleChatDisplay: () => {
window.chatBtnFn()
} }
} }
@@ -578,6 +574,9 @@ document.addEventListener('DOMContentLoaded', function () {
case 'hide-aside-btn': case 'hide-aside-btn':
rightSideFn.hideAsideBtn() rightSideFn.hideAsideBtn()
break break
case 'chat-btn':
rightSideFn.toggleChatDisplay()
break
default: default:
break break
} }
@@ -596,21 +595,16 @@ document.addEventListener('DOMContentLoaded', function () {
} }
/** /**
* 複製時加上版權信息 * 複製時加上版權信息
*/ */
const addCopyright = () => { const addCopyright = () => {
const copyright = GLOBAL_CONFIG.copyright const copyright = GLOBAL_CONFIG.copyright
document.body.oncopy = (e) => { document.body.oncopy = (e) => {
e.preventDefault() e.preventDefault()
let textFont; const copyFont = window.getSelection(0).toString() const copyFont = window.getSelection(0).toString()
let textFont = copyFont
if (copyFont.length > copyright.limitCount) { if (copyFont.length > copyright.limitCount) {
textFont = copyFont + '\n' + '\n' + '\n' + textFont = `${copyFont}\n\n\n${copyright.languages.author}\n${copyright.languages.link}${window.location.href}\n${copyright.languages.source}\n${copyright.languages.info}`
copyright.languages.author + '\n' +
copyright.languages.link + window.location.href + '\n' +
copyright.languages.source + '\n' +
copyright.languages.info
} else {
textFont = copyFont
} }
if (e.clipboardData) { if (e.clipboardData) {
return e.clipboardData.setData('text', textFont) return e.clipboardData.setData('text', textFont)
@@ -627,7 +621,7 @@ document.addEventListener('DOMContentLoaded', function () {
const $runtimeCount = document.getElementById('runtimeshow') const $runtimeCount = document.getElementById('runtimeshow')
if ($runtimeCount) { if ($runtimeCount) {
const publishDate = $runtimeCount.getAttribute('data-publishDate') const publishDate = $runtimeCount.getAttribute('data-publishDate')
$runtimeCount.innerText = btf.diffDate(publishDate) + ' ' + GLOBAL_CONFIG.runtime $runtimeCount.textContent = `${btf.diffDate(publishDate)} ${GLOBAL_CONFIG.runtime}`
} }
} }
@@ -638,7 +632,7 @@ document.addEventListener('DOMContentLoaded', function () {
const $lastPushDateItem = document.getElementById('last-push-date') const $lastPushDateItem = document.getElementById('last-push-date')
if ($lastPushDateItem) { if ($lastPushDateItem) {
const lastPushDate = $lastPushDateItem.getAttribute('data-lastPushDate') const lastPushDate = $lastPushDateItem.getAttribute('data-lastPushDate')
$lastPushDateItem.innerText = btf.diffDate(lastPushDate, true) $lastPushDateItem.textContent = btf.diffDate(lastPushDate, true)
} }
} }
@@ -771,10 +765,9 @@ document.addEventListener('DOMContentLoaded', function () {
const relativeDate = function (selector) { const relativeDate = function (selector) {
selector.forEach(item => { selector.forEach(item => {
const $this = item const timeVal = item.getAttribute('datetime')
const timeVal = $this.getAttribute('datetime') item.textContent = btf.diffDate(timeVal, true)
$this.innerText = btf.diffDate(timeVal, true) item.style.display = 'inline'
$this.style.display = 'inline'
}) })
} }
@@ -789,6 +782,13 @@ document.addEventListener('DOMContentLoaded', function () {
clickFnOfSubMenu() clickFnOfSubMenu()
GLOBAL_CONFIG.islazyload && lazyloadImg() GLOBAL_CONFIG.islazyload && lazyloadImg()
GLOBAL_CONFIG.copyright !== undefined && addCopyright() GLOBAL_CONFIG.copyright !== undefined && addCopyright()
if (GLOBAL_CONFIG.autoDarkmode) {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (saveToLocal.get('theme') !== undefined) return
e.matches ? modeChangeFn('dark') : modeChangeFn('light')
})
}
} }
window.refreshFn = function () { window.refreshFn = function () {

View File

@@ -282,7 +282,7 @@ window.addEventListener('load', () => {
window.pjax && window.pjax.refresh(container) window.pjax && window.pjax.refresh(container)
} }
$loadingStatus.innerHTML = '' $loadingStatus.textContent = ''
} }
let loadFlag = false let loadFlag = false

View File

@@ -1,10 +1,6 @@
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
const translate = GLOBAL_CONFIG.translate const { defaultEncoding, translateDelay, msgToTraditionalChinese, msgToSimplifiedChinese } = GLOBAL_CONFIG.translate
const snackbarData = GLOBAL_CONFIG.Snackbar const snackbarData = GLOBAL_CONFIG.Snackbar
const defaultEncoding = translate.defaultEncoding // 網站默認語言1: 繁體中文, 2: 簡體中文
const translateDelay = translate.translateDelay // 延遲時間,若不在前, 要設定延遲翻譯時間, 如100表示100ms,默認為0
const msgToTraditionalChinese = translate.msgToTraditionalChinese // 此處可以更改為你想要顯示的文字
const msgToSimplifiedChinese = translate.msgToSimplifiedChinese // 同上,但兩處均不建議更改
let currentEncoding = defaultEncoding let currentEncoding = defaultEncoding
const targetEncodingCookie = 'translate-chn-cht' const targetEncodingCookie = 'translate-chn-cht'
let targetEncoding = let targetEncoding =
@@ -12,7 +8,7 @@ document.addEventListener('DOMContentLoaded', function () {
? defaultEncoding ? defaultEncoding
: Number(saveToLocal.get('translate-chn-cht')) : Number(saveToLocal.get('translate-chn-cht'))
let translateButtonObject let translateButtonObject
const isSnackbar = GLOBAL_CONFIG.Snackbar !== undefined const isSnackbar = snackbarData !== undefined
function setLang () { function setLang () {
document.documentElement.lang = targetEncoding === 1 ? 'zh-TW' : 'zh-CN' document.documentElement.lang = targetEncoding === 1 ? 'zh-TW' : 'zh-CN'
@@ -58,12 +54,12 @@ document.addEventListener('DOMContentLoaded', function () {
if (targetEncoding === 1) { if (targetEncoding === 1) {
currentEncoding = 1 currentEncoding = 1
targetEncoding = 2 targetEncoding = 2
translateButtonObject.innerHTML = msgToTraditionalChinese translateButtonObject.textContent = msgToTraditionalChinese
isSnackbar && btf.snackbarShow(snackbarData.cht_to_chs) isSnackbar && btf.snackbarShow(snackbarData.cht_to_chs)
} else if (targetEncoding === 2) { } else if (targetEncoding === 2) {
currentEncoding = 2 currentEncoding = 2
targetEncoding = 1 targetEncoding = 1
translateButtonObject.innerHTML = msgToSimplifiedChinese translateButtonObject.textContent = msgToSimplifiedChinese
isSnackbar && btf.snackbarShow(snackbarData.chs_to_cht) isSnackbar && btf.snackbarShow(snackbarData.chs_to_cht)
} }
saveToLocal.set(targetEncodingCookie, targetEncoding, 2) saveToLocal.set(targetEncodingCookie, targetEncoding, 2)
@@ -104,7 +100,7 @@ document.addEventListener('DOMContentLoaded', function () {
translateButtonObject = document.getElementById('translateLink') translateButtonObject = document.getElementById('translateLink')
if (translateButtonObject) { if (translateButtonObject) {
if (currentEncoding !== targetEncoding) { if (currentEncoding !== targetEncoding) {
translateButtonObject.innerHTML = translateButtonObject.textContent =
targetEncoding === 1 targetEncoding === 1
? msgToSimplifiedChinese ? msgToSimplifiedChinese
: msgToTraditionalChinese : msgToTraditionalChinese

View File

@@ -186,10 +186,9 @@ const btf = {
}, },
unwrap: el => { unwrap: el => {
const elParentNode = el.parentNode const parent = el.parentNode
if (elParentNode !== document.body) { if (parent && parent !== document.body) {
elParentNode.parentNode.insertBefore(el, elParentNode) parent.replaceChild(el, parent)
elParentNode.parentNode.removeChild(elParentNode)
} }
}, },
@@ -211,13 +210,7 @@ const btf = {
const service = GLOBAL_CONFIG.lightbox const service = GLOBAL_CONFIG.lightbox
if (service === 'mediumZoom') { if (service === 'mediumZoom') {
const zoom = mediumZoom(ele) mediumZoom(ele, { background: 'var(--zoom-bg)' })
zoom.on('open', e => {
const photoBg = document.documentElement.getAttribute('data-theme') === 'dark' ? '#121212' : '#fff'
zoom.update({
background: photoBg
})
})
} }
if (service === 'fancybox') { if (service === 'fancybox') {
@@ -302,5 +295,13 @@ const btf = {
const scrollPercentRounded = Math.round(scrollPercent * 100) const scrollPercentRounded = Math.round(scrollPercent * 100)
const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded
return percentage return percentage
},
addModeChange: (name, fn) => {
if (window.themeChange && window.themeChange[name]) return
window.themeChange = {
...window.themeChange,
[name]: fn
}
} }
} }