Compare commits

...

41 Commits
5.3.3 ... 5.4.3

42 changed files with 605 additions and 298 deletions

2
.gitignore vendored
View File

@@ -1,2 +1,2 @@
.DS_Store .DS_Store
.DS_Store node_modules/

View File

@@ -13,6 +13,7 @@ nav:
# Navigation bar logo image # Navigation bar logo image
logo: logo:
display_title: true display_title: true
display_post_title: true
# Whether to fix navigation bar # Whether to fix navigation bar
fixed: false fixed: false
@@ -158,7 +159,7 @@ subtitle:
# Choose: false/1/2/3 # Choose: false/1/2/3
# false - disable the function # false - disable the function
# 1 - hitokoto.cn # 1 - hitokoto.cn
# 2 - yijuzhan.com # 2 - https://api.aa1.cn/doc/yiyan.html
# 3 - jinrishici.com # 3 - jinrishici.com
source: false source: false
# If you close the typewriter effect, the subtitle will only show the first line of sub # If you close the typewriter effect, the subtitle will only show the first line of sub
@@ -254,12 +255,15 @@ noticeOutdate:
# Footer Settings # Footer Settings
# -------------------------------------- # --------------------------------------
footer: footer:
nav:
owner: owner:
enable: true enable: true
since: 2019 since: 2025
custom_text:
# Copyright of theme and framework # Copyright of theme and framework
copyright: true copyright:
enable: true
version: true
custom_text:
# -------------------------------------- # --------------------------------------
# Aside Settings # Aside Settings
@@ -399,6 +403,9 @@ rightside_item_order:
# Default: toc,chat,comment # Default: toc,chat,comment
show: show:
# Animation for the bottom right config button
rightside_config_animation: true
# -------------------------------------- # --------------------------------------
# Global Settings # Global Settings
# -------------------------------------- # --------------------------------------
@@ -696,6 +703,12 @@ umami_analytics:
# Umami Cloud (API key) / self-hosted Umami (token) # Umami Cloud (API key) / self-hosted Umami (token)
token: token:
# https://www.googletagmanager.com/
google_tag_manager:
tag_id:
# optional
domain:
# -------------------------------------- # --------------------------------------
# Advertisement # Advertisement
# -------------------------------------- # --------------------------------------
@@ -987,6 +1000,8 @@ instantpage: false
# https://github.com/verlok/vanilla-lazyload # https://github.com/verlok/vanilla-lazyload
lazyload: lazyload:
enable: false enable: false
# Use browser's native lazyload instead of vanilla-lazyload
native: false
# Specify the field to use lazyload (site or post) # Specify the field to use lazyload (site or post)
field: site field: site
placeholder: placeholder:

View File

@@ -32,6 +32,7 @@ post:
copyright_content: 'All articles on this blog are licensed under <a href="%s">%s</a> unless otherwise stated.' copyright_content: 'All articles on this blog are licensed under <a href="%s">%s</a> unless otherwise stated.'
recommend: Related Articles recommend: Related Articles
edit: Edit edit: Edit
back_to_home: Back to Home
search: search:
title: Search title: Search

View File

@@ -32,6 +32,7 @@ post:
copyright_content: 'All articles on this blog are licensed under <a href="%s">%s</a> unless otherwise stated.' copyright_content: 'All articles on this blog are licensed under <a href="%s">%s</a> unless otherwise stated.'
recommend: Related Articles recommend: Related Articles
edit: Edit edit: Edit
back_to_home: Back to Home
search: search:
title: Search title: Search

View File

@@ -32,6 +32,7 @@ post:
copyright_content: 'このブログのすべての記事は、<a href="%s">%s</a> ライセンスの下で提供されており、特に明記されていない限り、すべての権利を留保します。転載時には出典を明記してください: <a href="%s">%s</a>。' copyright_content: 'このブログのすべての記事は、<a href="%s">%s</a> ライセンスの下で提供されており、特に明記されていない限り、すべての権利を留保します。転載時には出典を明記してください: <a href="%s">%s</a>。'
recommend: 関連記事 recommend: 関連記事
edit: 編集 edit: 編集
back_to_home: ホームに戻る
search: search:
title: 検索 title: 検索

View File

@@ -32,6 +32,7 @@ post:
copyright_content: '이 블로그의 모든 글은 <a href="%s">%s</a> 라이선스를 따르며, 별도로 명시되지 않는 한 모든 권리를 보유합니다. 재배포 시 출처를 명시해 주세요: <a href="%s">%s</a>.' copyright_content: '이 블로그의 모든 글은 <a href="%s">%s</a> 라이선스를 따르며, 별도로 명시되지 않는 한 모든 권리를 보유합니다. 재배포 시 출처를 명시해 주세요: <a href="%s">%s</a>.'
recommend: 관련 글 recommend: 관련 글
edit: 편집 edit: 편집
back_to_home: 홈으로 돌아가기
search: search:
title: 검색 title: 검색

View File

@@ -33,6 +33,7 @@ post:
<a href="%s" target="_blank">%s</a> 许可协议。转载请注明来源 <a href="%s" target="_blank">%s</a>' <a href="%s" target="_blank">%s</a> 许可协议。转载请注明来源 <a href="%s" target="_blank">%s</a>'
recommend: 相关推荐 recommend: 相关推荐
edit: 编辑 edit: 编辑
back_to_home: 返回首页
search: search:
title: 搜索 title: 搜索

View File

@@ -32,6 +32,7 @@ post:
copyright_content: '除特別聲明外,本博客所有文章均採用<a href="%s">%s</a> 授權協議。轉載請註明出處:<a href="%s">%s</a>。' copyright_content: '除特別聲明外,本博客所有文章均採用<a href="%s">%s</a> 授權協議。轉載請註明出處:<a href="%s">%s</a>。'
recommend: 相關文章 recommend: 相關文章
edit: 編輯 edit: 編輯
back_to_home: 返回首頁
search: search:
title: 搜尋 title: 搜尋

View File

@@ -32,6 +32,7 @@ post:
copyright_content: '本部落格所有文章除特別聲明外,均採用<a href="%s" target="_blank">%s</a> 授權協議。轉載請註明來源 <a href="%s" target="_blank">%s</a>' copyright_content: '本部落格所有文章除特別聲明外,均採用<a href="%s" target="_blank">%s</a> 授權協議。轉載請註明來源 <a href="%s" target="_blank">%s</a>'
recommend: 相關推薦 recommend: 相關推薦
edit: 編輯 edit: 編輯
back_to_home: 返回首頁
search: search:
title: 搜尋 title: 搜尋

View File

@@ -55,3 +55,7 @@ div
script(async data-pjax src= theme.asset.busuanzi || '//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js') script(async data-pjax src= theme.asset.busuanzi || '//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js')
!= partial('includes/third-party/search/index', {}, { cache: true }) != partial('includes/third-party/search/index', {}, { cache: true })
if theme.google_tag_manager && theme.google_tag_manager.tag_id
noscript
iframe(src=`${theme.google_tag_manager.domain ? theme.google_tag_manager.domain : 'https://www.googletagmanager.com'}/ns.html?id=${theme.google_tag_manager.tag_id}` height="0" width="0" style="display:none;visibility:hidden")

