improvement

This commit is contained in:
myw
2026-07-14 14:41:41 +08:00 Unverified
parent f4a6f79142
commit 37233ab28b
18 changed files with 1718 additions and 1660 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ const lazyload = htmlContent => {
// Handle src attributes with double quotes, single quotes, or no quotes (unified approach)
// Matches: src="..." or src='...' or src=... (e.g., after minification by hexo-minify)
return htmlContent.replace(/(<img(?![^>]*?\bdata-lazy-src=)(?:\s[^>]*?)?\ssrc=)(?:"([^"]*)"|'([^']*)'|([^\s>]+))(?![^<]*<\/script>)/gi, (match, prefix, srcDoubleQuote, srcSingleQuote, srcNoQuote) => {
const src = srcDoubleQuote || srcSingleQuote || srcNoQuote
const src = srcDoubleQuote ?? srcSingleQuote ?? srcNoQuote
return `${prefix}"${bg}" data-lazy-src="${src}"`
})
}
+51 -32
View File
@@ -6,33 +6,46 @@
hexo.extend.generator.register('post', locals => {
const imgTestReg = /\.(png|jpe?g|gif|svg|webp|avif)(\?.*)?$/i
const remoteImgReg = /^(?:https?:)?\/\//i
const dataImgReg = /^data:image\//i
const { post_asset_folder: postAssetFolder } = hexo.config
const { cover: { default_cover: defaultCover } } = hexo.theme.config
const isImage = value => {
return typeof value === 'string' &&
(remoteImgReg.test(value) || dataImgReg.test(value) || imgTestReg.test(value))
}
function * createCoverGenerator () {
if (!defaultCover) {
if (!defaultCover || (Array.isArray(defaultCover) && defaultCover.length === 0)) {
while (true) yield false
}
if (!Array.isArray(defaultCover)) {
while (true) yield defaultCover
}
const coverCount = defaultCover.length
if (coverCount === 1) {
if (defaultCover.length === 1) {
while (true) yield defaultCover[0]
}
const coverCount = defaultCover.length
const maxHistory = Math.min(3, coverCount - 1)
const history = []
while (true) {
let index
do {
index = Math.floor(Math.random() * coverCount)
} while (history.includes(index))
history.push(index)
if (history.length > maxHistory) history.shift()
if (history.length > maxHistory) {
history.shift()
}
yield defaultCover[index]
}
@@ -40,32 +53,31 @@ hexo.extend.generator.register('post', locals => {
const coverGenerator = createCoverGenerator()
const resolvePostAsset = (value, postPath) => {
if (
!postAssetFolder ||
typeof value !== 'string' ||
value.includes('/') ||
!imgTestReg.test(value)
) {
return value
}
return `${postPath}${value}`
}
const handleImg = data => {
let { cover: coverVal, top_img: topImg, pagination_cover: paginationCover } = data
data.top_img = resolvePostAsset(data.top_img, data.path)
data.cover = resolvePostAsset(data.cover, data.path)
data.pagination_cover = resolvePostAsset(data.pagination_cover, data.path)
// Add path to top_img and cover if post_asset_folder is enabled
if (postAssetFolder) {
if (topImg && topImg.indexOf('/') === -1 && imgTestReg.test(topImg)) {
data.top_img = `${data.path}${topImg}`
}
if (coverVal && coverVal.indexOf('/') === -1 && imgTestReg.test(coverVal)) {
data.cover = `${data.path}${coverVal}`
}
if (paginationCover && paginationCover.indexOf('/') === -1 && imgTestReg.test(paginationCover)) {
data.pagination_cover = `${data.path}${paginationCover}`
}
if (data.cover === false) return data
if (!data.cover) {
data.cover = coverGenerator.next().value
}
if (coverVal === false) return data
// If cover is not set, use random cover
if (!coverVal) {
const randomCover = coverGenerator.next().value
data.cover = randomCover
coverVal = randomCover
}
if (coverVal && (coverVal.indexOf('//') !== -1 || imgTestReg.test(coverVal))) {
if (isImage(data.cover)) {
data.cover_type = 'img'
}
@@ -75,16 +87,23 @@ hexo.extend.generator.register('post', locals => {
const posts = locals.posts.sort('date').toArray()
const { length } = posts
return posts.map((post, i) => {
if (i) post.prev = posts[i - 1]
if (i < length - 1) post.next = posts[i + 1]
return posts.map((post, index) => {
const data = post
post.__post = true
if (index > 0) {
data.prev = posts[index - 1]
}
if (index < length - 1) {
data.next = posts[index + 1]
}
data.__post = true
return {
data: handleImg(post),
data: handleImg(data),
layout: 'post',
path: post.path
path: data.path
}
})
})
+89 -37
View File
@@ -11,46 +11,87 @@ hexo.extend.helper.register('inject_head_js', function () {
const createCustomJs = () => `
const saveToLocal = {
set: (key, value, ttl) => {
if (!ttl) return
const expiry = Date.now() + ttl * 86400000
localStorage.setItem(key, JSON.stringify({ value, expiry }))
const data = { value }
if (ttl != null) {
data.expiry = Date.now() + ttl * 86400000
}
localStorage.setItem(key, JSON.stringify(data))
},
get: key => {
const itemStr = localStorage.getItem(key)
if (!itemStr) return undefined
const { value, expiry } = JSON.parse(itemStr)
if (Date.now() > expiry) {
if (!itemStr) return
try {
const data = JSON.parse(itemStr)
if (data.expiry && Date.now() > data.expiry) {
localStorage.removeItem(key)
return
}
return data.value
} catch {
localStorage.removeItem(key)
return undefined
}
return value
}
}
const scriptCache = new Map()
const cssCache = new Map()
window.btf = {
saveToLocal,
getScript: (url, attr = {}) => new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.async = true
Object.entries(attr).forEach(([key, val]) => script.setAttribute(key, val))
script.onload = script.onreadystatechange = () => {
if (!script.readyState || /loaded|complete/.test(script.readyState)) resolve()
getScript: (url, attr = {}) => {
if (scriptCache.has(url)) {
return scriptCache.get(url)
}
script.onerror = reject
document.head.appendChild(script)
}),
getCSS: (url, id) => new Promise((resolve, reject) => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = url
if (id) link.id = id
link.onload = link.onreadystatechange = () => {
if (!link.readyState || /loaded|complete/.test(link.readyState)) resolve()
const promise = new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.async = true
for (const key in attr) {
script.setAttribute(key, attr[key])
}
script.onload = resolve
script.onerror = reject
document.head.appendChild(script)
})
scriptCache.set(url, promise)
return promise
},
getCSS: (url, id) => {
if (cssCache.has(url)) {
return cssCache.get(url)
}
link.onerror = reject
document.head.appendChild(link)
}),
const promise = new Promise((resolve, reject) => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = url
if (id) {
link.id = id
}
link.onload = resolve
link.onerror = reject
document.head.appendChild(link)
})
cssCache.set(url, promise)
return promise
},
addGlobalFn: (key, fn, name = false, parent = window) => {
if (!${pjax.enable} && key.startsWith('pjax')) return
const globalFn = parent.globalFn || {}
@@ -65,16 +106,17 @@ hexo.extend.helper.register('inject_head_js', function () {
if (!darkmode.enable) return ''
let darkmodeJs = `
const metaThemeColor = document.querySelector('meta[name="theme-color"]')
const activateDarkMode = () => {
document.documentElement.setAttribute('data-theme', 'dark')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorDark}')
document.documentElement.dataset.theme = 'dark'
if (metaThemeColor !== null) {
metaThemeColor.setAttribute('content', '${themeColorDark}')
}
}
const activateLightMode = () => {
document.documentElement.setAttribute('data-theme', 'light')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '${themeColorLight}')
document.documentElement.dataset.theme = 'light'
if (metaThemeColor !== null) {
metaThemeColor.setAttribute('content', '${themeColorLight}')
}
}
@@ -95,10 +137,15 @@ hexo.extend.helper.register('inject_head_js', function () {
else if (mediaQueryDark.matches) activateDarkMode()
else {
const hour = new Date().getHours()
const isNight = hour <= ${start} || hour >= ${end}
const start = ${start}
const end = ${end}
const isNight =
start < end
? hour < start || hour >= end
: hour >= start || hour < end
isNight ? activateDarkMode() : activateLightMode()
}
mediaQueryDark.addEventListener('change', () => {
mediaQueryDark.addEventListener('change', e => {
if (saveToLocal.get('theme') === undefined) {
e.matches ? activateDarkMode() : activateLightMode()
}
@@ -111,7 +158,12 @@ hexo.extend.helper.register('inject_head_js', function () {
case 2:
darkmodeJs += `
const hour = new Date().getHours()
const isNight = hour <= ${start} || hour >= ${end}
const start = ${start}
const end = ${end}
const isNight =
start < end
? hour < start || hour >= end
: hour >= start || hour < end
if (theme === undefined) isNight ? activateDarkMode() : activateLightMode()
else theme === 'light' ? activateLightMode() : activateDarkMode()
`