breaking changes: 更改 rightside-bottom 為 rightside_bottom

feat: 置頂圖標改為在標題左側
feat: 可配置打賞按鈕的文字
feat: 側邊欄增加 系列文章顯示
feat: 增加 series 系列文章 標籤外掛
feat: 移除 addthis 分享
improvement: 代碼優化
improvement: tabs 標籤外掛的回到頂部箭頭位置調整
improvement: 更新 plugin.yml
This commit is contained in:
Jerry
2023-06-24 16:12:23 +08:00
parent 507780ebd6
commit c67b4304d2
30 changed files with 222 additions and 121 deletions

View File

@@ -76,7 +76,7 @@ npm i hexo-theme-butterfly
- [x] WordCount
- [x] Related articles
- [x] Displays outdated notice for a post
- [x] Share (AddThis/Sharejs/Addtoany)
- [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/messenger)

View File

@@ -76,7 +76,7 @@ theme: butterfly
- [x] 顯示字數統計
- [x] 顯示相關文章
- [x] 過期文章提醒
- [x] 多種分享系統(AddThis/Sharejs/Addtoany
- [x] 多種分享系統Sharejs/Addtoany
- [X] 多種評論系統Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/artalk
- [x] 支持雙評論部署
- [x] 多種在線聊天Chatra/Tidio/Daovoice/Crisp/messenger

View File

@@ -264,6 +264,10 @@ aside:
post_count: true
last_push_date: true
sort_order: # Don't modify the setting unless you know how it works
card_post_series:
enable: true
orderBy: 'date' # Order by title or date
order: -1 # Sort of order. 1, asc for ascending; -1, desc for descending
# busuanzi count for PV / UV in site
# 訪問人數
@@ -381,12 +385,6 @@ docsearch:
# Share System (分享)
# --------------------------------------
# AddThis
# https://www.addthis.com/
addThis:
enable: false
pubid:
# Share.js
# https://github.com/overtrue/share.js
sharejs:
@@ -651,7 +649,7 @@ mask:
footer: true
# the position of bottom right button/default unit: px (右下角按鈕距離底部的距離/默認單位為px)
rightside-bottom:
rightside_bottom:
# Enter transitions (開啓網頁進入效果)
enter_transitions: true
@@ -796,6 +794,13 @@ fancybox: true
# Tag Plugins settings (標籤外掛)
# --------------------------------------
# series (系列文章)
series:
enable: true
orderBy: 'title' # Order by title or date
order: 1 # Sort of order. 1, asc for ascending; -1, desc for descending
number: true
# abcjs (樂譜渲染)
# See https://github.com/paulrosen/abcjs
abcjs:

View File

@@ -15,7 +15,6 @@ page:
card_post_count: comments
sticky: Sticky
no_title: No title
post:
@@ -83,6 +82,7 @@ aside:
link: link
code: code
card_toc: Catalog
card_post_series: Series
date_suffix:
just: Just

View File

@@ -15,7 +15,6 @@ page:
card_post_count: comments
sticky: Sticky
no_title: No title
post:
@@ -83,6 +82,7 @@ aside:
link: link
code: code
card_toc: Catalog
card_post_series: Series
date_suffix:
just: Just

View File

@@ -15,7 +15,6 @@ page:
card_post_count: 条评论
sticky: 置顶
no_title: 无题
post:
@@ -84,6 +83,7 @@ aside:
link: 链接
code: 代码
card_toc: 目录
card_post_series: 系列文章
date_suffix:
just: 刚刚

View File

@@ -15,7 +15,6 @@ page:
card_post_count: 條評論
sticky: 置頂
no_title: 無題
post:
@@ -84,6 +83,7 @@ aside:
link: 連結
code: 程式碼
card_toc: 目錄
card_post_series: 系列文章
date_suffix:
just: 剛剛

View File

@@ -19,13 +19,11 @@ mixin postUI(posts)
else
div.post-bg(style=`background: ${post_cover}`)
.recent-post-info(class=no_cover)
a.article-title(href=url_for(link) title=title)= title
.article-meta-wrap
a.article-title(href=url_for(link) title=title)
if (is_home() && (article.top || article.sticky > 0))
span.article-meta
i.fas.fa-thumbtack.sticky
span.sticky= _p('sticky')
span.article-meta-separator |
i.fas.fa-thumbtack.sticky
= title
.article-meta-wrap
if (theme.post_meta.page.date_type)
span.post-meta-date
if (theme.post_meta.page.date_type === 'both')

View File

@@ -1,7 +1,7 @@
.post-reward
.reward-button
i.fas.fa-qrcode
= ' ' + _p('donate')
= theme.reward.text || _p('donate')
.reward-main
ul.reward-all
each item in theme.reward.QR_code

View File

@@ -1,2 +0,0 @@
.addthis_inline_share_toolbox
script(src=`//s7.addthis.com/js/300/addthis_widget.js#pubid=${theme.addThis.pubid}` async)

View File

@@ -1,7 +1,5 @@
.post_share
if theme.addThis.enable
!=partial('includes/third-party/share/add-this', {}, {cache: true})
else if theme.sharejs.enable
if theme.sharejs.enable
include ./share-js.pug
else if theme.addtoany.enable
!=partial('includes/third-party/share/addtoany', {}, {cache: true})

View File

@@ -0,0 +1,21 @@
if theme.aside.card_post_series.enable
- const array = fragment_cache('seriesArr', groupPosts)
.card-widget.card-post-series
.item-headline
i.fa-solid.fa-layer-group
span= _p('aside.card_post_series')
.aside-list
each item in array[page.series]
- const { path, title = _p('no_title'), cover, cover_type, date:dateA } = item
- let link = url_for(path)
- let no_cover = cover === false || !theme.cover.aside_enable ? 'no-cover' : ''
.aside-list-item(class=no_cover)
if cover && theme.cover.aside_enable
a.thumbnail(href=link title=title)
if cover_type === 'img'
img(src=url_for(cover) onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'` alt=title)
else
div(style=`background: ${cover}`)
.content
a.title(href=link title=title)= title
time(datetime=date_xml(dateA) title=_p('post.created') + ' ' + full_date(dateA)) #[=date(dateA, config.date_format)]

View File

@@ -13,6 +13,8 @@
.sticky_layout
if showToc
include ./card_post_toc.pug
if page.series
include ./card_post_series.pug
!=partial('includes/widget/card_recent_post', {}, {cache: true})
!=partial('includes/widget/card_ad', {}, {cache: true})
else

View File

@@ -1,11 +1,11 @@
algolia_search:
name: algoliasearch
file: dist/algoliasearch-lite.umd.js
version: 4.17.1
version: 4.18.0
instantsearch:
name: instantsearch.js
file: dist/instantsearch.production.min.js
version: 4.56.1
version: 4.56.3
pjax:
name: pjax
file: pjax.min.js
@@ -64,16 +64,16 @@ katex:
name: katex
file: dist/katex.min.css
other_name: KaTeX
version: 0.16.7
version: 0.16.8
katex_copytex:
name: katex
file: dist/contrib/copy-tex.min.js
other_name: KaTeX
version: 0.16.7
version: 0.16.8
mermaid:
name: mermaid
file: dist/mermaid.min.js
version: 10.2.2
version: 10.2.3
canvas_ribbon:
name: butterfly-extsrc
file: dist/canvas-ribbon.min.js
@@ -202,12 +202,12 @@ docsearch_js:
name: '@docsearch/js'
other_name: docsearch-js
file: dist/umd/index.js
version: 3.4.0
version: 3.5.1
docsearch_css:
name: '@docsearch/css'
other_name: docsearch-css
file: dist/style.css
version: 3.4.0
version: 3.5.1
abcjs_basic_js:
name: abcjs
file: dist/abcjs-basic-min.js

22
scripts/helpers/series.js Normal file
View File

@@ -0,0 +1,22 @@
'use strict'
hexo.extend.helper.register('groupPosts', function () {
const getGroupArray = array => {
const groups = {}
array.forEach(item => {
const Key = item.series
if (!Key) return
groups[Key] = groups[Key] || []
groups[Key].push(item)
})
return groups
}
const sortPosts = posts => {
const { orderBy = 'date', order = 1 } = this.theme.aside.card_post_series
if (orderBy === 'title') return posts.sort('title', order)
return posts.sort('date', order)
}
return getGroupArray(sortPosts(this.site.posts))
})

View File

@@ -9,17 +9,9 @@
const urlFor = require('hexo-util').url_for.bind(hexo)
function btn (args) {
const btn = args => {
args = args.join(' ').split(',')
let url = args[0] || ''
let text = args[1] || ''
let icon = args[2] || ''
let option = args[3] || ''
url = url.trim()
text = text.trim()
icon = icon.trim()
option = option.trim()
const [url = '', text = '', icon = '', option = ''] = args.map(arg => arg.trim())
return `<a class="btn-beautify ${option}" href="${urlFor(url)}"
title="${text}">${icon.length ? `<i class="${icon}"></i>` : ''}${text.length ? `<span>${text}</span>` : ''}</a>`

View File

@@ -10,7 +10,7 @@
const urlFor = require('hexo-util').url_for.bind(hexo)
function gallery (args, content) {
const gallery = (args, content) => {
const { data, languages } = hexo.theme.i18n
args = args.join(' ').split(',')
let rowHeight, limit, lazyload, type, dataStr
@@ -47,19 +47,18 @@ function gallery (args, content) {
</div>`
}
function galleryGroup (args) {
const name = args[0]
const descr = args[1]
const url = urlFor(args[2])
const img = urlFor(args[3])
const galleryGroup = args => {
const [name, descr, url, img] = args
const imgUrl = urlFor(img)
const urlLink = urlFor(url)
return `
<figure class="gallery-group">
<img class="gallery-group-img no-lightbox" src='${img}' alt="Group Image Gallery">
<img class="gallery-group-img no-lightbox" src='${imgUrl}' alt="Group Image Gallery">
<figcaption>
<div class="gallery-group-name">${name}</div>
<p>${descr}</p>
<a href='${url}'></a>
<a href='${urlLink}'></a>
</figcaption>
</figure>
`

View File

@@ -16,51 +16,46 @@
'use strict'
function hideInline (args) {
args = args.join(' ').split(',')
const content = args[0]
const display = args[1] || 'Click'
const bg = args[2] || false
const color = args[3] || false
let group = 'style="'
const parseArgs = args => {
return args.join(' ').split(',')
}
if (bg) group += `background-color: ${bg};`
if (color) group += `color: ${color}`
group += '"'
const generateStyle = (bg, color) => {
let style = 'style="'
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>`
}
function hideBlock (args, content) {
args = args.join(' ').split(',')
const display = args[0] || 'Click'
const bg = args[1] || false
const color = args[2] || false
let group = 'style="'
if (bg) group += `background-color: ${bg};`
if (color) group += `color: ${color}`
group += '"'
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>`
}
function hideToggle (args, content) {
args = args.join(' ').split(',')
const display = args[0]
const bg = args[1] || false
const color = args[2] || false
let group = 'style="'
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}"`
group += `background-color: ${bg};`
}
if (color) group += `color: ${color}`
group += '"'
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>`
}

View File

@@ -1,17 +1,19 @@
/**
* inlineImg 圖片
* {% inlineImg src height %}
* @param {Array} args 圖片名稱和高度
* @param {string} args[0] 圖片名稱
* @param {number} args[1] 圖片高度
* @returns {string} 圖片標籤
*/
'use strict'
const urlFor = require('hexo-util').url_for.bind(hexo)
function inlineImg (args) {
const img = args[0]
const height = args[1] ? `style="height:${args[1]}"` : ''
return `<img class="inline-img" src="${urlFor(img)}" ${height}/>`
const inlineImg = ([img, height = '']) => {
const heightStyle = height ? `style="height:${height}"` : ''
const src = urlFor(img)
return `<img class="inline-img" src="${src}" ${heightStyle} />`
}
hexo.extend.tag.register('inlineImg', inlineImg, { ends: false })

View File

@@ -6,10 +6,8 @@
'use strict'
function addLabel (args, content) {
const text = args[0]
const className = args[1] || 'default'
const addLabel = args => {
const [text, className = 'default'] = args
return `<mark class="hl-label ${className}">${text}</mark> `
}

View File

@@ -8,7 +8,7 @@
const { escapeHTML } = require('hexo-util')
function mermaid (args, content) {
const mermaid = (args, content) => {
return `<div class="mermaid-wrap"><pre class="mermaid-src" hidden>
${escapeHTML(content)}
</pre></div>`

View File

@@ -6,10 +6,10 @@
'use strict'
function postNote (args, content) {
const postNote = (args, content) => {
const styleConfig = hexo.theme.config.note.style
const lastArgs = args[args.length - 1]
if (!(lastArgs === 'flat' || lastArgs === 'modern' || lastArgs === 'simple' || lastArgs === 'disabled')) {
const noteTag = ['flat', 'modern', 'simple', 'disabled']
if (!noteTag.includes(args[args.length - 1])) {
args.push(styleConfig)
}

View File

@@ -3,20 +3,20 @@
* {% score %}
*/
'use strict';
'use strict'
function score(args, content) {
function escapeHtmlTags(s) {
let lookup = {
'&': "&amp;",
'"': "&quot;",
'\'': "&apos;",
'<': "&lt;",
'>': "&gt;"
};
return s.replace(/[&"'<>]/g, c => lookup[c]);
const score = (args, content) => {
const escapeHtmlTags = s => {
const lookup = {
'&': '&amp;',
'"': '&quot;',
'\'': '&apos;',
'<': '&lt;',
'>': '&gt;'
}
return `<div class="abc-music-sheet">${escapeHtmlTags(content)}</div>`;
return s.replace(/[&"'<>]/g, c => lookup[c])
}
return `<div class="abc-music-sheet">${escapeHtmlTags(content)}</div>`
}
hexo.extend.tag.register('score', score, {ends: true});
hexo.extend.tag.register('score', score, { ends: true })

69
scripts/tag/series.js Normal file
View File

@@ -0,0 +1,69 @@
/**
* series plugin
* Syntax:
* {% series [series name] %}
* Usage:
* {% series %}
* {% series series1 %}
*/
'use strict'
const urlFor = require('hexo-util').url_for.bind(hexo)
const groups = {}
hexo.extend.filter.register('before_post_render', data => {
if (!hexo.theme.config.series.enable) return data
const { layout, series } = data
if (layout === 'post' && series) {
groups[series] = groups[series] || []
groups[series].push({
title: data.title,
path: data.path,
date: data.date.unix()
})
}
return data
})
function series (args) {
const { series } = hexo.theme.config
if (!series.enable) {
hexo.log.warn('Series plugin is disabled in the theme config')
return ''
}
const seriesArr = args.length ? groups[args[0]] : groups[this.series]
if (!seriesArr) {
hexo.log.warn(`There is no series named "${args[0]}"`)
return ''
}
const isAsc = (series.order || 1) === 1 // 1: asc, -1: desc
const isSortByTitle = series.orderBy === 'title'
const compareFn = (a, b) => {
const itemA = isSortByTitle ? a.title.toUpperCase() : a.date
const itemB = isSortByTitle ? b.title.toUpperCase() : b.date
if (itemA < itemB) {
return isAsc ? -1 : 1
}
if (itemA > itemB) {
return isAsc ? 1 : -1
}
return 0
}
seriesArr.sort(compareFn)
let result = ''
seriesArr.forEach(ele => {
result += `<li><a href="${urlFor(ele.path)}" title="${ele.title}">${ele.title}</a></li>`
})
return series.number ? `<ol>${result}</ol>` : `<ul>${result}</ul>`
}
hexo.extend.tag.register('series', series, { ends: false })

View File

@@ -6,13 +6,11 @@
'use strict'
function postTabs (args, content) {
const postTabs = (args, content) => {
const tabBlock = /<!--\s*tab (.*?)\s*-->\n([\w\W\s\S]*?)<!--\s*endtab\s*-->/g
args = args.join(' ').split(',')
const tabName = args[0]
const tabActive = Number(args[1]) || 0
const matches = []
let match
let tabId = 0
@@ -22,8 +20,7 @@ function postTabs (args, content) {
!tabName && hexo.log.warn('Tabs block must have unique name!')
while ((match = tabBlock.exec(content)) !== null) {
matches.push(match[1])
matches.push(match[2])
matches.push(match[1], match[2])
}
for (let i = 0; i < matches.length; i += 2) {

View File

@@ -5,15 +5,15 @@
'use strict'
function timeLineFn (args, content) {
const timeLineFn = (args, content) => {
const tlBlock = /<!--\s*timeline (.*?)\s*-->\n([\w\W\s\S]*?)<!--\s*endtimeline\s*-->/g
let result = ''
let color = ''
let text = ''
if (args.length) {
args = args.join(' ').split(',')
color = args[1]
const mdContent = hexo.render.renderSync({ text: args[0], engine: 'markdown' })
[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>`
}

View File

@@ -15,6 +15,9 @@
color: var(--btn-color)
cursor: pointer
i
margin-right: 5px
&:hover
.reward-button
background: var(--btn-hover-color)

View File

@@ -62,6 +62,11 @@
transition: all .2s ease-in-out
-webkit-line-clamp: 2
.sticky
margin-right: 10px
color: $sticky-color
transform: rotate(45deg)
+maxWidth768()
font-size: 1.43em
@@ -76,9 +81,6 @@
& > .post-meta-date
cursor: default
.sticky
color: $sticky-color
i
margin: 0 4px 0 0

View File

@@ -61,9 +61,9 @@
animation: tabshow .5s
.tab-to-top
position: relative
position: absolute
right: 15px
display: block
margin: 0 0 0 auto
color: $tab-to-top-color
@keyframes tabshow

View File

@@ -101,7 +101,7 @@ $tag-hide-toggle-bg = #f0f0f0
$preloader-bg = #37474f
$preloader-word-color = #fff
// rightside
$rightside-bottom = hexo-config('rightside-bottom') ? convert(hexo-config('rightside-bottom')) : 40px
$rightside-bottom = hexo-config('rightside_bottom') ? convert(hexo-config('rightside_bottom')) : 40px
// fireworks
$fireworks-zIndex = hexo-config('fireworks.zIndex') ? hexo-config('fireworks.zIndex') : 99999
// Tag Plugins - Note