View File

@@ -1,19 +1,39 @@
#footer-wrap - const { nav, owner, copyright, custom_text } = theme.footer
if theme.footer.owner.enable
- const currentYear = new Date().getFullYear() if nav
- const sinceYear = theme.footer.owner.since .footer-flex
.copyright for block in nav
if sinceYear && sinceYear != currentYear .footer-flex-items(style=`${ block.width ? 'flex-grow:' + block.width : '' }`)
!= `&copy;${sinceYear} - ${currentYear} By ${config.author}` for blockItem in block.content
else .footer-flex-item
!= `&copy;${currentYear} By ${config.author}` .footer-flex-title= blockItem.title
if theme.footer.copyright .footer-flex-content
- const v = getVersion() for subitem in blockItem.item
.framework-info if subitem.html
span= _p('footer.framework') + ' ' div!= subitem.html
a(href='https://hexo.io')= `Hexo ${v.hexo}` else if subitem.url
span.footer-separator | a(href=url_for(subitem.url), target='_blank' title=subitem.title)= subitem.title
span= _p('footer.theme') + ' ' else if subitem.title
a(href='https://github.com/jerryc127/hexo-theme-butterfly')= `Butterfly ${v.theme}` div!= subitem.title
.footer-other
.footer-copyright
if owner.enable
- const currentYear = new Date().getFullYear()
- const sinceYear = owner.since
span.copyright
if sinceYear && sinceYear != currentYear
!= `&copy;&nbsp;${sinceYear} - ${currentYear} By ${config.author}`
else
!= `&copy;&nbsp;${currentYear} By ${config.author}`
if copyright.enable
- const v = copyright.version ? getVersion() : false
span.framework-info
if owner.enable && nav
span.footer-separator |
span= _p('footer.framework') + ' '
a(href='https://hexo.io')= `Hexo${ v ? ' ' + v.hexo : '' }`
span.footer-separator |
span= _p('footer.theme') + ' '
a(href='https://github.com/jerryc127/hexo-theme-butterfly')= `Butterfly${ v ? ' ' + v.theme : '' }`
if theme.footer.custom_text if theme.footer.custom_text
.footer_custom_text!= theme.footer.custom_text .footer_custom_text!= theme.footer.custom_text

View File

@@ -32,3 +32,14 @@ if theme.microsoft_clarity
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "!{theme.microsoft_clarity}"); })(window, document, "clarity", "script", "!{theme.microsoft_clarity}");
if (theme.google_tag_manager && theme.google_tag_manager.tag_id)
script.
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
"!{theme.google_tag_manager.domain ? theme.google_tag_manager.domain : 'https://www.googletagmanager.com'}/gtm.js?id="+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','!{theme.google_tag_manager.tag_id}');
btf.addGlobalFn('pjaxComplete', () => {
dataLayer.push({'event': 'pjaxComplete', 'page_title': document.title, 'page_location': location.href, 'page_path': window.location.pathname})
}, 'google_tag_manager')

View File

@@ -1,34 +1,55 @@
if theme.structured_data && page.layout === 'post' if theme.structured_data
- if page.layout === 'post'
// use json-ld to add structured data -
// https://developers.google.com/search/docs/appearance/structured-data/article
const title = page.title const title = page.title
const url = page.permalink const url = page.permalink
const imageVal = page.cover_type === 'img' ? page.cover : theme.avatar.img const imageVal = page.cover_type === 'img' ? page.cover : theme.avatar.img
const image = imageVal ? full_url_for(imageVal) : '' const image = imageVal ? full_url_for(imageVal) : ''
const datePublished = page.date.toISOString() const datePublished = page.date.toISOString()
const dateModified = (page.updated || page.date).toISOString() const dateModified = (page.updated || page.date).toISOString()
const author = page.copyright_author || config.author const author = page.copyright_author || config.author
const authorHrefVal = page.copyright_author_href || theme.post_copyright.author_href || site.url; const authorHrefVal = page.copyright_author_href || theme.post_copyright.author_href || config.url
const authorHref = full_url_for(authorHrefVal); const authorHref = full_url_for(authorHrefVal)
const jsonLd = { const jsonLd = {
"@context": "https://schema.org", "@context": "https://schema.org",
"@type": "BlogPosting", "@type": "BlogPosting",
"headline": title, "headline": title,
"url": url, "url": url,
"image": image, "image": image,
"datePublished": datePublished, "datePublished": datePublished,
"dateModified": dateModified, "dateModified": dateModified,
"author": [{ "author": [{
"@type": "Person", "@type": "Person",
"name": author, "name": author,
"url": authorHref "url": authorHref
}] }]
}; }
jsonLdScript = JSON.stringify(jsonLd, null, 2); jsonLdScript = JSON.stringify(jsonLd, null, 2)
- -
else if is_home() && (!page.current || page.current === 1)
-
// https://developers.google.com/search/docs/appearance/site-names#website
const baseUrl = config.url;
const currentPath = url_for('/');
const isRootOrSubdomain = currentPath.split('/').filter(Boolean).length === 0;
if (isRootOrSubdomain) {
const jsonLd = {
"@context": "https://schema.org",
"@type": "WebSite",
"name": config.title,
"url": full_url_for('/'),
}
jsonLdScript = JSON.stringify(jsonLd, null, 2)
}
-
script(type="application/ld+json"). script(type="application/ld+json").
!{jsonLdScript} !{jsonLdScript}

View File

@@ -5,9 +5,13 @@ nav#nav
img.site-icon(src=url_for(theme.nav.logo) alt='Logo') img.site-icon(src=url_for(theme.nav.logo) alt='Logo')
if theme.nav.display_title if theme.nav.display_title
span.site-name=config.title span.site-name=config.title
if globalPageType === 'post' if globalPageType === 'post' && theme.nav.display_post_title
a.nav-page-title(href=url_for('/')) a.nav-page-title(href=url_for('/'))
span.site-name=(page.title || config.title) span.site-name=(page.title || config.title)
span.site-name
i.fa-solid.fa-circle-arrow-left
span= ' ' + _p('post.back_to_home')
#menus #menus
if theme.search.use if theme.search.use
#search-button #search-button

View File

