mirror of
https://github.com/jerryc127/hexo-theme-butterfly.git
synced 2026-04-16 20:30:53 +08:00
update
This commit is contained in:
@@ -1,21 +1,21 @@
|
||||
/**
|
||||
* Button
|
||||
* {% btn url text icon option %}
|
||||
* option: color outline center block larger
|
||||
* color : default/blue/pink/red/purple/orange/green
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
const btn = args => {
|
||||
const [url = '', text = '', icon = '', option = ''] = args.join(' ').split(',').map(arg => arg.trim())
|
||||
|
||||
const iconHTML = icon ? `<i class="${icon}"></i>` : ''
|
||||
const textHTML = text ? `<span>${text}</span>` : ''
|
||||
|
||||
return `<a class="btn-beautify ${option}" href="${urlFor(url)}" title="${text}">${iconHTML}${textHTML}</a>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('btn', btn, { ends: false })
|
||||
/**
|
||||
* Button
|
||||
* {% btn url text icon option %}
|
||||
* option: color outline center block larger
|
||||
* color : default/blue/pink/red/purple/orange/green
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
const btn = args => {
|
||||
const [url = '', text = '', icon = '', option = ''] = args.join(' ').split(',').map(arg => arg.trim())
|
||||
|
||||
const iconHTML = icon ? `<i class="${icon}"></i>` : ''
|
||||
const textHTML = text ? `<span>${text}</span>` : ''
|
||||
|
||||
return `<a class="btn-beautify ${option}" href="${urlFor(url)}" title="${text}">${iconHTML}${textHTML}</a>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('btn', btn, { ends: false })
|
||||
|
||||
@@ -1,49 +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 })
|
||||
/**
|
||||
* 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 })
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
/**
|
||||
* flink
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
const flinkFn = (args, content) => {
|
||||
const data = hexo.render.renderSync({ text: content, engine: 'yaml' })
|
||||
let result = ''
|
||||
|
||||
data.forEach(item => {
|
||||
const className = item.class_name ? `<div class="flink-name">${item.class_name}</div>` : ''
|
||||
const classDesc = item.class_desc ? `<div class="flink-desc">${item.class_desc}</div>` : ''
|
||||
|
||||
const listResult = item.link_list.map(link => `
|
||||
<div class="flink-list-item">
|
||||
<a href="${link.link}" title="${link.name}" target="_blank">
|
||||
<div class="flink-item-icon">
|
||||
<img class="no-lightbox" src="${link.avatar}" onerror='this.onerror=null;this.src="${urlFor(hexo.theme.config.error_img.flink)}"' alt="${link.name}" />
|
||||
</div>
|
||||
<div class="flink-item-name">${link.name}</div>
|
||||
<div class="flink-item-desc" title="${link.descr}">${link.descr}</div>
|
||||
</a>
|
||||
</div>`).join('')
|
||||
|
||||
result += `${className}${classDesc}<div class="flink-list">${listResult}</div>`
|
||||
})
|
||||
|
||||
return `<div class="flink">${result}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('flink', flinkFn, { ends: true })
|
||||
/**
|
||||
* flink
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
const flinkFn = (args, content) => {
|
||||
const data = hexo.render.renderSync({ text: content, engine: 'yaml' })
|
||||
let result = ''
|
||||
|
||||
data.forEach(item => {
|
||||
const className = item.class_name ? `<div class="flink-name">${item.class_name}</div>` : ''
|
||||
const classDesc = item.class_desc ? `<div class="flink-desc">${item.class_desc}</div>` : ''
|
||||
|
||||
const listResult = item.link_list.map(link => `
|
||||
<div class="flink-list-item">
|
||||
<a href="${link.link}" title="${link.name}" target="_blank">
|
||||
<div class="flink-item-icon">
|
||||
<img class="no-lightbox" src="${link.avatar}" onerror='this.onerror=null;this.src="${urlFor(hexo.theme.config.error_img.flink)}"' alt="${link.name}" />
|
||||
</div>
|
||||
<div class="flink-item-name">${link.name}</div>
|
||||
<div class="flink-item-desc" title="${link.descr}">${link.descr}</div>
|
||||
</a>
|
||||
</div>`).join('')
|
||||
|
||||
result += `${className}${classDesc}<div class="flink-list">${listResult}</div>`
|
||||
})
|
||||
|
||||
return `<div class="flink">${result}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('flink', flinkFn, { ends: true })
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
/**
|
||||
* Butterfly
|
||||
* galleryGroup and gallery
|
||||
* {% galleryGroup [name] [descr] [url] [img] %}
|
||||
*
|
||||
* {% gallery [button],[limit],[firstLimit] %}
|
||||
* {% gallery url,[url],[button] %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
const DEFAULT_LIMIT = 10
|
||||
const DEFAULT_FIRST_LIMIT = 10
|
||||
const IMAGE_REGEX = /!\[(.*?)\]\(([^\s]*)\s*(?:["'](.*?)["']?)?\s*\)/g
|
||||
|
||||
// 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]
|
||||
}
|
||||
}
|
||||
|
||||
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] || ''
|
||||
})
|
||||
}
|
||||
|
||||
return images
|
||||
}
|
||||
|
||||
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.map(arg => arg.trim())
|
||||
|
||||
return `<figure class="gallery-group">
|
||||
<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='${urlFor(url)}'></a>
|
||||
</figcaption>
|
||||
</figure>`
|
||||
}
|
||||
|
||||
// Register tags
|
||||
hexo.extend.tag.register('gallery', gallery, { ends: true })
|
||||
hexo.extend.tag.register('galleryGroup', galleryGroup)
|
||||
/**
|
||||
* Butterfly
|
||||
* galleryGroup and gallery
|
||||
* {% galleryGroup [name] [descr] [url] [img] %}
|
||||
*
|
||||
* {% gallery [button],[limit],[firstLimit] %}
|
||||
* {% gallery url,[url],[button] %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
const DEFAULT_LIMIT = 10
|
||||
const DEFAULT_FIRST_LIMIT = 10
|
||||
const IMAGE_REGEX = /!\[(.*?)\]\(([^\s]*)\s*(?:["'](.*?)["']?)?\s*\)/g
|
||||
|
||||
// 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]
|
||||
}
|
||||
}
|
||||
|
||||
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] || ''
|
||||
})
|
||||
}
|
||||
|
||||
return images
|
||||
}
|
||||
|
||||
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.map(arg => arg.trim())
|
||||
|
||||
return `<figure class="gallery-group">
|
||||
<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='${urlFor(url)}'></a>
|
||||
</figcaption>
|
||||
</figure>`
|
||||
}
|
||||
|
||||
// Register tags
|
||||
hexo.extend.tag.register('gallery', gallery, { ends: true })
|
||||
hexo.extend.tag.register('galleryGroup', galleryGroup)
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
/**
|
||||
* Butterfly
|
||||
* @example
|
||||
* hideInline
|
||||
* {% hideInline content,display,bg,color %}
|
||||
* content不能包含當引號,可用 '
|
||||
* hideBlock
|
||||
* {% hideBlock display,bg,color %}
|
||||
* content
|
||||
* {% endhideBlock %}
|
||||
* hideToggle
|
||||
* {% hideToggle display,bg,color %}
|
||||
* content
|
||||
* {% endhideToggle %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const parseArgs = args => args.join(' ').split(',')
|
||||
|
||||
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 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 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 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)
|
||||
hexo.extend.tag.register('hideBlock', hideBlock, { ends: true })
|
||||
/**
|
||||
* Butterfly
|
||||
* @example
|
||||
* hideInline
|
||||
* {% hideInline content,display,bg,color %}
|
||||
* content不能包含當引號,可用 '
|
||||
* hideBlock
|
||||
* {% hideBlock display,bg,color %}
|
||||
* content
|
||||
* {% endhideBlock %}
|
||||
* hideToggle
|
||||
* {% hideToggle display,bg,color %}
|
||||
* content
|
||||
* {% endhideToggle %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const parseArgs = args => args.join(' ').split(',')
|
||||
|
||||
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 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 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 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)
|
||||
hexo.extend.tag.register('hideBlock', hideBlock, { ends: true })
|
||||
hexo.extend.tag.register('hideToggle', hideToggle, { ends: true })
|
||||
@@ -1,19 +1,19 @@
|
||||
/**
|
||||
* 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'
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
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 })
|
||||
/**
|
||||
* 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'
|
||||
|
||||
const urlFor = require('hexo-util').url_for.bind(hexo)
|
||||
|
||||
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 })
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/**
|
||||
* Butterfly
|
||||
* label
|
||||
* {% label text color %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const addLabel = args => {
|
||||
const [text, className = 'default'] = args
|
||||
return `<mark class="hl-label ${className}">${text}</mark>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('label', addLabel, { ends: false })
|
||||
/**
|
||||
* Butterfly
|
||||
* label
|
||||
* {% label text color %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const addLabel = args => {
|
||||
const [text, className = 'default'] = args
|
||||
return `<mark class="hl-label ${className}">${text}</mark>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('label', addLabel, { ends: false })
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/**
|
||||
* Butterfly
|
||||
* mermaid
|
||||
* https://github.com/mermaid-js/mermaid
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const { escapeHTML } = require('hexo-util')
|
||||
|
||||
const mermaid = (args, content) => {
|
||||
return `<div class="mermaid-wrap"><pre class="mermaid-src" hidden>
|
||||
${escapeHTML(content)}
|
||||
</pre></div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('mermaid', mermaid, { ends: true })
|
||||
/**
|
||||
* Butterfly
|
||||
* mermaid
|
||||
* https://github.com/mermaid-js/mermaid
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const { escapeHTML } = require('hexo-util')
|
||||
|
||||
const mermaid = (args, content) => {
|
||||
return `<div class="mermaid-wrap"><pre class="mermaid-src" hidden>
|
||||
${escapeHTML(content)}
|
||||
</pre></div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('mermaid', mermaid, { ends: true })
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
/**
|
||||
* note.js
|
||||
* transplant from hexo-theme-next
|
||||
* Modify by Jerry
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const postNote = (args, content) => {
|
||||
const styleConfig = hexo.theme.config.note.style
|
||||
const noteTag = ['flat', 'modern', 'simple', 'disabled']
|
||||
if (!noteTag.includes(args[args.length - 1])) {
|
||||
args.push(styleConfig)
|
||||
}
|
||||
|
||||
let icon = ''
|
||||
const iconArray = args[args.length - 2]
|
||||
if (iconArray && iconArray.startsWith('fa')) {
|
||||
icon = `<i class="note-icon ${iconArray}"></i>`
|
||||
args[args.length - 2] = 'icon-padding'
|
||||
}
|
||||
|
||||
return `<div class="note ${args.join(' ')}">${icon + hexo.render.renderSync({ text: content, engine: 'markdown' })}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('note', postNote, { ends: true })
|
||||
hexo.extend.tag.register('subnote', postNote, { ends: true })
|
||||
/**
|
||||
* note.js
|
||||
* transplant from hexo-theme-next
|
||||
* Modify by Jerry
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const postNote = (args, content) => {
|
||||
const styleConfig = hexo.theme.config.note.style
|
||||
const noteTag = ['flat', 'modern', 'simple', 'disabled']
|
||||
if (!noteTag.includes(args[args.length - 1])) {
|
||||
args.push(styleConfig)
|
||||
}
|
||||
|
||||
let icon = ''
|
||||
const iconArray = args[args.length - 2]
|
||||
if (iconArray && iconArray.startsWith('fa')) {
|
||||
icon = `<i class="note-icon ${iconArray}"></i>`
|
||||
args[args.length - 2] = 'icon-padding'
|
||||
}
|
||||
|
||||
return `<div class="note ${args.join(' ')}">${icon + hexo.render.renderSync({ text: content, engine: 'markdown' })}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('note', postNote, { ends: true })
|
||||
hexo.extend.tag.register('subnote', postNote, { ends: true })
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
/**
|
||||
* Music Score
|
||||
* {% score %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const score = (args, content) => {
|
||||
const escapeHtmlTags = s => {
|
||||
const lookup = {
|
||||
'&': '&',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
'<': '<',
|
||||
'>': '>'
|
||||
}
|
||||
return s.replace(/[&"'<>]/g, c => lookup[c])
|
||||
}
|
||||
return `<div class="abc-music-sheet">${escapeHtmlTags(content)}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('score', score, { ends: true })
|
||||
/**
|
||||
* Music Score
|
||||
* {% score %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const score = (args, content) => {
|
||||
const escapeHtmlTags = s => {
|
||||
const lookup = {
|
||||
'&': '&',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
'<': '<',
|
||||
'>': '>'
|
||||
}
|
||||
return s.replace(/[&"'<>]/g, c => lookup[c])
|
||||
}
|
||||
return `<div class="abc-music-sheet">${escapeHtmlTags(content)}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('score', score, { ends: true })
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
/**
|
||||
* 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) {
|
||||
if (!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
|
||||
|
||||
return itemA < itemB ? (isAsc ? -1 : 1) : itemA > itemB ? (isAsc ? 1 : -1) : 0
|
||||
}
|
||||
|
||||
seriesArr.sort(compareFn)
|
||||
|
||||
const listItems = seriesArr.map(ele =>
|
||||
`<li><a href="${urlFor(ele.path)}" title="${ele.title}">${ele.title}</a></li>`
|
||||
).join('')
|
||||
|
||||
return series.number ? `<ol class="series-items">${listItems}</ol>` : `<ul class="series-items">${listItems}</ul>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('series', series, { ends: false })
|
||||
/**
|
||||
* 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) {
|
||||
if (!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
|
||||
|
||||
return itemA < itemB ? (isAsc ? -1 : 1) : itemA > itemB ? (isAsc ? 1 : -1) : 0
|
||||
}
|
||||
|
||||
seriesArr.sort(compareFn)
|
||||
|
||||
const listItems = seriesArr.map(ele =>
|
||||
`<li><a href="${urlFor(ele.path)}" title="${ele.title}">${ele.title}</a></li>`
|
||||
).join('')
|
||||
|
||||
return series.number ? `<ol class="series-items">${listItems}</ol>` : `<ul class="series-items">${listItems}</ul>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('series', series, { ends: false })
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
/**
|
||||
* Tabs
|
||||
* transplant from hexo-theme-next
|
||||
* modify by Jerry
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
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] || 'tab'
|
||||
const tabActive = Number(args[1]) || 0
|
||||
const matches = []
|
||||
let match
|
||||
let tabId = 0
|
||||
let tabNav = ''
|
||||
let tabContent = ''
|
||||
let noDefault = true
|
||||
|
||||
while ((match = tabBlock.exec(content)) !== null) {
|
||||
matches.push(match[1], match[2])
|
||||
}
|
||||
|
||||
for (let i = 0; i < matches.length; i += 2) {
|
||||
const [tabCaption = '', tabIcon = ''] = matches[i].split('@')
|
||||
let postContent = matches[i + 1]
|
||||
|
||||
postContent = hexo.render.renderSync({ text: postContent, engine: 'markdown' }).trim()
|
||||
tabId += 1
|
||||
|
||||
const caption = (tabCaption || tabIcon) ? tabCaption : `${tabName} ${tabId}`
|
||||
const iconHtml = tabIcon ? `<i class="${tabIcon.trim()}"></i>` : ''
|
||||
const isActive = (tabActive > 0 && tabActive === tabId) || (tabActive === 0 && tabId === 1) ? ' active' : ''
|
||||
|
||||
if (isActive) noDefault = false
|
||||
|
||||
tabNav += `<button type="button" class="tab${isActive}">${iconHtml}${caption.trim()}</button>`
|
||||
tabContent += `<div class="tab-item-content${isActive}">${postContent}</div>`
|
||||
}
|
||||
|
||||
const toTop = '<div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div>'
|
||||
tabNav = `<div class="nav-tabs${noDefault ? ' no-default' : ''}">${tabNav}</div>`
|
||||
tabContent = `<div class="tab-contents">${tabContent}</div>`
|
||||
|
||||
return `<div class="tabs">${tabNav}${tabContent}${toTop}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('tabs', postTabs, { ends: true })
|
||||
hexo.extend.tag.register('subtabs', postTabs, { ends: true })
|
||||
hexo.extend.tag.register('subsubtabs', postTabs, { ends: true })
|
||||
/**
|
||||
* Tabs
|
||||
* transplant from hexo-theme-next
|
||||
* modify by Jerry
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
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] || 'tab'
|
||||
const tabActive = Number(args[1]) || 0
|
||||
const matches = []
|
||||
let match
|
||||
let tabId = 0
|
||||
let tabNav = ''
|
||||
let tabContent = ''
|
||||
let noDefault = true
|
||||
|
||||
while ((match = tabBlock.exec(content)) !== null) {
|
||||
matches.push(match[1], match[2])
|
||||
}
|
||||
|
||||
for (let i = 0; i < matches.length; i += 2) {
|
||||
const [tabCaption = '', tabIcon = ''] = matches[i].split('@')
|
||||
let postContent = matches[i + 1]
|
||||
|
||||
postContent = hexo.render.renderSync({ text: postContent, engine: 'markdown' }).trim()
|
||||
tabId += 1
|
||||
|
||||
const caption = (tabCaption || tabIcon) ? tabCaption : `${tabName} ${tabId}`
|
||||
const iconHtml = tabIcon ? `<i class="${tabIcon.trim()}"></i>` : ''
|
||||
const isActive = (tabActive > 0 && tabActive === tabId) || (tabActive === 0 && tabId === 1) ? ' active' : ''
|
||||
|
||||
if (isActive) noDefault = false
|
||||
|
||||
tabNav += `<button type="button" class="tab${isActive}">${iconHtml}${caption.trim()}</button>`
|
||||
tabContent += `<div class="tab-item-content${isActive}">${postContent}</div>`
|
||||
}
|
||||
|
||||
const toTop = '<div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div>'
|
||||
tabNav = `<div class="nav-tabs${noDefault ? ' no-default' : ''}">${tabNav}</div>`
|
||||
tabContent = `<div class="tab-contents">${tabContent}</div>`
|
||||
|
||||
return `<div class="tabs">${tabNav}${tabContent}${toTop}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('tabs', postTabs, { ends: true })
|
||||
hexo.extend.tag.register('subtabs', postTabs, { ends: true })
|
||||
hexo.extend.tag.register('subsubtabs', postTabs, { ends: true })
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
/**
|
||||
* Timeline tag for Hexo
|
||||
* Syntax:
|
||||
* {% timeline [headline],[color] %}
|
||||
* <!-- timeline [title] -->
|
||||
* [content]
|
||||
* <!-- endtimeline -->
|
||||
* <!-- timeline [title] -->
|
||||
* [content]
|
||||
* <!-- endtimeline -->
|
||||
* {% endtimeline %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const timeLineFn = (args, content) => {
|
||||
// Use named capture groups for better readability
|
||||
const tlBlock = /<!--\s*timeline\s*(?<title>.*?)\s*-->\n(?<content>[\s\S]*?)<!--\s*endtimeline\s*-->/g
|
||||
|
||||
// Pre-compile markdown render function
|
||||
const renderMd = text => hexo.render.renderSync({ text, engine: 'markdown' })
|
||||
|
||||
// Parse arguments more efficiently
|
||||
const [text, color = ''] = args.length ? args.join(' ').split(',') : []
|
||||
|
||||
// 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>`
|
||||
: ''
|
||||
|
||||
// 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('')
|
||||
|
||||
return `<div class="timeline ${color}">${headline}${items}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('timeline', timeLineFn, { ends: true })
|
||||
/**
|
||||
* Timeline tag for Hexo
|
||||
* Syntax:
|
||||
* {% timeline [headline],[color] %}
|
||||
* <!-- timeline [title] -->
|
||||
* [content]
|
||||
* <!-- endtimeline -->
|
||||
* <!-- timeline [title] -->
|
||||
* [content]
|
||||
* <!-- endtimeline -->
|
||||
* {% endtimeline %}
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const timeLineFn = (args, content) => {
|
||||
// Use named capture groups for better readability
|
||||
const tlBlock = /<!--\s*timeline\s*(?<title>.*?)\s*-->\n(?<content>[\s\S]*?)<!--\s*endtimeline\s*-->/g
|
||||
|
||||
// Pre-compile markdown render function
|
||||
const renderMd = text => hexo.render.renderSync({ text, engine: 'markdown' })
|
||||
|
||||
// Parse arguments more efficiently
|
||||
const [text, color = ''] = args.length ? args.join(' ').split(',') : []
|
||||
|
||||
// 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>`
|
||||
: ''
|
||||
|
||||
// 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('')
|
||||
|
||||
return `<div class="timeline ${color}">${headline}${items}</div>`
|
||||
}
|
||||
|
||||
hexo.extend.tag.register('timeline', timeLineFn, { ends: true })
|
||||
|
||||
Reference in New Issue
Block a user