From f91ce41a667998ddb8285032fb85588d2e2eb725 Mon Sep 17 00:00:00 2001 From: myw Date: Sat, 2 Nov 2024 18:58:20 +0800 Subject: [PATCH] update --- _config.yml | 12 +- layout/includes/head/config_site.pug | 3 +- layout/includes/page/shuoshuo.pug | 217 +++++++++++------- .../includes/third-party/comments/artalk.pug | 52 +++-- .../includes/third-party/comments/disqus.pug | 41 +++- .../third-party/comments/disqusjs.pug | 61 +++-- .../comments/facebook_comments.pug | 26 ++- .../includes/third-party/comments/giscus.pug | 54 ++++- .../includes/third-party/comments/gitalk.pug | 64 ++++-- .../includes/third-party/comments/livere.pug | 26 ++- .../third-party/comments/remark42.pug | 118 +++++----- .../includes/third-party/comments/twikoo.pug | 35 ++- .../third-party/comments/utterances.pug | 36 ++- .../includes/third-party/comments/valine.pug | 44 +++- .../includes/third-party/comments/waline.pug | 40 +++- .../third-party/newest-comments/remark42.pug | 1 + plugins.yml | 16 +- scripts/events/comment.js | 13 +- scripts/helpers/inject_head_js.js | 1 - scripts/helpers/page.js | 35 ++- source/css/_page/shuoshuo.styl | 52 +++-- source/js/main.js | 18 +- source/js/utils.js | 16 ++ 23 files changed, 661 insertions(+), 320 deletions(-) diff --git a/_config.yml b/_config.yml index ac99d06..cab31b5 100644 --- a/_config.yml +++ b/_config.yml @@ -928,16 +928,16 @@ chartjs: # 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)" + 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)" + 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" + light: 'transparent' + dark: 'transparent' # Note - Bootstrap Callout note: diff --git a/layout/includes/head/config_site.pug b/layout/includes/head/config_site.pug index f457549..7531f04 100644 --- a/layout/includes/head/config_site.pug +++ b/layout/includes/head/config_site.pug @@ -23,5 +23,6 @@ script#config-diff. isHome: !{is_home()}, isHighlightShrink: !{isHighlightShrink}, isToc: !{showToc}, - postUpdate: '!{full_date(page.updated)}' + postUpdate: '!{full_date(page.updated)}', + isShuoshuo: !{page.type == 'shuoshuo'} } diff --git a/layout/includes/page/shuoshuo.pug b/layout/includes/page/shuoshuo.pug index 097ea59..75ed49c 100644 --- a/layout/includes/page/shuoshuo.pug +++ b/layout/includes/page/shuoshuo.pug @@ -6,127 +6,180 @@ //- - 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.parentNode.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 getTimeZoneDate = date => { - if (date.length === 10) { - date = date + ' 00:00:00' - } + const renderData = (dataSlice) => { + const content = dataSlice.map(item => { + const formattedDate = formatToTimeZone(item.date) + const tags = item.tags && item.tags.map(tag => `${tag}`).join('') || '' + const commentButton = item.key && !{commentsJsLoad} + ? `
+ +
` + : '' + const commentContainer = item.key + ? `
` + : '' - 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 formattedDate = new Intl.DateTimeFormat('en-GB', options).format(new Date(date)) - - const [day, month, year, hour, minute, second] = formattedDate.match(/\d+/g) - return `${year}-${month}-${day} ${hour}:${minute}:${second}` - } - - const addData = data => { - const cLength = data.length - const end = start + 10 > cLength ? cLength : start + 10 - let result = '' - data.slice(start, end).forEach((item) => { - const getDate = getTimeZoneDate(item.date) - result += ` -
-
-
- -
-
-
${item.author || '!{config.author}'}
- -
-
-
- ${item.content} -
- + return ` +
+
+
+
- ` - }) +
+
${item.author || '!{config.author}'}
+ +
+
+
${item.content}
+ + ${commentContainer} +
` + }).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 handleIntersection = (entries) => { + if (!entries[0].isIntersecting) return + observer.unobserve(entries[0].target) - const observer = new IntersectionObserver((entries) => { - if (entries[0].isIntersecting) { - 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 .shuoshuo-item-header .shuoshuo-avatar img.no-lightbox(src=i.avatar || url_for(theme.avatar.img)) .shuoshuo-info .shuoshuo-author=i.author || config.author - - const getDate = getTimeZoneDate(i.date) - time.shuoshuo-date(title=getDate)=date(getDate) + 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 \ No newline at end of file + 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) \ No newline at end of file diff --git a/layout/includes/third-party/comments/artalk.pug b/layout/includes/third-party/comments/artalk.pug index befc32e..3640334 100644 --- a/layout/includes/third-party/comments/artalk.pug +++ b/layout/includes/third-party/comments/artalk.pug @@ -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.isShuoshuo + + 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) diff --git a/layout/includes/third-party/comments/disqus.pug b/layout/includes/third-party/comments/disqus.pug index 8d8864c..c521af3 100644 --- a/layout/includes/third-party/comments/disqus.pug +++ b/layout/includes/third-party/comments/disqus.pug @@ -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.isShuoshuo - 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,6 +61,13 @@ 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 { diff --git a/layout/includes/third-party/comments/disqusjs.pug b/layout/includes/third-party/comments/disqusjs.pug index 3550392..3141611 100644 --- a/layout/includes/third-party/comments/disqusjs.pug +++ b/layout/includes/third-party/comments/disqusjs.pug @@ -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.isShuoshuo + 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,6 +68,13 @@ 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 { diff --git a/layout/includes/third-party/comments/facebook_comments.pug b/layout/includes/third-party/comments/facebook_comments.pug index 3b47452..7b070d4 100644 --- a/layout/includes/third-party/comments/facebook_comments.pug +++ b/layout/includes/third-party/comments/facebook_comments.pug @@ -3,17 +3,28 @@ script. (()=>{ - const loadFBComment = () => { + const isShuoshuo = GLOBAL_CONFIG_SITE.isShuoshuo + + 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', '
') 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() diff --git a/layout/includes/third-party/comments/giscus.pug b/layout/includes/third-party/comments/giscus.pug index b55a4ec..bdc189f 100644 --- a/layout/includes/third-party/comments/giscus.pug +++ b/layout/includes/third-party/comments/giscus.pug @@ -4,27 +4,50 @@ - const giscusOriginUrl = new URL(giscusUrl).origin script. - (()=>{ + (() => { + const isShuoshuo = GLOBAL_CONFIG_SITE.isShuoshuo + 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,10 +66,17 @@ 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() } else { - window.loadOtherComment= loadGiscus + window.loadOtherComment = loadGiscus } })() diff --git a/layout/includes/third-party/comments/gitalk.pug b/layout/includes/third-party/comments/gitalk.pug index fb2d694..0b0a93e 100644 --- a/layout/includes/third-party/comments/gitalk.pug +++ b/layout/includes/third-party/comments/gitalk.pug @@ -2,29 +2,9 @@ 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)})) + const isShuoshuo = GLOBAL_CONFIG_SITE.isShuoshuo + const option = !{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 commentCount = n => { const isCommentCount = document.querySelector('#post-meta .gitalk-comment-count') if (isCommentCount) { @@ -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() diff --git a/layout/includes/third-party/comments/livere.pug b/layout/includes/third-party/comments/livere.pug index ecacb59..4c396c7 100644 --- a/layout/includes/third-party/comments/livere.pug +++ b/layout/includes/third-party/comments/livere.pug @@ -1,8 +1,23 @@ - const { use, lazyload } = theme.comments script. - (()=>{ - const loadLivere = () => { + (() => { + const isShuoshuo = GLOBAL_CONFIG_SITE.isShuoshuo + + 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() diff --git a/layout/includes/third-party/comments/remark42.pug b/layout/includes/third-party/comments/remark42.pug index 388fb97..0a1fbe7 100644 --- a/layout/includes/third-party/comments/remark42.pug +++ b/layout/includes/third-party/comments/remark42.pug @@ -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.isShuoshuo + 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() { - if (window.REMARK42) { - if (this.remark42Instance) { - this.remark42Instance.destroy() + 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) { + destroyRemark42() + window.remark42Instance = window.REMARK42.createInstance({ + ...remark_config + }) + } + } + + const loadRemark42 = (el, path) => { + if (isShuoshuo) { + window.shuoshuoComment.destroyRemark42 = () => { + destroyRemark42() + if (el.children.length) { + el.innerHTML = '' + el.classList.add('no-comment') + } + } } - this.remark42Instance = window.REMARK42.createInstance({ - ...remark_config - }) - } - } + 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 + } - 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) - } - } - - function loadRemark42 () { - if (window.REMARK42) { - this.initRemark42() - getCount() - } else { - addRemark42() - window.addEventListener('REMARK42::ready', () => { - this.initRemark42() + if (window.REMARK42) { + initRemark42(remark_config) getCount() - }) + } else { + addRemark42() + window.addEventListener('REMARK42::ready', () => { + 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') + btf.addGlobalFn('themeChange', remarkChangeMode, 'remark42') - 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() + 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 { + window.loadOtherComment = loadRemark42 + } + })() \ No newline at end of file diff --git a/layout/includes/third-party/comments/twikoo.pug b/layout/includes/third-party/comments/twikoo.pug index 8f3bc42..ac91bcf 100644 --- a/layout/includes/third-party/comments/twikoo.pug +++ b/layout/includes/third-party/comments/twikoo.pug @@ -3,6 +3,9 @@ script. (() => { + const isShuoshuo = GLOBAL_CONFIG_SITE.isShuoshuo + 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()' : ''} + + 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}) { diff --git a/layout/includes/third-party/comments/utterances.pug b/layout/includes/third-party/comments/utterances.pug index 1fdc0da..aaabd6f 100644 --- a/layout/includes/third-party/comments/utterances.pug +++ b/layout/includes/third-party/comments/utterances.pug @@ -5,24 +5,33 @@ script. (() => { + const isShuoshuo = GLOBAL_CONFIG_SITE.isShuoshuo + 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() diff --git a/layout/includes/third-party/comments/valine.pug b/layout/includes/third-party/comments/valine.pug index b53e3fc..4cdd140 100644 --- a/layout/includes/third-party/comments/valine.pug +++ b/layout/includes/third-party/comments/valine.pug @@ -7,32 +7,54 @@ if site.data.valine script. (() => { - const initValine = () => { - const valine = new Valine(Object.assign({ + const isShuoshuo = GLOBAL_CONFIG_SITE.isShuoshuo + 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 + } + + new Valine(valineConfig) } - const loadValine = async () => { - if (typeof Valine === 'function') initValine() - else { + const loadValine = async (el, path) => { + if (typeof Valine === 'function') { + initValine(el, path) + } else { await btf.getScript('!{url_for(theme.asset.valine)}') - initValine() + initValine(el, path) } } + if (isShuoshuo) { + '!{use[0]}' === 'Valine' + ? window.shuoshuoComment = { loadComment: loadValine } + : window.loadOtherComment = loadValine + return + } + if ('!{use[0]}' === 'Valine' || !!{lazyload}) { if (!{lazyload}) btf.loadComment(document.getElementById('vcomment'),loadValine) else setTimeout(loadValine, 0) } else { window.loadOtherComment = loadValine } - })() - + })() \ No newline at end of file diff --git a/layout/includes/third-party/comments/waline.pug b/layout/includes/third-party/comments/waline.pug index 47ef32f..8f914f4 100644 --- a/layout/includes/third-party/comments/waline.pug +++ b/layout/includes/third-party/comments/waline.pug @@ -4,37 +4,53 @@ script. (() => { let initFn = window.walineFn || null + const isShuoshuo = GLOBAL_CONFIG_SITE.isShuoshuo + 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) diff --git a/layout/includes/third-party/newest-comments/remark42.pug b/layout/includes/third-party/newest-comments/remark42.pug index c83fd0c..be3b2fc 100644 --- a/layout/includes/third-party/newest-comments/remark42.pug +++ b/layout/includes/third-party/newest-comments/remark42.pug @@ -1,4 +1,5 @@ - const { host, siteId } = theme.remark42 +!= partial("includes/third-party/newest-comments/common.pug", {}, { cache: true }) script. window.addEventListener('load', () => { diff --git a/plugins.yml b/plugins.yml index 57930e0..520adf4 100644 --- a/plugins.yml +++ b/plugins.yml @@ -1,7 +1,7 @@ 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 @@ -9,7 +9,7 @@ activate_power_mode: algolia_search: name: algoliasearch file: dist/lite/builds/browser.umd.js - version: 5.9.1 + version: 5.12.0 aplayer_css: name: aplayer file: dist/APlayer.min.css @@ -44,8 +44,8 @@ canvas_ribbon: version: 1.1.4 chartjs: name: chart.js - file: dist/chart.umd.min.js - version: 4.4.5 + file: dist/chart.umd.js + version: 4.4.6 clickShowText: name: butterfly-extsrc file: dist/click-show-text.min.js @@ -66,12 +66,12 @@ docsearch_css: name: '@docsearch/css' other_name: docsearch-css file: dist/style.css - version: 3.6.2 + version: 3.6.3 docsearch_js: name: '@docsearch/js' other_name: docsearch-js file: dist/umd/index.js - version: 3.6.2 + version: 3.6.3 egjs_infinitegrid: name: '@egjs/infinitegrid' other_name: egjs-infinitegrid @@ -111,7 +111,7 @@ instantpage: instantsearch: name: instantsearch.js file: dist/instantsearch.production.min.js - version: 4.75.1 + version: 4.75.3 katex: name: katex file: dist/katex.min.css @@ -137,7 +137,7 @@ medium_zoom: mermaid: name: mermaid file: dist/mermaid.min.js - version: 11.3.0 + version: 11.4.0 meting_js: name: butterfly-extsrc file: metingjs/dist/Meting.min.js diff --git a/scripts/events/comment.js b/scripts/events/comment.js index b38e1de..16da948 100644 --- a/scripts/events/comment.js +++ b/scripts/events/comment.js @@ -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 }) diff --git a/scripts/helpers/inject_head_js.js b/scripts/helpers/inject_head_js.js index 63723af..3cf31cb 100644 --- a/scripts/helpers/inject_head_js.js +++ b/scripts/helpers/inject_head_js.js @@ -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 } diff --git a/scripts/helpers/page.js b/scripts/helpers/page.js index 49cd121..c3d7643 100644 --- a/scripts/helpers/page.js +++ b/scripts/helpers/page.js @@ -5,13 +5,6 @@ const { prettyUrls } = require('hexo-util') const crypto = require('crypto') const moment = require('moment-timezone') -hexo.extend.helper.register('getTimeZoneDate', date => { - // This is a hack method, because hexo treats time as UTC time - // so you need to manually convert the time zone - const utcDate = moment.utc(date).format('YYYY-MM-DD HH:mm:ss') - return moment.tz(utcDate, hexo.config.timezone).format('YYYY-MM-DD HH:mm:ss') -}) - hexo.extend.helper.register('truncate', truncateContent) hexo.extend.helper.register('postDesc', data => { @@ -103,3 +96,31 @@ 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 + data.sort((a, b) => Date.parse(b.date) - Date.parse(a.date)) + + // Apply number limit or time limit conditionally + if (limit && limit.type === 'num' && limit.value > 0) { + finalResult = data.slice(0, limit.value) + } else if (limit && limit.type === 'date' && isValidDate(limit.value)) { + const limitDate = Date.parse(limit.value) + finalResult = data.filter(item => Date.parse(item.date) >= limitDate) + } + + // 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 +}) diff --git a/source/css/_page/shuoshuo.styl b/source/css/_page/shuoshuo.styl index 8939f6e..852da03 100644 --- a/source/css/_page/shuoshuo.styl +++ b/source/css/_page/shuoshuo.styl @@ -37,18 +37,42 @@ & > *:last-child margin-bottom: 0 - .shuoshuo-tag - display: inline-block - margin-right: 8px - padding: 0 8px - width: fit-content - border: 1px solid $light-blue - border-radius: 12px - color: $light-blue - font-size: .85em - cursor: default - transition: all .2s ease-in-out + .shuoshuo-footer + display: flex + align-items: center - &:hover - background: $light-blue - color: var(--white) + &.flex-between + justify-content: space-between + + &.flex-end + justify-content: flex-end + + .shuoshuo-tag + display: inline-block + margin-right: 8px + padding: 0 8px + width: fit-content + border: 1px solid $light-blue + border-radius: 12px + color: $light-blue + font-size: .85em + cursor: default + transition: all .2s ease-in-out + + &: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 diff --git a/source/js/main.js b/source/js/main.js index 91159aa..ed77f7c 100644 --- a/source/js/main.js +++ b/source/js/main.js @@ -806,22 +806,6 @@ document.addEventListener('DOMContentLoaded', () => { btf.addEventListenerPjax(cardCategory, 'click', handleToggleBtn, true) } - const switchComments = () => { - const switchBtn = document.getElementById('switch-btn') - if (!switchBtn) return - - let switchDone = false - const postComment = document.getElementById('post-comment') - const handleSwitchBtn = () => { - postComment.classList.toggle('move') - if (!switchDone && typeof loadOtherComment === 'function') { - switchDone = true - loadOtherComment() - } - } - btf.addEventListenerPjax(switchBtn, 'click', handleSwitchBtn) - } - const addPostOutdateNotice = () => { const { limitDay, messagePrev, messageNext, position } = GLOBAL_CONFIG.noticeOutdate const diffDay = btf.diffDate(GLOBAL_CONFIG_SITE.postUpdate) @@ -924,7 +908,7 @@ document.addEventListener('DOMContentLoaded', () => { scrollFn() forPostFn() - switchComments() + !GLOBAL_CONFIG_SITE.isShuoshuo && btf.switchComments(document) openMobileMenu() } diff --git a/source/js/utils.js b/source/js/utils.js index 42db7d2..48d8306 100644 --- a/source/js/utils.js +++ b/source/js/utils.js @@ -290,6 +290,22 @@ Object.keys(keyObj).forEach(i => keyObj[i]()) delete globalFn[key] + }, + + switchComments: (el = document, path) => { + const switchBtn = el.querySelector('#switch-btn') + if (!switchBtn) return + + let switchDone = false + const postComment = el.querySelector('#post-comment') + const handleSwitchBtn = () => { + postComment.classList.toggle('move') + if (!switchDone && typeof loadOtherComment === 'function') { + switchDone = true + loadOtherComment(el, path) + } + } + btf.addEventListenerPjax(switchBtn, 'click', handleSwitchBtn) } }