feat(theme): 主题整套联动——界面配色跟随文档主题(docs/22)

六套文档主题各加一组同气质的界面变量(data-doc-theme 驱动),选什么
主题,标题栏/菜单/侧边栏/状态栏就穿什么配色;界面跟随当前生效主题
(含单文档临时主题)。视图「深色主题」开关撤下,明暗并入主题;
data-theme 退化为 paperTone 派生信号供 Mermaid/源码编辑器读取。
This commit is contained in:
Muse
2026-11-14 15:57:23 +08:00
parent e94034c9a8
commit d637f0a849
4 changed files with 68 additions and 17 deletions

View File

@@ -196,7 +196,6 @@ export default function App() {
const uiSaveTimerRef = useRef<number | undefined>(undefined)
useEffect(() => {
document.documentElement.dataset.theme = ui.theme
if (!uiLoadedRef.current) return
window.clearTimeout(uiSaveTimerRef.current)
uiSaveTimerRef.current = window.setTimeout(() => {
@@ -228,6 +227,9 @@ export default function App() {
const effectiveDocTheme = (tab ? docOverrides[tab.id] : undefined) ?? ui.docTheme
useEffect(() => {
document.documentElement.dataset.docTheme = effectiveDocTheme
// 整套联动(docs/22):界面配色由 CSS 按 data-doc-theme 接管;
// data-theme 退化为明暗派生信号(深色纸面主题 = dark),供 Mermaid 等读取。
document.documentElement.dataset.theme = docThemeById(effectiveDocTheme).paperTone === 'dark' ? 'dark' : 'light'
}, [effectiveDocTheme])
useEffect(() => {
@@ -1157,7 +1159,6 @@ export default function App() {
{ label: '文档大纲', checked: sidebarMode === 'outline', onClick: () => { setSidebarMode('outline'); setUi((u) => ({ ...u, sidebar: true })) } },
{ divider: true },
{ label: '源代码模式', checked: sourceMode, disabled: !tab, onClick: toggleSourceMode },
{ label: '深色主题', checked: ui.theme === 'dark', onClick: () => setUi((u) => ({ ...u, theme: u.theme === 'dark' ? 'light' : 'dark' })) },
{ label: `自动保存(${ui.autosaveSeconds} 秒)`, checked: ui.autosave, onClick: () => setUi((u) => ({ ...u, autosave: !u.autosave })) },
{ label: '专注模式', checked: ui.focusMode, disabled: sourceMode, onClick: () => setUi((u) => ({ ...u, focusMode: !u.focusMode })) },
{ label: '打字机模式', checked: ui.typewriter, disabled: sourceMode, onClick: () => setUi((u) => ({ ...u, typewriter: !u.typewriter })) },
@@ -1260,9 +1261,7 @@ export default function App() {
tabId={tab.id}
initialText={tab.content}
initialCursorOffset={sourceCursorOffset}
dark={docThemeById(effectiveDocTheme).paperTone
? docThemeById(effectiveDocTheme).paperTone === 'dark'
: ui.theme === 'dark'}
dark={docThemeById(effectiveDocTheme).paperTone === 'dark'}
onChange={(text) => dispatch({ type: 'updateContent', id: tab.id, content: text })}
onReady={(api) => { sourceApiRef.current = api }}
/>

View File

@@ -26,7 +26,7 @@ export function AppearanceModal({ docTheme, override, customCss, autosave, autos
<div className="modal-backdrop" onClick={onClose}>
<div className="modal" style={{ width: 560 }} onClick={(e) => e.stopPropagation()}>
<h3>外观与设置</h3>
<div className="setting-label">文档主题(作用于编辑区排版)</div>
<div className="setting-label">主题(文档排版与界面配色整套生效)</div>
<div className="theme-grid">
{DOC_THEMES.map((t) => (
<button

View File

@@ -12,17 +12,39 @@
--hover: #e9e9e6;
--code-bg: #f4f4f2;
}
html[data-theme='dark'] {
--bg: #2b2b2b;
--bg-panel: #252525;
--bg-editor: #1f1f1f;
--border: #3a3a3a;
--text: #d6d6d3;
--text-dim: #9a9a96;
--accent: #7d93b2;
--accent-weak: #333c48;
--hover: #333333;
--code-bg: #2c2c2c;
/* ——— 主题整套联动:界面配色跟随当前文档主题(docs/22) ———
文档主题什么样,窗口框架就穿什么样:每套文档主题在这里给出同气质的
界面变量(背景/面板/边框/文字/强调色)。默认主题用 :root 基础值。
data-theme 只保留为「明暗」派生信号供 Mermaid 等 JS 消费,不再定义变量。 */
html[data-doc-theme='github'] {
--bg: #f6f8fa; --bg-panel: #eef1f4; --bg-editor: #ffffff;
--border: #d8dee4; --text: #1f2328; --text-dim: #59636e;
--accent: #0969da; --accent-weak: #e8f1fc; --hover: #eaeef2; --code-bg: #f6f8fa;
}
html[data-doc-theme='notion'] {
--bg: #f7f6f3; --bg-panel: #f1f0ec; --bg-editor: #ffffff;
--border: #e6e4e0; --text: #37352f; --text-dim: #787774;
--accent: #37352f; --accent-weak: #eceae6; --hover: #edece9; --code-bg: #f7f6f3;
}
html[data-doc-theme='simple-blue'] {
--bg: #f5f8fd; --bg-panel: #ecf2fb; --bg-editor: #ffffff;
--border: #d7e3f6; --text: #1e2a38; --text-dim: #5b7186;
--accent: #2563eb; --accent-weak: #e2ebfc; --hover: #e8effc; --code-bg: #eef4fd;
}
html[data-doc-theme='dark-eye'] {
--bg: #1d221c; --bg-panel: #181c17; --bg-editor: #20261f;
--border: #39412f; --text: #c9d1c0; --text-dim: #9aa78f;
--accent: #9ec49a; --accent-weak: #2e3a2c; --hover: #2a322a; --code-bg: #2a322a;
}
html[data-doc-theme='focus'] {
--bg: #f7f4ee; --bg-panel: #f0ebdf; --bg-editor: #fffdf8;
--border: #e2dac6; --text: #3a362c; --text-dim: #857d68;
--accent: #8a6d3b; --accent-weak: #ede4cd; --hover: #eee8d8; --code-bg: #f3efe4;
}
html[data-doc-theme='paper'] {
--bg: #f3ecd7; --bg-panel: #ede3c8; --bg-editor: #f7f1e3;
--border: #ddd0a8; --text: #433422; --text-dim: #8a7a52;
--accent: #8a5a2b; --accent-weak: #e9dcb6; --hover: #ece0ba; --code-bg: #efe6d0;
}
* { box-sizing: border-box; }
html, body, #root { height: 100%; margin: 0; }