diff --git a/frontend-web/src/strategy-components/components/resource-management/llmwiki/WeKnoraKnowledgeDetailPage.tsx b/frontend-web/src/strategy-components/components/resource-management/llmwiki/WeKnoraKnowledgeDetailPage.tsx index a7484cfd..919cb543 100644 --- a/frontend-web/src/strategy-components/components/resource-management/llmwiki/WeKnoraKnowledgeDetailPage.tsx +++ b/frontend-web/src/strategy-components/components/resource-management/llmwiki/WeKnoraKnowledgeDetailPage.tsx @@ -28,7 +28,7 @@ function cssVar(name: string, fallback = ""): string { function collectThemePayload(): DeerFlowThemePayload { const isDark = document.documentElement.classList.contains("dark") || - document.documentElement.dataset.theme === "dark"; + document.documentElement.getAttribute("theme-mode") === "dark"; return { type: "deerflow-weknora-theme", theme: isDark ? "dark" : "light", @@ -91,7 +91,9 @@ export function WeKnoraKnowledgeDetailPage() { const path = session.frame_path.startsWith("/") ? session.frame_path : `/${session.frame_path}`; - setFrameSrc(`${base}${path}`); + const nextUrl = new URL(`${base}${path}`); + nextUrl.searchParams.set("theme", collectThemePayload().theme); + setFrameSrc(nextUrl.toString()); }) .catch((error: unknown) => { if (cancelled) return; @@ -112,7 +114,7 @@ export function WeKnoraKnowledgeDetailPage() { const observer = new MutationObserver(send); observer.observe(document.documentElement, { attributes: true, - attributeFilter: ["class", "style", "data-theme"], + attributeFilter: ["class", "style", "data-theme", "theme-mode"], }); window.addEventListener("storage", send); return () => { diff --git a/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py b/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py index 09b39451..f7dc777e 100644 --- a/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py +++ b/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py @@ -644,10 +644,17 @@ html.deerflow-weknora-embed [class*=" guide__"] {{ function tone(color, alpha) {{ return `color-mix(in srgb, ${{color}} ${{Math.round(alpha * 100)}}%, transparent)`; }} + let applyingTheme = false; function applyTheme(message) {{ if (!message || message.type !== "deerflow-weknora-theme") return; + applyingTheme = true; + window.__deerflowWeKnoraTheme = message; const vars = message.vars || {{}}; const dark = message.theme === "dark"; + root.classList.toggle("dark", dark); + root.setAttribute("theme-mode", dark ? "dark" : "light"); + root.setAttribute("data-theme-mode", dark ? "dark" : "light"); + root.setAttribute("data-theme", dark ? "dark" : "light"); const pairs = {{ "--td-brand-color": vars.primary, "--td-brand-color-hover": vars.primary, @@ -675,8 +682,31 @@ html.deerflow-weknora-embed [class*=" guide__"] {{ if (value) root.style.setProperty(key, value); }} root.style.colorScheme = dark ? "dark" : "light"; + try {{ + localStorage.setItem("theme-mode", dark ? "dark" : "light"); + localStorage.setItem("tdesign-starter-theme-mode", dark ? "dark" : "light"); + localStorage.setItem("weknora-theme-mode", dark ? "dark" : "light"); + }} catch (_) {{}} + window.setTimeout(() => {{ applyingTheme = false; }}, 0); }} window.addEventListener("message", (event) => applyTheme(event.data)); + const urlTheme = new URLSearchParams(location.search).get("theme"); + if (urlTheme === "dark" || urlTheme === "light") {{ + applyTheme({{ + type: "deerflow-weknora-theme", + theme: urlTheme, + vars: {{ + primary: urlTheme === "dark" ? "#2b81ff" : "#0062d9", + background: urlTheme === "dark" ? "#0e172b" : "#ffffff", + foreground: urlTheme === "dark" ? "#eff2f5" : "#202a3a", + card: urlTheme === "dark" ? "#1a2539" : "#ffffff", + muted: urlTheme === "dark" ? "#232e40" : "#f3f5f8", + mutedForeground: urlTheme === "dark" ? "#8e9aa4" : "#7f7f7f", + border: urlTheme === "dark" ? "rgba(255,255,255,0.12)" : "#dbdbdb", + destructive: "#d54941" + }} + }}); + }} const allowedPath = cfg.allowedPath; function allowedUrl(url) {{ @@ -705,6 +735,14 @@ html.deerflow-weknora-embed [class*=" guide__"] {{ try {{ node.remove(); }} catch (_) {{}} }}); }} + let themeRefreshTimer = 0; + function refreshThemeSoon() {{ + if (applyingTheme || !window.__deerflowWeKnoraTheme || themeRefreshTimer) return; + themeRefreshTimer = window.setTimeout(() => {{ + themeRefreshTimer = 0; + applyTheme(window.__deerflowWeKnoraTheme); + }}, 80); + }} const rawPushState = history.pushState.bind(history); const rawReplaceState = history.replaceState.bind(history); history.pushState = (state, title, url) => rawPushState(state, title, url ? allowedUrl(url) : location.href); @@ -734,8 +772,11 @@ html.deerflow-weknora-embed [class*=" guide__"] {{ ready = true; root.classList.add("deerflow-weknora-ready"); }} - const readyObserver = new MutationObserver(() => markReady(false)); - readyObserver.observe(document.documentElement, {{ childList: true, subtree: true }}); + const readyObserver = new MutationObserver(() => {{ + markReady(false); + refreshThemeSoon(); + }}); + readyObserver.observe(document.documentElement, {{ childList: true, subtree: true, attributes: true, attributeFilter: ["class", "style", "data-theme", "theme-mode"] }}); if (document.readyState === "complete") {{ setTimeout(() => markReady(false), 180); }} else {{