mirror of
https://github.com/jerryc127/hexo-theme-butterfly.git
synced 2026-04-10 21:17:07 +08:00
update
This commit is contained in:
@@ -98,6 +98,7 @@ npm i hexo-theme-butterfly
|
|||||||
- [x] Busuanzi visitor counter
|
- [x] Busuanzi visitor counter
|
||||||
- [x] Medium Zoom/Fancybox
|
- [x] Medium Zoom/Fancybox
|
||||||
- [x] Mermaid
|
- [x] Mermaid
|
||||||
|
- [x] Chart.js
|
||||||
- [x] Justified Gallery
|
- [x] Justified Gallery
|
||||||
- [x] Lazyload images
|
- [x] Lazyload images
|
||||||
- [x] Instantpage/Pangu/Snackbar notification toast/PWA......
|
- [x] Instantpage/Pangu/Snackbar notification toast/PWA......
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ theme: butterfly
|
|||||||
- [x] 不蒜子訪問統計
|
- [x] 不蒜子訪問統計
|
||||||
- [x] 兩種大圖模式(Medium Zoom/Fancybox)
|
- [x] 兩種大圖模式(Medium Zoom/Fancybox)
|
||||||
- [x] Mermaid 圖表顯示
|
- [x] Mermaid 圖表顯示
|
||||||
|
- [x] Chart.js 圖表顯示
|
||||||
- [x] 照片牆
|
- [x] 照片牆
|
||||||
- [x] 圖片懶加載
|
- [x] 圖片懶加載
|
||||||
- [x] Instantpage/Pangu/Snackbar彈窗/PWA......
|
- [x] Instantpage/Pangu/Snackbar彈窗/PWA......
|
||||||
|
|||||||
28
_config.yml
28
_config.yml
@@ -602,7 +602,7 @@ facebook_comments:
|
|||||||
pageSize: 10
|
pageSize: 10
|
||||||
# Choose: social / time / reverse_time
|
# Choose: social / time / reverse_time
|
||||||
order_by: social
|
order_by: social
|
||||||
lang: zh_TW
|
lang: en_US
|
||||||
|
|
||||||
# Twikoo
|
# Twikoo
|
||||||
# https://github.com/imaegoo/twikoo
|
# https://github.com/imaegoo/twikoo
|
||||||
@@ -927,20 +927,21 @@ mermaid:
|
|||||||
# chartjs
|
# chartjs
|
||||||
# see https://www.chartjs.org/docs/latest/
|
# see https://www.chartjs.org/docs/latest/
|
||||||
chartjs:
|
chartjs:
|
||||||
enable: true
|
enable: false
|
||||||
# 下面的設置是正對 ChartJS 的預設樣式設置,非必要請勿修改,除非你理解他們是如何工作的
|
# Do not modify unless you understand how they work.
|
||||||
# 當然,樣式會以具體的 MD 語法設置優先,其次為該預設設置,最後為 ChartJS 本身的預設設置
|
# The default settings are only used when the MD syntax is not specified.
|
||||||
color: # 表格通用字體顏色
|
# General font color for the chart
|
||||||
light: "rgba(0, 0, 0, 0.8)" # 淺色模式
|
fontColor:
|
||||||
dark: "rgba(255, 255, 255, 0.8)" # 深色模式
|
light: "rgba(0, 0, 0, 0.8)"
|
||||||
borderColor: # 表格通用邊框顏色
|
dark: "rgba(255, 255, 255, 0.8)"
|
||||||
|
# General border color for the chart
|
||||||
|
borderColor:
|
||||||
light: "rgba(0, 0, 0, 0.1)"
|
light: "rgba(0, 0, 0, 0.1)"
|
||||||
dark: "rgba(255, 255, 255, 0.2)"
|
dark: "rgba(255, 255, 255, 0.2)"
|
||||||
scale:
|
# Background color for scale labels on radar and polar area charts
|
||||||
ticks:
|
scale_ticks_backdropColor:
|
||||||
backdropColor: # 針對雷達圖和極地圖的刻度標籤背景色
|
light: "transparent"
|
||||||
light: "transparent"
|
dark: "transparent"
|
||||||
dark: "transparent"
|
|
||||||
|
|
||||||
# Note - Bootstrap Callout
|
# Note - Bootstrap Callout
|
||||||
note:
|
note:
|
||||||
@@ -1068,6 +1069,7 @@ CDN:
|
|||||||
# canvas_fluttering_ribbon:
|
# canvas_fluttering_ribbon:
|
||||||
# canvas_nest:
|
# canvas_nest:
|
||||||
# canvas_ribbon:
|
# canvas_ribbon:
|
||||||
|
# chartjs:
|
||||||
# click_heart:
|
# click_heart:
|
||||||
# clickShowText:
|
# clickShowText:
|
||||||
# disqusjs:
|
# disqusjs:
|
||||||
|
|||||||
138
layout/includes/third-party/math/chartjs.pug
vendored
138
layout/includes/third-party/math/chartjs.pug
vendored
@@ -1,79 +1,91 @@
|
|||||||
|
- const { fontColor, borderColor, scale_ticks_backdropColor } = theme.chartjs
|
||||||
|
|
||||||
script.
|
script.
|
||||||
(() => {
|
(() => {
|
||||||
const $chartjs = document.querySelectorAll('#article-container .chartjs-wrap')
|
const $chartjs = document.querySelectorAll('#article-container .chartjs-container')
|
||||||
if ($chartjs.length === 0) return
|
if ($chartjs.length === 0) return
|
||||||
|
|
||||||
const applyThemeDefaultsConfig = (theme) => {
|
const applyThemeDefaultsConfig = theme => {
|
||||||
if (theme === 'dark-mode') {
|
if (theme === 'dark-mode') {
|
||||||
Chart.defaults.color = "!{theme.chartjs.color.dark}"
|
Chart.defaults.color = "!{fontColor.dark}"
|
||||||
Chart.defaults.borderColor = "!{theme.chartjs.borderColor.dark}"
|
Chart.defaults.borderColor = "!{borderColor.dark}"
|
||||||
Chart.defaults.scale.ticks.backdropColor = "!{theme.chartjs.scale.ticks.backdropColor.dark}"
|
Chart.defaults.scale.ticks.backdropColor = "!{scale_ticks_backdropColor.dark}"
|
||||||
} else {
|
} else {
|
||||||
Chart.defaults.color = "!{theme.chartjs.color.light}"
|
Chart.defaults.color = "!{fontColor.light}"
|
||||||
Chart.defaults.borderColor = "!{theme.chartjs.borderColor.light}"
|
Chart.defaults.borderColor = "!{borderColor.light}"
|
||||||
Chart.defaults.scale.ticks.backdropColor = "!{theme.chartjs.scale.ticks.backdropColor.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 = () => {
|
||||||
|
window.loadChartJS = true
|
||||||
|
|
||||||
|
Array.from($chartjs).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()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归遍历 config 对象,自动根据当前主题选择双模式配色方案
|
const chartDefinition = chartSrc.textContent
|
||||||
const applyThemeConfig = (obj, theme) => {
|
const canvas = document.createElement('canvas')
|
||||||
if (typeof obj !== 'object' || obj === null) return
|
canvas.id = chartID
|
||||||
|
|
||||||
Object.keys(obj).forEach(key => {
|
const div = document.createElement('div')
|
||||||
const value = obj[key]
|
div.className = 'chartjs-wrap'
|
||||||
// 如果属性是对象,并且有与主题相关的选项,进行应用
|
|
||||||
if (typeof value === 'object' && value !== null) {
|
if (width) {
|
||||||
if (value[theme]) {
|
div.style.width = width
|
||||||
obj[key] = value[theme] // 应用当前主题的值
|
|
||||||
} else {
|
|
||||||
// 递归处理子对象
|
|
||||||
applyThemeConfig(value, theme)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const runChartJS = () => {
|
div.appendChild(canvas)
|
||||||
window.loadChartJS = true
|
chartSrc.insertAdjacentElement('afterend', div)
|
||||||
|
|
||||||
Array.from($chartjs).forEach((item, index) => {
|
const ctx = document.getElementById(chartID).getContext('2d')
|
||||||
const chartSrc = item.firstElementChild
|
|
||||||
const chartID = item.getAttribute('data-chartjs-id') || ('chartjs-' + index) // 使用自定义 ID 或默认 ID
|
|
||||||
const existingCanvas = document.getElementById(chartID)
|
|
||||||
|
|
||||||
// 如果已经存在 canvas,先将其移除,避免重复渲染
|
const config = JSON.parse(chartDefinition)
|
||||||
if (existingCanvas) {
|
|
||||||
existingCanvas.remove()
|
|
||||||
}
|
|
||||||
|
|
||||||
const chartDefinition = chartSrc.textContent
|
const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark-mode' : 'light-mode'
|
||||||
const canvas = document.createElement('canvas')
|
|
||||||
canvas.id = chartID
|
|
||||||
chartSrc.insertAdjacentElement('afterend', canvas)
|
|
||||||
|
|
||||||
const ctx = document.getElementById(chartID).getContext('2d')
|
// Set default styles (initial setup)
|
||||||
|
applyThemeDefaultsConfig(theme)
|
||||||
|
|
||||||
const config = JSON.parse(chartDefinition)
|
// Automatically traverse the config and apply dual-mode color schemes
|
||||||
|
applyThemeConfig(config, theme)
|
||||||
|
|
||||||
// 根据当前主题选择相应的配色方案
|
new Chart(ctx, config)
|
||||||
const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark-mode' : 'light-mode'
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 设置默认样式(默认初始化)
|
const loadChartJS = () => {
|
||||||
applyThemeDefaultsConfig(theme)
|
window.loadChartJS ? runChartJS() : btf.getScript('!{url_for(theme.asset.chartjs)}').then(runChartJS)
|
||||||
|
}
|
||||||
|
|
||||||
// 自动遍历 config,应用双模式配色方案
|
// Listen for theme change events
|
||||||
applyThemeConfig(config, theme)
|
btf.addGlobalFn('themeChange', runChartJS, 'chartjs')
|
||||||
|
btf.addGlobalFn('encrypt', runChartJS, 'chartjs')
|
||||||
|
|
||||||
new Chart(ctx, config)
|
window.pjax ? loadChartJS() : document.addEventListener('DOMContentLoaded', loadChartJS)
|
||||||
})
|
})()
|
||||||
}
|
|
||||||
|
|
||||||
const loadChartJS = () => {
|
|
||||||
window.loadChartJS ? runChartJS() : btf.getScript('!{url_for(theme.asset.chartjs)}').then(runChartJS)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听主题切换
|
|
||||||
btf.addGlobalFn('themeChange', runChartJS, 'chartjs')
|
|
||||||
|
|
||||||
window.pjax ? loadChartJS() : document.addEventListener('DOMContentLoaded', loadChartJS)
|
|
||||||
})()
|
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ canvas_ribbon:
|
|||||||
name: butterfly-extsrc
|
name: butterfly-extsrc
|
||||||
file: dist/canvas-ribbon.min.js
|
file: dist/canvas-ribbon.min.js
|
||||||
version: 1.1.4
|
version: 1.1.4
|
||||||
|
chartjs:
|
||||||
|
name: chart.js
|
||||||
|
file: dist/chart.umd.min.js
|
||||||
|
version: 4.4.4
|
||||||
clickShowText:
|
clickShowText:
|
||||||
name: butterfly-extsrc
|
name: butterfly-extsrc
|
||||||
file: dist/click-show-text.min.js
|
file: dist/click-show-text.min.js
|
||||||
@@ -134,10 +138,6 @@ mermaid:
|
|||||||
name: mermaid
|
name: mermaid
|
||||||
file: dist/mermaid.min.js
|
file: dist/mermaid.min.js
|
||||||
version: 11.2.1
|
version: 11.2.1
|
||||||
chartjs:
|
|
||||||
name: chart.js
|
|
||||||
file: dist/chart.umd.min.js
|
|
||||||
version: 4.4.4
|
|
||||||
meting_js:
|
meting_js:
|
||||||
name: butterfly-extsrc
|
name: butterfly-extsrc
|
||||||
file: metingjs/dist/Meting.min.js
|
file: metingjs/dist/Meting.min.js
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ hexo.extend.filter.register('before_generate', () => {
|
|||||||
user_id: null,
|
user_id: null,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
order_by: 'social',
|
order_by: 'social',
|
||||||
lang: 'zh_TW'
|
lang: 'en_US'
|
||||||
},
|
},
|
||||||
twikoo: {
|
twikoo: {
|
||||||
envId: null,
|
envId: null,
|
||||||
@@ -514,21 +514,17 @@ hexo.extend.filter.register('before_generate', () => {
|
|||||||
},
|
},
|
||||||
chartjs: {
|
chartjs: {
|
||||||
enable: false,
|
enable: false,
|
||||||
color: {
|
fontColor: {
|
||||||
light: "rgba(0, 0, 0, 0.8)",
|
light: 'rgba(0, 0, 0, 0.8)',
|
||||||
dark: "rgba(255, 255, 255, 0.8)"
|
dark: 'rgba(255, 255, 255, 0.8)'
|
||||||
},
|
},
|
||||||
borderColor: {
|
borderColor: {
|
||||||
light: "rgba(0, 0, 0, 0.1)",
|
light: 'rgba(0, 0, 0, 0.1)',
|
||||||
dark: "rgba(255, 255, 255, 0.2)"
|
dark: 'rgba(255, 255, 255, 0.2)'
|
||||||
},
|
},
|
||||||
scale: {
|
scale_ticks_backdropColor: {
|
||||||
ticks: {
|
light: 'transparent',
|
||||||
backdropColor: {
|
dark: 'transparent'
|
||||||
light: "transparent",
|
|
||||||
dark: "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
note: {
|
note: {
|
||||||
|
|||||||
@@ -2,7 +2,12 @@
|
|||||||
* Butterfly
|
* Butterfly
|
||||||
* chartjs
|
* chartjs
|
||||||
* https://www.chartjs.org/
|
* https://www.chartjs.org/
|
||||||
* Author: SeaYJ
|
* {% chartjs [width, abreast, chartId] %}
|
||||||
|
* <!-- chart -->
|
||||||
|
* <!-- endchart -->
|
||||||
|
* <!-- desc -->
|
||||||
|
* <!-- enddesc -->
|
||||||
|
* {% endchartjs %}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
'use strict'
|
||||||
@@ -10,30 +15,35 @@
|
|||||||
const { escapeHTML } = require('hexo-util')
|
const { escapeHTML } = require('hexo-util')
|
||||||
|
|
||||||
const chartjs = (args, content) => {
|
const chartjs = (args, content) => {
|
||||||
const chartBlock = /<!--\s*chart\s*-->\n([\w\W\s\S]*?)<!--\s*endchart\s*-->/g
|
if (!content) return
|
||||||
const descBlock = /<!--\s*desc\s*-->\n([\w\W\s\S]*?)<!--\s*enddesc\s*-->/g
|
|
||||||
const id = args[0]
|
|
||||||
const descMatches = []
|
|
||||||
let chartConfig
|
|
||||||
let descDOM = ''
|
|
||||||
let match
|
|
||||||
|
|
||||||
!content && hexo.log.warn('chartjs has no content!')
|
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()
|
||||||
|
|
||||||
if ((match = chartBlock.exec(content)) !== null) {
|
const [width = '', layout = false, chartId = ''] = selfConfig.split(',').map(s => s.trim())
|
||||||
chartConfig = match[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((match = descBlock.exec(content)) !== null) {
|
const chartMatch = content.match(chartRegex)
|
||||||
descMatches.push(match[1])
|
const descMatch = content.match(descRegex)
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < descMatches.length; i++) {
|
if (!chartMatch) {
|
||||||
let descContent = hexo.render.renderSync({ text: descMatches[i], engine: 'markdown' }).trim()
|
hexo.log.warn('chartjs tag: chart content is required!')
|
||||||
descDOM += (descContent ? `<div class="chatjs-desc-${i}">${descContent}</div>` : '')
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return `<div class="chartjs-wrap" data-chartjs-id="${id}"><pre class="chartjs-src" hidden>${escapeHTML(chartConfig)}</pre>${descDOM}</div>`
|
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 })
|
hexo.extend.tag.register('chartjs', chartjs, { ends: true })
|
||||||
|
|||||||
@@ -75,9 +75,31 @@ if hexo-config('mermaid.enable')
|
|||||||
pre > code.mermaid
|
pre > code.mermaid
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
.chartjs-wrap
|
if hexo-config('chartjs.enable')
|
||||||
margin: 0 0 20px
|
.chartjs-container
|
||||||
text-align: center
|
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,
|
.utterances,
|
||||||
.fb-comments iframe
|
.fb-comments iframe
|
||||||
|
|||||||
Reference in New Issue
Block a user