@@ -96,6 +96,12 @@ def __init__(self, id: str = "theme-manager"):
9696 const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
9797 document.documentElement.classList.toggle('dark', systemPrefersDark);
9898 localStorage.removeItem('theme'); // Use system default
99+
100+ // Emit custom theme change event
101+ window.dispatchEvent(new CustomEvent('dashkit:theme-changed', {
102+ detail: { theme: 'system', isDark: systemPrefersDark }
103+ }));
104+
99105 return { theme: 'system' };
100106 }
101107 return window.dash_clientside.no_update;
@@ -114,6 +120,12 @@ def __init__(self, id: str = "theme-manager"):
114120 console.log('Setting theme to: light');
115121 document.documentElement.classList.remove('dark');
116122 localStorage.setItem('theme', 'light');
123+
124+ // Emit custom theme change event
125+ window.dispatchEvent(new CustomEvent('dashkit:theme-changed', {
126+ detail: { theme: 'light', isDark: false }
127+ }));
128+
117129 return { theme: 'light' };
118130 }
119131 return window.dash_clientside.no_update;
@@ -132,6 +144,12 @@ def __init__(self, id: str = "theme-manager"):
132144 console.log('Setting theme to: dark');
133145 document.documentElement.classList.add('dark');
134146 localStorage.setItem('theme', 'dark');
147+
148+ // Emit custom theme change event
149+ window.dispatchEvent(new CustomEvent('dashkit:theme-changed', {
150+ detail: { theme: 'dark', isDark: true }
151+ }));
152+
135153 return { theme: 'dark' };
136154 }
137155 return window.dash_clientside.no_update;
@@ -234,6 +252,12 @@ def __init__(self, id: str = "theme-manager"):
234252 const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
235253 const handleSystemChange = (e) => {
236254 document.documentElement.classList.toggle('dark', e.matches);
255+
256+ // Emit custom theme change event for system theme changes
257+ window.dispatchEvent(new CustomEvent('dashkit:theme-changed', {
258+ detail: { theme: 'system', isDark: e.matches }
259+ }));
260+
237261 // Trigger table theme update by updating the theme store
238262 const themeStore = document.querySelector('#theme-store');
239263 if (themeStore && window.dash_clientside) {
@@ -258,3 +282,70 @@ def __init__(self, id: str = "theme-manager"):
258282 Input ("theme-store" , "data" ),
259283 prevent_initial_call = False ,
260284 )
285+
286+ # Add mantine and plotly theme management callback
287+ clientside_callback (
288+ """
289+ function(data) {
290+ const theme = data && data.theme ? data.theme : 'system';
291+ let isDark = false;
292+
293+ if (theme === 'dark') {
294+ isDark = true;
295+ } else if (theme === 'system') {
296+ isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
297+ }
298+
299+ // Update Mantine theme
300+ const mantineProvider = document.querySelector('[data-mantine-color-scheme]');
301+ if (mantineProvider) {
302+ mantineProvider.setAttribute('data-mantine-color-scheme', isDark ? 'dark' : 'light');
303+ }
304+
305+ // Update all Plotly figures to use dark theme
306+ if (window.Plotly) {
307+ const plotlyDivs = document.querySelectorAll('div[id*="graph"], div.plotly-graph-div');
308+ plotlyDivs.forEach(div => {
309+ if (div._fullData && div._fullLayout) {
310+ const newTemplate = isDark ? 'plotly_dark' : 'plotly';
311+ window.Plotly.relayout(div, {
312+ template: newTemplate
313+ });
314+ }
315+ });
316+ }
317+
318+ // Listen for theme change events and update themes accordingly
319+ if (!window.themeChangeListener) {
320+ window.themeChangeListener = function(event) {
321+ const isDarkTheme = event.detail.isDark;
322+
323+ // Update Mantine theme
324+ const mantineProvider = document.querySelector('[data-mantine-color-scheme]');
325+ if (mantineProvider) {
326+ mantineProvider.setAttribute('data-mantine-color-scheme', isDarkTheme ? 'dark' : 'light');
327+ }
328+
329+ // Update Plotly figures
330+ if (window.Plotly) {
331+ const plotlyDivs = document.querySelectorAll('div[id*="graph"], div.plotly-graph-div');
332+ plotlyDivs.forEach(div => {
333+ if (div._fullData && div._fullLayout) {
334+ const newTemplate = isDarkTheme ? 'plotly_dark' : 'plotly';
335+ window.Plotly.relayout(div, {
336+ template: newTemplate
337+ });
338+ }
339+ });
340+ }
341+ };
342+ window.addEventListener('dashkit:theme-changed', window.themeChangeListener);
343+ }
344+
345+ return window.dash_clientside.no_update;
346+ }
347+ """ ,
348+ Output ("theme-store" , "storage_type" ),
349+ Input ("theme-store" , "data" ),
350+ prevent_initial_call = False ,
351+ )
0 commit comments