[feat] support run-time theme switch, and visitor preferred theme (#449)

This commit is contained in:
calfzhou 2024-04-28 00:56:26 +08:00 committed by GitHub
parent 4f62677468
commit 09d91d06b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 139 additions and 57 deletions

View File

@ -272,6 +272,9 @@ footer:
# comments:
# icon: '<img src="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/social/942ebbf1a4b91.svg"/>'
# url: /about/#comments
# theme:
# icon: default:theme
# onclick: 'switchTheme()'
sitemap:
# '博客':
# - '[近期](/)'

View File

@ -32,6 +32,7 @@ default:category: <svg style="margin-bottom:1px" xmlns="http://www.w3.org/2000/s
default:edit: <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M11.943 1.25H13.5a.75.75 0 0 1 0 1.5H12c-2.378 0-4.086.002-5.386.176c-1.279.172-2.05.5-2.62 1.069c-.569.57-.896 1.34-1.068 2.619c-.174 1.3-.176 3.008-.176 5.386s.002 4.086.176 5.386c.172 1.279.5 2.05 1.069 2.62c.57.569 1.34.896 2.619 1.068c1.3.174 3.008.176 5.386.176s4.086-.002 5.386-.176c1.279-.172 2.05-.5 2.62-1.069c.569-.57.896-1.34 1.068-2.619c.174-1.3.176-3.008.176-5.386v-1.5a.75.75 0 0 1 1.5 0v1.557c0 2.309 0 4.118-.19 5.53c-.194 1.444-.6 2.584-1.494 3.479c-.895.895-2.035 1.3-3.48 1.494c-1.411.19-3.22.19-5.529.19h-.114c-2.309 0-4.118 0-5.53-.19c-1.444-.194-2.584-.6-3.479-1.494c-.895-.895-1.3-2.035-1.494-3.48c-.19-1.411-.19-3.22-.19-5.529v-.114c0-2.309 0-4.118.19-5.53c.194-1.444.6-2.584 1.494-3.479c.895-.895 2.035-1.3 3.48-1.494c1.411-.19 3.22-.19 5.529-.19m4.827 1.026a3.503 3.503 0 0 1 4.954 4.953l-6.648 6.649c-.371.37-.604.604-.863.806a5.34 5.34 0 0 1-.987.61c-.297.141-.61.245-1.107.411l-2.905.968a1.492 1.492 0 0 1-1.887-1.887l.968-2.905c.166-.498.27-.81.411-1.107c.167-.35.372-.68.61-.987c.202-.26.435-.492.806-.863zm3.893 1.06a2.003 2.003 0 0 0-2.832 0l-.376.377c.022.096.054.21.098.338c.143.413.415.957.927 1.469a3.875 3.875 0 0 0 1.807 1.025l.376-.376a2.003 2.003 0 0 0 0-2.832m-1.558 4.391a5.397 5.397 0 0 1-1.686-1.146a5.395 5.395 0 0 1-1.146-1.686L11.218 9.95c-.417.417-.58.582-.72.76a3.84 3.84 0 0 0-.437.71c-.098.203-.172.423-.359.982l-.431 1.295l1.032 1.033l1.295-.432c.56-.187.779-.261.983-.358c.251-.12.49-.267.71-.439c.177-.139.342-.302.759-.718z" clip-rule="evenodd"/></svg>
default:upup: <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 12c0-4.714 0-7.071 1.464-8.536C4.93 2 7.286 2 12 2c4.714 0 7.071 0 8.535 1.464C22 4.93 22 7.286 22 12c0 4.714 0 7.071-1.465 8.535C19.072 22 16.714 22 12 22s-7.071 0-8.536-1.465C2 19.072 2 16.714 2 12Z"/><path stroke-linecap="round" stroke-linejoin="round" d="m9 15.5l3-3l3 3m-6-4l3-3l3 3"/></g></svg>
default:tocomment: <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M10.46 1.25h3.08c1.603 0 2.86 0 3.864.095c1.023.098 1.861.3 2.6.752a5.75 5.75 0 0 1 1.899 1.899c.452.738.654 1.577.752 2.6c.095 1.004.095 2.261.095 3.865v1.067c0 1.141 0 2.036-.05 2.759c-.05.735-.153 1.347-.388 1.913a5.75 5.75 0 0 1-3.112 3.112c-.805.334-1.721.408-2.977.43a10.81 10.81 0 0 0-.929.036c-.198.022-.275.054-.32.08c-.047.028-.112.078-.224.232c-.121.166-.258.396-.476.764l-.542.916c-.773 1.307-2.69 1.307-3.464 0l-.542-.916a10.605 10.605 0 0 0-.476-.764c-.112-.154-.177-.204-.224-.232c-.045-.026-.122-.058-.32-.08c-.212-.023-.49-.03-.93-.037c-1.255-.021-2.171-.095-2.976-.429A5.75 5.75 0 0 1 1.688 16.2c-.235-.566-.338-1.178-.389-1.913c-.049-.723-.049-1.618-.049-2.76v-1.066c0-1.604 0-2.86.095-3.865c.098-1.023.3-1.862.752-2.6a5.75 5.75 0 0 1 1.899-1.899c.738-.452 1.577-.654 2.6-.752C7.6 1.25 8.857 1.25 10.461 1.25M6.739 2.839c-.914.087-1.495.253-1.959.537A4.25 4.25 0 0 0 3.376 4.78c-.284.464-.45 1.045-.537 1.96c-.088.924-.089 2.11-.089 3.761v1c0 1.175 0 2.019.046 2.685c.045.659.131 1.089.278 1.441a4.25 4.25 0 0 0 2.3 2.3c.515.214 1.173.294 2.429.316h.031c.398.007.747.013 1.037.045c.311.035.616.104.909.274c.29.17.5.395.682.645c.169.232.342.525.538.856l.559.944a.52.52 0 0 0 .882 0l.559-.944c.196-.331.37-.624.538-.856c.182-.25.392-.476.682-.645c.293-.17.598-.24.909-.274c.29-.032.639-.038 1.037-.045h.032c1.255-.022 1.913-.102 2.428-.316a4.25 4.25 0 0 0 2.3-2.3c.147-.352.233-.782.278-1.441c.046-.666.046-1.51.046-2.685v-1c0-1.651 0-2.837-.089-3.762c-.087-.914-.253-1.495-.537-1.959a4.25 4.25 0 0 0-1.403-1.403c-.464-.284-1.045-.45-1.96-.537c-.924-.088-2.11-.089-3.761-.089h-3c-1.651 0-2.837 0-3.762.089" clip-rule="evenodd"/><path fill="currentColor" d="M9 11a1 1 0 1 1-2 0a1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0a1 1 0 0 1 2 0m4 0a1 1 0 1 1-2 0a1 1 0 0 1 2 0"/></svg>
default:theme: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path fill="currentColor" fill-rule="evenodd" d="M582.4 326.4c-140.8 0-256 115.2-256 256s115.2 256 256 256 256-115.2 256-256-115.2-256-256-256z m0 448c-70.4 0-131.2-36.8-164.8-92.8 12.8 3.2 27.2 4.8 40 4.8 121.6 0 219.2-99.2 219.2-219.2 0-17.6-1.6-35.2-6.4-52.8 60.8 32 102.4 96 102.4 169.6 1.6 104-84.8 190.4-190.4 190.4zM582.4 262.4c17.6 0 32-14.4 32-32v-128c0-17.6-14.4-32-32-32s-32 14.4-32 32v128c0 17.6 14.4 32 32 32zM262.4 582.4c0-17.6-14.4-32-32-32h-128c-17.6 0-32 14.4-32 32s14.4 32 32 32h128c17.6 0 32-14.4 32-32zM310.4 356.8c6.4 6.4 14.4 9.6 22.4 9.6 8 0 16-3.2 22.4-9.6 12.8-12.8 12.8-32 0-44.8l-91.2-91.2c-12.8-12.8-32-12.8-44.8 0-12.8 12.8-12.8 32 0 44.8l91.2 91.2zM944 220.8c-12.8-12.8-32-12.8-44.8 0l-91.2 91.2c-12.8 12.8-12.8 32 0 44.8 6.4 6.4 14.4 9.6 22.4 9.6 8 0 16-3.2 22.4-9.6l91.2-91.2c12.8-12.8 12.8-33.6 0-44.8zM310.4 808l-91.2 91.2c-12.8 12.8-12.8 32 0 44.8 6.4 6.4 14.4 9.6 22.4 9.6 8 0 16-3.2 22.4-9.6l91.2-91.2c12.8-12.8 12.8-32 0-44.8-11.2-11.2-32-11.2-44.8 0z"></path></svg>
github:logo: <svg aria-hidden="true" role="img" class="color-icon-primary" viewBox="0 0 16 16" width="1em" height="1em" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path></svg>
github:repo: <svg aria-hidden="true" role="img" class="color-icon-primary" viewBox="0 0 16 16" width="1em" height="1em" fill="currentColor" style="user-select:none;overflow:visible"><path fill-rule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"></path></svg>

View File

@ -53,6 +53,10 @@ search:
message:
copied: Copied!
theme_switched:
light: Switched to Light Mode
dark: Switched to Dark Mode
auto: Switched to Auto Mode
symbol:
comma: ", "

View File

@ -53,6 +53,10 @@ search:
message:
copied: 复制成功
theme_switched:
light: 切换到浅色模式
dark: 切换到深色模式
auto: 切换到跟随系统配色
symbol:
comma: ""

View File

@ -53,6 +53,10 @@ search:
message:
copied: 複製成功
theme_switched:
light: 切換到淺色模式
dark: 切換到深色模式
auto: 切換到跟隨系統配色
symbol:
comma: ""

View File

@ -22,6 +22,8 @@ function custom_inject() {
<!-- required -->
<script src="<%- `${theme.stellar.main_js}?v=${stellar_info('version')}` %>" async></script>
<%- partial('scripts/theme') %>
<!-- optional -->
<%- partial('comments/script') %>

View File

@ -0,0 +1,62 @@
<script type="text/javascript">
const applyTheme = (theme) => {
if (theme === 'auto') {
document.documentElement.removeAttribute('data-theme')
} else {
document.documentElement.setAttribute('data-theme', theme)
}
applyThemeToGiscus(theme)
}
const applyThemeToGiscus = (theme) => {
theme = theme === 'auto' ? 'preferred_color_scheme' : theme
const cmt = document.getElementById('giscus')
if (cmt) {
// This works before giscus load.
cmt.setAttribute('data-theme', theme)
}
const iframe = document.querySelector('#comments > section.giscus > iframe')
if (iframe) {
// This works after giscus loaded.
const src = iframe.src
const newSrc = src.replace(/theme=[\w]+/, `theme=${theme}`)
iframe.src = newSrc
}
}
const switchTheme = () => {
// light -> dark -> auto -> light -> ...
const currentTheme = document.documentElement.getAttribute('data-theme')
let newTheme;
switch (currentTheme) {
case 'light':
newTheme = 'dark'
break
case 'dark':
newTheme = 'auto'
break
default:
newTheme = 'light'
}
applyTheme(newTheme)
window.localStorage.setItem('Stellar.theme', newTheme)
const messages = {
light: `<%- __('message.theme_switched.light') %>`,
dark: `<%- __('message.theme_switched.dark') %>`,
auto: `<%- __('message.theme_switched.auto') %>`,
}
hud?.toast?.(messages[newTheme])
}
(() => {
// Apply user's preferred theme, if any.
const theme = window.localStorage.getItem('Stellar.theme')
if (theme !== null) {
applyTheme(theme)
}
})()
</script>

View File

@ -37,7 +37,11 @@ if (theme.style.site && theme.style.site['background-image']) {
}
var html = `<!DOCTYPE html>`
html += `<html lang="${page.lang}">`
if (theme.style.prefers_theme === 'auto') {
html += `<html lang="${page.lang}">`
} else {
html += `<html lang="${page.lang}" data-theme="${theme.style.prefers_theme}">`
}
html += partial('_partial/head')
html += `<body>`
html += site_background

View File

@ -59,9 +59,9 @@ a.button.start.gradient
&:hover:after
filter: blur(36px)
opacity 1
if theme(dark)
:root[data-theme="dark"] &
ondark()
else if theme(auto)
:root:not([data-theme]) &
@media (prefers-color-scheme: dark)
ondark()

View File

@ -27,9 +27,9 @@
trans1: all
ondark()
--blur-bg: alpha(#000, .4)
if theme(dark)
:root[data-theme="dark"] &
ondark()
else if theme(auto)
:root:not([data-theme]) &
@media (prefers-color-scheme: dark)
ondark()
@ -52,7 +52,7 @@
//
.l_body[leftbar] .float-panel, .l_body[rightbar] .float-panel
box-shadow: 0 0 4px -1px $color-theme, 0 0 16px -4px $color-theme, 0 0 32px -12px $color-theme, 0 0 128px -32px $color-theme
.l_body[leftbar] .float-panel button.leftbar-toggle
background: var(--alpha100)

View File

@ -26,7 +26,7 @@
.l_body[text-indent] .article.banner .content .bottom.only-title
justify-content: center
//
.article.banner
@ -50,8 +50,8 @@
--button-hover-bg: rgba(black, 0.05)
ondark()
--button-hover-bg: rgba(white, 0.15)
if theme(dark)
:root[data-theme="dark"] &
ondark()
else if theme(auto)
:root:not([data-theme]) &
@media (prefers-color-scheme: dark)
ondark()

View File

@ -109,9 +109,9 @@ _dark_tags()
set_text_black()
if theme(dark)
:root[data-theme="dark"]
_dark_tags()
else if theme(auto)
:root:not([data-theme])
@media (prefers-color-scheme: dark)
_dark_tags()

View File

@ -113,13 +113,12 @@ hoverable-card()
ondark()
&:hover
box-shadow: 0 0 4px -2px $color-theme, 0 0 24px -8px $color-theme
if theme(light)
:root[data-theme="light"] &
onlight()
else if theme(dark)
:root[data-theme="dark"] &
ondark()
else
:root:not([data-theme]) &
@media (prefers-color-scheme: light)
onlight()
@media (prefers-color-scheme: dark)
ondark()

View File

@ -1,3 +1,4 @@
// Deprecated function. Keep for compatibility.
theme($t)
convert(hexo-config('style.prefers_theme')) == $t
@ -40,47 +41,45 @@ _common_root()
--theme-link: $color-link
_light_root()
:root
--site-bg: hsl($color-background-h, $color-background-s, $color-background-l)
--card: hsl($color-block-h, $color-block-s, 100)
--block: hsl($color-block-h, $color-block-s, 95)
--block-border: hsl($color-block-h, $color-block-s, 90)
--block-hover: hsl($color-block-h, $color-block-s, 92)
--theme-link-opa: rgba($color-link, 0.2)
--leftbar-bg: hsl($color-block-h, $color-block-s, 90)
--alpha20: rgba(white, 0.2)
--alpha50: rgba(white, 0.5)
--alpha60: rgba(white, 0.6)
--alpha75: rgba(white, 0.75)
--alpha100: white
_dark_text()
--site-bg: hsl($color-background-h, $color-background-s, $color-background-l)
--card: hsl($color-block-h, $color-block-s, 100)
--block: hsl($color-block-h, $color-block-s, 95)
--block-border: hsl($color-block-h, $color-block-s, 90)
--block-hover: hsl($color-block-h, $color-block-s, 92)
--theme-link-opa: rgba($color-link, 0.2)
--leftbar-bg: hsl($color-block-h, $color-block-s, 90)
--alpha20: rgba(white, 0.2)
--alpha50: rgba(white, 0.5)
--alpha60: rgba(white, 0.6)
--alpha75: rgba(white, 0.75)
--alpha100: white
_dark_text()
_dark_root()
:root
--site-bg: hsl($color-background-h, $color-background-s * 0.5, (100 - $color-background-l) * 2 + 8)
--card: hsl($color-block-h, $color-block-s * 1.2, 24)
--block: hsl($color-block-h, $color-block-s, 16)
--block-border: hsl($color-block-h, $color-block-s, 24)
--block-hover: hsl($color-block-h, $color-block-s, 20)
--theme-link-opa: rgba($color-link, 0.4)
--leftbar-bg: hsl($color-block-h, $color-block-s, 24)
--alpha20: rgba(black, 0.2)
--alpha50: rgba(black, 0.5)
--alpha60: rgba(black, 0.6)
--alpha75: rgba(black, 0.75)
--alpha100: black
_light_text()
@media screen and (max-width: $device-mobile-max)
--site-bg: black
--site-bg: hsl($color-background-h, $color-background-s * 0.5, (100 - $color-background-l) * 2 + 8)
--card: hsl($color-block-h, $color-block-s * 1.2, 24)
--block: hsl($color-block-h, $color-block-s, 16)
--block-border: hsl($color-block-h, $color-block-s, 24)
--block-hover: hsl($color-block-h, $color-block-s, 20)
--theme-link-opa: rgba($color-link, 0.4)
--leftbar-bg: hsl($color-block-h, $color-block-s, 24)
--alpha20: rgba(black, 0.2)
--alpha50: rgba(black, 0.5)
--alpha60: rgba(black, 0.6)
--alpha75: rgba(black, 0.75)
--alpha100: black
_light_text()
@media screen and (max-width: $device-mobile-max)
--site-bg: black
_common_root()
//
if theme(light)
:root[data-theme="light"]
_light_root()
else if theme(dark)
:root[data-theme="dark"]
_dark_root()
else
:root:not([data-theme])
@media (prefers-color-scheme: light)
_light_root()
@media (prefers-color-scheme: dark)
_dark_root()
_dark_root()

View File

@ -36,7 +36,7 @@
--waline-border: 1px solid var(--waline-border-color);
--waline-avatar-radius: 50%;
--waline-box-shadow: none;
.cmt-body.waline
ondark()
--waline-white: #000;
@ -61,8 +61,8 @@
font-size: 1.25em;
color: #fff;
if theme(dark)
:root[data-theme="dark"] &
ondark()
else if theme(auto)
:root:not([data-theme]) &
@media (prefers-color-scheme: dark)
ondark()

View File

@ -108,8 +108,8 @@ _dark_mermaid()
fill: #ccc
if theme(dark)
:root[data-theme="dark"]
_dark_mermaid()
else if theme(auto)
:root:not([data-theme])
@media (prefers-color-scheme: dark)
_dark_mermaid()