mirror of
https://github.com/jerryc127/hexo-theme-butterfly.git
synced 2026-04-17 04:40:53 +08:00
Compare commits
60 Commits
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
@@ -86,7 +86,7 @@ npm i hexo-theme-butterfly
|
||||
- [x] Share (Sharejs/Addtoany)
|
||||
- [X] Comment (Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/artalk)
|
||||
- [x] Multiple Comment System Support
|
||||
- [x] Online Chats (Chatra/Tidio/Daovoice/Crisp)
|
||||
- [x] Online Chats (Chatra/Tidio/Crisp)
|
||||
- [x] Web analytics
|
||||
- [x] Google AdSense
|
||||
- [x] Webmaster Verification
|
||||
@@ -98,9 +98,10 @@ npm i hexo-theme-butterfly
|
||||
- [x] Busuanzi visitor counter
|
||||
- [x] Medium Zoom/Fancybox
|
||||
- [x] Mermaid
|
||||
- [x] Chart.js
|
||||
- [x] Justified Gallery
|
||||
- [x] Lazyload images
|
||||
- [x] Instantpage/Pangu/Snackbar notification toast/PWA......
|
||||
- [x] Instantpage/Snackbar notification toast/PWA......
|
||||
|
||||
## ✨ Contributors
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ theme: butterfly
|
||||
- [x] 多種分享系統(Sharejs/Addtoany)
|
||||
- [X] 多種評論系統(Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/artalk)
|
||||
- [x] 支持雙評論部署
|
||||
- [x] 多種在線聊天(Chatra/Tidio/Daovoice/Crisp)
|
||||
- [x] 多種在線聊天(Chatra/Tidio/Crisp)
|
||||
- [x] 多種分析系統
|
||||
- [x] 谷歌廣告/手動廣告位置
|
||||
- [x] 各種站長驗證
|
||||
@@ -98,9 +98,10 @@ theme: butterfly
|
||||
- [x] 不蒜子訪問統計
|
||||
- [x] 兩種大圖模式(Medium Zoom/Fancybox)
|
||||
- [x] Mermaid 圖表顯示
|
||||
- [x] Chart.js 圖表顯示
|
||||
- [x] 照片牆
|
||||
- [x] 圖片懶加載
|
||||
- [x] Instantpage/Pangu/Snackbar彈窗/PWA......
|
||||
- [x] Instantpage/Snackbar彈窗/PWA......
|
||||
|
||||
## ✨ 貢獻者
|
||||
|
||||
|
||||
42
_config.yml
42
_config.yml
@@ -158,7 +158,7 @@ subtitle:
|
||||
# Choose: false/1/2/3
|
||||
# false - disable the function
|
||||
# 1 - hitokoto.cn
|
||||
# 2 - yijuzhan.com
|
||||
# 2 - https://api.aa1.cn/doc/yiyan.html
|
||||
# 3 - jinrishici.com
|
||||
source: false
|
||||
# If you close the typewriter effect, the subtitle will only show the first line of sub
|
||||
@@ -602,7 +602,7 @@ facebook_comments:
|
||||
pageSize: 10
|
||||
# Choose: social / time / reverse_time
|
||||
order_by: social
|
||||
lang: zh_TW
|
||||
lang: en_US
|
||||
|
||||
# Twikoo
|
||||
# https://github.com/imaegoo/twikoo
|
||||
@@ -645,7 +645,7 @@ artalk:
|
||||
# --------------------------------------
|
||||
|
||||
chat:
|
||||
# Choose: chatra/tidio/daovoice/crisp
|
||||
# Choose: chatra/tidio/crisp
|
||||
# Leave it empty if you don't need chat
|
||||
use:
|
||||
# Chat Button [recommend]
|
||||
@@ -662,10 +662,6 @@ chatra:
|
||||
tidio:
|
||||
public_key:
|
||||
|
||||
# http://dashboard.daovoice.io/app
|
||||
daovoice:
|
||||
app_id:
|
||||
|
||||
# https://crisp.chat/en/
|
||||
crisp:
|
||||
website_id:
|
||||
@@ -924,6 +920,25 @@ mermaid:
|
||||
light: default
|
||||
dark: dark
|
||||
|
||||
# chartjs
|
||||
# see https://www.chartjs.org/docs/latest/
|
||||
chartjs:
|
||||
enable: false
|
||||
# Do not modify unless you understand how they work.
|
||||
# The default settings are only used when the MD syntax is not specified.
|
||||
# General font color for the chart
|
||||
fontColor:
|
||||
light: 'rgba(0, 0, 0, 0.8)'
|
||||
dark: 'rgba(255, 255, 255, 0.8)'
|
||||
# General border color for the chart
|
||||
borderColor:
|
||||
light: 'rgba(0, 0, 0, 0.1)'
|
||||
dark: 'rgba(255, 255, 255, 0.2)'
|
||||
# Background color for scale labels on radar and polar area charts
|
||||
scale_ticks_backdropColor:
|
||||
light: 'transparent'
|
||||
dark: 'transparent'
|
||||
|
||||
# Note - Bootstrap Callout
|
||||
note:
|
||||
# Note tag style values:
|
||||
@@ -968,13 +983,6 @@ snackbar:
|
||||
# https://instant.page/
|
||||
instantpage: false
|
||||
|
||||
# Pangu - Insert a space between Chinese character and English character
|
||||
# https://github.com/vinta/pangu.js
|
||||
pangu:
|
||||
enable: false
|
||||
# Specify the field to use pangu (site or post)
|
||||
field: site
|
||||
|
||||
# Lazyload
|
||||
# https://github.com/verlok/vanilla-lazyload
|
||||
lazyload:
|
||||
@@ -1008,6 +1016,10 @@ Open_Graph_meta:
|
||||
# fb_admins:
|
||||
# fb_app_id:
|
||||
|
||||
# Structured Data
|
||||
# https://developers.google.com/search/docs/guides/intro-structured-data
|
||||
structured_data: true
|
||||
|
||||
# Add the vendor prefixes to ensure compatibility
|
||||
css_prefix: true
|
||||
|
||||
@@ -1050,6 +1062,7 @@ CDN:
|
||||
# canvas_fluttering_ribbon:
|
||||
# canvas_nest:
|
||||
# canvas_ribbon:
|
||||
# chartjs:
|
||||
# click_heart:
|
||||
# clickShowText:
|
||||
# disqusjs:
|
||||
@@ -1076,7 +1089,6 @@ CDN:
|
||||
# medium_zoom:
|
||||
# mermaid:
|
||||
# meting_js:
|
||||
# pangu:
|
||||
# prismjs_autoloader:
|
||||
# prismjs_js:
|
||||
# prismjs_lineNumber_js:
|
||||
|
||||
@@ -11,15 +11,12 @@ div
|
||||
if theme.instantpage
|
||||
script(src=url_for(theme.asset.instantpage), type='module')
|
||||
|
||||
if theme.lazyload.enable
|
||||
if theme.lazyload.enable && !theme.lazyload.native
|
||||
script(src=url_for(theme.asset.lazyload))
|
||||
|
||||
if theme.snackbar.enable
|
||||
script(src=url_for(theme.asset.snackbar))
|
||||
|
||||
if theme.pangu.enable
|
||||
!= partial("includes/third-party/pangu.pug", {}, { cache: true })
|
||||
|
||||
.js-pjax
|
||||
if needLoadCountJs
|
||||
!= partial("includes/third-party/card-post-count/index", {}, { cache: true })
|
||||
@@ -36,7 +33,7 @@ div
|
||||
!= partial("includes/third-party/prismjs", {}, { cache: true })
|
||||
|
||||
if theme.aside.enable && theme.aside.card_newest_comments.enable
|
||||
if theme.pjax.enable || (!is_post() && page.aside !== false)
|
||||
if theme.pjax.enable || (globalPageType !== 'post' && page.aside !== false)
|
||||
!= partial("includes/third-party/newest-comments/index", {}, { cache: true })
|
||||
|
||||
!= fragment_cache('injectBottom', function(){return injectHtml(theme.inject.bottom)})
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
else
|
||||
!= `©${currentYear} By ${config.author}`
|
||||
if theme.footer.copyright
|
||||
- const v = getVersion()
|
||||
.framework-info
|
||||
span= _p('footer.framework') + ' '
|
||||
a(href='https://hexo.io')= 'Hexo'
|
||||
a(href='https://hexo.io')= `Hexo ${v.hexo}`
|
||||
span.footer-separator |
|
||||
span= _p('footer.theme') + ' '
|
||||
a(href='https://github.com/jerryc127/hexo-theme-butterfly')= 'Butterfly'
|
||||
a(href='https://github.com/jerryc127/hexo-theme-butterfly')= `Butterfly ${v.theme}`
|
||||
if theme.footer.custom_text
|
||||
.footer_custom_text!= theme.footer.custom_text
|
||||
@@ -1,12 +1,18 @@
|
||||
- var pageTitle
|
||||
- is_archive() ? page.title = findArchivesTitle(page, theme.menu, date) : ''
|
||||
- if (is_tag()) pageTitle = _p('page.tag') + ': ' + page.tag
|
||||
- else if (is_category()) pageTitle = _p('page.category') + ': ' + page.category
|
||||
- else if (is_current('/404.html', [strict])) pageTitle = _p('error404')
|
||||
- else pageTitle = page.title || config.title || ''
|
||||
- globalPageType === 'archive' ? page.title = findArchivesTitle(page, theme.menu, date) : ''
|
||||
case globalPageType
|
||||
when 'tag'
|
||||
- pageTitle = _p('page.tag') + ': ' + page.tag
|
||||
when 'category'
|
||||
- pageTitle = _p('page.category') + ': ' + page.category
|
||||
when '404'
|
||||
- pageTitle = _p('error404')
|
||||
default
|
||||
- pageTitle = page.title || config.title || ''
|
||||
|
||||
|
||||
- var isSubtitle = config.subtitle ? ' - ' + config.subtitle : ''
|
||||
- var tabTitle = is_home() || !pageTitle ? config.title + isSubtitle : pageTitle + ' | ' + config.title
|
||||
- var tabTitle = globalPageType === 'home' || !pageTitle ? config.title + isSubtitle : pageTitle + ' | ' + config.title
|
||||
- var pageAuthor = config.email ? config.author + ',' + config.email : config.author
|
||||
- var pageCopyright = config.copyright || config.author
|
||||
- var themeColorLight = theme.theme_color && theme.theme_color.enable && theme.theme_color.meta_theme_color_light || '#ffffff'
|
||||
@@ -25,6 +31,9 @@ meta(name="theme-color" content=themeColor)
|
||||
//- Open_Graph
|
||||
include ./head/Open_Graph.pug
|
||||
|
||||
//- Structured Data
|
||||
include ./head/structured_data.pug
|
||||
|
||||
!=favicon_tag(theme.favicon || config.favicon)
|
||||
link(rel="canonical" href=urlNoIndex(null,config.pretty_urls.trailing_index,config.pretty_urls.trailing_html))
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ if theme.Open_Graph_meta.enable
|
||||
-
|
||||
const coverVal = page.cover_type === 'img' ? page.cover : theme.avatar.img
|
||||
let ogOption = Object.assign({
|
||||
type: is_post() ? 'article' : 'website',
|
||||
type: globalPageType === 'post' ? 'article' : 'website',
|
||||
image: coverVal ? full_url_for(coverVal) : '',
|
||||
fb_admins: theme.facebook_comments.user_id || '',
|
||||
fb_app_id: theme.facebook_comments.app_id || '',
|
||||
|
||||
@@ -69,16 +69,6 @@
|
||||
})
|
||||
}
|
||||
|
||||
let noticeOutdate = 'undefined'
|
||||
if (theme.noticeOutdate && theme.noticeOutdate.enable) {
|
||||
noticeOutdate = JSON.stringify({
|
||||
limitDay: theme.noticeOutdate.limit_day,
|
||||
position: theme.noticeOutdate.position,
|
||||
messagePrev: theme.noticeOutdate.message_prev,
|
||||
messageNext: theme.noticeOutdate.message_next,
|
||||
})
|
||||
}
|
||||
|
||||
let highlight = 'undefined'
|
||||
let syntaxHighlighter = config.syntax_highlighter
|
||||
let highlightEnable = syntaxHighlighter ? ['highlight.js', 'prismjs'].includes(syntaxHighlighter) : (config.highlight.enable || config.prismjs.enable)
|
||||
@@ -100,7 +90,6 @@ script.
|
||||
algolia: !{algolia},
|
||||
localSearch: !{localSearch},
|
||||
translate: !{translate},
|
||||
noticeOutdate: !{noticeOutdate},
|
||||
highlight: !{highlight},
|
||||
copy: {
|
||||
success: '!{_p("copy.success")}',
|
||||
@@ -127,7 +116,7 @@ script.
|
||||
buttonText: '!{_p("load_more")}'
|
||||
},
|
||||
isPhotoFigcaption: !{theme.photofigcaption},
|
||||
islazyload: !{theme.lazyload.enable},
|
||||
islazyloadPlugin: !{theme.lazyload.enable && !theme.lazyload.native},
|
||||
isAnchor: !{theme.anchor.auto_update || false},
|
||||
percent: {
|
||||
toc: !{theme.toc.scroll_percent},
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
var showToc = false
|
||||
if (theme.aside.enable && page.aside !== false) {
|
||||
let tocEnable = false
|
||||
if (is_post() && theme.toc.post) tocEnable = true
|
||||
else if (is_page() && theme.toc.page) tocEnable = true
|
||||
if (globalPageType === 'post' && theme.toc.post) tocEnable = true
|
||||
else if (globalPageType === 'page' && theme.toc.page) tocEnable = true
|
||||
const pageToc = typeof page.toc === 'boolean' ? page.toc : tocEnable
|
||||
showToc = pageToc && (toc(page.content) !== '' || page.encrypt === true)
|
||||
}
|
||||
@@ -19,9 +19,7 @@
|
||||
script#config-diff.
|
||||
var GLOBAL_CONFIG_SITE = {
|
||||
title: '!{titleVal}',
|
||||
isPost: !{is_post()},
|
||||
isHome: !{is_home()},
|
||||
isHighlightShrink: !{isHighlightShrink},
|
||||
isToc: !{showToc},
|
||||
postUpdate: '!{full_date(page.updated)}'
|
||||
pageType: '!{page.type == 'shuoshuo' ? 'shuoshuo' : globalPageType}'
|
||||
}
|
||||
|
||||
34
layout/includes/head/structured_data.pug
Normal file
34
layout/includes/head/structured_data.pug
Normal file
@@ -0,0 +1,34 @@
|
||||
if theme.structured_data && page.layout === 'post'
|
||||
-
|
||||
// use json-ld to add structured data
|
||||
|
||||
const title = page.title
|
||||
const url = page.permalink
|
||||
const imageVal = page.cover_type === 'img' ? page.cover : theme.avatar.img
|
||||
const image = imageVal ? full_url_for(imageVal) : ''
|
||||
const datePublished = page.date.toISOString()
|
||||
const dateModified = (page.updated || page.date).toISOString()
|
||||
const author = page.copyright_author || config.author
|
||||
const authorHrefVal = page.copyright_author_href || theme.post_copyright.author_href || site.url;
|
||||
const authorHref = full_url_for(authorHrefVal);
|
||||
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
"headline": title,
|
||||
"url": url,
|
||||
"image": image,
|
||||
"datePublished": datePublished,
|
||||
"dateModified": dateModified,
|
||||
"author": [{
|
||||
"@type": "Person",
|
||||
"name": author,
|
||||
"url": authorHref
|
||||
}]
|
||||
};
|
||||
|
||||
jsonLdScript = JSON.stringify(jsonLd, null, 2);
|
||||
-
|
||||
|
||||
script(type="application/ld+json").
|
||||
!{jsonLdScript}
|
||||
@@ -6,33 +6,32 @@
|
||||
var bg_img = ''
|
||||
|
||||
if !theme.disable_top_img && page.top_img !== false
|
||||
if is_post()
|
||||
case globalPageType
|
||||
when 'post'
|
||||
- top_img = page.top_img || page.cover || theme.default_top_img
|
||||
else if is_page()
|
||||
when 'page'
|
||||
- top_img = page.top_img || theme.default_top_img
|
||||
else if is_tag()
|
||||
- top_img = theme.tag_per_img && theme.tag_per_img[page.tag]
|
||||
- top_img = top_img || returnTopImg(theme.tag_img)
|
||||
else if is_category()
|
||||
- top_img = theme.category_per_img && theme.category_per_img[page.category]
|
||||
- top_img = top_img || returnTopImg(theme.category_img)
|
||||
else if is_home()
|
||||
when 'tag'
|
||||
- top_img = theme.tag_per_img && theme.tag_per_img[page.tag] || returnTopImg(theme.tag_img)
|
||||
when 'category'
|
||||
- top_img = theme.category_per_img && theme.category_per_img[page.category] || returnTopImg(theme.category_img)
|
||||
when 'home'
|
||||
- top_img = returnTopImg(theme.index_img)
|
||||
else if is_archive()
|
||||
when 'archive'
|
||||
- top_img = returnTopImg(theme.archive_img)
|
||||
else
|
||||
default
|
||||
- top_img = page.top_img || theme.default_top_img
|
||||
|
||||
if top_img !== false
|
||||
- bg_img = getBgPath(top_img)
|
||||
- headerClassName = is_home() ? 'full_page' : is_post() ? 'post-bg' : 'not-home-page'
|
||||
- headerClassName = globalPageType === 'home' ? 'full_page' : globalPageType === 'post' ? 'post-bg' : 'not-home-page'
|
||||
|
||||
header#page-header(class=`${headerClassName + isFixedClass}` style=bg_img)
|
||||
include ./nav.pug
|
||||
if top_img !== false
|
||||
if is_post()
|
||||
if globalPageType === 'post'
|
||||
include ./post-info.pug
|
||||
else if is_home()
|
||||
else if globalPageType === 'home'
|
||||
#site-info
|
||||
h1#site-title=config.title
|
||||
if theme.subtitle.enable
|
||||
@@ -48,6 +47,6 @@ header#page-header(class=`${headerClassName + isFixedClass}` style=bg_img)
|
||||
#page-site-info
|
||||
h1#site-title=page.title || page.tag || page.category
|
||||
else
|
||||
//- improvement seo
|
||||
if !is_post()
|
||||
//- improve seo
|
||||
if globalPageType !== 'post'
|
||||
h1.title-seo=page.title || page.tag || page.category || config.title
|
||||
@@ -5,7 +5,7 @@ nav#nav
|
||||
img.site-icon(src=url_for(theme.nav.logo) alt='Logo')
|
||||
if theme.nav.display_title
|
||||
span.site-name=config.title
|
||||
if is_post()
|
||||
if globalPageType === 'post'
|
||||
a.nav-page-title(href=url_for('/'))
|
||||
span.site-name=(page.title || config.title)
|
||||
#menus
|
||||
|
||||
@@ -60,47 +60,38 @@
|
||||
if block
|
||||
block
|
||||
|
||||
mixin otherPV()
|
||||
if theme.umami_analytics.enable && theme.umami_analytics.UV_PV.page_pv
|
||||
+pvBlock('', '', '')
|
||||
span#umamiPV(data-path=url_for(page.path))
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
else if theme.busuanzi.page_pv
|
||||
+pvBlock('', 'post-meta-pv-cv', '')
|
||||
span#busuanzi_value_page_pv
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
|
||||
- const commentUse = comments.use && comments.use[0]
|
||||
if page.comments !== false && commentUse && !comments.lazyload
|
||||
case commentUse
|
||||
when 'Valine'
|
||||
if theme.valine.visitor
|
||||
if commentUse === 'Valine' && theme.valine.visitor
|
||||
+pvBlock(url_for(page.path), 'leancloud_visitors', page.title)
|
||||
span.leancloud-visitors-count
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
when 'Waline'
|
||||
if theme.waline.pageview
|
||||
else if commentUse === 'Waline' && theme.waline.pageview
|
||||
+pvBlock('', '', '')
|
||||
span.waline-pageview-count(data-path=url_for(page.path))
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
when 'Twikoo'
|
||||
if theme.twikoo.visitor
|
||||
else if commentUse === 'Twikoo' && theme.twikoo.visitor
|
||||
+pvBlock('', '', '')
|
||||
span#twikoo_visitors
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
when 'Artalk'
|
||||
if theme.artalk.visitor
|
||||
else if commentUse === 'Artalk' && theme.artalk.visitor
|
||||
+pvBlock('', '', '')
|
||||
span#ArtalkPV
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
default
|
||||
if theme.umami_analytics.enable && theme.umami_analytics.UV_PV.page_pv
|
||||
+pvBlock('', '', '')
|
||||
span#umamiPV(data-path=url_for(page.path))
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
else if theme.busuanzi.page_pv
|
||||
+pvBlock('', 'post-meta-pv-cv', '')
|
||||
span#busuanzi_value_page_pv
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
else
|
||||
if theme.umami_analytics.enable && theme.umami_analytics.UV_PV.page_pv
|
||||
+pvBlock('', '', '')
|
||||
span#umamiPV(data-path=url_for(page.path))
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
else if theme.busuanzi.page_pv
|
||||
+pvBlock('', 'post-meta-pv-cv', '')
|
||||
span#busuanzi_value_page_pv
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
+otherPV()
|
||||
else
|
||||
+otherPV()
|
||||
|
||||
if comments.count && !comments.lazyload && page.comments !== false && comments.use
|
||||
- var whichCount = comments.use[0]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
- var globalPageType = getPageType(page, is_home)
|
||||
- var htmlClassHideAside = theme.aside.enable && theme.aside.hide ? 'hide-aside' : ''
|
||||
- page.aside = is_archive() ? theme.aside.display.archive: is_category() ? theme.aside.display.category : is_tag() ? theme.aside.display.tag : page.aside
|
||||
- page.aside = globalPageType === 'archive' ? theme.aside.display.archive: globalPageType === 'category' ? theme.aside.display.category : globalPageType === 'tag' ? theme.aside.display.tag : page.aside
|
||||
- var hideAside = !theme.aside.enable || page.aside === false ? 'hide-aside' : ''
|
||||
- var pageType = is_post() ? 'post' : 'page'
|
||||
- var pageType = globalPageType === 'post' ? 'post' : 'page'
|
||||
- pageType = page.type ? pageType + ' type-' + page.type : pageType
|
||||
|
||||
doctype html
|
||||
|
||||
@@ -20,7 +20,7 @@ mixin indexPostUI()
|
||||
div.post-bg(style=`background: ${post_cover}`)
|
||||
.recent-post-info(class=no_cover)
|
||||
a.article-title(href=url_for(link) title=title)
|
||||
if is_home() && (article.top || article.sticky > 0)
|
||||
if globalPageType === 'home' && (article.top || article.sticky > 0)
|
||||
i.fas.fa-thumbtack.sticky
|
||||
= title
|
||||
.article-meta-wrap
|
||||
@@ -105,15 +105,9 @@ mixin indexPostUI()
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
|
||||
//- Display the article introduction on homepage
|
||||
case theme.index_post_content.method
|
||||
when false
|
||||
- break
|
||||
when 1
|
||||
.content!= article.description
|
||||
when 2
|
||||
.content!= article.description || truncate(article.content, theme.index_post_content.length)
|
||||
default
|
||||
.content!= truncate(article.content, theme.index_post_content.length)
|
||||
- const content = postDesc(article)
|
||||
if content
|
||||
.content!=content
|
||||
|
||||
if theme.ad && theme.ad.index
|
||||
if (index + 1) % 3 === 0
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#article-container
|
||||
#article-container.container
|
||||
!= page.content
|
||||
@@ -1,4 +1,4 @@
|
||||
#article-container
|
||||
#article-container.container
|
||||
.flink
|
||||
- let { content, random, flink_url } = page
|
||||
- let pageContent = content
|
||||
|
||||
@@ -6,98 +6,183 @@
|
||||
//- - tag1
|
||||
//- - tag2
|
||||
|
||||
|
||||
- page.comments = false
|
||||
- page.toc = false
|
||||
|
||||
#article-container
|
||||
if page.comments !== false && theme.comments.use
|
||||
- commentsJsLoad = true
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const commentDiv = `!{partial('includes/third-party/comments/index', {}, {cache: true})}`
|
||||
|
||||
const runDestroy = (shuoshuoComment) => {
|
||||
if (!shuoshuoComment) return
|
||||
|
||||
for (const [key, fn] of Object.entries(shuoshuoComment)) {
|
||||
if (key.startsWith('destroy')) fn()
|
||||
}
|
||||
}
|
||||
|
||||
window.addCommentToShuoshuo = e => {
|
||||
const btn = e.target.closest('.shuoshuo-comment-btn')
|
||||
if (!btn) return
|
||||
|
||||
const ele = btn.closest('.container').nextElementSibling
|
||||
const { shuoshuoComment } = window
|
||||
const isInclude = ele.classList.contains('no-comment')
|
||||
runDestroy(shuoshuoComment)
|
||||
if (isInclude) {
|
||||
ele.classList.remove('no-comment')
|
||||
ele.innerHTML = commentDiv
|
||||
const key = `${location.pathname.replace(/\/$/, '')}?key=${ele.getAttribute('data-key')}`
|
||||
btf.switchComments(ele, key)
|
||||
shuoshuoComment.loadComment && shuoshuoComment.loadComment(ele, key)
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
if page.shuoshuo_url
|
||||
script.
|
||||
(() => {
|
||||
const limitConfig = !{ JSON.stringify(page.limit || {}) }
|
||||
|
||||
const sortDataByDate = data => data.sort((a, b) => new Date(b.date) - new Date(a.date))
|
||||
|
||||
const filterDataByLimit = (data, limit) => {
|
||||
if (!limit || !limit.type) return data
|
||||
if (limit.type === 'num') return data.slice(0, limit.value)
|
||||
if (limit.type === 'date') {
|
||||
const limitDate = new Date(limit.value)
|
||||
return data.filter(item => new Date(item.date) >= limitDate)
|
||||
}
|
||||
return data
|
||||
};
|
||||
|
||||
const formatToTimeZone = (date) => {
|
||||
const fullDate = date.length === 10 ? `${date} 00:00:00` : date
|
||||
const visitorTimeZone = '#{config.timezone}' || Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
const options = {
|
||||
timeZone: visitorTimeZone,
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: false
|
||||
}
|
||||
const [day, month, year, hour, minute, second] = new Intl.DateTimeFormat('en-GB', options)
|
||||
.format(new Date(fullDate))
|
||||
.match(/\d+/g)
|
||||
return `${year}-${month}-${day} ${hour}:${minute}:${second}`
|
||||
}
|
||||
|
||||
const loadShuoshuo = async () => {
|
||||
try {
|
||||
const fetchContent = await fetch('!{url_for(page.shuoshuo_url)}')
|
||||
const shuoshuo = await fetchContent.json()
|
||||
const response = await fetch('!{url_for(page.shuoshuo_url)}')
|
||||
let data = await response.json()
|
||||
|
||||
data = filterDataByLimit(sortDataByDate(data), limitConfig)
|
||||
|
||||
let start = 0
|
||||
const container = document.getElementById('article-container')
|
||||
let start = 0
|
||||
|
||||
const addData = data => {
|
||||
const cLength = data.length
|
||||
const end = start + 10 > cLength ? cLength : start + 10
|
||||
let result = ''
|
||||
data.slice(start, end).forEach((item) => {
|
||||
result += `
|
||||
const renderData = (dataSlice) => {
|
||||
const content = dataSlice.map(item => {
|
||||
const formattedDate = formatToTimeZone(item.date)
|
||||
const tags = item.tags && item.tags.map(tag => `<span class="shuoshuo-tag">${tag}</span>`).join('') || ''
|
||||
const commentButton = item.key && !{commentsJsLoad}
|
||||
? `<div class="shuoshuo-comment-btn" onclick="addCommentToShuoshuo(event)">
|
||||
<i class="fa-solid fa-comments"></i>
|
||||
</div>`
|
||||
: ''
|
||||
const commentContainer = item.key
|
||||
? `<div class="shuoshuo-comment no-comment" data-key="${item.key}"></div>`
|
||||
: ''
|
||||
|
||||
return `
|
||||
<div class="shuoshuo-item">
|
||||
<div class="container">
|
||||
<div class="shuoshuo-item-header">
|
||||
<div class="shuoshuo-avatar">
|
||||
<img class="no-lightbox" src="${item.avatar || '!{url_for(theme.avatar.img)}'}">
|
||||
</div>
|
||||
<div class="shuoshuo-info">
|
||||
<div class="shuoshuo-author">${item.author || '!{config.author}'}</div>
|
||||
<div class="shuoshuo-date">${btf.diffDate(item.date, true)}</div>
|
||||
<time class="shuoshuo-date" title="${formattedDate}">
|
||||
${btf.diffDate(formattedDate, true)}
|
||||
</time>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shuoshuo-content">
|
||||
${item.content}
|
||||
</div>
|
||||
<div class="shuoshuo-footer">
|
||||
<div class="shuoshuo-tags">
|
||||
${item.tags.map(tag => `<span class="shuoshuo-tag">${tag}</span>`).join('')}
|
||||
<div class="shuoshuo-content">${item.content}</div>
|
||||
<div class="shuoshuo-footer ${tags ? 'flex-between' : 'flex-end'}">
|
||||
${tags ? `<div class="shuoshuo-tags">${tags}</div>` : ''}
|
||||
${commentButton}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
${commentContainer}
|
||||
</div>`
|
||||
}).join('')
|
||||
|
||||
start = end
|
||||
container.insertAdjacentHTML('beforeend', result)
|
||||
|
||||
if (start >= cLength) {
|
||||
observer.disconnect()
|
||||
} else {
|
||||
setTimeout(() => observer.observe(container.lastElementChild), 100)
|
||||
}
|
||||
container.insertAdjacentHTML('beforeend', content)
|
||||
|
||||
window.lazyLoadInstance.update()
|
||||
btf.loadLightbox(document.querySelectorAll('#article-container img:not(.no-lightbox)'))
|
||||
}
|
||||
|
||||
addData(shuoshuo)
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
if (entries[0].isIntersecting) {
|
||||
const handleIntersection = (entries) => {
|
||||
if (!entries[0].isIntersecting) return
|
||||
observer.unobserve(entries[0].target)
|
||||
addData(shuoshuo)
|
||||
|
||||
const slice = data.slice(start, start + 10)
|
||||
renderData(slice)
|
||||
start += 10
|
||||
|
||||
if (start < data.length) {
|
||||
setTimeout(() => observer.observe(container.lastElementChild), 100)
|
||||
} else {
|
||||
observer.disconnect()
|
||||
}
|
||||
}, {
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver(handleIntersection, {
|
||||
root: null,
|
||||
rootMargin: '0px',
|
||||
threshold: 1.0
|
||||
})
|
||||
|
||||
if (container.lastElementChild) {
|
||||
observer.observe(container.lastElementChild)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
renderData(data.slice(start, 10))
|
||||
start += 10
|
||||
|
||||
if (container.lastElementChild) observer.observe(container.lastElementChild)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
};
|
||||
|
||||
window.pjax ? loadShuoshuo() : window.addEventListener('load', loadShuoshuo)
|
||||
})()
|
||||
else
|
||||
if site.data.shuoshuo
|
||||
each i in site.data.shuoshuo
|
||||
each i in shuoshuoFN(site.data.shuoshuo, page)
|
||||
.shuoshuo-item
|
||||
.container
|
||||
.shuoshuo-item-header
|
||||
.shuoshuo-avatar
|
||||
img.no-lightbox(src=i.avatar || url_for(theme.avatar.img))
|
||||
.shuoshuo-info
|
||||
.shuoshuo-author=i.author || config.author
|
||||
.shuoshuo-date=relative_date(i.date)
|
||||
time.shuoshuo-date(title=i.date)=i.date
|
||||
.shuoshuo-content
|
||||
!=markdown(i.content)
|
||||
.shuoshuo-footer
|
||||
.shuoshuo-footer(class=i.tags && i.tags.length ? 'flex-between' : 'flex-end')
|
||||
if i.tags
|
||||
.shuoshuo-tags
|
||||
each tag in i.tags
|
||||
span.shuoshuo-tag=tag
|
||||
if i.key && commentsJsLoad
|
||||
.shuoshuo-comment-btn(onclick='addCommentToShuoshuo(event)')
|
||||
i.fa-solid.fa-comments
|
||||
if i.key && commentsJsLoad
|
||||
.shuoshuo-comment.no-comment(data-key=i.key)
|
||||
@@ -1,2 +1,2 @@
|
||||
.tag-cloud-list.is-center
|
||||
.tag-cloud-list.text-center
|
||||
!=cloudTags({source: site.tags, orderby: page.orderby || 'random', order: page.order || 1, minfontsize: 1.2, maxfontsize: 1.5, limit: 0, unit: 'em'})
|
||||
@@ -6,34 +6,32 @@
|
||||
escape: false
|
||||
}
|
||||
|
||||
if is_post()
|
||||
- let prev = theme.post_pagination === 1 ? page.prev : page.next
|
||||
- let next = theme.post_pagination === 1 ? page.next : page.prev
|
||||
nav#pagination.pagination-post
|
||||
if(prev)
|
||||
- var hasPageNext = next ? 'pull-left' : 'pull-full'
|
||||
a.prev-post(class=hasPageNext href=url_for(prev.path) title=prev.title)
|
||||
if prev.cover_type === 'img'
|
||||
img.cover(src=url_for(prev.cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of previous post')
|
||||
else
|
||||
.cover(style=`background: ${prev.cover || 'var(--default-bg-color)'}`)
|
||||
.pagination-info
|
||||
.label=_p('pagination.prev')
|
||||
.prev_info=prev.title
|
||||
if globalPageType === 'post'
|
||||
- let paginationOrder = theme.post_pagination === 1 ? { prev: page.prev, next: page.next } : { prev: page.next, next: page.prev }
|
||||
|
||||
if(next)
|
||||
- var hasPagePrev = prev ? 'pull-right' : 'pull-full'
|
||||
a.next-post(class=hasPagePrev href=url_for(next.path) title=next.title)
|
||||
if next.cover_type === 'img'
|
||||
img.cover(src=url_for(next.cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of next post')
|
||||
nav#pagination.pagination-post
|
||||
each direction, key in paginationOrder
|
||||
if direction
|
||||
- const getPostDesc = direction.postDesc || postDesc(direction)
|
||||
- let className = key === 'prev' ? (paginationOrder.next ? '' : 'full-width') : (paginationOrder.prev ? '' : 'full-width')
|
||||
- className = getPostDesc ? className : className + ' no-desc'
|
||||
|
||||
a.pagination-related(class=className href=url_for(direction.path) title=direction.title)
|
||||
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`)
|
||||
else
|
||||
.cover(style=`background: ${next.cover || 'var(--default-bg-color)'}`)
|
||||
.pagination-info
|
||||
.label=_p('pagination.next')
|
||||
.next_info=next.title
|
||||
.cover(style=`background: ${direction.cover || 'var(--default-bg-color)'}`)
|
||||
|
||||
.info(class=key === 'prev' ? '' : 'text-right')
|
||||
.info-1
|
||||
.info-item-1=_p(`pagination.${key}`)
|
||||
.info-item-2!=direction.title
|
||||
if getPostDesc
|
||||
.info-2
|
||||
.info-item-1!=getPostDesc
|
||||
else
|
||||
nav#pagination
|
||||
.pagination
|
||||
if is_home()
|
||||
if globalPageType === 'home'
|
||||
- options.format = 'page/%d/#content-inner'
|
||||
!=paginator(options)
|
||||
8
layout/includes/post/outdate-notice.pug
Normal file
8
layout/includes/post/outdate-notice.pug
Normal file
@@ -0,0 +1,8 @@
|
||||
- const { limit_day, message_prev, message_next, position} = theme.noticeOutdate
|
||||
- const notice_data = { limitDay: limit_day, messagePrev: message_prev, messageNext: message_next, postUpdate: full_date(page.updated)}
|
||||
if position === 'top'
|
||||
#post-outdate-notice(data=notice_data hidden)
|
||||
!=page.content
|
||||
else
|
||||
!=page.content
|
||||
#post-outdate-notice(data=notice_data hidden)
|
||||
@@ -3,7 +3,7 @@ mixin rightsideItem(array)
|
||||
each item in array
|
||||
case item
|
||||
when 'readmode'
|
||||
if is_post() && readmode
|
||||
if globalPageType === 'post' && readmode
|
||||
button#readmode(type="button" title=_p('rightside.readmode_title'))
|
||||
i.fas.fa-book-open
|
||||
when 'translate'
|
||||
@@ -23,7 +23,7 @@ mixin rightsideItem(array)
|
||||
i.fas.fa-list-ul
|
||||
when 'chat'
|
||||
if chat.rightside_button && chat.use
|
||||
button#chat-btn(type="button" title=_p("rightside.chat"))
|
||||
button#chat-btn(type="button" title=_p("rightside.chat") style="display:none")
|
||||
i.fas.fa-message
|
||||
when 'comment'
|
||||
if commentsJsLoad
|
||||
@@ -45,7 +45,7 @@ mixin rightsideItem(array)
|
||||
button#rightside-config(type="button" title=_p("rightside.setting"))
|
||||
i.fas.fa-cog.fa-spin
|
||||
else
|
||||
if is_post()
|
||||
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
|
||||
|
||||
@@ -2,16 +2,16 @@ if theme.menu
|
||||
#sidebar
|
||||
#menu-mask
|
||||
#sidebar-menus
|
||||
.avatar-img.is-center
|
||||
img(src=url_for(theme.avatar.img) onerror=`onerror=null;src='${theme.error_img.flink}'` alt="avatar")
|
||||
.site-data.is-center
|
||||
a(href=url_for(config.archive_dir) + '/')
|
||||
.avatar-img.text-center
|
||||
img(src=url_for(theme.avatar.img) onerror=`this.onerror=null;this.src='${url_for(theme.error_img.flink)}'` alt="avatar")
|
||||
.site-data.text-center
|
||||
a(href=`${url_for(config.archive_dir)}/`)
|
||||
.headline= _p('aside.articles')
|
||||
.length-num= site.posts.length
|
||||
a(href=url_for(config.tag_dir) + '/' )
|
||||
a(href=`${url_for(config.tag_dir)}/`)
|
||||
.headline= _p('aside.tags')
|
||||
.length-num= site.tags.length
|
||||
a(href=url_for(config.category_dir) + '/')
|
||||
a(href=`${url_for(config.category_dir)}/`)
|
||||
.headline= _p('aside.categories')
|
||||
.length-num= site.categories.length
|
||||
|
||||
|
||||
51
layout/includes/third-party/abcjs/abcjs.pug
vendored
51
layout/includes/third-party/abcjs/abcjs.pug
vendored
@@ -1,17 +1,46 @@
|
||||
script.
|
||||
(() => {
|
||||
const abcjsInit = () => {
|
||||
const abcjsFn = () => {
|
||||
document.querySelectorAll(".abc-music-sheet").forEach(ele => {
|
||||
if (ele.children.length > 0) return
|
||||
ABCJS.renderAbc(ele, ele.innerHTML, {responsive: 'resize'})
|
||||
})
|
||||
(function() {
|
||||
const abcjsInit = function() {
|
||||
const abcjsFn = function() {
|
||||
setTimeout(function() {
|
||||
const sheets = document.querySelectorAll(".abc-music-sheet")
|
||||
for (let i = 0; i < sheets.length; i++) {
|
||||
const ele = sheets[i]
|
||||
if (ele.children.length > 0) continue
|
||||
|
||||
// Parse parameters from data-params attribute
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
typeof ABCJS === 'object' ? abcjsFn()
|
||||
: btf.getScript('!{url_for(theme.asset.abcjs_basic_js)}').then(abcjsFn)
|
||||
// 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)
|
||||
}
|
||||
|
||||
window.pjax ? abcjsInit() : window.addEventListener('load', abcjsInit)
|
||||
btf.addGlobalFn('encrypt', abcjsInit, 'abcjs')
|
||||
if (typeof ABCJS === "object") {
|
||||
abcjsFn()
|
||||
} else {
|
||||
btf.getScript("!{url_for(theme.asset.abcjs_basic_js)}").then(abcjsFn)
|
||||
}
|
||||
}
|
||||
|
||||
if (window.pjax) {
|
||||
abcjsInit()
|
||||
} else {
|
||||
window.addEventListener("load", abcjsInit)
|
||||
}
|
||||
|
||||
btf.addGlobalFn("encrypt", abcjsInit, "abcjs")
|
||||
})()
|
||||
5
layout/includes/third-party/abcjs/index.pug
vendored
5
layout/includes/third-party/abcjs/index.pug
vendored
@@ -1,6 +1,3 @@
|
||||
if theme.abcjs.enable
|
||||
if theme.abcjs.per_page
|
||||
if is_post() || is_page()
|
||||
include ./abcjs.pug
|
||||
else if page.abcjs
|
||||
if theme.abcjs.per_page && (['post','page'].includes(globalPageType)) || page.abcjs
|
||||
include ./abcjs.pug
|
||||
|
||||
24
layout/includes/third-party/chat/chatra.pug
vendored
24
layout/includes/third-party/chat/chatra.pug
vendored
@@ -1,6 +1,12 @@
|
||||
//- https://chatra.io/help/api/
|
||||
script.
|
||||
(() => {
|
||||
window.ChatraID = '#{theme.chatra.id}'
|
||||
window.Chatra = window.Chatra || function() {
|
||||
(window.Chatra.q = window.Chatra.q || []).push(arguments)
|
||||
}
|
||||
|
||||
btf.getScript('https://call.chatra.io/chatra.js').then(() => {
|
||||
const isChatBtn = !{theme.chat.rightside_button}
|
||||
const isChatHideShow = !{theme.chat.button_hide_show}
|
||||
|
||||
@@ -17,26 +23,16 @@ script.
|
||||
|
||||
window.ChatraSetup = { startHidden: true }
|
||||
|
||||
window.chatBtnFn = () => {
|
||||
document.getElementById('chatra').classList.contains('chatra--expanded') ? close() : open()
|
||||
}
|
||||
window.chatBtnFn = () => document.getElementById('chatra').classList.contains('chatra--expanded') ? close() : open()
|
||||
|
||||
document.getElementById('chat-btn').style.display = 'block'
|
||||
} 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')
|
||||
})
|
||||
})()
|
||||
|
||||
|
||||
|
||||
15
layout/includes/third-party/chat/crisp.pug
vendored
15
layout/includes/third-party/chat/crisp.pug
vendored
@@ -1,16 +1,9 @@
|
||||
script.
|
||||
(() => {
|
||||
window.$crisp = [];
|
||||
window.CRISP_WEBSITE_ID = "!{theme.crisp.website_id}";
|
||||
(function () {
|
||||
d = document;
|
||||
s = d.createElement("script");
|
||||
s.src = "https://client.crisp.chat/l.js";
|
||||
s.async = 1;
|
||||
d.getElementsByTagName("head")[0].appendChild(s);
|
||||
})();
|
||||
$crisp.push(["safe", true])
|
||||
window.$crisp = ['safe', true]
|
||||
window.CRISP_WEBSITE_ID = "!{theme.crisp.website_id}"
|
||||
|
||||
btf.getScript('https://client.crisp.chat/l.js').then(() => {
|
||||
const isChatBtn = !{theme.chat.rightside_button}
|
||||
const isChatHideShow = !{theme.chat.button_hide_show}
|
||||
|
||||
@@ -28,10 +21,12 @@ script.
|
||||
|
||||
window.chatBtnFn = () => $crisp.is("chat:visible") ? close() : open()
|
||||
|
||||
document.getElementById('chat-btn').style.display = 'block'
|
||||
} else if (isChatHideShow) {
|
||||
window.chatBtn = {
|
||||
hide: () => $crisp.push(["do", "chat:hide"]),
|
||||
show: () => $crisp.push(["do", "chat:show"])
|
||||
}
|
||||
}
|
||||
})
|
||||
})()
|
||||
40
layout/includes/third-party/chat/daovoice.pug
vendored
40
layout/includes/third-party/chat/daovoice.pug
vendored
@@ -1,40 +0,0 @@
|
||||
//- https://guide.daocloud.io/daovoice/javascript-api-5869833.html
|
||||
script.
|
||||
(() => {
|
||||
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/!{theme.daovoice.app_id}.js","daovoice")
|
||||
|
||||
const isChatBtn = !{theme.chat.rightside_button}
|
||||
const isChatHideShow = !{theme.chat.button_hide_show}
|
||||
|
||||
daovoice('init', {
|
||||
app_id: '!{theme.daovoice.app_id}',},{
|
||||
launcher: {
|
||||
disableLauncherIcon: isChatBtn
|
||||
},
|
||||
});
|
||||
daovoice('update');
|
||||
|
||||
if (isChatBtn) {
|
||||
window.chatBtnFn = () => {
|
||||
const isShow = document.getElementById('daodream-messenger').classList.contains('daodream-messenger-active')
|
||||
isShow ? daovoice('hide') : daovoice('show')
|
||||
}
|
||||
} else if (isChatHideShow) {
|
||||
window.chatBtn = {
|
||||
hide: () => {
|
||||
daovoice('update', {},{
|
||||
launcher: {
|
||||
disableLauncherIcon: true
|
||||
}
|
||||
})
|
||||
},
|
||||
show: () => {
|
||||
daovoice('update', {}, {
|
||||
launcher: {
|
||||
disableLauncherIcon: false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})()
|
||||
2
layout/includes/third-party/chat/index.pug
vendored
2
layout/includes/third-party/chat/index.pug
vendored
@@ -3,7 +3,5 @@ case theme.chat.use
|
||||
include ./chatra.pug
|
||||
when 'tidio'
|
||||
include ./tidio.pug
|
||||
when 'daovoice'
|
||||
include ./daovoice.pug
|
||||
when 'crisp'
|
||||
include ./crisp.pug
|
||||
6
layout/includes/third-party/chat/tidio.pug
vendored
6
layout/includes/third-party/chat/tidio.pug
vendored
@@ -1,6 +1,6 @@
|
||||
script(src=`//code.tidio.co/${theme.tidio.public_key}.js` async)
|
||||
script.
|
||||
(() => {
|
||||
btf.getScript('//code.tidio.co/!{theme.tidio.public_key}.js').then(() => {
|
||||
const isChatBtn = !{theme.chat.rightside_button}
|
||||
const isChatHideShow = !{theme.chat.button_hide_show}
|
||||
|
||||
@@ -31,11 +31,15 @@ script.
|
||||
if (!window.tidioChatApi) return
|
||||
isShow ? close() : open()
|
||||
}
|
||||
|
||||
document.getElementById('chat-btn').style.display = 'block'
|
||||
|
||||
} else if (isChatHideShow) {
|
||||
window.chatBtn = {
|
||||
hide: () => window.tidioChatApi && window.tidioChatApi.hide(),
|
||||
show: () => window.tidioChatApi && window.tidioChatApi.show()
|
||||
}
|
||||
}
|
||||
})
|
||||
})()
|
||||
|
||||
|
||||
52
layout/includes/third-party/comments/artalk.pug
vendored
52
layout/includes/third-party/comments/artalk.pug
vendored
@@ -4,14 +4,27 @@
|
||||
script.
|
||||
(() => {
|
||||
let artalkItem = null
|
||||
const initArtalk = () => {
|
||||
artalkItem = Artalk.init(Object.assign({
|
||||
el: '#artalk-wrap',
|
||||
const option = !{JSON.stringify(option)}
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||||
|
||||
const destroyArtalk = () => {
|
||||
if (artalkItem) {
|
||||
artalkItem.destroy()
|
||||
artalkItem = null
|
||||
}
|
||||
}
|
||||
|
||||
const artalkChangeMode = theme => artalkItem && artalkItem.setDarkMode(theme === 'dark')
|
||||
|
||||
const initArtalk = (el = document, pageKey = location.pathname) => {
|
||||
artalkItem = Artalk.init({
|
||||
el: el.querySelector('#artalk-wrap'),
|
||||
server: '!{server}',
|
||||
site: '!{site}',
|
||||
pageKey: location.pathname,
|
||||
darkMode: document.documentElement.getAttribute('data-theme') === 'dark',
|
||||
},!{JSON.stringify(option)}))
|
||||
...option,
|
||||
pageKey: isShuoshuo ? pageKey : (option && option.pageKey) || pageKey
|
||||
})
|
||||
|
||||
if (GLOBAL_CONFIG.lightbox === 'null') return
|
||||
artalkItem.on('list-loaded', () => {
|
||||
@@ -21,31 +34,36 @@ script.
|
||||
})
|
||||
})
|
||||
|
||||
const destroyArtalk = () => {
|
||||
artalkItem.destroy()
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyArtalk = () => {
|
||||
destroyArtalk()
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
btf.addGlobalFn('pjaxSendOnce', destroyArtalk, 'destroyArtalk')
|
||||
btf.addGlobalFn('themeChange', artalkChangeMode, 'artalk')
|
||||
}
|
||||
|
||||
const loadArtalk = async () => {
|
||||
if (typeof Artalk === 'object') initArtalk()
|
||||
const loadArtalk = async (el, pageKey) => {
|
||||
if (typeof Artalk === 'object') initArtalk(el, pageKey)
|
||||
else {
|
||||
await btf.getCSS('!{theme.asset.artalk_css}')
|
||||
await btf.getScript('!{theme.asset.artalk_js}')
|
||||
initArtalk()
|
||||
initArtalk(el, pageKey)
|
||||
}
|
||||
}
|
||||
|
||||
const artalkChangeMode = theme => {
|
||||
const artalkWrap = document.getElementById('artalk-wrap')
|
||||
if (!(artalkWrap && artalkWrap.children.length)) return
|
||||
const isDark = theme === 'dark'
|
||||
artalkItem.setDarkMode(isDark)
|
||||
if (isShuoshuo) {
|
||||
'!{use[0]}' === 'Artalk'
|
||||
? window.shuoshuoComment = { loadComment: loadArtalk }
|
||||
: window.loadOtherComment = loadArtalk
|
||||
return
|
||||
}
|
||||
|
||||
btf.addGlobalFn('themeChange', artalkChangeMode, 'artalk')
|
||||
|
||||
if ('!{use[0]}' === 'Artalk' || !!{lazyload}) {
|
||||
if (!{lazyload}) btf.loadComment(document.getElementById('artalk-wrap'), loadArtalk)
|
||||
else setTimeout(loadArtalk, 100)
|
||||
|
||||
43
layout/includes/third-party/comments/disqus.pug
vendored
43
layout/includes/third-party/comments/disqus.pug
vendored
@@ -4,29 +4,43 @@
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const disqus_config = function () {
|
||||
this.page.url = '!{ page.permalink }'
|
||||
this.page.identifier = '!{ url_for(page.path) }'
|
||||
this.page.title = '!{ disqusPageTitle }'
|
||||
}
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||||
|
||||
const disqusReset = () => {
|
||||
const disqusReset = conf => {
|
||||
window.DISQUS && window.DISQUS.reset({
|
||||
reload: true,
|
||||
config: disqus_config
|
||||
config: conf
|
||||
})
|
||||
}
|
||||
|
||||
btf.addGlobalFn('themeChange', disqusReset, 'disqus')
|
||||
const loadDisqus = (el, path) => {
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyDisqus = () => {
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const loadDisqus = () =>{
|
||||
if (window.DISQUS) disqusReset()
|
||||
window.disqus_identifier = isShuoshuo ? path : '!{ url_for(page.path) }'
|
||||
window.disqus_url = isShuoshuo ? location.origin + path : '!{ page.permalink }'
|
||||
|
||||
const disqus_config = function () {
|
||||
this.page.url = disqus_url
|
||||
this.page.identifier = disqus_identifier
|
||||
this.page.title = '!{ disqusPageTitle }'
|
||||
}
|
||||
|
||||
if (window.DISQUS) disqusReset(disqus_config)
|
||||
else {
|
||||
const script = document.createElement('script')
|
||||
script.src = 'https://!{shortname}.disqus.com/embed.js'
|
||||
script.setAttribute('data-timestamp', +new Date())
|
||||
document.head.appendChild(script)
|
||||
}
|
||||
|
||||
btf.addGlobalFn('themeChange', () => disqusReset(disqus_config), 'disqus')
|
||||
}
|
||||
|
||||
const getCount = async() => {
|
||||
@@ -47,11 +61,18 @@ script.
|
||||
}
|
||||
}
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{use[0]}' === 'Disqus'
|
||||
? window.shuoshuoComment = { loadComment: loadDisqus }
|
||||
: window.loadOtherComment = loadDisqus
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{use[0]}' === 'Disqus' || !!{lazyload}) {
|
||||
if (!{lazyload}) btf.loadComment(document.getElementById('disqus_thread'), loadDisqus)
|
||||
else {
|
||||
loadDisqus()
|
||||
!{ count ? 'GLOBAL_CONFIG_SITE.isPost && getCount()' : '' }
|
||||
!{ count ? `GLOBAL_CONFIG_SITE.pageType === 'post' && getCount()` : '' }
|
||||
}
|
||||
} else {
|
||||
window.loadOtherComment = loadDisqus
|
||||
|
||||
@@ -1,36 +1,52 @@
|
||||
- let disqusjsPageTitle = page.title.replace(/'/ig,"\\'")
|
||||
- let disqusjsPageTitle = page.title && page.title.replace(/'/ig,"\\'")
|
||||
- const { shortname:dqShortname, apikey:dqApikey, option:dqOption } = theme.disqusjs
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const initDisqusjs = () => {
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'== 'shuoshuo'
|
||||
const dqOption = !{JSON.stringify(dqOption)}
|
||||
|
||||
const destroyDisqusjs = () => {
|
||||
disqusjs.destroy()
|
||||
window.disqusjs = null
|
||||
disqusjs = new DisqusJS(Object.assign({
|
||||
}
|
||||
|
||||
const themeChange = (el, path) => {
|
||||
destroyDisqusjs()
|
||||
initDisqusjs(el, path)
|
||||
}
|
||||
|
||||
const initDisqusjs = (el = document, path) => {
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyDisqusjs = () => {
|
||||
destroyDisqusjs()
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
disqusjs = new DisqusJS({
|
||||
shortname: '!{dqShortname}',
|
||||
identifier: '!{ url_for(page.path) }',
|
||||
url: '!{ page.permalink }',
|
||||
title: '!{ disqusjsPageTitle }',
|
||||
apikey: '!{dqApikey}',
|
||||
},!{JSON.stringify(dqOption)}))
|
||||
...dqOption,
|
||||
identifier: isShuoshuo ? path : (dqOption && dqOption.identifier) || '!{ url_for(page.path) }',
|
||||
url: isShuoshuo ? location.origin + path : (dqOption && dqOption.url) || '!{ page.permalink }'
|
||||
})
|
||||
|
||||
disqusjs.render(document.getElementById('disqusjs-wrap'))
|
||||
disqusjs.render(el.querySelector('#disqusjs-wrap'))
|
||||
|
||||
btf.addGlobalFn('themeChange', () => themeChange(el, path), 'disqusjs')
|
||||
}
|
||||
|
||||
const themeChange = () => {
|
||||
const ele = document.getElementById('disqus_thread')
|
||||
if(!ele) return
|
||||
disqusjs.destroy()
|
||||
initDisqusjs()
|
||||
}
|
||||
|
||||
btf.addGlobalFn('themeChange', themeChange, 'disqusjs')
|
||||
|
||||
const loadDisqusjs = async() => {
|
||||
if (window.disqusJsLoad) initDisqusjs()
|
||||
const loadDisqusjs = async(el, path) => {
|
||||
if (window.disqusJsLoad) initDisqusjs(el, path)
|
||||
else {
|
||||
await btf.getCSS('!{url_for(theme.asset.disqusjs_css)}')
|
||||
await btf.getScript('!{url_for(theme.asset.disqusjs)}')
|
||||
initDisqusjs()
|
||||
initDisqusjs(el, path)
|
||||
window.disqusJsLoad = true
|
||||
}
|
||||
}
|
||||
@@ -52,11 +68,18 @@ script.
|
||||
}
|
||||
}
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{theme.comments.use[0]}' === 'Disqusjs'
|
||||
? window.shuoshuoComment = { loadComment: loadDisqusjs }
|
||||
: window.loadOtherComment = loadDisqusjs
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{theme.comments.use[0]}' === 'Disqusjs' || !!{theme.comments.lazyload}) {
|
||||
if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('disqusjs-wrap'), loadDisqusjs)
|
||||
else {
|
||||
loadDisqusjs()
|
||||
!{ theme.comments.count ? 'GLOBAL_CONFIG_SITE.isPost && getCount()' : '' }
|
||||
!{ theme.comments.count ? `GLOBAL_CONFIG_SITE.pageType === 'post' && getCount()` : '' }
|
||||
}
|
||||
} else {
|
||||
window.loadOtherComment = loadDisqusjs
|
||||
|
||||
@@ -3,17 +3,28 @@
|
||||
|
||||
script.
|
||||
(()=>{
|
||||
const loadFBComment = () => {
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'== 'shuoshuo'
|
||||
|
||||
const loadFBComment = (el = document, path) => {
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyFB = () => {
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('fb-root') ? '' : document.body.insertAdjacentHTML('afterend', '<div id="fb-root"></div>')
|
||||
|
||||
const themeNow = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
|
||||
const $fbComment = document.getElementsByClassName('fb-comments')[0]
|
||||
const $fbComment = el.getElementsByClassName('fb-comments')[0]
|
||||
$fbComment.setAttribute('data-colorscheme',themeNow)
|
||||
$fbComment.setAttribute('data-href', '!{urlNoIndex(page.permalink)}')
|
||||
$fbComment.setAttribute('data-href', isShuoshuo ? '!{urlNoIndex(page.permalink)}' + '#' + path : '!{urlNoIndex(page.permalink)}')
|
||||
|
||||
if (typeof FB === 'object') {
|
||||
FB.XFBML.parse(document.getElementsByClassName('post-meta-commentcount')[0])
|
||||
FB.XFBML.parse(document.getElementById('post-comment'))
|
||||
FB.XFBML.parse(el.querySelector('#post-comment'))
|
||||
}
|
||||
else {
|
||||
let ele = document.createElement('script')
|
||||
@@ -36,6 +47,13 @@ script.
|
||||
|
||||
btf.addGlobalFn('themeChange', fbModeChange, 'facebook_comments')
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{theme.comments.use[0]}' === 'Facebook Comments'
|
||||
? window.shuoshuoComment = { loadComment: loadFBComment }
|
||||
: window.loadOtherComment = loadFBComment
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{theme.comments.use[0]}' === 'Facebook Comments' || !!{theme.comments.lazyload}) {
|
||||
if (!{theme.comments.lazyload}) btf.loadComment(document.querySelector('#post-comment .fb-comments'), loadFBComment)
|
||||
else loadFBComment()
|
||||
|
||||
50
layout/includes/third-party/comments/giscus.pug
vendored
50
layout/includes/third-party/comments/giscus.pug
vendored
@@ -5,26 +5,49 @@
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||||
const option = !{JSON.stringify(option)}
|
||||
|
||||
const getGiscusTheme = theme => theme === 'dark' ? '!{dark_theme}' : '!{light_theme}'
|
||||
|
||||
const loadGiscus = () => {
|
||||
const config = Object.assign({
|
||||
const createScriptElement = config => {
|
||||
const ele = document.createElement('script')
|
||||
Object.entries(config).forEach(([key, value]) => {
|
||||
ele.setAttribute(key, value)
|
||||
})
|
||||
return ele
|
||||
}
|
||||
|
||||
const loadGiscus = (el = document, key) => {
|
||||
const mappingConfig = isShuoshuo
|
||||
? { 'data-mapping': 'specific', 'data-term': key }
|
||||
: { 'data-mapping': (option && option['data-mapping']) || 'pathname' }
|
||||
|
||||
const giscusConfig = {
|
||||
src: '!{giscusUrl}',
|
||||
'data-repo': '!{repo}',
|
||||
'data-repo-id': '!{repo_id}',
|
||||
'data-category-id': '!{category_id}',
|
||||
'data-mapping': 'pathname',
|
||||
'data-theme': getGiscusTheme(document.documentElement.getAttribute('data-theme')),
|
||||
'data-reactions-enabled': '1',
|
||||
crossorigin: 'anonymous',
|
||||
async: true
|
||||
},!{JSON.stringify(option)})
|
||||
|
||||
const ele = document.createElement('script')
|
||||
for (let key in config) {
|
||||
ele.setAttribute(key, config[key])
|
||||
async: true,
|
||||
...option,
|
||||
...mappingConfig
|
||||
}
|
||||
|
||||
const scriptElement = createScriptElement(giscusConfig)
|
||||
|
||||
el.querySelector('#giscus-wrap').appendChild(scriptElement)
|
||||
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyGiscus = () => {
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
document.getElementById('giscus-wrap').appendChild(ele)
|
||||
}
|
||||
|
||||
const changeGiscusTheme = theme => {
|
||||
@@ -43,6 +66,13 @@ script.
|
||||
|
||||
btf.addGlobalFn('themeChange', changeGiscusTheme, 'giscus')
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{use[0]}' === 'Giscus'
|
||||
? window.shuoshuoComment = { loadComment: loadGiscus }
|
||||
: window.loadOtherComment = loadGiscus
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{use[0]}' === 'Giscus' || !!{lazyload}) {
|
||||
if (!{lazyload}) btf.loadComment(document.getElementById('giscus-wrap'), loadGiscus)
|
||||
else loadGiscus()
|
||||
|
||||
64
layout/includes/third-party/comments/gitalk.pug
vendored
64
layout/includes/third-party/comments/gitalk.pug
vendored
@@ -2,28 +2,8 @@
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const initGitalk = () => {
|
||||
const gitalk = new Gitalk(Object.assign({
|
||||
clientID: '!{client_id}',
|
||||
clientSecret: '!{client_secret}',
|
||||
repo: '!{repo}',
|
||||
owner: '!{owner}',
|
||||
admin: ['!{admin}'],
|
||||
id: '!{md5(page.path)}',
|
||||
updateCountCallback: commentCount
|
||||
},!{JSON.stringify(option)}))
|
||||
|
||||
gitalk.render('gitalk-container')
|
||||
}
|
||||
|
||||
const loadGitalk = async() => {
|
||||
if (typeof Gitalk === 'function') initGitalk()
|
||||
else {
|
||||
await btf.getCSS('!{url_for(theme.asset.gitalk_css)}')
|
||||
await btf.getScript('!{url_for(theme.asset.gitalk)}')
|
||||
initGitalk()
|
||||
}
|
||||
}
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||||
const option = !{JSON.stringify(option)}
|
||||
|
||||
const commentCount = n => {
|
||||
const isCommentCount = document.querySelector('#post-meta .gitalk-comment-count')
|
||||
@@ -32,6 +12,46 @@ script.
|
||||
}
|
||||
}
|
||||
|
||||
const initGitalk = (el, path) => {
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyGitalk = () => {
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gitalk = new Gitalk({
|
||||
clientID: '!{client_id}',
|
||||
clientSecret: '!{client_secret}',
|
||||
repo: '!{repo}',
|
||||
owner: '!{owner}',
|
||||
admin: ['!{admin}'],
|
||||
updateCountCallback: commentCount,
|
||||
...option,
|
||||
id: isShuoshuo ? path : (option && option.id) || '!{md5(page.path)}'
|
||||
})
|
||||
|
||||
gitalk.render('gitalk-container')
|
||||
}
|
||||
|
||||
const loadGitalk = async(el, path) => {
|
||||
if (typeof Gitalk === 'function') initGitalk(el, path)
|
||||
else {
|
||||
await btf.getCSS('!{url_for(theme.asset.gitalk_css)}')
|
||||
await btf.getScript('!{url_for(theme.asset.gitalk)}')
|
||||
initGitalk(el, path)
|
||||
}
|
||||
}
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{theme.comments.use[0]}' === 'Gitalk'
|
||||
? window.shuoshuoComment = { loadComment: loadGitalk }
|
||||
: window.loadOtherComment = loadGitalk
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{theme.comments.use[0]}' === 'Gitalk' || !!{theme.comments.lazyload}) {
|
||||
if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('gitalk-container'), loadGitalk)
|
||||
else loadGitalk()
|
||||
|
||||
24
layout/includes/third-party/comments/livere.pug
vendored
24
layout/includes/third-party/comments/livere.pug
vendored
@@ -2,7 +2,22 @@
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const loadLivere = () => {
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||||
|
||||
const loadLivere = (el, path) => {
|
||||
window.livereOptions = {
|
||||
refer: path || location.pathname
|
||||
}
|
||||
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyLivere = () => {
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof LivereTower === 'object') window.LivereTower.init()
|
||||
else {
|
||||
(function(d, s) {
|
||||
@@ -16,6 +31,13 @@ script.
|
||||
}
|
||||
}
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{use[0]}' === 'Livere'
|
||||
? window.shuoshuoComment = { loadComment: loadLivere }
|
||||
: window.loadOtherComment = loadLivere
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{use[0]}' === 'Livere' || !!{lazyload}) {
|
||||
if (!{lazyload}) btf.loadComment(document.getElementById('lv-container'), loadLivere)
|
||||
else loadLivere()
|
||||
|
||||
@@ -1,68 +1,78 @@
|
||||
- const { host, siteId, option } = theme.remark42
|
||||
|
||||
script.
|
||||
var remark_config = Object.assign({
|
||||
host: '!{host}',
|
||||
site_id: '!{siteId}',
|
||||
components: ['embed'],
|
||||
theme: document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
|
||||
},!{JSON.stringify(option)})
|
||||
(() => {
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||||
const option = !{JSON.stringify(option)}
|
||||
|
||||
function addRemark42(){
|
||||
for (let i = 0; i < remark_config.components.length; i++) {
|
||||
const s = document.createElement('script')
|
||||
s.src = remark_config.host + '/web/' + remark_config.components[i] + '.js'
|
||||
s.defer = true
|
||||
document.head.appendChild(s)
|
||||
}
|
||||
const loadScript = src => {
|
||||
const script = document.createElement('script')
|
||||
script.src = src
|
||||
script.defer = true
|
||||
document.head.appendChild(script)
|
||||
}
|
||||
|
||||
function initRemark42() {
|
||||
const addRemark42 = () => loadScript('!{host}/web/embed.js')
|
||||
|
||||
const getCount = () => document.querySelector('.remark42__counter') && loadScript('!{host}/web/count.js')
|
||||
|
||||
const destroyRemark42 = () => window.remark42Instance && window.remark42Instance.destroy()
|
||||
|
||||
const initRemark42 = remark_config => {
|
||||
if (window.REMARK42) {
|
||||
if (this.remark42Instance) {
|
||||
this.remark42Instance.destroy()
|
||||
}
|
||||
|
||||
this.remark42Instance = window.REMARK42.createInstance({
|
||||
destroyRemark42()
|
||||
window.remark42Instance = window.REMARK42.createInstance({
|
||||
...remark_config
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function getCount () {
|
||||
const ele = document.querySelector('.remark42__counter')
|
||||
if (ele) {
|
||||
const s = document.createElement('script')
|
||||
s.src = remark_config.host + '/web/counter.js'
|
||||
s.defer = true
|
||||
document.head.appendChild(s)
|
||||
const loadRemark42 = (el, path) => {
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyRemark42 = () => {
|
||||
destroyRemark42()
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadRemark42 () {
|
||||
window.remark_config = {
|
||||
host: '!{host}',
|
||||
site_id: '!{siteId}',
|
||||
theme: document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light',
|
||||
...option,
|
||||
url: isShuoshuo ? window.location.origin + path : (option && option.url) || window.location.origin + window.location.pathname
|
||||
}
|
||||
|
||||
if (window.REMARK42) {
|
||||
this.initRemark42()
|
||||
initRemark42(remark_config)
|
||||
getCount()
|
||||
} else {
|
||||
addRemark42()
|
||||
window.addEventListener('REMARK42::ready', () => {
|
||||
this.initRemark42()
|
||||
initRemark42(remark_config)
|
||||
getCount()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function remarkChangeMode (theme) {
|
||||
if (!window.REMARK42) return
|
||||
window.REMARK42.changeTheme(theme)
|
||||
}
|
||||
const remarkChangeMode = theme => window.REMARK42 && window.REMARK42.changeTheme(theme)
|
||||
|
||||
btf.addGlobalFn('themeChange', remarkChangeMode, 'remark42')
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{theme.comments.use[0]}' === 'Remark42'
|
||||
? window.shuoshuoComment = { loadComment: loadRemark42 }
|
||||
: window.loadOtherComment = loadRemark42
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{theme.comments.use[0]}' === 'Remark42' || !!{theme.comments.lazyload}) {
|
||||
if (!{theme.comments.lazyload}) btf.loadComment(document.getElementById('remark42'), loadRemark42)
|
||||
else loadRemark42()
|
||||
} else {
|
||||
function loadOtherComment () {
|
||||
loadRemark42()
|
||||
}
|
||||
window.loadOtherComment = loadRemark42
|
||||
}
|
||||
})()
|
||||
37
layout/includes/third-party/comments/twikoo.pug
vendored
37
layout/includes/third-party/comments/twikoo.pug
vendored
@@ -3,6 +3,9 @@
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||||
const option = !{JSON.stringify(option)}
|
||||
|
||||
const getCount = () => {
|
||||
const countELement = document.getElementById('twikoo-count')
|
||||
if(!countELement) return
|
||||
@@ -18,22 +21,38 @@ script.
|
||||
})
|
||||
}
|
||||
|
||||
const init = () => {
|
||||
twikoo.init(Object.assign({
|
||||
el: '#twikoo-wrap',
|
||||
const init = (el = document, path = location.pathname) => {
|
||||
twikoo.init({
|
||||
el: el.querySelector('#twikoo-wrap'),
|
||||
envId: '!{envId}',
|
||||
region: '!{region}',
|
||||
onCommentLoaded: () => {
|
||||
btf.loadLightbox(document.querySelectorAll('#twikoo .tk-content img:not(.tk-owo-emotion)'))
|
||||
}
|
||||
}, !{JSON.stringify(option)}))
|
||||
},
|
||||
...option,
|
||||
path: isShuoshuo ? path : (option && option.path) || path
|
||||
})
|
||||
|
||||
!{count ? 'GLOBAL_CONFIG_SITE.isPost && getCount()' : ''}
|
||||
!{count ? `GLOBAL_CONFIG_SITE.pageType === 'post' && getCount()` : ''}
|
||||
|
||||
isShuoshuo && (window.shuoshuoComment.destroyTwikoo = () => {
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const loadTwikoo = () => {
|
||||
if (typeof twikoo === 'object') setTimeout(init,0)
|
||||
else btf.getScript('!{url_for(theme.asset.twikoo)}').then(init)
|
||||
const loadTwikoo = (el, path) => {
|
||||
if (typeof twikoo === 'object') setTimeout(() => init(el, path), 0)
|
||||
else btf.getScript('!{url_for(theme.asset.twikoo)}').then(() => init(el, path))
|
||||
}
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{use[0]}' === 'Twikoo'
|
||||
? window.shuoshuoComment = { loadComment: loadTwikoo }
|
||||
: window.loadOtherComment = loadTwikoo
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{use[0]}' === 'Twikoo' || !!{lazyload}) {
|
||||
|
||||
@@ -5,24 +5,33 @@
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||||
const option = !{JSON.stringify(option)}
|
||||
const getUtterancesTheme = theme => theme === 'dark' ? '#{dark_theme}' : '#{light_theme}'
|
||||
|
||||
const loadUtterances = () => {
|
||||
const config = Object.assign({
|
||||
id: 'utterances_comment',
|
||||
const loadUtterances = (el = document, key) => {
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyUtterances = () => {
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const config = {
|
||||
src: '!{utterancesUrl}',
|
||||
repo: '!{repo}',
|
||||
'issue-term': '!{issue_term}',
|
||||
theme: getUtterancesTheme(document.documentElement.getAttribute('data-theme')),
|
||||
crossorigin: 'anonymous',
|
||||
async: true
|
||||
},!{JSON.stringify(option)})
|
||||
async: true,
|
||||
...option,
|
||||
'issue-term': isShuoshuo ? key : (option && option['issue-term']) || '!{issue_term}'
|
||||
}
|
||||
|
||||
const ele = document.createElement('script')
|
||||
for (let key in config) {
|
||||
ele.setAttribute(key, config[key])
|
||||
}
|
||||
document.getElementById('utterances-wrap').appendChild(ele)
|
||||
Object.entries(config).forEach(([key, value]) => ele.setAttribute(key, value))
|
||||
el.querySelector('#utterances-wrap').appendChild(ele)
|
||||
}
|
||||
|
||||
const changeUtterancesTheme = theme => {
|
||||
@@ -38,6 +47,13 @@ script.
|
||||
|
||||
btf.addGlobalFn('themeChange', changeUtterancesTheme, 'utterances')
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{use[0]}' === 'Utterances'
|
||||
? window.shuoshuoComment = { loadComment: loadUtterances }
|
||||
: window.loadOtherComment = loadUtterances
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{use[0]}' === 'Utterances' || !!{lazyload}) {
|
||||
if (!{lazyload}) btf.loadComment(document.getElementById('utterances-wrap'), loadUtterances)
|
||||
else loadUtterances()
|
||||
|
||||
44
layout/includes/third-party/comments/valine.pug
vendored
44
layout/includes/third-party/comments/valine.pug
vendored
@@ -7,25 +7,48 @@ if site.data.valine
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const initValine = () => {
|
||||
const valine = new Valine(Object.assign({
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||||
const option = !{JSON.stringify(option)}
|
||||
|
||||
const initValine = (el, path) => {
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyValine = () => {
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const valineConfig = {
|
||||
el: '#vcomment',
|
||||
appId: '#{appId}',
|
||||
appKey: '#{appKey}',
|
||||
avatar: '#{avatar}',
|
||||
serverURLs: '#{serverURLs}',
|
||||
emojiMaps: !{emojiMaps},
|
||||
path: window.location.pathname,
|
||||
visitor: #{visitor}
|
||||
}, !{JSON.stringify(option)}))
|
||||
visitor: #{visitor},
|
||||
...option,
|
||||
path: isShuoshuo ? path : (option && option.path) || window.location.pathname
|
||||
}
|
||||
|
||||
const loadValine = async () => {
|
||||
if (typeof Valine === 'function') initValine()
|
||||
else {
|
||||
await btf.getScript('!{url_for(theme.asset.valine)}')
|
||||
initValine()
|
||||
new Valine(valineConfig)
|
||||
}
|
||||
|
||||
const loadValine = async (el, path) => {
|
||||
if (typeof Valine === 'function') {
|
||||
initValine(el, path)
|
||||
} else {
|
||||
await btf.getScript('!{url_for(theme.asset.valine)}')
|
||||
initValine(el, path)
|
||||
}
|
||||
}
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{use[0]}' === 'Valine'
|
||||
? window.shuoshuoComment = { loadComment: loadValine }
|
||||
: window.loadOtherComment = loadValine
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{use[0]}' === 'Valine' || !!{lazyload}) {
|
||||
@@ -35,4 +58,3 @@ script.
|
||||
window.loadOtherComment = loadValine
|
||||
}
|
||||
})()
|
||||
|
||||
|
||||
42
layout/includes/third-party/comments/waline.pug
vendored
42
layout/includes/third-party/comments/waline.pug
vendored
@@ -4,37 +4,53 @@
|
||||
script.
|
||||
(() => {
|
||||
let initFn = window.walineFn || null
|
||||
const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
|
||||
const option = !{JSON.stringify(option)}
|
||||
|
||||
const initWaline = (Fn) => {
|
||||
const waline = Fn(Object.assign({
|
||||
el: '#waline-wrap',
|
||||
const destroyWaline = ele => ele.destroy()
|
||||
|
||||
const initWaline = (Fn, el = document, path = window.location.pathname) => {
|
||||
const waline = Fn({
|
||||
el: el.querySelector('#waline-wrap'),
|
||||
serverURL: '!{serverURL}',
|
||||
pageview: !{lazyload ? false : pageview},
|
||||
dark: 'html[data-theme="dark"]',
|
||||
path: window.location.pathname,
|
||||
comment: !{lazyload ? false : count},
|
||||
}, !{JSON.stringify(option)}))
|
||||
...option,
|
||||
path: isShuoshuo ? path : (option && option.path) || path
|
||||
})
|
||||
|
||||
const destroyWaline = () => {
|
||||
waline.destroy()
|
||||
if (isShuoshuo) {
|
||||
window.shuoshuoComment.destroyWaline = () => {
|
||||
destroyWaline(waline)
|
||||
if (el.children.length) {
|
||||
el.innerHTML = ''
|
||||
el.classList.add('no-comment')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
btf.addGlobalFn('pjaxSendOnce', destroyWaline, 'destroyWaline')
|
||||
}
|
||||
|
||||
const loadWaline = () => {
|
||||
if (initFn) initWaline(initFn)
|
||||
const loadWaline = (el, path) => {
|
||||
if (initFn) initWaline(initFn, el, path)
|
||||
else {
|
||||
btf.getCSS('!{url_for(theme.asset.waline_css)}')
|
||||
.then(() => import('!{url_for(theme.asset.waline_js)}'))
|
||||
.then(({ init }) => {
|
||||
initFn = init || Waline.init
|
||||
initWaline(initFn)
|
||||
initWaline(initFn, el, path)
|
||||
window.walineFn = initFn
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (isShuoshuo) {
|
||||
'!{use[0]}' === 'Waline'
|
||||
? window.shuoshuoComment = { loadComment: loadWaline }
|
||||
: window.loadOtherComment = loadWaline
|
||||
return
|
||||
}
|
||||
|
||||
if ('!{use[0]}' === 'Waline' || !!{lazyload}) {
|
||||
if (!{lazyload}) btf.loadComment(document.getElementById('waline-wrap'),loadWaline)
|
||||
else setTimeout(loadWaline, 0)
|
||||
|
||||
91
layout/includes/third-party/math/chartjs.pug
vendored
Normal file
91
layout/includes/third-party/math/chartjs.pug
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
- const { fontColor, borderColor, scale_ticks_backdropColor } = theme.chartjs
|
||||
|
||||
script.
|
||||
(() => {
|
||||
const applyThemeDefaultsConfig = theme => {
|
||||
if (theme === 'dark-mode') {
|
||||
Chart.defaults.color = "!{fontColor.dark}"
|
||||
Chart.defaults.borderColor = "!{borderColor.dark}"
|
||||
Chart.defaults.scale.ticks.backdropColor = "!{scale_ticks_backdropColor.dark}"
|
||||
} else {
|
||||
Chart.defaults.color = "!{fontColor.light}"
|
||||
Chart.defaults.borderColor = "!{borderColor.light}"
|
||||
Chart.defaults.scale.ticks.backdropColor = "!{scale_ticks_backdropColor.light}"
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively traverse the config object and automatically apply theme-specific color schemes
|
||||
const applyThemeConfig = (obj, theme) => {
|
||||
if (typeof obj !== 'object' || obj === null) return
|
||||
|
||||
Object.keys(obj).forEach(key => {
|
||||
const value = obj[key]
|
||||
// If the property is an object and has theme-specific options, apply them
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (value[theme]) {
|
||||
obj[key] = value[theme] // Apply the value for the current theme
|
||||
} else {
|
||||
// Recursively process child objects
|
||||
applyThemeConfig(value, theme)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const runChartJS = ele => {
|
||||
window.loadChartJS = true
|
||||
|
||||
Array.from(ele).forEach((item, index) => {
|
||||
const chartSrc = item.firstElementChild
|
||||
const chartID = item.getAttribute('data-chartjs-id') || ('chartjs-' + index) // Use custom ID or default ID
|
||||
const width = item.getAttribute('data-width')
|
||||
const existingCanvas = document.getElementById(chartID)
|
||||
|
||||
// If a canvas already exists, remove it to avoid rendering duplicates
|
||||
if (existingCanvas) {
|
||||
existingCanvas.parentNode.remove()
|
||||
}
|
||||
|
||||
const chartDefinition = chartSrc.textContent
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.id = chartID
|
||||
|
||||
const div = document.createElement('div')
|
||||
div.className = 'chartjs-wrap'
|
||||
|
||||
if (width) {
|
||||
div.style.width = width
|
||||
}
|
||||
|
||||
div.appendChild(canvas)
|
||||
chartSrc.insertAdjacentElement('afterend', div)
|
||||
|
||||
const ctx = document.getElementById(chartID).getContext('2d')
|
||||
|
||||
const config = JSON.parse(chartDefinition)
|
||||
|
||||
const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark-mode' : 'light-mode'
|
||||
|
||||
// Set default styles (initial setup)
|
||||
applyThemeDefaultsConfig(theme)
|
||||
|
||||
// Automatically traverse the config and apply dual-mode color schemes
|
||||
applyThemeConfig(config, theme)
|
||||
|
||||
new Chart(ctx, config)
|
||||
})
|
||||
}
|
||||
|
||||
const loadChartJS = () => {
|
||||
const chartJSEle = document.querySelectorAll('#article-container .chartjs-container')
|
||||
if (chartJSEle.length === 0) return
|
||||
|
||||
window.loadChartJS ? runChartJS(chartJSEle) : btf.getScript('!{url_for(theme.asset.chartjs)}').then(() => runChartJS(chartJSEle))
|
||||
}
|
||||
|
||||
// Listen for theme change events
|
||||
btf.addGlobalFn('themeChange', loadChartJS, 'chartjs')
|
||||
btf.addGlobalFn('encrypt', loadChartJS, 'chartjs')
|
||||
|
||||
window.pjax ? loadChartJS() : document.addEventListener('DOMContentLoaded', loadChartJS)
|
||||
})()
|
||||
7
layout/includes/third-party/math/index.pug
vendored
7
layout/includes/third-party/math/index.pug
vendored
@@ -1,11 +1,14 @@
|
||||
case theme.math.use
|
||||
when 'mathjax'
|
||||
if (theme.math.per_page && (is_post() || is_page())) || page.mathjax
|
||||
if (theme.math.per_page && (['post','page'].includes(globalPageType))) || page.mathjax
|
||||
include ./mathjax.pug
|
||||
|
||||
when 'katex'
|
||||
if (theme.math.per_page && (is_post() || is_page())) || page.katex
|
||||
if (theme.math.per_page && (['post','page'].includes(globalPageType))) || page.katex
|
||||
include ./katex.pug
|
||||
|
||||
if theme.mermaid.enable
|
||||
include ./mermaid.pug
|
||||
|
||||
if theme.chartjs.enable
|
||||
include ./chartjs.pug
|
||||
@@ -34,7 +34,7 @@ script.
|
||||
|
||||
const searchParams = new URLSearchParams({
|
||||
'site_name': '!{site}',
|
||||
'limit': '!{theme.aside.card_newest_comments.limit}',
|
||||
'limit': '!{newestCommentsLimit * 2}', // Fetch more comments to filter pending comments
|
||||
})
|
||||
|
||||
const getComment = async (ele) => {
|
||||
@@ -42,7 +42,10 @@ script.
|
||||
const res = await fetch(`!{server}/api/v2/stats/latest_comments?${searchParams}`)
|
||||
const result = await res.json()
|
||||
const { avatarCdn, avatarDefault } = await getAvatarValue()
|
||||
const artalk = result.data.map(e => {
|
||||
const artalk = result.data
|
||||
.filter(e => !e.is_pending) // Filter pending comments
|
||||
.slice(0, !{newestCommentsLimit}) // Limit the number of comments
|
||||
.map(e => {
|
||||
const avatar = avatarCdn && e.email_encrypted ? `${avatarCdn}${e.email_encrypted}?${avatarDefault}` : ''
|
||||
return {
|
||||
'avatar': avatar,
|
||||
|
||||
@@ -23,8 +23,9 @@ script.
|
||||
result += '<div class="aside-list-item">'
|
||||
|
||||
if (!{theme.aside.card_newest_comments.avatar} && array[i].avatar) {
|
||||
const imgAttr = '!{theme.lazyload.enable ? "data-lazy-src" : "src"}'
|
||||
result += `<a href="${array[i].url}" class="thumbnail"><img ${imgAttr}="${array[i].avatar}" alt="${array[i].nick}"></a>`
|
||||
const imgAttr = '!{theme.lazyload.enable && !theme.lazyload.native ? "data-lazy-src" : "src"}'
|
||||
const lazyloadNative = '!{theme.lazyload.enable && theme.lazyload.native ? "loading=\"lazy\"" : ""}'
|
||||
result += `<a href="${array[i].url}" class="thumbnail"><img ${imgAttr}="${array[i].avatar}" alt="${array[i].nick}" ${lazyloadNative}></a>`
|
||||
}
|
||||
|
||||
result += `<div class="content">
|
||||
|
||||
@@ -6,7 +6,7 @@ script.
|
||||
const { changeContent, generateHtml, run } = window.newestComments
|
||||
|
||||
const getComment = ele => {
|
||||
fetch('https://disqus.com/api/3.0/forums/listPosts.json?forum=!{forum}&related=thread&limit=!{theme.aside.card_newest_comments.limit}&api_key=!{apiKey}')
|
||||
fetch('https://disqus.com/api/3.0/forums/listPosts.json?forum=!{forum}&related=thread&limit=!{newestCommentsLimit}&api_key=!{apiKey}')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const disqusArray = data.response.map(item => {
|
||||
|
||||
@@ -32,7 +32,7 @@ script.
|
||||
}
|
||||
|
||||
const getComment = ele => {
|
||||
fetch('https://api.github.com/repos/!{userRepo}/issues/comments?sort=updated&direction=desc&per_page=!{theme.aside.card_newest_comments.limit}&page=1',{
|
||||
fetch('https://api.github.com/repos/!{userRepo}/issues/comments?sort=updated&direction=desc&per_page=!{newestCommentsLimit}&page=1',{
|
||||
"headers": {
|
||||
Accept: 'application/vnd.github.v3.html+json'
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
- let { use } = theme.comments
|
||||
|
||||
if use
|
||||
- let forum,apiKey,userRepo
|
||||
-
|
||||
let forum,apiKey,userRepo
|
||||
let { limit:newestCommentsLimit } = theme.aside.card_newest_comments
|
||||
if (newestCommentsLimit > 10 || newestCommentsLimit < 1) newestCommentsLimit = 6
|
||||
|
||||
case use[0]
|
||||
when 'Valine'
|
||||
include ./valine.pug
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
- const { host, siteId } = theme.remark42
|
||||
!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true })
|
||||
|
||||
script.
|
||||
window.addEventListener('load', () => {
|
||||
@@ -6,7 +7,7 @@ script.
|
||||
const { changeContent, generateHtml, run } = window.newestComments
|
||||
|
||||
const getComment = ele => {
|
||||
fetch('!{host}/api/v1/last/!{theme.aside.card_newest_comments.limit}?site=!{siteId}')
|
||||
fetch('!{host}/api/v1/last/!{newestCommentsLimit}?site=!{siteId}')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const remark42 = data.map(e => {
|
||||
|
||||
@@ -10,7 +10,7 @@ script.
|
||||
twikoo.getRecentComments({
|
||||
envId: '!{theme.twikoo.envId}',
|
||||
region: '!{theme.twikoo.region}',
|
||||
pageSize: !{theme.aside.card_newest_comments.limit},
|
||||
pageSize: !{newestCommentsLimit},
|
||||
includeReply: true
|
||||
}).then(res => {
|
||||
const twikooArray = res.map(e => {
|
||||
|
||||
@@ -27,7 +27,7 @@ script.
|
||||
},
|
||||
}
|
||||
|
||||
fetch(`${serverURL}/1.1/classes/Comment?limit=!{theme.aside.card_newest_comments.limit}&order=-createdAt`,settings)
|
||||
fetch(`${serverURL}/1.1/classes/Comment?limit=!{newestCommentsLimit}&order=-createdAt`,settings)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const valineArray = data.results.map(e => {
|
||||
|
||||
@@ -9,7 +9,7 @@ script.
|
||||
|
||||
const getComment = async (ele) => {
|
||||
try {
|
||||
const res = await fetch('!{serverURL}/api/comment?type=recent&count=!{theme.aside.card_newest_comments.limit}', { method: 'GET' })
|
||||
const res = await fetch('!{serverURL}/api/comment?type=recent&count=!{newestCommentsLimit}')
|
||||
const result = await res.json()
|
||||
const walineArray = result.data.map(e => {
|
||||
return {
|
||||
|
||||
23
layout/includes/third-party/pangu.pug
vendored
23
layout/includes/third-party/pangu.pug
vendored
@@ -1,23 +0,0 @@
|
||||
script.
|
||||
(() => {
|
||||
const panguFn = () => {
|
||||
if (typeof pangu === 'object') pangu.autoSpacingPage()
|
||||
else {
|
||||
btf.getScript('!{url_for(theme.asset.pangu)}')
|
||||
.then(() => {
|
||||
pangu.autoSpacingPage()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const panguInit = () => {
|
||||
if (!{theme.pangu.field === 'post'}){
|
||||
GLOBAL_CONFIG_SITE.isPost && panguFn()
|
||||
} else {
|
||||
panguFn()
|
||||
}
|
||||
}
|
||||
|
||||
btf.addGlobalFn('pjaxComplete', panguInit, 'pangu')
|
||||
document.addEventListener('DOMContentLoaded', panguInit)
|
||||
})()
|
||||
13
layout/includes/third-party/pjax.pug
vendored
13
layout/includes/third-party/pjax.pug
vendored
@@ -7,10 +7,12 @@ if theme.pjax.exclude
|
||||
|
||||
- let choose = theme.comments.use
|
||||
if choose
|
||||
if theme.Open_Graph_meta.enable && (choose.includes('Livere') || choose.includes('Utterances') || choose.includes('Giscus'))
|
||||
- pjaxSelectors.unshift('meta[property="og:image"]', 'meta[property="og:title"]', 'meta[property="og:url"]')
|
||||
if choose.includes('Utterances') || choose.includes('Giscus')
|
||||
if choose.includes('Livere') || choose.includes('Utterances') || choose.includes('Giscus')
|
||||
- pjaxSelectors.unshift('link[rel="canonical"]')
|
||||
if theme.Open_Graph_meta.enable
|
||||
- pjaxSelectors.unshift('meta[property="og:image"]', 'meta[property="og:title"]', 'meta[property="og:url"]', 'meta[property="og:description"]')
|
||||
else
|
||||
- pjaxSelectors.unshift('meta[name="description"]')
|
||||
|
||||
script(src=url_for(theme.asset.pjax))
|
||||
script.
|
||||
@@ -57,7 +59,10 @@ script.
|
||||
|
||||
document.addEventListener('pjax:error', e => {
|
||||
if (e.request.status === 404) {
|
||||
pjax.loadUrl('!{url_for("/404.html")}')
|
||||
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
|
||||
}
|
||||
})
|
||||
})()
|
||||
@@ -6,7 +6,7 @@
|
||||
button.search-close-button
|
||||
i.fas.fa-times
|
||||
|
||||
#loading-database.is-center
|
||||
#loading-database.text-center
|
||||
i.fas.fa-spinner.fa-pulse
|
||||
span= ' ' + _p("search.load_data")
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.addtoany
|
||||
.a2a_kit.a2a_kit_size_32.a2a_default_style
|
||||
- let addtoanyItem = theme.addtoany.item.split(',')
|
||||
- let addtoanyItem = theme.share.addtoany.item.split(',')
|
||||
each name in addtoanyItem
|
||||
a(class="a2a_button_" + name)
|
||||
|
||||
|
||||
76
layout/includes/third-party/subtitle.pug
vendored
76
layout/includes/third-party/subtitle.pug
vendored
@@ -22,6 +22,26 @@ script.
|
||||
} else {
|
||||
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')
|
||||
@@ -33,14 +53,12 @@ case source
|
||||
fetch('https://v1.hitokoto.cn')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (!{effect}) {
|
||||
const from = '出自 ' + data.from
|
||||
const sub = !{JSON.stringify(subContent)}
|
||||
sub.unshift(data.hitokoto, from)
|
||||
typedJSFn.init(sub)
|
||||
} else {
|
||||
document.getElementById('subtitle').textContent = data.hitokoto
|
||||
}
|
||||
typedJSFn.processSubtitle(data.hitokoto, [from])
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Failed to get the Hitokoto API:', err)
|
||||
typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
|
||||
})
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
@@ -48,46 +66,48 @@ case source
|
||||
when 2
|
||||
script.
|
||||
function subtitleType () {
|
||||
btf.getScript('https://yijuzhan.com/api/word.php?m=js').then(() => {
|
||||
const con = str[0]
|
||||
if (!{effect}) {
|
||||
const from = '出自 ' + str[1]
|
||||
const sub = !{JSON.stringify(subContent)}
|
||||
sub.unshift(con, from)
|
||||
typedJSFn.init(sub)
|
||||
fetch('https://v.api.aa1.cn/api/yiyan/index.php')
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
const reg = /<p>(.*?)<\/p>/g
|
||||
const result = reg.exec(data)
|
||||
if (result && result[1]) {
|
||||
typedJSFn.processSubtitle(result[1])
|
||||
} 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)
|
||||
|
||||
when 3
|
||||
script.
|
||||
function subtitleType () {
|
||||
btf.getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js').then(() => {
|
||||
btf.getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js')
|
||||
.then(() => {
|
||||
jinrishici.load(result => {
|
||||
if (!{effect}) {
|
||||
const sub = !{JSON.stringify(subContent)}
|
||||
const content = result.data.content
|
||||
sub.unshift(content)
|
||||
typedJSFn.init(sub)
|
||||
if (result && result.data && result.data.content) {
|
||||
typedJSFn.processSubtitle(result.data.content)
|
||||
} else {
|
||||
document.getElementById('subtitle').textContent = result.data.content
|
||||
throw new Error('Failed to parse the return value of Jinrishici API')
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Failed to get the Jinrishici API:', err)
|
||||
typedJSFn.processSubtitle(!{JSON.stringify(subContent.length)})
|
||||
})
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
|
||||
default
|
||||
- subContent = subContent.length ? subContent : new Array(config.subtitle)
|
||||
if subContent.length > 0
|
||||
script.
|
||||
function subtitleType () {
|
||||
if (!{effect}) {
|
||||
typedJSFn.init(!{JSON.stringify(subContent)})
|
||||
} else {
|
||||
document.getElementById("subtitle").textContent = !{JSON.stringify(subContent[0])}
|
||||
}
|
||||
typedJSFn.processSubtitle(!{JSON.stringify(subContent)})
|
||||
}
|
||||
typedJSFn.run(subtitleType)
|
||||
@@ -35,7 +35,7 @@ script.
|
||||
|
||||
const insertData = async () => {
|
||||
try {
|
||||
if (GLOBAL_CONFIG_SITE.isPost && config.page_pv) {
|
||||
if (GLOBAL_CONFIG_SITE.pageType === 'post' && config.page_pv) {
|
||||
const pagePV = document.getElementById('umamiPV')
|
||||
if (pagePV) {
|
||||
const data = await getData(true)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
if theme.aside.card_author.enable
|
||||
.card-widget.card-info.is-center
|
||||
.card-widget.card-info.text-center
|
||||
.avatar-img
|
||||
img(src=url_for(theme.avatar.img) onerror=`this.onerror=null;this.src='` + url_for(theme.error_img.flink) + `'` alt="avatar")
|
||||
.author-info-name= config.author
|
||||
|
||||
@@ -12,4 +12,3 @@
|
||||
.toc-content.toc-div-class(class=tocExpandClass style="display:none")!=toc(page.origin, {list_number: tocNumber})
|
||||
else
|
||||
.toc-content(class=tocExpandClass)!=toc(page.content, {list_number: tocNumber})
|
||||
|
||||
@@ -6,40 +6,39 @@ if theme.aside.card_webinfo.enable
|
||||
.webinfo
|
||||
if theme.aside.card_webinfo.post_count
|
||||
.webinfo-item
|
||||
.item-name= _p('aside.card_webinfo.article_name') + " :"
|
||||
.item-name= `${_p('aside.card_webinfo.article_name')} :`
|
||||
.item-count= site.posts.length
|
||||
if theme.aside.card_webinfo.runtime_date
|
||||
.webinfo-item
|
||||
.item-name= _p('aside.card_webinfo.runtime.name') + " :"
|
||||
.item-name= `${_p('aside.card_webinfo.runtime.name')} :`
|
||||
.item-count#runtimeshow(data-publishDate=date_xml(theme.aside.card_webinfo.runtime_date))
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
if theme.wordcount.enable && theme.wordcount.total_wordcount
|
||||
.webinfo-item
|
||||
.item-name=_p('aside.card_webinfo.site_wordcount') + " :"
|
||||
.item-name= `${_p('aside.card_webinfo.site_wordcount')} :`
|
||||
.item-count= totalcount(site)
|
||||
if theme.umami_analytics.enable && theme.umami_analytics.UV_PV.site_uv
|
||||
.webinfo-item
|
||||
.item-name= _p('aside.card_webinfo.site_uv_name') + " :"
|
||||
.item-name= `${_p('aside.card_webinfo.site_uv_name')} :`
|
||||
.item-count#umami-site-uv
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
else if theme.busuanzi.site_uv
|
||||
.webinfo-item
|
||||
.item-name= _p('aside.card_webinfo.site_uv_name') + " :"
|
||||
.item-name= `${_p('aside.card_webinfo.site_uv_name')} :`
|
||||
.item-count#busuanzi_value_site_uv
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
if theme.umami_analytics.enable && theme.umami_analytics.UV_PV.site_pv
|
||||
.webinfo-item
|
||||
.item-name= _p('aside.card_webinfo.site_pv_name') + " :"
|
||||
.item-name= `${_p('aside.card_webinfo.site_pv_name')} :`
|
||||
.item-count#umami-site-pv
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
else if theme.busuanzi.site_pv
|
||||
.webinfo-item
|
||||
.item-name= _p('aside.card_webinfo.site_pv_name') + " :"
|
||||
.item-name= `${_p('aside.card_webinfo.site_pv_name')} :`
|
||||
.item-count#busuanzi_value_site_pv
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
if theme.aside.card_webinfo.last_push_date
|
||||
.webinfo-item
|
||||
.item-name= _p('aside.card_webinfo.last_push_date.name') + " :"
|
||||
.item-name= `${_p('aside.card_webinfo.last_push_date.name')} :`
|
||||
.item-count#last-push-date(data-lastPushDate=date_xml(Date.now()))
|
||||
i.fa-solid.fa-spinner.fa-spin
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#aside-content.aside-content
|
||||
//- post
|
||||
if is_post()
|
||||
if globalPageType === 'post'
|
||||
- const tocStyle = page.toc_style_simple
|
||||
- const tocStyleVal = tocStyle === true || tocStyle === false ? tocStyle : theme.toc.style_simple
|
||||
if showToc && tocStyleVal
|
||||
|
||||
@@ -5,7 +5,11 @@ block content
|
||||
if top_img === false
|
||||
include includes/header/post-info.pug
|
||||
|
||||
article#article-container.post-content!=page.content
|
||||
article#article-container.container.post-content
|
||||
if theme.noticeOutdate.enable && page.noticeOutdate !== false
|
||||
include includes/post/outdate-notice.pug
|
||||
else
|
||||
!=page.content
|
||||
include includes/post/post-copyright.pug
|
||||
.tag_share
|
||||
if (page.tags.length > 0 && theme.post_meta.post.tags)
|
||||
@@ -29,4 +33,3 @@ block content
|
||||
if page.comments !== false && theme.comments.use
|
||||
- var commentsJsLoad = true
|
||||
!=partial('includes/third-party/comments/index', {}, {cache: true})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hexo-theme-butterfly",
|
||||
"version": "5.0.0",
|
||||
"version": "5.3.5",
|
||||
"description": "A Simple and Card UI Design theme for Hexo",
|
||||
"main": "package.json",
|
||||
"scripts": {
|
||||
|
||||
36
plugins.yml
36
plugins.yml
@@ -1,15 +1,15 @@
|
||||
abcjs_basic_js:
|
||||
name: abcjs
|
||||
file: dist/abcjs-basic-min.js
|
||||
version: 6.4.3
|
||||
version: 6.4.4
|
||||
activate_power_mode:
|
||||
name: butterfly-extsrc
|
||||
file: dist/activate-power-mode.min.js
|
||||
version: 1.1.4
|
||||
algolia_search:
|
||||
name: algoliasearch
|
||||
file: dist/algoliasearch-lite.umd.js
|
||||
version: 5.7.0
|
||||
file: dist/lite/builds/browser.umd.js
|
||||
version: 5.20.3
|
||||
aplayer_css:
|
||||
name: aplayer
|
||||
file: dist/APlayer.min.css
|
||||
@@ -42,6 +42,10 @@ canvas_ribbon:
|
||||
name: butterfly-extsrc
|
||||
file: dist/canvas-ribbon.min.js
|
||||
version: 1.1.4
|
||||
chartjs:
|
||||
name: chart.js
|
||||
file: dist/chart.umd.js
|
||||
version: 4.4.8
|
||||
clickShowText:
|
||||
name: butterfly-extsrc
|
||||
file: dist/click-show-text.min.js
|
||||
@@ -62,12 +66,12 @@ docsearch_css:
|
||||
name: '@docsearch/css'
|
||||
other_name: docsearch-css
|
||||
file: dist/style.css
|
||||
version: 3.6.2
|
||||
version: 3.9.0
|
||||
docsearch_js:
|
||||
name: '@docsearch/js'
|
||||
other_name: docsearch-js
|
||||
file: dist/umd/index.js
|
||||
version: 3.6.2
|
||||
version: 3.9.0
|
||||
egjs_infinitegrid:
|
||||
name: '@egjs/infinitegrid'
|
||||
other_name: egjs-infinitegrid
|
||||
@@ -91,7 +95,7 @@ fontawesome:
|
||||
name: '@fortawesome/fontawesome-free'
|
||||
file: css/all.min.css
|
||||
other_name: font-awesome
|
||||
version: 6.6.0
|
||||
version: 6.7.2
|
||||
gitalk:
|
||||
name: gitalk
|
||||
file: dist/gitalk.min.js
|
||||
@@ -107,17 +111,17 @@ instantpage:
|
||||
instantsearch:
|
||||
name: instantsearch.js
|
||||
file: dist/instantsearch.production.min.js
|
||||
version: 4.74.2
|
||||
version: 4.77.3
|
||||
katex:
|
||||
name: katex
|
||||
file: dist/katex.min.css
|
||||
other_name: KaTeX
|
||||
version: 0.16.11
|
||||
version: 0.16.21
|
||||
katex_copytex:
|
||||
name: katex
|
||||
file: dist/contrib/copy-tex.min.js
|
||||
other_name: KaTeX
|
||||
version: 0.16.11
|
||||
version: 0.16.21
|
||||
lazyload:
|
||||
name: vanilla-lazyload
|
||||
file: dist/lazyload.iife.min.js
|
||||
@@ -133,7 +137,7 @@ medium_zoom:
|
||||
mermaid:
|
||||
name: mermaid
|
||||
file: dist/mermaid.min.js
|
||||
version: 11.2.1
|
||||
version: 11.4.1
|
||||
meting_js:
|
||||
name: butterfly-extsrc
|
||||
file: metingjs/dist/Meting.min.js
|
||||
@@ -148,10 +152,6 @@ pace_js:
|
||||
other_name: pace
|
||||
file: pace.min.js
|
||||
version: 1.2.4
|
||||
pangu:
|
||||
name: pangu
|
||||
file: dist/browser/pangu.min.js
|
||||
version: 4.0.7
|
||||
pjax:
|
||||
name: pjax
|
||||
file: pjax.min.js
|
||||
@@ -190,7 +190,7 @@ snackbar_css:
|
||||
twikoo:
|
||||
name: twikoo
|
||||
file: dist/twikoo.all.min.js
|
||||
version: 1.6.39
|
||||
version: 1.6.41
|
||||
typed:
|
||||
name: typed.js
|
||||
file: dist/typed.umd.js
|
||||
@@ -198,14 +198,14 @@ typed:
|
||||
valine:
|
||||
name: valine
|
||||
file: dist/Valine.min.js
|
||||
version: 1.5.2
|
||||
version: 1.5.3
|
||||
waline_css:
|
||||
name: '@waline/client'
|
||||
file: dist/waline.css
|
||||
other_name: waline
|
||||
version: 3.3.2
|
||||
version: 3.5.5
|
||||
waline_js:
|
||||
name: '@waline/client'
|
||||
file: dist/waline.js
|
||||
other_name: waline
|
||||
version: 3.3.2
|
||||
version: 3.5.5
|
||||
|
||||
36
scripts/common/postDesc.js
Normal file
36
scripts/common/postDesc.js
Normal file
@@ -0,0 +1,36 @@
|
||||
'use strict'
|
||||
|
||||
const { stripHTML, truncate } = require('hexo-util')
|
||||
|
||||
// Truncates the given content to a specified length, removing HTML tags and replacing newlines with spaces.
|
||||
const truncateContent = (content, length) => {
|
||||
return truncate(stripHTML(content), { length, separator: ' ' }).replace(/\n/g, ' ')
|
||||
}
|
||||
|
||||
// Generates a post description based on the provided data and theme configuration.
|
||||
const postDesc = (data, hexo) => {
|
||||
const { description, content, postDesc } = data
|
||||
|
||||
if (postDesc) return postDesc
|
||||
|
||||
const { length, method } = hexo.theme.config.index_post_content
|
||||
|
||||
if (method === false) return
|
||||
|
||||
let result
|
||||
switch (method) {
|
||||
case 1:
|
||||
result = description
|
||||
break
|
||||
case 2:
|
||||
result = description || truncateContent(content, length)
|
||||
break
|
||||
default:
|
||||
result = truncateContent(content, length)
|
||||
}
|
||||
|
||||
data.postDesc = result
|
||||
return result
|
||||
}
|
||||
|
||||
module.exports = { truncateContent, postDesc }
|
||||
@@ -7,11 +7,18 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
let { use } = themeConfig.comments
|
||||
if (!use) return
|
||||
|
||||
// 確保 use 是一個陣列
|
||||
// Make sure use is an array
|
||||
use = Array.isArray(use) ? use : use.split(',')
|
||||
|
||||
// 將每個項目轉換為小寫並將首字母大寫
|
||||
themeConfig.comments.use = use.map(item =>
|
||||
// Capitalize the first letter of each comment name
|
||||
use = use.map(item =>
|
||||
item.trim().toLowerCase().replace(/\b[a-z]/g, s => s.toUpperCase())
|
||||
)
|
||||
|
||||
// Disqus and Disqusjs conflict, only keep the first one
|
||||
if (use.includes('Disqus') && use.includes('Disqusjs')) {
|
||||
use = [use[0]]
|
||||
}
|
||||
|
||||
themeConfig.comments.use = use
|
||||
})
|
||||
|
||||
@@ -341,7 +341,7 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
user_id: null,
|
||||
pageSize: 10,
|
||||
order_by: 'social',
|
||||
lang: 'zh_TW'
|
||||
lang: 'en_US'
|
||||
},
|
||||
twikoo: {
|
||||
envId: null,
|
||||
@@ -380,9 +380,6 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
tidio: {
|
||||
public_key: null
|
||||
},
|
||||
daovoice: {
|
||||
app_id: null
|
||||
},
|
||||
crisp: {
|
||||
website_id: null
|
||||
},
|
||||
@@ -512,6 +509,21 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
dark: 'dark'
|
||||
}
|
||||
},
|
||||
chartjs: {
|
||||
enable: false,
|
||||
fontColor: {
|
||||
light: 'rgba(0, 0, 0, 0.8)',
|
||||
dark: 'rgba(255, 255, 255, 0.8)'
|
||||
},
|
||||
borderColor: {
|
||||
light: 'rgba(0, 0, 0, 0.1)',
|
||||
dark: 'rgba(255, 255, 255, 0.2)'
|
||||
},
|
||||
scale_ticks_backdropColor: {
|
||||
light: 'transparent',
|
||||
dark: 'transparent'
|
||||
}
|
||||
},
|
||||
note: {
|
||||
style: 'flat',
|
||||
icons: true,
|
||||
@@ -533,12 +545,9 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
bg_dark: '#1f1f1f'
|
||||
},
|
||||
instantpage: false,
|
||||
pangu: {
|
||||
enable: false,
|
||||
field: 'site'
|
||||
},
|
||||
lazyload: {
|
||||
enable: false,
|
||||
native: false,
|
||||
field: 'site',
|
||||
placeholder: null,
|
||||
blur: false
|
||||
@@ -555,6 +564,7 @@ hexo.extend.filter.register('before_generate', () => {
|
||||
enable: true,
|
||||
option: null
|
||||
},
|
||||
structured_data: true,
|
||||
css_prefix: true,
|
||||
inject: {
|
||||
head: null,
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
const lazyload = htmlContent => {
|
||||
if (hexo.theme.config.lazyload.native) {
|
||||
return htmlContent.replace(/(<img.*?)(>)/ig, '$1 loading=\'lazy\'$2')
|
||||
}
|
||||
|
||||
const bg = hexo.theme.config.lazyload.placeholder ? urlFor(hexo.theme.config.lazyload.placeholder) : 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
|
||||
return htmlContent.replace(/(<img.*? src=)/ig, `$1 "${bg}" data-lazy-src=`)
|
||||
}
|
||||
|
||||
@@ -1,33 +1,57 @@
|
||||
/**
|
||||
* Butterfly
|
||||
* ramdom cover
|
||||
* Random cover for posts
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
hexo.extend.filter.register('before_post_render', data => {
|
||||
const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/i
|
||||
hexo.extend.generator.register('post', locals => {
|
||||
const previousIndexes = []
|
||||
|
||||
const getRandomCover = defaultCover => {
|
||||
if (!defaultCover) return false
|
||||
if (!Array.isArray(defaultCover)) return defaultCover
|
||||
|
||||
const coverCount = defaultCover.length
|
||||
|
||||
if (coverCount === 1) {
|
||||
return defaultCover[0]
|
||||
}
|
||||
|
||||
const maxPreviousIndexes = coverCount === 2 ? 1 : (coverCount === 3 ? 2 : 3)
|
||||
|
||||
let index
|
||||
do {
|
||||
index = Math.floor(Math.random() * coverCount)
|
||||
} while (previousIndexes.includes(index) && previousIndexes.length < coverCount)
|
||||
|
||||
previousIndexes.push(index)
|
||||
if (previousIndexes.length > maxPreviousIndexes) {
|
||||
previousIndexes.shift()
|
||||
}
|
||||
|
||||
return defaultCover[index]
|
||||
}
|
||||
|
||||
const handleImg = data => {
|
||||
const imgTestReg = /\.(png|jpe?g|gif|svg|webp|avif)(\?.*)?$/i
|
||||
let { cover: coverVal, top_img: topImg } = data
|
||||
|
||||
// Add path to top_img and cover if post_asset_folder is enabled
|
||||
if (hexo.config.post_asset_folder) {
|
||||
if (topImg && topImg.indexOf('/') === -1 && imgTestReg.test(topImg)) data.top_img = `${data.path}${topImg}`
|
||||
if (coverVal && coverVal.indexOf('/') === -1 && imgTestReg.test(coverVal)) data.cover = `${data.path}${coverVal}`
|
||||
if (topImg && topImg.indexOf('/') === -1 && imgTestReg.test(topImg)) {
|
||||
data.top_img = `${data.path}${topImg}`
|
||||
}
|
||||
if (coverVal && coverVal.indexOf('/') === -1 && imgTestReg.test(coverVal)) {
|
||||
data.cover = `${data.path}${coverVal}`
|
||||
}
|
||||
|
||||
const randomCoverFn = () => {
|
||||
const { cover: { default_cover: defaultCover } } = hexo.theme.config
|
||||
if (!defaultCover) return false
|
||||
if (!Array.isArray(defaultCover)) return defaultCover
|
||||
const num = Math.floor(Math.random() * defaultCover.length)
|
||||
return defaultCover[num]
|
||||
}
|
||||
|
||||
if (coverVal === false) return data
|
||||
|
||||
// If cover is not set, use random cover
|
||||
if (!coverVal) {
|
||||
const randomCover = randomCoverFn()
|
||||
const { cover: { default_cover: defaultCover } } = hexo.theme.config
|
||||
const randomCover = getRandomCover(defaultCover)
|
||||
data.cover = randomCover
|
||||
coverVal = randomCover // update coverVal
|
||||
}
|
||||
@@ -37,4 +61,22 @@ hexo.extend.filter.register('before_post_render', data => {
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// https://github.com/hexojs/hexo/blob/master/lib%2Fplugins%2Fgenerator%2Fpost.ts
|
||||
const posts = locals.posts.sort('date').toArray()
|
||||
const { length } = posts
|
||||
|
||||
return posts.map((post, i) => {
|
||||
if (i) post.prev = posts[i - 1]
|
||||
if (i < length - 1) post.next = posts[i + 1]
|
||||
|
||||
post.__post = true
|
||||
|
||||
return {
|
||||
data: handleImg(post),
|
||||
layout: 'post',
|
||||
path: post.path
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,38 +2,68 @@
|
||||
|
||||
hexo.extend.helper.register('aside_archives', function (options = {}) {
|
||||
const { config, page, site, url_for, _p } = this
|
||||
const archiveDir = config.archive_dir
|
||||
const { timezone } = config
|
||||
const lang = toMomentLocale(page.lang || page.language || config.language)
|
||||
const type = options.type || 'monthly'
|
||||
const format = options.format || (type === 'monthly' ? 'MMMM YYYY' : 'YYYY')
|
||||
const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count') ? options.show_count : true
|
||||
const order = options.order || -1
|
||||
const limit = options.limit
|
||||
const {
|
||||
archive_dir: archiveDir,
|
||||
timezone,
|
||||
language
|
||||
} = config
|
||||
|
||||
// Destructure and set default options with object destructuring
|
||||
const {
|
||||
type = 'monthly',
|
||||
format = type === 'monthly' ? 'MMMM YYYY' : 'YYYY',
|
||||
show_count: showCount = true,
|
||||
order = -1,
|
||||
limit,
|
||||
transform
|
||||
} = options
|
||||
|
||||
// Optimize locale handling
|
||||
const lang = toMomentLocale(page.lang || page.language || language)
|
||||
|
||||
// Memoize comparison function to improve performance
|
||||
const compareFunc = type === 'monthly'
|
||||
? (yearA, monthA, yearB, monthB) => yearA === yearB && monthA === monthB
|
||||
: (yearA, monthA, yearB, monthB) => yearA === yearB
|
||||
: (yearA, yearB) => yearA === yearB
|
||||
|
||||
const posts = site.posts.sort('date', order)
|
||||
if (!posts.length) return ''
|
||||
// Early return if no posts
|
||||
if (!site.posts.length) return ''
|
||||
|
||||
const data = []
|
||||
posts.forEach(post => {
|
||||
// Use reduce for more efficient data processing
|
||||
const data = site.posts
|
||||
.sort('date', order)
|
||||
.reduce((acc, post) => {
|
||||
let date = post.date.clone()
|
||||
if (timezone) date = date.tz(timezone)
|
||||
|
||||
const year = date.year()
|
||||
const month = date.month() + 1
|
||||
|
||||
if (!data.length || !compareFunc(data[data.length - 1].year, data[data.length - 1].month, year, month)) {
|
||||
if (lang) date = date.locale(lang)
|
||||
data.push({ name: date.format(format), year, month, count: 1 })
|
||||
} else {
|
||||
data[data.length - 1].count++
|
||||
}
|
||||
})
|
||||
|
||||
const link = item => {
|
||||
// Find or create archive entry
|
||||
const lastEntry = acc[acc.length - 1]
|
||||
if (!lastEntry || !compareFunc(
|
||||
lastEntry.year,
|
||||
lastEntry.month,
|
||||
year,
|
||||
month
|
||||
)) {
|
||||
acc.push({
|
||||
name: date.format(format),
|
||||
year,
|
||||
month,
|
||||
count: 1
|
||||
})
|
||||
} else {
|
||||
lastEntry.count++
|
||||
}
|
||||
|
||||
return acc
|
||||
}, [])
|
||||
|
||||
// Create link generator function
|
||||
const createArchiveLink = item => {
|
||||
let url = `${archiveDir}/${item.year}/`
|
||||
if (type === 'monthly') {
|
||||
url += item.month < 10 ? `0${item.month}/` : `${item.month}/`
|
||||
@@ -41,37 +71,48 @@ hexo.extend.helper.register('aside_archives', function (options = {}) {
|
||||
return url_for(url)
|
||||
}
|
||||
|
||||
const len = data.length
|
||||
const limitLength = limit === 0 ? len : Math.min(len, limit)
|
||||
// Limit results efficiently
|
||||
const limitedData = limit > 0
|
||||
? data.slice(0, Math.min(data.length, limit))
|
||||
: data
|
||||
|
||||
let result = `
|
||||
// Use template literal for better readability
|
||||
const archiveHeader = `
|
||||
<div class="item-headline">
|
||||
<i class="fas fa-archive"></i>
|
||||
<span>${_p('aside.card_archives')}</span>
|
||||
${len > limitLength ? `<a class="card-more-btn" href="${url_for(archiveDir)}/" title="${_p('aside.more_button')}"><i class="fas fa-angle-right"></i></a>` : ''}
|
||||
${data.length > limitedData.length
|
||||
? `<a class="card-more-btn" href="${url_for(archiveDir)}/"
|
||||
title="${_p('aside.more_button')}">
|
||||
<i class="fas fa-angle-right"></i>
|
||||
</a>`
|
||||
: ''}
|
||||
</div>
|
||||
<ul class="card-archive-list">
|
||||
`
|
||||
|
||||
for (let i = 0; i < limitLength; i++) {
|
||||
const item = data[i]
|
||||
result += `
|
||||
// Use map for generating list items, join for performance
|
||||
const archiveList = `
|
||||
<ul class="card-archive-list">
|
||||
${limitedData.map(item => `
|
||||
<li class="card-archive-list-item">
|
||||
<a class="card-archive-list-link" href="${link(item)}">
|
||||
<span class="card-archive-list-date">${options.transform ? options.transform(item.name) : item.name}</span>
|
||||
${showCount ? `<span class="card-archive-list-count">${item.count}</span>` : ''}
|
||||
<a class="card-archive-list-link" href="${createArchiveLink(item)}">
|
||||
<span class="card-archive-list-date">
|
||||
${transform ? transform(item.name) : item.name}
|
||||
</span>
|
||||
${showCount
|
||||
? `<span class="card-archive-list-count">${item.count}</span>`
|
||||
: ''}
|
||||
</a>
|
||||
</li>
|
||||
`).join('')}
|
||||
</ul>
|
||||
`
|
||||
}
|
||||
|
||||
result += '</ul>'
|
||||
return result
|
||||
return archiveHeader + archiveList
|
||||
})
|
||||
|
||||
const toMomentLocale = function (lang) {
|
||||
if (!lang || lang === 'en' || lang === 'default') {
|
||||
return 'en'
|
||||
}
|
||||
// Improved locale conversion function
|
||||
const toMomentLocale = lang => {
|
||||
if (!lang || ['en', 'default'].includes(lang)) return 'en'
|
||||
return lang.toLowerCase().replace('_', '-')
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ hexo.extend.helper.register('inject_head_js', function () {
|
||||
if (!${pjax.enable} && key.startsWith('pjax')) return
|
||||
const globalFn = parent.globalFn || {}
|
||||
globalFn[key] = globalFn[key] || {}
|
||||
if (name && globalFn[key][name]) return
|
||||
globalFn[key][name || Object.keys(globalFn[key]).length] = fn
|
||||
parent.globalFn = globalFn
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
const { stripHTML, prettyUrls, truncate } = require('hexo-util')
|
||||
const { truncateContent, postDesc } = require('../common/postDesc')
|
||||
const { prettyUrls } = require('hexo-util')
|
||||
const crypto = require('crypto')
|
||||
const moment = require('moment-timezone')
|
||||
|
||||
hexo.extend.helper.register('truncate', (content, length) => {
|
||||
return truncate(stripHTML(content), { length, separator: ' ' }).replace(/\n/g, ' ')
|
||||
hexo.extend.helper.register('truncate', truncateContent)
|
||||
|
||||
hexo.extend.helper.register('postDesc', data => {
|
||||
return postDesc(data, hexo)
|
||||
})
|
||||
|
||||
hexo.extend.helper.register('cloudTags', function (options = {}) {
|
||||
@@ -82,7 +86,7 @@ hexo.extend.helper.register('getBgPath', path => {
|
||||
|
||||
const absoluteUrlPattern = /^(?:[a-z][a-z\d+.-]*:)?\/\//i
|
||||
const relativeUrlPattern = /^(\.\/|\.\.\/|\/|[^/]+\/).*$/
|
||||
const colorPattern = /^(#|rgb|rgba|hsl|hsla|linear-gradient|radial-gradient)/i
|
||||
const colorPattern = /^(#|rgb|rgba|hsl|hsla)/i
|
||||
|
||||
if (colorPattern.test(path)) {
|
||||
return `background-color: ${path};`
|
||||
@@ -92,3 +96,57 @@ hexo.extend.helper.register('getBgPath', path => {
|
||||
return `background: ${path};`
|
||||
}
|
||||
})
|
||||
|
||||
hexo.extend.helper.register('shuoshuoFN', (data, page) => {
|
||||
const { limit } = page
|
||||
let finalResult = ''
|
||||
|
||||
// Check if limit.value is a valid date
|
||||
const isValidDate = date => !isNaN(Date.parse(date))
|
||||
|
||||
// order by date
|
||||
const orderByDate = data => data.sort((a, b) => Date.parse(b.date) - Date.parse(a.date))
|
||||
|
||||
// Apply number limit or time limit conditionally
|
||||
const limitData = data => {
|
||||
if (limit && limit.type === 'num' && limit.value > 0) {
|
||||
return data.slice(0, limit.value)
|
||||
} else if (limit && limit.type === 'date' && isValidDate(limit.value)) {
|
||||
const limitDate = Date.parse(limit.value)
|
||||
return data.filter(item => Date.parse(item.date) >= limitDate)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
orderByDate(data)
|
||||
finalResult = limitData(data)
|
||||
|
||||
// This is a hack method, because hexo treats time as UTC time
|
||||
// so you need to manually convert the time zone
|
||||
finalResult.forEach(item => {
|
||||
const utcDate = moment.utc(item.date).format('YYYY-MM-DD HH:mm:ss')
|
||||
item.date = moment.tz(utcDate, hexo.config.timezone).format('YYYY-MM-DD HH:mm:ss')
|
||||
})
|
||||
|
||||
return finalResult
|
||||
})
|
||||
|
||||
hexo.extend.helper.register('getPageType', (page, isHome) => {
|
||||
const { layout, tag, category, type, archive } = page
|
||||
if (layout) return layout
|
||||
if (tag) return 'tag'
|
||||
if (category) return 'category'
|
||||
if (archive) return 'archive'
|
||||
if (type) {
|
||||
if (type === 'tags' || type === 'categories') return type
|
||||
else return 'page'
|
||||
}
|
||||
if (isHome) return 'home'
|
||||
return 'post'
|
||||
})
|
||||
|
||||
hexo.extend.helper.register('getVersion', () => {
|
||||
const { version } = require('../../package.json')
|
||||
return { hexo: hexo.version, theme: version }
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable camelcase */
|
||||
/**
|
||||
* Butterfly
|
||||
* Related Posts
|
||||
@@ -6,12 +7,15 @@
|
||||
|
||||
'use strict'
|
||||
|
||||
const { postDesc } = require('../common/postDesc')
|
||||
|
||||
hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
|
||||
let relatedPosts = []
|
||||
const tagsData = currentPost.tags
|
||||
tagsData.length && tagsData.forEach(function (tag) {
|
||||
allPosts.forEach(function (post) {
|
||||
if (currentPost.path !== post.path && isTagRelated(tag.name, post.tags)) {
|
||||
const getPostDesc = post.postDesc || postDesc(post, hexo)
|
||||
const relatedPost = {
|
||||
title: post.title,
|
||||
path: post.path,
|
||||
@@ -19,7 +23,8 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
|
||||
cover_type: post.cover_type,
|
||||
weight: 1,
|
||||
updated: post.updated,
|
||||
created: post.date
|
||||
created: post.date,
|
||||
postDesc: getPostDesc
|
||||
}
|
||||
const index = findItem(relatedPosts, 'path', post.path)
|
||||
if (index !== -1) {
|
||||
@@ -50,20 +55,27 @@ hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
|
||||
result += '<div class="relatedPosts-list">'
|
||||
|
||||
for (let i = 0; i < Math.min(relatedPosts.length, limitNum); i++) {
|
||||
const cover = relatedPosts[i].cover || 'var(--default-bg-color)'
|
||||
const title = this.escape_html(relatedPosts[i].title)
|
||||
result += `<a href="${this.url_for(relatedPosts[i].path)}" title="${title}">`
|
||||
if (relatedPosts[i].cover_type === 'img') {
|
||||
result += `<img class="cover" src="${this.url_for(cover)}" alt="cover">`
|
||||
let { cover, title, path, cover_type, created, updated, postDesc } = relatedPosts[i]
|
||||
const { escape_html, url_for, date } = this
|
||||
cover = cover || 'var(--default-bg-color)'
|
||||
title = escape_html(title)
|
||||
const className = postDesc ? 'pagination-related' : 'pagination-related no-desc'
|
||||
result += `<a class="${className}" href="${url_for(path)}" title="${title}">`
|
||||
if (cover_type === 'img') {
|
||||
result += `<img class="cover" src="${url_for(cover)}" alt="cover">`
|
||||
} else {
|
||||
result += `<div class="cover" style="background: ${cover}"></div>`
|
||||
}
|
||||
if (dateType === 'created') {
|
||||
result += `<div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> ${this.date(relatedPosts[i].created, hexoConfig.date_format)}</div>`
|
||||
result += `<div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="far fa-calendar-alt fa-fw"></i> ${date(created, hexoConfig.date_format)}</div>`
|
||||
} else {
|
||||
result += `<div class="content is-center"><div class="date"><i class="fas fa-history fa-fw"></i> ${this.date(relatedPosts[i].updated, hexoConfig.date_format)}</div>`
|
||||
result += `<div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="fas fa-history fa-fw"></i> ${date(updated, hexoConfig.date_format)}</div>`
|
||||
}
|
||||
result += `<div class="info-item-2">${title}</div></div>`
|
||||
|
||||
if (postDesc) {
|
||||
result += `<div class="info-2"><div class="info-item-1">${postDesc}</div></div>`
|
||||
}
|
||||
result += `<div class="title">${title}</div>`
|
||||
result += '</div></a>'
|
||||
}
|
||||
|
||||
|
||||
49
scripts/tag/chartjs.js
Normal file
49
scripts/tag/chartjs.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Butterfly
|
||||
* chartjs
|
||||
* https://www.chartjs.org/
|
||||
* {% chartjs [width, abreast, chartId] %}
|
||||
* <!-- chart -->
|
||||
* <!-- endchart -->
|
||||
* <!-- desc -->
|
||||
* <!-- enddesc -->
|
||||
* {% endchartjs %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const { escapeHTML } = require('hexo-util')
|
||||
|
||||
const chartjs = (args, content) => {
|
||||
if (!content) return
|
||||
|
||||
const chartRegex = /<!--\s*chart\s*-->\n([\w\W\s\S]*?)<!--\s*endchart\s*-->/
|
||||
const descRegex = /<!--\s*desc\s*-->\n([\w\W\s\S]*?)<!--\s*enddesc\s*-->/
|
||||
const selfConfig = args.join(' ').trim()
|
||||
|
||||
const [width = '', layout = false, chartId = ''] = selfConfig.split(',').map(s => s.trim())
|
||||
|
||||
const chartMatch = content.match(chartRegex)
|
||||
const descMatch = content.match(descRegex)
|
||||
|
||||
if (!chartMatch) {
|
||||
hexo.log.warn('chartjs tag: chart content is required!')
|
||||
return
|
||||
}
|
||||
|
||||
const chartConfig = chartMatch && chartMatch[1] ? chartMatch[1] : ''
|
||||
const descContent = descMatch && descMatch[1] ? descMatch[1] : ''
|
||||
|
||||
const renderedDesc = descContent ? hexo.render.renderSync({ text: descContent, engine: 'markdown' }).trim() : ''
|
||||
|
||||
const descDOM = renderedDesc ? `<div class="chartjs-desc">${renderedDesc}</div>` : ''
|
||||
const abreastClass = layout ? ' chartjs-abreast' : ''
|
||||
const widthStyle = width ? `data-width="${width}%"` : ''
|
||||
|
||||
return `<div class="chartjs-container${abreastClass}" data-chartjs-id="${chartId}" ${widthStyle}>
|
||||
<pre class="chartjs-src" hidden>${escapeHTML(chartConfig)}</pre>
|
||||
${descDOM}
|
||||
</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('chartjs', chartjs, { ends: true })
|
||||
@@ -3,7 +3,7 @@
|
||||
* galleryGroup and gallery
|
||||
* {% galleryGroup [name] [descr] [url] [img] %}
|
||||
*
|
||||
* {% gallery [button],%}
|
||||
* {% gallery [button],[limit],[firstLimit] %}
|
||||
* {% gallery url,[url],[button] %}
|
||||
*/
|
||||
|
||||
@@ -11,54 +11,66 @@
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
const gallery = (args, content) => {
|
||||
args = args.join(' ').split(',')
|
||||
let button = false
|
||||
let type = 'data'
|
||||
let dataStr = ''
|
||||
const DEFAULT_LIMIT = 10
|
||||
const DEFAULT_FIRST_LIMIT = 10
|
||||
const IMAGE_REGEX = /!\[(.*?)\]\(([^\s]*)\s*(?:["'](.*?)["']?)?\s*\)/g
|
||||
|
||||
if (args[0] === 'url') {
|
||||
[type, dataStr, button] = args // url,[link],[lazyload]
|
||||
dataStr = urlFor(dataStr)
|
||||
} else {
|
||||
[button] = args // [lazyload]
|
||||
const regex = /!\[(.*?)\]\(([^\s]*)\s*(?:["'](.*?)["']?)?\s*\)/g
|
||||
let m
|
||||
const arr = []
|
||||
while ((m = regex.exec(content)) !== null) {
|
||||
if (m.index === regex.lastIndex) {
|
||||
regex.lastIndex++
|
||||
// Helper functions
|
||||
const parseGalleryArgs = args => {
|
||||
const [type, ...rest] = args.join(' ').split(',').map(arg => arg.trim())
|
||||
return {
|
||||
isUrl: type === 'url',
|
||||
params: type === 'url' ? rest : [type, ...rest]
|
||||
}
|
||||
arr.push({
|
||||
url: m[2],
|
||||
alt: m[1],
|
||||
title: m[3]
|
||||
}
|
||||
|
||||
const parseImageContent = content => {
|
||||
const images = []
|
||||
let match
|
||||
|
||||
while ((match = IMAGE_REGEX.exec(content)) !== null) {
|
||||
images.push({
|
||||
url: match[2],
|
||||
alt: match[1] || '',
|
||||
title: match[3] || ''
|
||||
})
|
||||
}
|
||||
|
||||
dataStr = JSON.stringify(arr)
|
||||
return images
|
||||
}
|
||||
|
||||
return `<div class="gallery-container" data-type="${type}" data-button="${button}">
|
||||
const createGalleryHTML = (type, dataStr, button, limit, firstLimit) => {
|
||||
return `<div class="gallery-container" data-type="${type}" data-button="${button}" data-limit="${limit}" data-first="${firstLimit}">
|
||||
<div class="gallery-items">${dataStr}</div>
|
||||
</div>`
|
||||
}
|
||||
|
||||
const gallery = (args, content) => {
|
||||
const { isUrl, params } = parseGalleryArgs(args)
|
||||
|
||||
if (isUrl) {
|
||||
const [dataStr, button = false, limit = DEFAULT_LIMIT, firstLimit = DEFAULT_FIRST_LIMIT] = params
|
||||
return createGalleryHTML('url', urlFor(dataStr), button, limit, firstLimit)
|
||||
}
|
||||
|
||||
const [button = false, limit = DEFAULT_LIMIT, firstLimit = DEFAULT_FIRST_LIMIT] = params
|
||||
const images = parseImageContent(content)
|
||||
return createGalleryHTML('data', JSON.stringify(images), button, limit, firstLimit)
|
||||
}
|
||||
|
||||
const galleryGroup = args => {
|
||||
const [name, descr, url, img] = args
|
||||
const imgUrl = urlFor(img)
|
||||
const urlLink = urlFor(url)
|
||||
const [name = '', descr = '', url = '', img = ''] = args.map(arg => arg.trim())
|
||||
|
||||
return `<figure class="gallery-group">
|
||||
<img class="gallery-group-img no-lightbox" src='${imgUrl}' alt="Group Image Gallery">
|
||||
<img class="gallery-group-img no-lightbox" src='${urlFor(img)}' alt="Group Image Gallery">
|
||||
<figcaption>
|
||||
<div class="gallery-group-name">${name}</div>
|
||||
<p>${descr}</p>
|
||||
<a href='${urlLink}'></a>
|
||||
<a href='${urlFor(url)}'></a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
`
|
||||
</figure>`
|
||||
}
|
||||
|
||||
// Register tags
|
||||
hexo.extend.tag.register('gallery', gallery, { ends: true })
|
||||
hexo.extend.tag.register('galleryGroup', galleryGroup)
|
||||
|
||||
@@ -16,48 +16,35 @@
|
||||
|
||||
'use strict'
|
||||
|
||||
const parseArgs = args => {
|
||||
return args.join(' ').split(',')
|
||||
}
|
||||
const parseArgs = args => args.join(' ').split(',')
|
||||
|
||||
const generateStyle = (bg, color) => {
|
||||
let style = 'style="'
|
||||
if (bg) {
|
||||
style += `background-color: ${bg};`
|
||||
}
|
||||
if (color) {
|
||||
style += `color: ${color}`
|
||||
}
|
||||
if (bg) style += `background-color: ${bg};`
|
||||
if (color) style += `color: ${color}`
|
||||
style += '"'
|
||||
return style
|
||||
}
|
||||
|
||||
const hideInline = args => {
|
||||
const [content, display = 'Click', bg = false, color = false] = parseArgs(args)
|
||||
const group = generateStyle(bg, color)
|
||||
|
||||
return `<span class="hide-inline"><button type="button" class="hide-button" ${group}>${display}
|
||||
</button><span class="hide-content">${content}</span></span>`
|
||||
const style = generateStyle(bg, color)
|
||||
return `<span class="hide-inline"><button type="button" class="hide-button" ${style}>${display}</button><span class="hide-content">${content}</span></span>`
|
||||
}
|
||||
|
||||
const hideBlock = (args, content) => {
|
||||
const [display = 'Click', bg = false, color = false] = parseArgs(args)
|
||||
const group = generateStyle(bg, color)
|
||||
|
||||
return `<div class="hide-block"><button type="button" class="hide-button" ${group}>${display}
|
||||
</button><div class="hide-content">${hexo.render.renderSync({ text: content, engine: 'markdown' })}</div></div>`
|
||||
const style = generateStyle(bg, color)
|
||||
const renderedContent = hexo.render.renderSync({ text: content, engine: 'markdown' })
|
||||
return `<div class="hide-block"><button type="button" class="hide-button" ${style}>${display}</button><div class="hide-content">${renderedContent}</div></div>`
|
||||
}
|
||||
|
||||
const hideToggle = (args, content) => {
|
||||
const [display, bg = false, color = false] = parseArgs(args)
|
||||
const group = generateStyle(bg, color)
|
||||
let border = ''
|
||||
|
||||
if (bg) {
|
||||
border = `style="border: 1px solid ${bg}"`
|
||||
}
|
||||
|
||||
return `<details class="toggle" ${border}><summary class="toggle-button" ${group}>${display}</summary><div class="toggle-content">${hexo.render.renderSync({ text: content, engine: 'markdown' })}</div></details>`
|
||||
const style = generateStyle(bg, color)
|
||||
const border = bg ? `style="border: 1px solid ${bg}"` : ''
|
||||
const renderedContent = hexo.render.renderSync({ text: content, engine: 'markdown' })
|
||||
return `<details class="toggle" ${border}><summary class="toggle-button" ${style}>${display}</summary><div class="toggle-content">${renderedContent}</div></details>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('hideInline', hideInline)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* inlineImg 圖片
|
||||
* @param {Array} args 圖片名稱和高度
|
||||
* @param {string} args[0] 圖片名稱
|
||||
* @param {number} args[1] 圖片高度
|
||||
* @returns {string} 圖片標籤
|
||||
* inlineImg
|
||||
* @param {Array} args - Image name and height
|
||||
* @param {string} args[0] - Image name
|
||||
* @param {number} args[1] - Image height
|
||||
* @returns {string} - Image tag
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
@@ -6,17 +6,45 @@
|
||||
'use strict'
|
||||
|
||||
const score = (args, content) => {
|
||||
// Escape HTML tags and some special characters, including curly braces
|
||||
const escapeHtmlTags = s => {
|
||||
const lookup = {
|
||||
'&': '&',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
"'": ''',
|
||||
'<': '<',
|
||||
'>': '>'
|
||||
'>': '>',
|
||||
'{': '{',
|
||||
'}': '}'
|
||||
}
|
||||
return s.replace(/[&"'<>]/g, c => lookup[c])
|
||||
}
|
||||
return `<div class="abc-music-sheet">${escapeHtmlTags(content)}</div>`
|
||||
return s.replace(/[&"'<>{}]/g, c => lookup[c])
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('score', score, { ends: true })
|
||||
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 })
|
||||
@@ -1,41 +1,50 @@
|
||||
/**
|
||||
* timeline
|
||||
* by Jerry
|
||||
* Timeline tag for Hexo
|
||||
* Syntax:
|
||||
* {% timeline [headline],[color] %}
|
||||
* <!-- timeline [title] -->
|
||||
* [content]
|
||||
* <!-- endtimeline -->
|
||||
* <!-- timeline [title] -->
|
||||
* [content]
|
||||
* <!-- endtimeline -->
|
||||
* {% endtimeline %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const timeLineFn = (args, content) => {
|
||||
const tlBlock = /<!--\s*timeline (.*?)\s*-->\n([\w\W\s\S]*?)<!--\s*endtimeline\s*-->/g
|
||||
// Use named capture groups for better readability
|
||||
const tlBlock = /<!--\s*timeline\s*(?<title>.*?)\s*-->\n(?<content>[\s\S]*?)<!--\s*endtimeline\s*-->/g
|
||||
|
||||
let result = ''
|
||||
let color = ''
|
||||
let text = ''
|
||||
if (args.length) {
|
||||
[text, color] = args.join(' ').split(',')
|
||||
const mdContent = hexo.render.renderSync({ text, engine: 'markdown' })
|
||||
result += `<div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'>${mdContent}</div></div></div>`
|
||||
}
|
||||
// Pre-compile markdown render function
|
||||
const renderMd = text => hexo.render.renderSync({ text, engine: 'markdown' })
|
||||
|
||||
const matches = []
|
||||
let match
|
||||
// Parse arguments more efficiently
|
||||
const [text, color = ''] = args.length ? args.join(' ').split(',') : []
|
||||
|
||||
while ((match = tlBlock.exec(content)) !== null) {
|
||||
matches.push(match[1])
|
||||
matches.push(match[2])
|
||||
}
|
||||
// Build initial headline if text exists
|
||||
const headline = text
|
||||
? `<div class='timeline-item headline'>
|
||||
<div class='timeline-item-title'>
|
||||
<div class='item-circle'>${renderMd(text)}</div>
|
||||
</div>
|
||||
</div>`
|
||||
: ''
|
||||
|
||||
for (let i = 0; i < matches.length; i += 2) {
|
||||
const tlChildTitle = hexo.render.renderSync({ text: matches[i], engine: 'markdown' })
|
||||
const tlChildContent = hexo.render.renderSync({ text: matches[i + 1], engine: 'markdown' })
|
||||
// Match all timeline blocks in one pass and transform
|
||||
const items = Array.from(content.matchAll(tlBlock))
|
||||
.map(({ groups: { title, content } }) =>
|
||||
`<div class='timeline-item'>
|
||||
<div class='timeline-item-title'>
|
||||
<div class='item-circle'>${renderMd(title)}</div>
|
||||
</div>
|
||||
<div class='timeline-item-content'>${renderMd(content)}</div>
|
||||
</div>`
|
||||
)
|
||||
.join('')
|
||||
|
||||
const tlTitleHtml = `<div class='timeline-item-title'><div class='item-circle'>${tlChildTitle}</div></div>`
|
||||
const tlContentHtml = `<div class='timeline-item-content'>${tlChildContent}</div>`
|
||||
|
||||
result += `<div class='timeline-item'>${tlTitleHtml + tlContentHtml}</div>`
|
||||
}
|
||||
|
||||
return `<div class="timeline ${color || ''}">${result}</div>`
|
||||
return `<div class="timeline ${color}">${headline}${items}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('timeline', timeLineFn, { ends: true })
|
||||
|
||||
@@ -44,7 +44,7 @@ addBorderRadius(x = 6, hide = false)
|
||||
.postImgHover
|
||||
&:hover
|
||||
.cover
|
||||
opacity: .7
|
||||
opacity: .5
|
||||
transform: scale(1.1)
|
||||
|
||||
.cover
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
--preloader-bg: $preloader-bg
|
||||
--preloader-color: $preloader-word-color
|
||||
--tab-border-color: $tab-border-color
|
||||
--tab-botton-bg: $tab-botton-bg
|
||||
--tab-botton-color: $tab-botton-color
|
||||
--tab-button-bg: $tab-button-bg
|
||||
--tab-button-color: $tab-button-color
|
||||
--tab-button-hover-bg: $tab-button-hover-bg
|
||||
--tab-button-active-bg: $tab-button-active-bg
|
||||
--card-bg: $card-bg
|
||||
@@ -179,14 +179,11 @@ if $site-name-font
|
||||
#aside-content .author-info-description
|
||||
font-family: $site-name-font
|
||||
|
||||
.is-center
|
||||
.text-center
|
||||
text-align: center
|
||||
|
||||
.pull-left
|
||||
float: left
|
||||
|
||||
.pull-right
|
||||
float: right
|
||||
.text-right
|
||||
text-align: right
|
||||
|
||||
img
|
||||
&[src=''],
|
||||
|
||||
@@ -42,7 +42,7 @@ $code-block
|
||||
counter-reset: line
|
||||
white-space: pre-wrap
|
||||
|
||||
#article-container
|
||||
.container
|
||||
pre,
|
||||
code
|
||||
font-size: $code-font-size
|
||||
@@ -164,7 +164,7 @@ $code-block
|
||||
border: none
|
||||
|
||||
if $highlight_macstyle
|
||||
#article-container
|
||||
.container
|
||||
figure.highlight
|
||||
margin: 0 0 24px
|
||||
border-radius: 7px
|
||||
@@ -202,7 +202,7 @@ if $highlight_macstyle
|
||||
transform: rotate(90deg)
|
||||
|
||||
if hexo-config('code_blocks.height_limit')
|
||||
#article-container
|
||||
.container
|
||||
.code-expand-btn
|
||||
position: absolute
|
||||
bottom: 0
|
||||
@@ -243,7 +243,7 @@ if hexo-config('code_blocks.height_limit')
|
||||
opacity: .6
|
||||
|
||||
if hexo-config('code_blocks.fullpage')
|
||||
#article-container
|
||||
.container
|
||||
figure.highlight.code-fullpage
|
||||
position: fixed
|
||||
top: 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
if $highlight_theme != false
|
||||
@require 'diff'
|
||||
|
||||
#article-container
|
||||
.container
|
||||
figure.highlight
|
||||
.line
|
||||
if wordWrap
|
||||
|
||||
@@ -4,7 +4,7 @@ if $prismjs_line_number
|
||||
if $highlight_theme != false
|
||||
@require 'diff'
|
||||
|
||||
#article-container
|
||||
.container
|
||||
pre[class*='language-']
|
||||
// scrollbar - firefox
|
||||
@-moz-document url-prefix()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#article-container
|
||||
.container
|
||||
pre[class*='language-']
|
||||
&.line-numbers
|
||||
position: relative
|
||||
|
||||
@@ -159,8 +159,8 @@
|
||||
a
|
||||
display: flex
|
||||
flex-direction: row
|
||||
padding: 2px 8px
|
||||
margin: 2px 0
|
||||
padding: 2px 8px
|
||||
color: var(--font-color)
|
||||
transition: all .3s
|
||||
addBorderRadius()
|
||||
@@ -354,11 +354,12 @@
|
||||
.headline
|
||||
@extend .limit-one-line
|
||||
color: var(--font-color)
|
||||
font-size: .95em
|
||||
|
||||
.length-num
|
||||
margin-top: -.32em
|
||||
margin-top: -.45em
|
||||
color: var(--text-highlight-color)
|
||||
font-size: 1.4em
|
||||
font-size: 1.2em
|
||||
|
||||
@keyframes more-btn-move
|
||||
0%,
|
||||
|
||||
@@ -146,10 +146,11 @@
|
||||
position: fixed
|
||||
top: -60px
|
||||
z-index: 91
|
||||
background: rgba(255, 255, 255, .8)
|
||||
background: rgba(255, 255, 255, .7)
|
||||
box-shadow: 0 5px 6px -5px alpha($grey, .6)
|
||||
transition: transform .2s ease-in-out, opacity .2s ease-in-out
|
||||
will-change: transform
|
||||
backdrop-filter: blur(7px)
|
||||
|
||||
#blog-info
|
||||
color: var(--font-color)
|
||||
@@ -430,6 +431,7 @@
|
||||
background-color: lighten($theme-color, 30%)
|
||||
content: ''
|
||||
transition: all .3s ease-in-out
|
||||
addBorderRadius()
|
||||
|
||||
&:hover
|
||||
&:after
|
||||
|
||||
@@ -8,50 +8,32 @@
|
||||
background: $theme-paginator-color
|
||||
color: var(--white)
|
||||
|
||||
.pagination-info
|
||||
position: absolute
|
||||
top: 50%
|
||||
padding: 20px 40px
|
||||
width: 100%
|
||||
transform: translate(0, -50%)
|
||||
|
||||
.prev_info,
|
||||
.next_info
|
||||
@extend .limit-one-line
|
||||
color: var(--white)
|
||||
font-weight: 500
|
||||
|
||||
.next-post
|
||||
.pagination-info
|
||||
text-align: right
|
||||
|
||||
.pull-full
|
||||
.full-width
|
||||
width: 100% !important
|
||||
|
||||
.prev-post .label,
|
||||
.next-post .label
|
||||
color: var(--light-grey)
|
||||
text-transform: uppercase
|
||||
font-size: 90%
|
||||
|
||||
.prev-post,
|
||||
.next-post
|
||||
@extend .postImgHover
|
||||
position: relative
|
||||
display: block
|
||||
overflow: hidden
|
||||
width: 50%
|
||||
.pagination-related
|
||||
height: 150px
|
||||
|
||||
+maxWidth768()
|
||||
width: 100%
|
||||
+minWidth768()
|
||||
flex: 1
|
||||
|
||||
.info-1
|
||||
.info-item-2
|
||||
-webkit-line-clamp: 1
|
||||
|
||||
.info-2
|
||||
.info-item-1
|
||||
-webkit-line-clamp: 2
|
||||
|
||||
&.pagination-post
|
||||
overflow: hidden
|
||||
margin-top: 40px
|
||||
width: 100%
|
||||
background: $dark-black
|
||||
addBorderRadius()
|
||||
display: flex
|
||||
|
||||
+maxWidth768()
|
||||
flex-direction: column
|
||||
|
||||
.layout
|
||||
.pagination
|
||||
@@ -75,3 +57,50 @@
|
||||
|
||||
& > *:not(.space)
|
||||
box-shadow: none
|
||||
|
||||
.pagination-related
|
||||
position: relative
|
||||
display: inline-block
|
||||
overflow: hidden
|
||||
background: $dark-black
|
||||
vertical-align: bottom
|
||||
@extend .postImgHover
|
||||
|
||||
&.next-post
|
||||
.info
|
||||
text-align: right
|
||||
|
||||
.info
|
||||
.info-1,
|
||||
.info-2
|
||||
@extend .verticalCenter
|
||||
padding: 20px 40px
|
||||
color: var(--white)
|
||||
transition: transform .3s, opacity .3s
|
||||
|
||||
.info-1
|
||||
.info-item-1
|
||||
color: var(--light-grey)
|
||||
text-transform: uppercase
|
||||
font-size: 90%
|
||||
|
||||
.info-item-2
|
||||
@extend .limit-more-line
|
||||
color: var(--white)
|
||||
font-weight: 500
|
||||
|
||||
.info-2
|
||||
opacity: 0
|
||||
transform: translate(0, 0)
|
||||
|
||||
.info-item-1
|
||||
@extend .limit-more-line
|
||||
|
||||
&:not(.no-desc):hover
|
||||
.info-1
|
||||
opacity: 0
|
||||
transform: translate(0, -100%)
|
||||
|
||||
.info-2
|
||||
opacity: 1
|
||||
transform: translate(0, -50%)
|
||||
@@ -19,9 +19,9 @@ beautify()
|
||||
&:before
|
||||
position: absolute
|
||||
top: calc(50% - 7px)
|
||||
left: 0
|
||||
color: $title-prefix-icon-color
|
||||
content: $title-prefix-icon
|
||||
left: 0
|
||||
line-height: 1
|
||||
transition: all .2s ease-out
|
||||
@extend .fontawesomeIcon
|
||||
@@ -69,7 +69,7 @@ beautify()
|
||||
hr
|
||||
@extend .custom-hr
|
||||
|
||||
#article-container
|
||||
.container
|
||||
word-wrap: break-word
|
||||
overflow-wrap: break-word
|
||||
|
||||
@@ -119,16 +119,16 @@ beautify()
|
||||
width: fit-content
|
||||
|
||||
a:not(.headerlink)
|
||||
position relative
|
||||
z-index 10
|
||||
position: relative
|
||||
z-index: 10
|
||||
|
||||
a.headerlink
|
||||
position: absolute
|
||||
top: 0
|
||||
right: 0
|
||||
left 0
|
||||
bottom: 0
|
||||
width 100%
|
||||
left: 0
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
ol,
|
||||
@@ -236,7 +236,7 @@ beautify()
|
||||
&:hover
|
||||
text-decoration: none
|
||||
|
||||
.post-outdate-notice
|
||||
#post-outdate-notice
|
||||
position: relative
|
||||
margin: 0 0 20px
|
||||
padding: .5em 1.2em
|
||||
@@ -244,6 +244,9 @@ beautify()
|
||||
color: $noticeOutdate-color
|
||||
addBorderRadius(3)
|
||||
|
||||
.num
|
||||
padding: 0 4px
|
||||
|
||||
if hexo-config('noticeOutdate.style') == 'flat'
|
||||
padding: .5em 1em .5em 2.6em
|
||||
border-left: 5px solid $noticeOutdate-border
|
||||
|
||||
@@ -8,15 +8,9 @@
|
||||
|
||||
& > .relatedPosts-list
|
||||
& > a
|
||||
position: relative
|
||||
display: inline-block
|
||||
overflow: hidden
|
||||
margin: 3px
|
||||
width: calc(33.333% - 6px)
|
||||
height: 200px
|
||||
background: $dark-black
|
||||
vertical-align: bottom
|
||||
@extend .postImgHover
|
||||
addBorderRadius()
|
||||
|
||||
+maxWidth768()
|
||||
@@ -27,15 +21,11 @@
|
||||
+maxWidth600()
|
||||
width: calc(100% - 4px)
|
||||
|
||||
.content
|
||||
padding: 0 20px
|
||||
@extend .verticalCenter
|
||||
|
||||
.date
|
||||
color: var(--light-grey)
|
||||
font-size: 90%
|
||||
|
||||
.title
|
||||
@extend .limit-more-line
|
||||
color: var(--white)
|
||||
.info
|
||||
.info-1
|
||||
.info-item-2
|
||||
-webkit-line-clamp: 2
|
||||
|
||||
.info-2
|
||||
.info-item-1
|
||||
-webkit-line-clamp: 3
|
||||
@@ -75,6 +75,32 @@ if hexo-config('mermaid.enable')
|
||||
pre > code.mermaid
|
||||
display: none
|
||||
|
||||
if hexo-config('chartjs.enable')
|
||||
.chartjs-container
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
align-items: center
|
||||
margin: 0 0 20px
|
||||
text-align: center
|
||||
gap: 20px
|
||||
|
||||
+maxWidth600()
|
||||
.chartjs-wrap
|
||||
width: 100% !important
|
||||
|
||||
&.chartjs-abreast
|
||||
flex-direction: row
|
||||
|
||||
+maxWidth600()
|
||||
flex-direction: column
|
||||
|
||||
.chartjs-wrap
|
||||
width: -webkit-fill-available
|
||||
|
||||
canvas
|
||||
display: inline-block !important
|
||||
|
||||
.utterances,
|
||||
.fb-comments iframe
|
||||
width: 100% !important
|
||||
@@ -127,7 +153,7 @@ if hexo-config('math.use')
|
||||
.aplayer
|
||||
color: $font-black
|
||||
|
||||
#article-container
|
||||
.container
|
||||
.aplayer
|
||||
margin: 0 0 20px
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
|
||||
--preloader-bg: darken(#121212, 2)
|
||||
--preloader-color: alpha(#FFFFFF, .7)
|
||||
--tab-border-color: #2c2c2c
|
||||
--tab-botton-bg: #2c2c2c
|
||||
--tab-botton-color: alpha(#FFFFFF, .7)
|
||||
--tab-button-bg: #2c2c2c
|
||||
--tab-button-color: alpha(#FFFFFF, .7)
|
||||
--tab-button-hover-bg: lighten(#121212, 15)
|
||||
--tab-button-active-bg: #121212
|
||||
--card-bg: #121212
|
||||
@@ -41,7 +41,7 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
|
||||
background-color: alpha($dark-black, .7)
|
||||
content: ''
|
||||
|
||||
#article-container
|
||||
.container
|
||||
code
|
||||
background: #2c2c2c
|
||||
|
||||
@@ -87,9 +87,9 @@ if hexo-config('darkmode.enable') || hexo-config('display_mode') == 'dark'
|
||||
.hide-button,
|
||||
.btn-beautify,
|
||||
.hl-label,
|
||||
.post-outdate-notice,
|
||||
#post-outdate-notice,
|
||||
.error-img,
|
||||
#article-container iframe,
|
||||
.container iframe,
|
||||
.gist,
|
||||
.ads-wrap
|
||||
filter: brightness(.8)
|
||||
|
||||
@@ -77,13 +77,13 @@ if hexo-config('readmode')
|
||||
#footer,
|
||||
#post > *:not(#post-info):not(.post-content),
|
||||
#nav,
|
||||
.post-outdate-notice,
|
||||
#post-outdate-notice,
|
||||
#web_bg,
|
||||
#rightside,
|
||||
.not-top-img
|
||||
display: none !important
|
||||
|
||||
#article-container
|
||||
.container
|
||||
a
|
||||
color: #99a9bf
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#article-container
|
||||
.container
|
||||
.flink
|
||||
margin-bottom: 20px
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
.shuoshuo-item-header
|
||||
display: flex
|
||||
align-items: center
|
||||
cursor: default
|
||||
|
||||
.shuoshuo-avatar
|
||||
overflow: hidden
|
||||
@@ -36,6 +37,16 @@
|
||||
& > *:last-child
|
||||
margin-bottom: 0
|
||||
|
||||
.shuoshuo-footer
|
||||
display: flex
|
||||
align-items: center
|
||||
|
||||
&.flex-between
|
||||
justify-content: space-between
|
||||
|
||||
&.flex-end
|
||||
justify-content: flex-end
|
||||
|
||||
.shuoshuo-tag
|
||||
display: inline-block
|
||||
margin-right: 8px
|
||||
@@ -51,3 +62,17 @@
|
||||
&:hover
|
||||
background: $light-blue
|
||||
color: var(--white)
|
||||
|
||||
.shuoshuo-comment-btn
|
||||
padding: 2px
|
||||
color: #90a4ae
|
||||
cursor: pointer
|
||||
|
||||
&:hover
|
||||
color: $light-blue
|
||||
|
||||
.shuoshuo-comment
|
||||
padding-top: 10px
|
||||
|
||||
&.no-comment
|
||||
display: none
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
height: 24px
|
||||
text-align: center
|
||||
line-height: 24px
|
||||
addBorderRadius()
|
||||
|
||||
.ais-Pagination-item--selected
|
||||
a
|
||||
@@ -74,11 +75,11 @@
|
||||
overflow-y: overlay
|
||||
margin: 0 -20px
|
||||
padding: 0 22px
|
||||
max-height: calc(80vh - 240px)
|
||||
max-height: calc(80vh - 220px)
|
||||
|
||||
+maxWidth768()
|
||||
max-height: none
|
||||
height: calc(var(--search-height) - 265px)
|
||||
height: calc(var(--search-height) - 235px)
|
||||
|
||||
#algolia-info
|
||||
div
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
height: 100%
|
||||
border-radius: 0
|
||||
|
||||
hr
|
||||
margin: 20px auto
|
||||
|
||||
.search-nav
|
||||
margin: 0 0 14px
|
||||
color: $search-color
|
||||
@@ -40,7 +37,7 @@
|
||||
color: $search-color
|
||||
|
||||
hr
|
||||
margin: 20px auto
|
||||
margin: 15px auto
|
||||
@extend .custom-hr
|
||||
|
||||
#search-mask
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user