From 6a6a2d6006a3b5bad89ef0dc9a5de33e7ca37c84 Mon Sep 17 00:00:00 2001 From: Aisland Date: Tue, 1 Sep 2026 21:48:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(console):=20=E7=BA=AF=E8=89=B2=E8=83=8C?= =?UTF-8?q?=E6=99=AF=E9=BB=98=E8=AE=A4/=E6=81=A2=E5=A4=8D=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E4=B8=8E=E4=B8=BB=E9=A2=98=E8=81=94=E5=8A=A8=E2=80=94?= =?UTF-8?q?=E2=80=94=E6=B7=B1=E8=89=B2=3D=E5=8E=9F=E6=B7=B1=E8=93=9D?= =?UTF-8?q?=E9=BB=91=E3=80=81=E6=B5=85=E8=89=B2=3D=E7=99=BD#eef1f5?= =?UTF-8?q?=EF=BC=9B=E7=BD=91=E6=A0=BC=E7=BA=BF=E9=9A=8F=E4=B8=BB=E9=A2=98?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E8=87=AA=E5=8A=A8=E5=8F=98=E7=81=B0=EF=BC=9B?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E4=B8=BB=E9=A2=98=E6=97=B6=E6=9C=AA=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E7=9A=84=E7=BA=AF=E8=89=B2=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E8=B7=9F=E9=9A=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 01_content/lib/client.js | 26 +++++++++++++++++++++++--- 01_content/src/client/split.tsx | 31 ++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/01_content/lib/client.js b/01_content/lib/client.js index d52f115..342a44c 100644 --- a/01_content/lib/client.js +++ b/01_content/lib/client.js @@ -17379,6 +17379,8 @@ function HslValInput(props) { } ); } +var PLAIN_HSL_DARK = { h: -140, s: 31, l: 6 }; +var PLAIN_HSL_LIGHT = { h: -146, s: 26, l: 95 }; function ConsolePane() { const [, setTick] = (0, import_react.useState)(0); const [now, setNow] = (0, import_react.useState)(() => Date.now()); @@ -17394,7 +17396,11 @@ function ConsolePane() { const photoUrlRef = (0, import_react.useRef)(""); const [openMenu, setOpenMenu] = (0, import_react.useState)(null); const [bgEdit, setBgEdit] = (0, import_react.useState)(null); - const [plainHsl, setPlainHslState] = (0, import_react.useState)(() => splitEnv?.console?.getPlainHsl?.() ?? { h: -140, s: 31, l: 6 }); + const [plainHsl, setPlainHslState] = (0, import_react.useState)(() => { + const saved = splitEnv?.console?.getPlainHsl?.(); + if (saved) return saved; + return splitEnv?.console?.getTheme?.() === "light" ? { ...PLAIN_HSL_LIGHT } : { ...PLAIN_HSL_DARK }; + }); const [glowHsl, setGlowHslState] = (0, import_react.useState)(() => splitEnv?.console?.getGlowHsl?.() ?? { h: 0, s: 100, l: 100 }); const [photoHsl, setPhotoHslState] = (0, import_react.useState)({ h: 0, s: 100, l: 100 }); const gridRef = (0, import_react.useRef)(null); @@ -17538,8 +17544,9 @@ function ConsolePane() { }; const resetHsl = (kind) => { if (kind === "plain") { - setPlainHslState({ h: -140, s: 31, l: 6 }); - splitEnv?.console?.setPlainHsl?.({ h: -140, s: 31, l: 6 }); + const def = resolvedTheme === "light" ? { ...PLAIN_HSL_LIGHT } : { ...PLAIN_HSL_DARK }; + setPlainHslState(def); + splitEnv?.console?.setPlainHsl?.(def); } else if (kind === "glow") { setGlowHslState({ h: 0, s: 100, l: 100 }); splitEnv?.console?.setGlowHsl?.({ h: 0, s: 100, l: 100 }); @@ -17666,6 +17673,19 @@ function ConsolePane() { setThemeMode(th); env?.setTheme?.(th); }; + const prevPlainThemeRef = (0, import_react.useRef)(null); + (0, import_react.useEffect)(() => { + const prev = prevPlainThemeRef.current; + prevPlainThemeRef.current = resolvedTheme; + if (!prev || prev === resolvedTheme) return; + const isDarkDef = plainHsl.h === PLAIN_HSL_DARK.h && plainHsl.s === PLAIN_HSL_DARK.s && plainHsl.l === PLAIN_HSL_DARK.l; + const isLightDef = plainHsl.h === PLAIN_HSL_LIGHT.h && plainHsl.s === PLAIN_HSL_LIGHT.s && plainHsl.l === PLAIN_HSL_LIGHT.l; + const next = resolvedTheme === "light" && isDarkDef ? { ...PLAIN_HSL_LIGHT } : resolvedTheme === "dark" && isLightDef ? { ...PLAIN_HSL_DARK } : null; + if (next) { + setPlainHslState(next); + splitEnv?.console?.setPlainHsl?.(next); + } + }, [resolvedTheme]); const fmtDur = (ms) => { const s = Math.max(0, Math.floor(ms / 1e3)); const h = Math.floor(s / 3600); diff --git a/01_content/src/client/split.tsx b/01_content/src/client/split.tsx index 5cbc72b..0507c9a 100644 --- a/01_content/src/client/split.tsx +++ b/01_content/src/client/split.tsx @@ -1081,6 +1081,10 @@ function HslValInput(props: { value: number; max: number; min?: number; onCommit ) } +/** 纯色背景默认值(与主题关联):深色 = 原深蓝黑 #0a0d13;浅色 = 白 #eef1f5;网格线由 --wt-grid 主题变量自动切换 */ +const PLAIN_HSL_DARK = { h: -140, s: 31, l: 6 } +const PLAIN_HSL_LIGHT = { h: -146, s: 26, l: 95 } + /** 控制室面板:项目卡片网格(每行 3 张、超出换行);数据由工作台组装推送(纯读镜像)。 * 主题:dark/light 直接生效;system = 跟随宿主 html 的 color-scheme(DSH 深色/白色/跟随系统都会反映到它) */ function ConsolePane() { @@ -1098,7 +1102,11 @@ function ConsolePane() { const photoUrlRef = useRef('') const [openMenu, setOpenMenu] = useState(null) const [bgEdit, setBgEdit] = useState<'plain' | 'glow' | 'photo' | null>(null) - const [plainHsl, setPlainHslState] = useState<{ h: number; s: number; l: number }>(() => splitEnv?.console?.getPlainHsl?.() ?? { h: -140, s: 31, l: 6 }) + const [plainHsl, setPlainHslState] = useState<{ h: number; s: number; l: number }>(() => { + const saved = splitEnv?.console?.getPlainHsl?.() + if (saved) return saved + return splitEnv?.console?.getTheme?.() === 'light' ? { ...PLAIN_HSL_LIGHT } : { ...PLAIN_HSL_DARK } + }) const [glowHsl, setGlowHslState] = useState<{ h: number; s: number; l: number }>(() => splitEnv?.console?.getGlowHsl?.() ?? { h: 0, s: 100, l: 100 }) const [photoHsl, setPhotoHslState] = useState<{ h: number; s: number; l: number }>({ h: 0, s: 100, l: 100 }) const gridRef = useRef(null) @@ -1222,8 +1230,9 @@ function ConsolePane() { } const resetHsl = (kind: 'plain' | 'glow' | 'photo') => { if (kind === 'plain') { - setPlainHslState({ h: -140, s: 31, l: 6 }) - splitEnv?.console?.setPlainHsl?.({ h: -140, s: 31, l: 6 }) + const def = resolvedTheme === 'light' ? { ...PLAIN_HSL_LIGHT } : { ...PLAIN_HSL_DARK } + setPlainHslState(def) + splitEnv?.console?.setPlainHsl?.(def) } else if (kind === 'glow') { setGlowHslState({ h: 0, s: 100, l: 100 }) splitEnv?.console?.setGlowHsl?.({ h: 0, s: 100, l: 100 }) @@ -1316,6 +1325,22 @@ function ConsolePane() { return sysDark ? 'dark' : 'light' })() const setTheme = (th: 'dark' | 'light' | 'system') => { setThemeMode(th); env?.setTheme?.(th) } + // 主题联动:切换主题时,若纯色还是另一主题的默认值 → 自动跟随新主题默认;自定义过则保持 + const prevPlainThemeRef = useRef<'dark' | 'light' | null>(null) + useEffect(() => { + const prev = prevPlainThemeRef.current + prevPlainThemeRef.current = resolvedTheme + if (!prev || prev === resolvedTheme) return + const isDarkDef = plainHsl.h === PLAIN_HSL_DARK.h && plainHsl.s === PLAIN_HSL_DARK.s && plainHsl.l === PLAIN_HSL_DARK.l + const isLightDef = plainHsl.h === PLAIN_HSL_LIGHT.h && plainHsl.s === PLAIN_HSL_LIGHT.s && plainHsl.l === PLAIN_HSL_LIGHT.l + const next = resolvedTheme === 'light' && isDarkDef ? { ...PLAIN_HSL_LIGHT } + : resolvedTheme === 'dark' && isLightDef ? { ...PLAIN_HSL_DARK } : null + if (next) { + setPlainHslState(next) + splitEnv?.console?.setPlainHsl?.(next) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [resolvedTheme]) const fmtDur = (ms: number) => { const s = Math.max(0, Math.floor(ms / 1000)) const h = Math.floor(s / 3600)