Skip to content

Commit 4f43f92

Browse files
committed
feat: events on theme change
1 parent f7bc5db commit 4f43f92

3 files changed

Lines changed: 96 additions & 9 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "dash-dashkit"
3-
version = "1.3.1"
3+
version = "1.4.0"
44
description = "Modern dashboard components for Dash applications"
55
readme = "README.md"
66
requires-python = ">=3.10"

src/dashkit/theme_manager.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
)

uv.lock

Lines changed: 4 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)