Skip to content

Commit dffce16

Browse files
Don't create a new theme for each view
1 parent 2aa57ac commit dffce16

1 file changed

Lines changed: 85 additions & 61 deletions

File tree

js/src/VuetifyView.js

Lines changed: 85 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,32 @@ import * as Vue from "vue"; // eslint-disable-line import/no-extraneous-dependen
22
import { VueView, createViewContext, vueRender } from "jupyter-vue";
33
import "vuetify/styles";
44
import colors from "vuetify/lib/util/colors.mjs";
5-
import { createVuetify, useTheme } from "vuetify";
5+
import { createVuetify } from "vuetify";
66
import * as components from "vuetify/components";
77
import * as directives from "vuetify/directives";
88
import { VDataTable } from "vuetify/labs/VDataTable";
99
import { ThemeColorsModel, ThemeModel } from "./Themes";
1010

11-
const observer = new MutationObserver((mutationList, observer) => {
11+
// Every widget view gets its own Vue app, but all views for one widget manager
12+
// should share a single Vuetify plugin and theme state.
13+
const managerStateByWidgetManager = new WeakMap();
14+
15+
function getManagerState(widgetManager) {
16+
let managerState = managerStateByWidgetManager.get(widgetManager);
17+
if (!managerState) {
18+
managerState = {
19+
themeInitialized: false,
20+
vuetify: createVuetify({
21+
components: { ...components, VDataTable },
22+
directives,
23+
}),
24+
};
25+
managerStateByWidgetManager.set(widgetManager, managerState);
26+
}
27+
return managerState;
28+
}
29+
30+
const observer = new MutationObserver((mutationList) => {
1231
for (const mutation of mutationList) {
1332
if (mutation.type === "childList") {
1433
const overlay = document.querySelector(".v-overlay-container");
@@ -26,10 +45,7 @@ observer.observe(document.body, { childList: true });
2645
export class VuetifyView extends VueView {
2746
addPlugins(vueApp) {
2847
super.addPlugins(vueApp);
29-
const vuetify = createVuetify({
30-
components: { ...components, VDataTable },
31-
directives,
32-
});
48+
const { vuetify } = getManagerState(this.model.widget_manager);
3349
this.el.classList.add("vuetify-styles");
3450
document.querySelector("html").style.fontSize = "16px";
3551
vueApp.use(vuetify);
@@ -73,67 +89,75 @@ export class VuetifyView extends VueView {
7389
if (!this.themeModel) {
7490
return;
7591
}
76-
this.theme = useTheme();
77-
78-
if (ThemeModel.themeManager) {
79-
const setAutoTheme = () => {
80-
if (this.themeModel.get("dark") === null) {
81-
const isDark = document.body.dataset.jpThemeLight === "false";
82-
this.theme.global.name.value = isDark ? "dark" : "light";
83-
this.themeModel.set("dark_jlab", isDark);
84-
this.themeModel.save_changes();
85-
}
86-
};
87-
ThemeModel.themeManager.themeChanged.connect(() => {
88-
setAutoTheme();
89-
}, this);
90-
setAutoTheme();
92+
const managerState = getManagerState(this.model.widget_manager);
93+
if (!managerState.themeInitialized) {
94+
initializeTheme(
95+
managerState,
96+
this.themeModel,
97+
this.themeLightModel,
98+
this.themeDarkModel
99+
);
91100
}
101+
}
102+
}
92103

93-
const onDark = () => {
94-
this.theme.global.name.value = this.themeModel.get("dark")
95-
? "dark"
96-
: "light";
97-
};
98-
99-
const onColorsLight = () => {
100-
this.theme.themes.value.light.colors = getColors(this.themeLightModel);
101-
};
102-
onColorsLight();
103-
104-
const onColorsDark = () => {
105-
this.theme.themes.value.dark.colors = getColors(this.themeDarkModel);
104+
function initializeTheme(
105+
managerState,
106+
themeModel,
107+
themeLightModel,
108+
themeDarkModel
109+
) {
110+
const theme = managerState.vuetify.theme;
111+
112+
if (ThemeModel.themeManager) {
113+
const setAutoTheme = () => {
114+
if (themeModel.get("dark") === null) {
115+
const isDark = document.body.dataset.jpThemeLight === "false";
116+
theme.global.name.value = isDark ? "dark" : "light";
117+
themeModel.set("dark_jlab", isDark);
118+
themeModel.save_changes();
119+
}
106120
};
107-
onColorsDark();
108-
109-
if (this.themeModel.get("dark") !== null) {
110-
onDark();
111-
} else if (document.body.dataset.jpThemeLight) {
112-
const isDark = document.body.dataset.jpThemeLight === "false";
113-
this.theme.global.name.value = isDark ? "dark" : "light";
114-
this.themeModel.set("dark_jlab", isDark);
115-
this.themeModel.save_changes();
116-
} else if (document.body.classList.contains("theme-dark")) {
117-
this.theme.global.name.value = "dark";
118-
this.themeModel.set("dark", true);
119-
this.themeModel.save_changes();
120-
} else if (document.body.classList.contains("theme-light")) {
121-
this.themeModel.set("dark", false);
122-
this.themeModel.save_changes();
123-
}
124-
125-
Vue.onMounted(() => {
126-
this.themeModel.on("change:dark", onDark);
127-
this.themeLightModel.on("change", onColorsLight);
128-
this.themeDarkModel.on("change", onColorsDark);
121+
ThemeModel.themeManager.themeChanged.connect(() => {
122+
setAutoTheme();
129123
});
124+
setAutoTheme();
125+
}
130126

131-
Vue.onUnmounted(() => {
132-
this.themeModel.off("change:dark", onDark);
133-
this.themeLightModel.off("change", onColorsLight);
134-
this.themeDarkModel.off("change", onColorsDark);
135-
});
127+
const onDark = () => {
128+
theme.global.name.value = themeModel.get("dark") ? "dark" : "light";
129+
};
130+
131+
const onColorsLight = () => {
132+
theme.themes.value.light.colors = getColors(themeLightModel);
133+
};
134+
onColorsLight();
135+
136+
const onColorsDark = () => {
137+
theme.themes.value.dark.colors = getColors(themeDarkModel);
138+
};
139+
onColorsDark();
140+
141+
if (themeModel.get("dark") !== null) {
142+
onDark();
143+
} else if (document.body.dataset.jpThemeLight) {
144+
const isDark = document.body.dataset.jpThemeLight === "false";
145+
theme.global.name.value = isDark ? "dark" : "light";
146+
themeModel.set("dark_jlab", isDark);
147+
themeModel.save_changes();
148+
} else if (document.body.classList.contains("theme-dark")) {
149+
theme.global.name.value = "dark";
150+
themeModel.set("dark", true);
151+
themeModel.save_changes();
152+
} else if (document.body.classList.contains("theme-light")) {
153+
themeModel.set("dark", false);
154+
themeModel.save_changes();
136155
}
156+
157+
themeModel.on("change:dark", onDark);
158+
themeLightModel.on("change", onColorsLight);
159+
themeDarkModel.on("change", onColorsDark);
160+
managerState.themeInitialized = true;
137161
}
138162

139163
function parseColor(colorStr) {

0 commit comments

Comments
 (0)