@@ -14,6 +14,7 @@ script.
const $body = document.body const $body = document.body
const preloader = { const preloader = {
endLoading: () => { endLoading: () => {
if ($loadingBox.classList.contains('loaded')) return
$body.style.overflow = '' $body.style.overflow = ''
$loadingBox.classList.add('loaded') $loadingBox.classList.add('loaded')
}, },
@@ -24,7 +25,15 @@ script.
} }
preloader.initLoading() preloader.initLoading()
window.addEventListener('load', preloader.endLoading)
if (document.readyState === 'complete') {
preloader.endLoading()
} else {
window.addEventListener('load', preloader.endLoading)
document.addEventListener('DOMContentLoaded', preloader.endLoading)
// Add timeout protection: force end after 7 seconds
setTimeout(preloader.endLoading, 7000)
}
if (!{theme.pjax && theme.pjax.enable}) { if (!{theme.pjax && theme.pjax.enable}) {
btf.addGlobalFn('pjaxSend', preloader.initLoading, 'preloader_init') btf.addGlobalFn('pjaxSend', preloader.initLoading, 'preloader_init')

View File

@@ -1,37 +1,38 @@
- if page.total !== 1
var options = { -
prev_text: '<i class="fas fa-chevron-left fa-fw"></i>', var options = {
next_text: '<i class="fas fa-chevron-right fa-fw"></i>', prev_text: '<i class="fas fa-chevron-left fa-fw"></i>',
mid_size: 1, next_text: '<i class="fas fa-chevron-right fa-fw"></i>',
escape: false mid_size: 1,
} escape: false
}
if globalPageType === 'post' if globalPageType === 'post'
- let paginationOrder = theme.post_pagination === 1 ? { prev: page.prev, next: page.next } : { prev: page.next, next: page.prev } - let paginationOrder = theme.post_pagination === 2 ? { prev: page.prev, next: page.next } : { prev: page.next, next: page.prev }
nav#pagination.pagination-post nav#pagination.pagination-post
each direction, key in paginationOrder each direction, key in paginationOrder
if direction if direction
- const getPostDesc = direction.postDesc || postDesc(direction) - const getPostDesc = direction.postDesc || postDesc(direction)
- let className = key === 'prev' ? (paginationOrder.next ? '' : 'full-width') : (paginationOrder.prev ? '' : 'full-width') - let className = key === 'prev' ? (paginationOrder.next ? '' : 'full-width') : (paginationOrder.prev ? '' : 'full-width')
- className = getPostDesc ? className : className + ' no-desc' - className = getPostDesc ? className : className + ' no-desc'
a.pagination-related(class=className href=url_for(direction.path) title=direction.title) a.pagination-related(class=className href=url_for(direction.path) title=direction.title)
if direction.cover_type === 'img' if direction.cover_type === 'img'
img.cover(src=url_for(direction.cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt=`cover of ${key === 'prev' ? 'previous' : 'next'} post`) img.cover(src=url_for(direction.cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt=`cover of ${key === 'prev' ? 'previous' : 'next'} post`)
else else
.cover(style=`background: ${direction.cover || 'var(--default-bg-color)'}`) .cover(style=`background: ${direction.cover || 'var(--default-bg-color)'}`)
.info(class=key === 'prev' ? '' : 'text-right') .info(class=key === 'prev' ? '' : 'text-right')
.info-1 .info-1
.info-item-1=_p(`pagination.${key}`) .info-item-1=_p(`pagination.${key}`)
.info-item-2!=direction.title .info-item-2!=direction.title
if getPostDesc if getPostDesc
.info-2 .info-2
.info-item-1!=getPostDesc .info-item-1!=getPostDesc
else else
nav#pagination nav#pagination
.pagination .pagination
if globalPageType === 'home' if globalPageType === 'home'
- options.format = 'page/%d/#content-inner' - options.format = 'page/%d/#content-inner'
!=paginator(options) !=paginator(options)

View File

@@ -1,4 +1,5 @@
- const { readmode, translate, darkmode, aside, chat } = theme - const { readmode, translate, darkmode, aside, chat } = theme
mixin rightsideItem(array) mixin rightsideItem(array)
each item in array each item in array
case item case item
@@ -30,30 +31,22 @@ mixin rightsideItem(array)
a#to_comment(href="#post-comment" title=_p("rightside.scroll_to_comment")) a#to_comment(href="#post-comment" title=_p("rightside.scroll_to_comment"))
i.fas.fa-comments i.fas.fa-comments
- const { enable, hide, show } = theme.rightside_item_order
- const hideArray = enable && hide ? hide.split(',') : ['readmode','translate','darkmode','hideAside']
- const showArray = enable && show ? show.split(',') : ['toc','chat','comment']
- const needCogBtn = (enable && hide) || (!enable && ((globalPageType === 'post' && (readmode || translate.enable || (darkmode.enable && darkmode.button))) || (translate.enable || (darkmode.enable && darkmode.button))))
#rightside #rightside
- const { enable, hide, show } = theme.rightside_item_order
- const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode','hideAside']
- const showArray = enable ? show && show.split(',') : ['toc','chat','comment']
#rightside-config-hide #rightside-config-hide
if hideArray if hideArray.length
+rightsideItem(hideArray) +rightsideItem(hideArray)
#rightside-config-show
if enable
if hide
button#rightside-config(type="button" title=_p("rightside.setting"))
i.fas.fa-cog.fa-spin
else
if globalPageType === 'post'
if (readmode || translate.enable || (darkmode.enable && darkmode.button))
button#rightside-config(type="button" title=_p("rightside.setting"))
i.fas.fa-cog.fa-spin
else if translate.enable || (darkmode.enable && darkmode.button)
button#rightside-config(type="button" title=_p("rightside.setting"))
i.fas.fa-cog.fa-spin
if showArray #rightside-config-show
if needCogBtn
button#rightside-config(type="button" title=_p("rightside.setting"))
i.fas.fa-cog(class=theme.rightside_config_animation ? 'fa-spin' : '')
if showArray.length
+rightsideItem(showArray) +rightsideItem(showArray)
button#go-up(type="button" title=_p("rightside.back_to_top")) button#go-up(type="button" title=_p("rightside.back_to_top"))

View File

@@ -1,17 +1,46 @@
script. script.
(() => { (() => {
const abcjsInit = () => { const abcjsInit = () => {
const abcjsFn = () => setTimeout(() => { const abcjsFn = () => {
document.querySelectorAll(".abc-music-sheet").forEach(ele => { setTimeout(() => {
if (ele.children.length > 0) return const sheets = document.querySelectorAll(".abc-music-sheet")
ABCJS.renderAbc(ele, ele.innerHTML, {responsive: 'resize'}) for (let i = 0; i < sheets.length; i++) {
}) const ele = sheets[i]
}, 100) if (ele.children.length > 0) continue
typeof ABCJS === 'object' ? abcjsFn() // Parse parameters from data-params attribute
: btf.getScript('!{url_for(theme.asset.abcjs_basic_js)}').then(abcjsFn) let params = {}
const dp = ele.getAttribute("data-params")
if (dp) {
try {
params = JSON.parse(dp)
} catch (e) {
console.error("Failed to parse data-params:", e)
}
}
// Merge parsed parameters with the responsive option
// Ensures params content appears before responsive
const options = { ...params, responsive: "resize" }
// Render the music score using ABCJS.renderAbc
ABCJS.renderAbc(ele, ele.innerHTML, options)
}
}, 100)
}
if (typeof ABCJS === "object") {
abcjsFn()
} else {
btf.getScript("!{url_for(theme.asset.abcjs_basic_js)}").then(abcjsFn)
}
} }
window.pjax ? abcjsInit() : window.addEventListener('load', abcjsInit) if (window.pjax) {
btf.addGlobalFn('encrypt', abcjsInit, 'abcjs') abcjsInit()
} else {
window.addEventListener("load", abcjsInit)
}
btf.addGlobalFn("encrypt", abcjsInit, "abcjs")
})() })()

View File

@@ -18,7 +18,9 @@ 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.textContent = res[index].count if (res[index]) {
item.textContent = res[index].count
}
}) })
}).catch(function (err) { }).catch(function (err) {
console.log(err) console.log(err)

View File

@@ -3,7 +3,7 @@
script. script.
(() => { (() => {
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo' const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
const option = !{JSON.stringify(option)} const options = !{JSON.stringify(option)}
const loadScript = src => { const loadScript = src => {
const script = document.createElement('script') const script = document.createElement('script')
@@ -42,8 +42,8 @@ script.
host: '!{host}', host: '!{host}',
site_id: '!{siteId}', site_id: '!{siteId}',
theme: document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light', theme: document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light',
...option, ...options,
url: isShuoshuo ? window.location.origin + path : (option && option.url) || window.location.origin + window.location.pathname url: isShuoshuo ? window.location.origin + path : (options && options.url) || window.location.origin + window.location.pathname
} }
if (window.REMARK42) { if (window.REMARK42) {

View File

@@ -59,7 +59,10 @@ script.
document.addEventListener('pjax:error', e => { document.addEventListener('pjax:error', e => {
if (e.request.status === 404) { if (e.request.status === 404) {
window.location.href = e.request.responseURL const usePjax = !{theme.pjax && theme.pjax.enable}
!{theme.error_404 && theme.error_404.enable}
? (usePjax ? pjax.loadUrl('!{url_for("/404.html")}') : window.location.href = '!{url_for("/404.html")}')
: window.location.href = e.request.responseURL
} }
}) })
})() })()

View File

@@ -1,4 +1,4 @@
- const { effect,source,sub,typed_option } = theme.subtitle - const { effect, source, sub, typed_option } = theme.subtitle
- let subContent = sub || new Array() - let subContent = sub || new Array()
script. script.
@@ -22,6 +22,26 @@ script.
} else { } else {
subtitleType() subtitleType()
} }
},
processSubtitle: (content, extraContents = []) => {
if (!{effect}) {
const sub = !{JSON.stringify(subContent)}.slice()
if (extraContents.length > 0) {
sub.unshift(...extraContents)
}
if (typeof content === 'string') {
sub.unshift(content)
} else if (Array.isArray(content)) {
sub.unshift(...content)
}
sub.length > 0 && typedJSFn.init(sub)
} else {
document.getElementById('subtitle').textContent = typeof content === 'string' ? content :
(Array.isArray(content) && content.length > 0 ? content[0] : '')
}
} }
} }
btf.addGlobalFn('pjaxSendOnce', () => { typed.destroy() }, 'typedDestroy') btf.addGlobalFn('pjaxSendOnce', () => { typed.destroy() }, 'typedDestroy')
@@ -33,14 +53,12 @@ case source
fetch('https://v1.hitokoto.cn') fetch('https://v1.hitokoto.cn')
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (!{effect}) { const from = '出自 ' + data.from
const from = '出自 ' + data.from typedJSFn.processSubtitle(data.hitokoto, [from])
const sub = !{JSON.stringify(subContent)} })
sub.unshift(data.hitokoto, from) .catch(err => {
typedJSFn.init(sub) console.error('Failed to get the Hitokoto API:', err)
} else { typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
document.getElementById('subtitle').textContent = data.hitokoto
}
}) })
} }
typedJSFn.run(subtitleType) typedJSFn.run(subtitleType)
@@ -48,46 +66,48 @@ case source
when 2 when 2
script. script.
function subtitleType () { function subtitleType () {
btf.getScript('https://yijuzhan.com/api/word.php?m=js').then(() => { fetch('https://v.api.aa1.cn/api/yiyan/index.php')
const con = str[0] .then(response => response.text())
if (!{effect}) { .then(data => {
const from = '出自 ' + str[1] const reg = /<p>(.*?)<\/p>/g
const sub = !{JSON.stringify(subContent)} const result = reg.exec(data)
sub.unshift(con, from) if (result && result[1]) {
typedJSFn.init(sub) typedJSFn.processSubtitle(result[1])
} else { } else {
document.getElementById('subtitle').textContent = con throw new Error('Failed to parse the return value of the Yiyan API')
} }
}) })
.catch(err => {
console.error('Failed to get the Yiyan API:', err)
typedJSFn.processSubtitle(!{JSON.stringify(subContent.length)})
})
} }
typedJSFn.run(subtitleType) typedJSFn.run(subtitleType)
when 3 when 3
script. script.
function subtitleType () { function subtitleType () {
btf.getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js').then(() => { btf.getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js')
jinrishici.load(result =>{ .then(() => {
if (!{effect}) { jinrishici.load(result => {
const sub = !{JSON.stringify(subContent)} if (result && result.data && result.data.content) {
const content = result.data.content typedJSFn.processSubtitle(result.data.content)
sub.unshift(content) } else {
typedJSFn.init(sub) throw new Error('Failed to parse the return value of Jinrishici API')
} else { }
document.getElementById('subtitle').textContent = result.data.content })
} })
.catch(err => {
console.error('Failed to get the Jinrishici API:', err)
typedJSFn.processSubtitle(!{JSON.stringify(subContent.length)})
}) })
})
} }
typedJSFn.run(subtitleType) typedJSFn.run(subtitleType)
default default
- subContent = subContent.length ? subContent : new Array(config.subtitle) if subContent.length > 0
script. script.
function subtitleType () { function subtitleType () {
if (!{effect}) { typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
typedJSFn.init(!{JSON.stringify(subContent)})
} else {
document.getElementById("subtitle").textContent = !{JSON.stringify(subContent[0])}
} }
} typedJSFn.run(subtitleType)
typedJSFn.run(subtitleType)

