feat: 前台明暗切换改为本机偏好,不再要求登录

- 新增 src/theme.ts:localStorage 的 stash-theme 作为本机偏好,优先于站点默认
- 前台页头的月亮/太阳只写本机偏好,未登录也能用,刷新后保持
- 后台「页头 → 配色」与后台页头按钮改的是站点默认值;后台按钮同时清掉本机偏好,
  保证点完看到的就是新默认
- 两个壳都按「本机偏好 ?? 站点默认」决定 data-scheme
This commit is contained in:
2026-11-01 19:00:05 +08:00
parent 84fc148a39
commit 923903b4b2
3 changed files with 62 additions and 26 deletions
+6 -4
View File
@@ -26,6 +26,7 @@ import { useEffect, useMemo, useState } from 'react'
import { changePassword, fetchSession, logout, type SessionState } from '../../auth'
import { LoginDialog } from '../auth/LoginDialog'
import { GroupMark as GroupGlyph } from '../common/GroupMark'
import { isDarkScheme, readThemeOverride, writeThemeOverride } from '../../theme'
import {
fetchSettings,
saveSettings,
@@ -135,7 +136,8 @@ export function AdminNext() {
if (meta === undefined) return
const title = meta.title.trim()
if (title !== '') window.document.title = title
window.document.documentElement.dataset.scheme = meta.theme
// 本机偏好优先于站点默认,跟前台一致
window.document.documentElement.dataset.scheme = readThemeOverride() ?? meta.theme
const href = meta.favicon.trim() === '' ? '/favicon.svg' : meta.favicon.trim()
let link = window.document.head.querySelector<HTMLLinkElement>('link[rel="icon"]')
if (link === null) {
@@ -178,15 +180,15 @@ export function AdminNext() {
toast.success('侧边栏已保存')
}
/** 页头的明暗切换:写回 site.theme,前后台一起变 */
/** 页头的明暗切换:改的是站点默认值,并清掉本机偏好,保证点完看到的就是新默认 */
const themeSetting = draft?.site.theme ?? document?.settings.site.theme ?? 'auto'
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
const isDark = themeSetting === 'dark' || (themeSetting === 'auto' && prefersDark)
const isDark = isDarkScheme(readThemeOverride() ?? themeSetting)
const toggleTheme = async () => {
if (document === null || draft === null) return
const next = isDark ? 'light' : 'dark'
setSaving(true)
writeThemeOverride(null)
const result = await saveSettings(document.version, {
...draft,
site: { ...draft.site, theme: next },