Skip to content

Commit 9bdc173

Browse files
committed
Enable dark mode HTML graph
1 parent 7c20fc3 commit 9bdc173

File tree

2 files changed

+94
-6
lines changed

2 files changed

+94
-6
lines changed

website/src/theme/Root.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React, { useEffect } from 'react';
2+
import { useColorMode } from '@docusaurus/theme-common';
3+
4+
export default function Root({ children }) {
5+
const { colorMode } = useColorMode();
6+
7+
useEffect(() => {
8+
// Function to send theme to all iframes
9+
const sendThemeToIframes = () => {
10+
const iframes = document.querySelectorAll('iframe');
11+
iframes.forEach((iframe) => {
12+
try {
13+
iframe.contentWindow.postMessage(
14+
{
15+
type: 'themeChange',
16+
theme: colorMode,
17+
},
18+
'*'
19+
);
20+
} catch (e) {
21+
// Ignore errors
22+
}
23+
});
24+
};
25+
26+
// Send theme when it changes
27+
sendThemeToIframes();
28+
29+
// Also send theme on a slight delay to catch lazy-loaded iframes
30+
const timer = setTimeout(sendThemeToIframes, 100);
31+
32+
// Listen for theme requests from iframes
33+
const handleMessage = (event) => {
34+
if (event.data && event.data.type === 'requestTheme') {
35+
event.source.postMessage(
36+
{
37+
type: 'themeChange',
38+
theme: colorMode,
39+
},
40+
'*'
41+
);
42+
}
43+
};
44+
45+
window.addEventListener('message', handleMessage);
46+
47+
return () => {
48+
clearTimeout(timer);
49+
window.removeEventListener('message', handleMessage);
50+
};
51+
}, [colorMode]);
52+
53+
return <>{children}</>;
54+
}
55+

website/static/img/cart_pole_graph.html

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -260,15 +260,43 @@ <h1></h1>
260260
}
261261
}
262262

263+
// Message handler for cross-origin theme communication
264+
let parentTheme = null;
265+
266+
window.addEventListener('message', (event) => {
267+
// Accept messages from any origin (parent page)
268+
if (event.data && event.data.type === 'themeChange') {
269+
const isDark = event.data.theme === 'dark';
270+
parentTheme = event.data.theme;
271+
272+
if (!manualThemeSet) {
273+
updateThemeUI(isDark);
274+
currentTheme = isDark ? 'dark' : 'light';
275+
updateNodeColors(isDark);
276+
}
277+
}
278+
});
279+
263280
function checkDarkMode() {
264281
// If user manually set theme, use that
265282
if (manualThemeSet) {
266283
const storedTheme = localStorage.getItem('vis-theme');
267284
return storedTheme === 'dark';
268285
}
269286

287+
// If in iframe and we received theme from parent via postMessage
288+
if (isInIframe && parentTheme) {
289+
const isDark = parentTheme === 'dark';
290+
updateThemeUI(isDark);
291+
if (currentTheme !== parentTheme && typeof network !== 'undefined' && network !== null) {
292+
currentTheme = parentTheme;
293+
updateNodeColors(isDark);
294+
}
295+
return isDark;
296+
}
297+
270298
try {
271-
// Check parent window's theme (when embedded in iframe)
299+
// Try to check parent window's theme (works in same-origin only)
272300
if (isInIframe && window.parent && window.parent.document) {
273301
const isDark = window.parent.document.documentElement.getAttribute('data-theme') === 'dark';
274302
const newTheme = isDark ? 'dark' : 'light';
@@ -285,7 +313,7 @@ <h1></h1>
285313
return isDark;
286314
}
287315
} catch (e) {
288-
// Cross-origin or error
316+
// Cross-origin error - wait for postMessage instead
289317
}
290318

291319
// Standalone mode: check URL parameter first
@@ -311,6 +339,11 @@ <h1></h1>
311339
updateThemeUI(prefersDark);
312340
return prefersDark;
313341
}
342+
343+
// Request initial theme from parent
344+
if (isInIframe) {
345+
window.parent.postMessage({ type: 'requestTheme' }, '*');
346+
}
314347

315348
// Function to toggle theme manually
316349
function toggleTheme() {
@@ -360,16 +393,16 @@ <h1></h1>
360393
const initialDark = checkDarkMode();
361394
currentTheme = initialDark ? 'dark' : 'light';
362395

363-
// Listen for theme changes in parent (only if in iframe and not manually set)
396+
// For same-origin iframes, poll occasionally as backup
364397
if (isInIframe) {
365398
setInterval(() => {
366-
if (!manualThemeSet) {
399+
if (!manualThemeSet && !parentTheme) {
367400
checkDarkMode();
368401
}
369-
}, 100);
402+
}, 500); // Less frequent polling as backup
370403
}
371404

372-
// Also listen to system preference changes
405+
// Also listen to system preference changes (for standalone mode)
373406
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
374407
if (!manualThemeSet && !isInIframe) {
375408
const isDark = e.matches;

0 commit comments

Comments
 (0)