View File

@@ -1,6 +1,6 @@
{ {
"name": "hexo-theme-butterfly", "name": "hexo-theme-butterfly",
"version": "5.3.3", "version": "5.4.3",
"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": {
@@ -15,16 +15,18 @@
"hexo-theme-butterfly" "hexo-theme-butterfly"
], ],
"repository": { "repository": {
"type" : "git", "type": "git",
"url" : "https://github.com/jerryc127/hexo-theme-butterfly.git" "url": "https://github.com/jerryc127/hexo-theme-butterfly.git"
}, },
"bugs": { "bugs": {
"url": "https://github.com/jerryc127/hexo-theme-butterfly/issues", "url": "https://github.com/jerryc127/hexo-theme-butterfly/issues",
"email": "my@crazywong.com" "email": "my@crazywong.com"
}, },
"dependencies": { "dependencies": {
"hexo-renderer-pug": "^3.0.0",
"hexo-renderer-stylus": "^3.0.1", "hexo-renderer-stylus": "^3.0.1",
"hexo-renderer-pug": "^3.0.0" "hexo-util": "^3.3.0",
"moment-timezone": "^0.5.48"
}, },
"homepage": "https://butterfly.js.org/", "homepage": "https://butterfly.js.org/",
"author": "Jerry <my@crazywong.com>", "author": "Jerry <my@crazywong.com>",

View File

@@ -1,7 +1,7 @@
abcjs_basic_js: abcjs_basic_js:
name: abcjs name: abcjs
file: dist/abcjs-basic-min.js file: dist/abcjs-basic-min.js
version: 6.4.4 version: 6.5.1
activate_power_mode: activate_power_mode:
name: butterfly-extsrc name: butterfly-extsrc
file: dist/activate-power-mode.min.js file: dist/activate-power-mode.min.js
@@ -9,7 +9,7 @@ activate_power_mode:
algolia_search: algolia_search:
name: algoliasearch name: algoliasearch
file: dist/lite/builds/browser.umd.js file: dist/lite/builds/browser.umd.js
version: 5.20.2 version: 5.34.1
aplayer_css: aplayer_css:
name: aplayer name: aplayer
file: dist/APlayer.min.css file: dist/APlayer.min.css
@@ -45,7 +45,7 @@ canvas_ribbon:
chartjs: chartjs:
name: chart.js name: chart.js
file: dist/chart.umd.js file: dist/chart.umd.js
version: 4.4.7 version: 4.5.0
clickShowText: clickShowText:
name: butterfly-extsrc name: butterfly-extsrc
file: dist/click-show-text.min.js file: dist/click-show-text.min.js
@@ -57,21 +57,21 @@ click_heart:
disqusjs: disqusjs:
name: disqusjs name: disqusjs
file: dist/browser/disqusjs.es2015.umd.min.js file: dist/browser/disqusjs.es2015.umd.min.js
version: 3.0.2 version: 3.1.0
disqusjs_css: disqusjs_css:
name: disqusjs name: disqusjs
file: dist/browser/styles/disqusjs.css file: dist/browser/styles/disqusjs.css
version: 3.0.2 version: 3.1.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.8.3 version: 3.9.0
docsearch_js: 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.8.3 version: 3.9.0
egjs_infinitegrid: egjs_infinitegrid:
name: '@egjs/infinitegrid' name: '@egjs/infinitegrid'
other_name: egjs-infinitegrid other_name: egjs-infinitegrid
@@ -80,12 +80,12 @@ egjs_infinitegrid:
fancybox: fancybox:
name: '@fancyapps/ui' name: '@fancyapps/ui'
file: dist/fancybox/fancybox.umd.js file: dist/fancybox/fancybox.umd.js
version: 5.0.36 version: 6.0.17
other_name: fancyapps-ui other_name: fancyapps-ui
fancybox_css: fancybox_css:
name: '@fancyapps/ui' name: '@fancyapps/ui'
file: dist/fancybox/fancybox.css file: dist/fancybox/fancybox.css
version: 5.0.36 version: 6.0.17
other_name: fancyapps-ui other_name: fancyapps-ui
fireworks: fireworks:
name: butterfly-extsrc name: butterfly-extsrc
@@ -111,17 +111,17 @@ instantpage:
instantsearch: instantsearch:
name: instantsearch.js name: instantsearch.js
file: dist/instantsearch.production.min.js file: dist/instantsearch.production.min.js
version: 4.77.3 version: 4.79.2
katex: katex:
name: katex name: katex
file: dist/katex.min.css file: dist/katex.min.css
other_name: KaTeX other_name: KaTeX
version: 0.16.21 version: 0.16.22
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.21 version: 0.16.22
lazyload: lazyload:
name: vanilla-lazyload name: vanilla-lazyload
file: dist/lazyload.iife.min.js file: dist/lazyload.iife.min.js
@@ -137,7 +137,7 @@ medium_zoom:
mermaid: mermaid:
name: mermaid name: mermaid
file: dist/mermaid.min.js file: dist/mermaid.min.js
version: 11.4.1 version: 11.9.0
meting_js: meting_js:
name: butterfly-extsrc name: butterfly-extsrc
file: metingjs/dist/Meting.min.js file: metingjs/dist/Meting.min.js
@@ -160,17 +160,17 @@ prismjs_autoloader:
name: prismjs name: prismjs
file: plugins/autoloader/prism-autoloader.min.js file: plugins/autoloader/prism-autoloader.min.js
other_name: prism other_name: prism
version: 1.29.0 version: 1.30.0
prismjs_js: prismjs_js:
name: prismjs name: prismjs
file: prism.js file: prism.js
other_name: prism other_name: prism
version: 1.29.0 version: 1.30.0
prismjs_lineNumber_js: prismjs_lineNumber_js:
name: prismjs name: prismjs
file: plugins/line-numbers/prism-line-numbers.min.js file: plugins/line-numbers/prism-line-numbers.min.js
other_name: prism other_name: prism
version: 1.29.0 version: 1.30.0
sharejs: sharejs:
name: butterfly-extsrc name: butterfly-extsrc
file: sharejs/dist/js/social-share.min.js file: sharejs/dist/js/social-share.min.js
@@ -190,7 +190,7 @@ snackbar_css:
twikoo: twikoo:
name: twikoo name: twikoo
file: dist/twikoo.all.min.js file: dist/twikoo.all.min.js
version: 1.6.41 version: 1.6.44
typed: typed:
name: typed.js name: typed.js
file: dist/typed.umd.js file: dist/typed.umd.js
@@ -203,9 +203,9 @@ waline_css:
name: '@waline/client' name: '@waline/client'
file: dist/waline.css file: dist/waline.css
other_name: waline other_name: waline
version: 3.5.2 version: 3.6.0
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: 3.5.2 version: 3.6.0

View File

@@ -3,13 +3,14 @@
const { stripHTML, truncate } = require('hexo-util') const { stripHTML, truncate } = require('hexo-util')
// Truncates the given content to a specified length, removing HTML tags and replacing newlines with spaces. // Truncates the given content to a specified length, removing HTML tags and replacing newlines with spaces.
const truncateContent = (content, length) => { const truncateContent = (content, length, encrypt = false) => {
return truncate(stripHTML(content), { length, separator: ' ' }).replace(/\n/g, ' ') if (!content || encrypt) return ''
return truncate(stripHTML(content).replace(/\n/g, ' '), { length })
} }
// Generates a post description based on the provided data and theme configuration. // Generates a post description based on the provided data and theme configuration.
const postDesc = (data, hexo) => { const postDesc = (data, hexo) => {
const { description, content, postDesc } = data const { description, content, postDesc, encrypt } = data
if (postDesc) return postDesc if (postDesc) return postDesc
@@ -23,10 +24,10 @@ const postDesc = (data, hexo) => {
result = description result = description
break break
case 2: case 2:
result = description || truncateContent(content, length) result = description || truncateContent(content, length, encrypt)
break break
default: default:
result = truncateContent(content, length) result = truncateContent(content, length, encrypt)
} }
data.postDesc = result data.postDesc = result

View File

@@ -5,6 +5,7 @@ hexo.extend.filter.register('before_generate', () => {
nav: { nav: {
logo: null, logo: null,
display_title: true, display_title: true,
display_post_title: true,
fixed: false fixed: false
}, },
menu: null, menu: null,
@@ -119,12 +120,16 @@ hexo.extend.filter.register('before_generate', () => {
message_next: 'days since the last update, the content of the article may be outdated.' message_next: 'days since the last update, the content of the article may be outdated.'
}, },
footer: { footer: {
nav: null,
owner: { owner: {
enable: true, enable: true,
since: 2019 since: 2024
}, },
custom_text: null, copyright: {
copyright: true enable: true,
version: true
},
custom_text: null
}, },
aside: { aside: {
enable: true, enable: true,
@@ -223,6 +228,7 @@ hexo.extend.filter.register('before_generate', () => {
hide: null, hide: null,
show: null show: null
}, },
rightside_config_animation: true,
anchor: { anchor: {
auto_update: false, auto_update: false,
click_to_scroll: false click_to_scroll: false
@@ -383,6 +389,10 @@ hexo.extend.filter.register('before_generate', () => {
crisp: { crisp: {
website_id: null website_id: null
}, },
google_tag_manager: {
tag_id: null,
domain: 'https://www.googletagmanager.com'
},
baidu_analytics: null, baidu_analytics: null,
google_analytics: null, google_analytics: null,
cloudflare_analytics: null, cloudflare_analytics: null,

View File

@@ -2,11 +2,7 @@
hexo.extend.helper.register('aside_archives', function (options = {}) { hexo.extend.helper.register('aside_archives', function (options = {}) {
const { config, page, site, url_for, _p } = this const { config, page, site, url_for, _p } = this
const { const { archive_dir: archiveDir, timezone, language } = config
archive_dir: archiveDir,
timezone,
language
} = config
// Destructure and set default options with object destructuring // Destructure and set default options with object destructuring
const { const {
@@ -22,33 +18,42 @@ hexo.extend.helper.register('aside_archives', function (options = {}) {
const lang = toMomentLocale(page.lang || page.language || language) const lang = toMomentLocale(page.lang || page.language || language)
// Memoize comparison function to improve performance // Memoize comparison function to improve performance
const compareFunc = type === 'monthly' const compareFunc =
? (yearA, monthA, yearB, monthB) => yearA === yearB && monthA === monthB type === 'monthly'
: (yearA, yearB) => yearA === yearB ? (yearA, monthA, yearB, monthB) => yearA === yearB && monthA === monthB
: (yearA, yearB) => yearA === yearB
// Early return if no posts // Early return if no posts
if (!site.posts.length) return '' if (!site.posts.length) return ''
// Use reduce for more efficient data processing // Use reduce for more efficient data processing
const data = site.posts const data = site.posts.sort('date', order).reduce((acc, post) => {
.sort('date', order) let date = post.date.clone()
.reduce((acc, post) => { if (timezone) date = date.tz(timezone)
let date = post.date.clone()
if (timezone) date = date.tz(timezone)
const year = date.year() const year = date.year()
const month = date.month() + 1 const month = date.month() + 1
if (lang) date = date.locale(lang) if (lang) date = date.locale(lang)
// Find or create archive entry // Find or create archive entry
const lastEntry = acc[acc.length - 1] const lastEntry = acc[acc.length - 1]
if (!lastEntry || !compareFunc(
lastEntry.year, if (type === 'yearly') {
lastEntry.month, const existingYearIndex = acc.findIndex(entry => entry.year === year)
year, if (existingYearIndex !== -1) {
month acc[existingYearIndex].count++
)) { } else {
// 否則創建新條目
acc.push({
name: date.format(format),
year,
month,
count: 1
})
}
} else {
if (!lastEntry || !compareFunc(lastEntry.year, lastEntry.month, year, month)) {
acc.push({ acc.push({
name: date.format(format), name: date.format(format),
year, year,
@@ -58,9 +63,10 @@ hexo.extend.helper.register('aside_archives', function (options = {}) {
} else { } else {
lastEntry.count++ lastEntry.count++
} }
}
return acc return acc
}, []) }, [])
// Create link generator function // Create link generator function
const createArchiveLink = item => { const createArchiveLink = item => {
@@ -72,39 +78,41 @@ hexo.extend.helper.register('aside_archives', function (options = {}) {
} }
// Limit results efficiently // Limit results efficiently
const limitedData = limit > 0 const limitedData = limit > 0 ? data.slice(0, Math.min(data.length, limit)) : data
? data.slice(0, Math.min(data.length, limit))
: data
// Use template literal for better readability // Use template literal for better readability
const archiveHeader = ` const archiveHeader = `
<div class="item-headline"> <div class="item-headline">
<i class="fas fa-archive"></i> <i class="fas fa-archive"></i>
<span>${_p('aside.card_archives')}</span> <span>${_p('aside.card_archives')}</span>
${data.length > limitedData.length ${
? `<a class="card-more-btn" href="${url_for(archiveDir)}/" data.length > limitedData.length
? `<a class="card-more-btn" href="${url_for(archiveDir)}/"
title="${_p('aside.more_button')}"> title="${_p('aside.more_button')}">
<i class="fas fa-angle-right"></i> <i class="fas fa-angle-right"></i>
</a>` </a>`
: ''} : ''
}
</div> </div>
` `
// Use map for generating list items, join for performance // Use map for generating list items, join for performance
const archiveList = ` const archiveList = `
<ul class="card-archive-list"> <ul class="card-archive-list">
${limitedData.map(item => ` ${limitedData
.map(
item => `
<li class="card-archive-list-item"> <li class="card-archive-list-item">
<a class="card-archive-list-link" href="${createArchiveLink(item)}"> <a class="card-archive-list-link" href="${createArchiveLink(item)}">
<span class="card-archive-list-date"> <span class="card-archive-list-date">
${transform ? transform(item.name) : item.name} ${transform ? transform(item.name) : item.name}
</span> </span>
${showCount ${showCount ? `<span class="card-archive-list-count">${item.count}</span>` : ''}
? `<span class="card-archive-list-count">${item.count}</span>`
: ''}
</a> </a>
</li> </li>
`).join('')} `
)
.join('')}
</ul> </ul>
` `

View File

@@ -81,7 +81,7 @@ hexo.extend.helper.register('findArchivesTitle', function (page, menu, date) {
return loop(menu) || defaultTitle return loop(menu) || defaultTitle
}) })
hexo.extend.helper.register('getBgPath', path => { hexo.extend.helper.register('getBgPath', function(path) {
if (!path) return '' if (!path) return ''
const absoluteUrlPattern = /^(?:[a-z][a-z\d+.-]*:)?\/\//i const absoluteUrlPattern = /^(?:[a-z][a-z\d+.-]*:)?\/\//i
@@ -91,7 +91,7 @@ hexo.extend.helper.register('getBgPath', path => {
if (colorPattern.test(path)) { if (colorPattern.test(path)) {
return `background-color: ${path};` return `background-color: ${path};`
} else if (absoluteUrlPattern.test(path) || relativeUrlPattern.test(path)) { } else if (absoluteUrlPattern.test(path) || relativeUrlPattern.test(path)) {
return `background-image: url(${path});` return `background-image: url(${this.url_for(path)});`
} else { } else {
return `background: ${path};` return `background: ${path};`
} }

View File

@@ -6,17 +6,45 @@
'use strict' 'use strict'
const score = (args, content) => { const score = (args, content) => {
// Escape HTML tags and some special characters, including curly braces
const escapeHtmlTags = s => { const escapeHtmlTags = s => {
const lookup = { const lookup = {
'&': '&amp;', '&': '&amp;',
'"': '&quot;', '"': '&quot;',
'\'': '&apos;', "'": '&apos;',
'<': '&lt;', '<': '&lt;',
'>': '&gt;' '>': '&gt;',
'{': '&#123;',
'}': '&#125;'
} }
return s.replace(/[&"'<>]/g, c => lookup[c]) return s.replace(/[&"'<>{}]/g, c => lookup[c])
} }
return `<div class="abc-music-sheet">${escapeHtmlTags(content)}</div>`
const trimmed = content.trim()
// Split content using six dashes as a delimiter
const parts = trimmed.split('------')
if (parts.length < 2) {
// If no delimiter is found, treat the entire content as the score
return `<div class="abc-music-sheet">${escapeHtmlTags(trimmed)}</div>`
}
// First part is parameters (JSON string), the rest is the score content
const paramPart = parts[0].trim()
const scorePart = parts.slice(1).join('------').trim()
let paramsObj = {}
try {
paramsObj = JSON.parse(paramPart)
} catch (e) {
console.error("Failed to parse JSON in score tag:", e)
}
// Use double quotes for data-params attribute value,
// ensuring JSON internal double quotes are escaped
return `<div class="abc-music-sheet" data-params="${escapeHtmlTags(JSON.stringify(paramsObj))}">
${escapeHtmlTags(scorePart)}
</div>`
} }
hexo.extend.tag.register('score', score, { ends: true }) hexo.extend.tag.register("score", score, { ends: true })

View File

@@ -11,7 +11,7 @@
.fontawesomeIcon .fontawesomeIcon
display: inline-block display: inline-block
font-weight: 600 font-weight: 600
font-family: 'Font Awesome 6 Free' font-family: 'Font Awesome 7 Free', 'Font Awesome 6 Free'
text-rendering: auto text-rendering: auto
-webkit-font-smoothing: antialiased -webkit-font-smoothing: antialiased

View File

@@ -10,8 +10,8 @@
--preloader-bg: $preloader-bg --preloader-bg: $preloader-bg
--preloader-color: $preloader-word-color --preloader-color: $preloader-word-color
--tab-border-color: $tab-border-color --tab-border-color: $tab-border-color
--tab-botton-bg: $tab-botton-bg --tab-button-bg: $tab-button-bg
--tab-botton-color: $tab-botton-color --tab-button-color: $tab-button-color
--tab-button-hover-bg: $tab-button-hover-bg --tab-button-hover-bg: $tab-button-hover-bg
--tab-button-active-bg: $tab-button-active-bg --tab-button-active-bg: $tab-button-active-bg
--card-bg: $card-bg --card-bg: $card-bg
@@ -222,3 +222,7 @@ blockquote
& > :last-child & > :last-child
margin-bottom: 0 !important margin-bottom: 0 !important
.fa-fw
width: 1.25em
text-align: center

View File

@@ -23,8 +23,8 @@
&:not(#card-toc) &:not(#card-toc)
display: none display: none
&:last-child // &:last-child
margin-bottom: 0 // margin-bottom: 0
.card-info .card-info
.author-info .author-info

View File

@@ -13,17 +13,16 @@
background-color: var(--mark-bg) background-color: var(--mark-bg)
content: '' content: ''
#footer-wrap & > *
position: relative position: relative
padding: 40px 20px color: var(--light-grey)
color: var(--light-grey)
text-align: center
a a
color: var(--light-grey) color: var(--light-grey)
transition: all .3s ease-in-out
&:hover &:hover
text-decoration: underline color: $light-blue
.footer-separator .footer-separator
margin: 0 4px margin: 0 4px
@@ -33,3 +32,56 @@
max-height: 1.4em max-height: 1.4em
width: auto width: auto
vertical-align: text-bottom vertical-align: text-bottom
.footer-flex
display: flex
flex-direction: row
flex-wrap: wrap
justify-content: space-between
margin: 0 auto
padding: 40px 60px
max-width: 1200px
width: 100%
text-align: left
gap: 13px
+maxWidth768()
padding: 30px
gap: 10px
.footer-flex-items
flex-shrink: 0
min-width: 100px
text-align: left
white-space: nowrap
.footer-flex-title
margin-bottom: 5px
white-space: nowrap
font-weight: 600
font-size: 1.4em
.footer-flex-item
margin: 10px 0
white-space: nowrap
a
display: block
white-space: nowrap
.footer-other
padding: 40px 20px
width: 100%
text-align: center
if hexo-config('footer.nav')
padding: 10px 8px
background-color: rgba(0, 0, 0, .1)
.copyright,
.framework-info,
.footer_custom_text
font-size: .9em
else
.framework-info
display: block

View File

@@ -436,3 +436,28 @@
&:hover &:hover
&:after &:after
width: 100% width: 100%
.nav-page-title
position: relative
overflow: hidden
& > :first-child,
& > :last-child
display: inline-block
transition: all .3s ease-in-out
& > :last-child
position: absolute
top: 50%
left: 0
opacity: 0
transform: translateY(-50%) translateY(-10px)
&:hover
& > :last-child
opacity: 1
transform: translateY(-50%) translateY(0)
& > :first-child
opacity: 0
transform: translateY(10px)

View File

@@ -10,8 +10,8 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
--preloader-bg: darken(#121212, 2) --preloader-bg: darken(#121212, 2)
--preloader-color: alpha(#FFFFFF, .7) --preloader-color: alpha(#FFFFFF, .7)
--tab-border-color: #2c2c2c --tab-border-color: #2c2c2c
--tab-botton-bg: #2c2c2c --tab-button-bg: #2c2c2c
--tab-botton-color: alpha(#FFFFFF, .7) --tab-button-color: alpha(#FFFFFF, .7)
--tab-button-hover-bg: lighten(#121212, 15) --tab-button-hover-bg: lighten(#121212, 15)
--tab-button-active-bg: #121212 --tab-button-active-bg: #121212
--card-bg: #121212 --card-bg: #121212

View File

@@ -172,3 +172,4 @@ $indexEnable = hexo-config('cover.index_enable')
& > .content & > .content
@extend .limit-more-line @extend .limit-more-line
-webkit-line-clamp: 2 -webkit-line-clamp: 2
word-break: break-word

View File

@@ -14,14 +14,14 @@
flex-wrap: wrap flex-wrap: wrap
margin: 0 margin: 0
padding: 0 padding: 0
background: var(--tab-botton-bg) background: var(--tab-button-bg)
> .tab > .tab
flex-grow: 1 flex-grow: 1
padding: 8px 18px padding: 8px 18px
border-top: 2px solid var(--tab-border-color) border-top: 2px solid var(--tab-border-color)
background: var(--tab-botton-bg) background: var(--tab-button-bg)
color: var(--tab-botton-color) color: var(--tab-button-color)
line-height: 2 line-height: 2
transition: all .4s transition: all .4s

View File

@@ -14,18 +14,18 @@ $code-background = $themeColorEnable && hexo-config('theme_color.code_background
$theme-toc-color = $themeColorEnable && hexo-config('theme_color.toc_color') ? convert(hexo-config('theme_color.toc_color')) : $strong-cyan $theme-toc-color = $themeColorEnable && hexo-config('theme_color.toc_color') ? convert(hexo-config('theme_color.toc_color')) : $strong-cyan
// font // font
$chinseFont = $language == 'zh-CN' ? 'Microsoft YaHei' : 'Microsoft JhengHei' $chineseFont = $language == 'zh-CN' ? 'Microsoft YaHei' : 'Microsoft JhengHei'
$dafault-font-family = -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Lato, Roboto, 'PingFang SC', $chinseFont, sans-serif $default-font-family = -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Lato, Roboto, 'PingFang SC', $chineseFont, sans-serif
$dafault-code-font = consolas, Menlo, monospace, 'PingFang SC', $chinseFont, sans-serif $default-code-font = consolas, Menlo, monospace, 'PingFang SC', $chineseFont, sans-serif
$font-family = hexo-config('font.font_family') ? unquote(hexo-config('font.font_family')) : $dafault-font-family $font-family = hexo-config('font.font_family') ? unquote(hexo-config('font.font_family')) : $default-font-family
$code-font-family = hexo-config('font.code_font_family') ? unquote(hexo-config('font.code_font_family')) : $dafault-code-font $code-font-family = hexo-config('font.code_font_family') ? unquote(hexo-config('font.code_font_family')) : $default-code-font
$site-name-font = hexo-config('blog_title_font.font_family') && unquote(hexo-config('blog_title_font.font_family')) $site-name-font = hexo-config('blog_title_font.font_family') && unquote(hexo-config('blog_title_font.font_family'))
// hr // hr
$hrEnable = hexo-config('hr_icon') && hexo-config('hr_icon.enable') $hrEnable = hexo-config('hr_icon') && hexo-config('hr_icon.enable')
$hr-icon = $hrEnable && hexo-config('hr_icon.icon') ? hexo-config('hr_icon.icon') : '\f0c4' $hr-icon = $hrEnable && hexo-config('hr_icon.icon') ? hexo-config('hr_icon.icon') : '\f0c4'
$hr-icon-top = $hrEnable && hexo-config('hr_icon.icon_top') ? convert(hexo-config('hr_icon.icon_top')) : -10px $hr-icon-top = $hrEnable && hexo-config('hr_icon.icon_top') ? convert(hexo-config('hr_icon.icon_top')) : -10px
// page beatutify // page beautify
$beautifyEnable = hexo-config('beautify.enable') $beautifyEnable = hexo-config('beautify.enable')
$title-prefix-icon = $beautifyEnable && hexo-config('beautify.title_prefix_icon') ? hexo-config('beautify.title_prefix_icon') : '\f0c1' $title-prefix-icon = $beautifyEnable && hexo-config('beautify.title_prefix_icon') ? hexo-config('beautify.title_prefix_icon') : '\f0c1'
$title-prefix-icon-color = $beautifyEnable && hexo-config('beautify.title_prefix_icon_color') ? convert(hexo-config('beautify.title_prefix_icon_color')) : $light-red $title-prefix-icon-color = $beautifyEnable && hexo-config('beautify.title_prefix_icon_color') ? convert(hexo-config('beautify.title_prefix_icon_color')) : $light-red
@@ -175,8 +175,8 @@ $tagsP-purple-color = #6f42c1
$tagsP-green-color = #5cb85c $tagsP-green-color = #5cb85c
// Tag Plugins - Tab // Tag Plugins - Tab
$tab-border-color = #f0f0f0 $tab-border-color = #f0f0f0
$tab-botton-bg = #f0f0f0 $tab-button-bg = #f0f0f0
$tab-botton-color = $font-color $tab-button-color = $font-color
$tab-button-hover-bg = darken($tab-border-color, 8) $tab-button-hover-bg = darken($tab-border-color, 8)
$tab-active-border-color = $theme-color $tab-active-border-color = $theme-color
$tab-button-active-bg = $card-bg $tab-button-active-bg = $card-bg

View File

@@ -186,6 +186,7 @@
if (service === 'medium_zoom') { if (service === 'medium_zoom') {
mediumZoom(ele, { background: 'var(--zoom-bg)' }) mediumZoom(ele, { background: 'var(--zoom-bg)' })
return
} }
if (service === 'fancybox') { if (service === 'fancybox') {
@@ -198,35 +199,71 @@
}) })
if (!window.fancyboxRun) { if (!window.fancyboxRun) {
Fancybox.bind('[data-fancybox]', { let options = ''
Hash: false, if (Fancybox.version < '6') {
Thumbs: { options = {
showOnStart: false Hash: false,
}, Thumbs: {
Images: { showOnStart: false
Panzoom: { },
maxScale: 4 Images: {
} Panzoom: {
}, maxScale: 4
Carousel: { }
transition: 'slide' },
}, Carousel: {
Toolbar: { transition: 'slide'
display: { },
left: ['infobar'], Toolbar: {
middle: [ display: {
'zoomIn', left: ['infobar'],
'zoomOut', middle: [
'toggle1to1', 'zoomIn',
'rotateCCW', 'zoomOut',
'rotateCW', 'toggle1to1',
'flipX', 'rotateCCW',
'flipY' 'rotateCW',
], 'flipX',
right: ['slideshow', 'thumbs', 'close'] 'flipY'
],
right: ['slideshow', 'thumbs', 'close']
}
} }
} }
}) } else {
options = {
Hash: false,
Carousel: {
transition: 'slide',
Thumbs: {
showOnStart: false
},
Toolbar: {
display: {
left: ['counter'],
middle: [
'zoomIn',
'zoomOut',
'toggle1to1',
'rotateCCW',
'rotateCW',
'flipX',
'flipY',
"reset"
],
right: ['autoplay', 'thumbs', 'close']
}
},
Zoomable: {
Panzoom: {
maxScale: 4
}
}
}
}
}
Fancybox.bind('[data-fancybox]', options)
window.fancyboxRun = true window.fancyboxRun = true
} }
} }