Mesh:Tool: restore light mode + follow the CMMS theme

Upstream 913977ec hard-wired set_darkmode() to dark and rewrote
web/mesh/index.css to be dark-only. Restored the dark-conditional body of
set_darkmode() from 913977ec^; the boot call now takes its arg from
MESH_TOOL_CONFIG.dark (parsed from a new cmms_dark=1|0 query param that
public/mesh-edit.php sets from theme_is_dark()), defaulting to dark when
absent so the freestanding app is unchanged. Added a scoped
#app:not(.dark) light-chrome layer to index.css (additive; never matches
in the always-dark freestanding app).
This commit is contained in:
Stuart 2026-08-31 11:42:07 +10:00
commit ba806a55af
2 changed files with 55 additions and 8 deletions

View file

@ -166,6 +166,11 @@ function init() {
// read from regardless of how config arrived.
const cmmsParams = new URLSearchParams(location.search);
const cmmsLoadUrl = cmmsParams.get('cmms_load');
// CMMS light/dark: cmms_dark=1|0 from theme_is_dark() (public/mesh-edit.php).
// Absent for non-CMMS use -> undefined -> boot defaults to dark (below), so
// the freestanding app keeps today's look.
const cmmsDarkParam = cmmsParams.get('cmms_dark');
const cmmsDark = cmmsDarkParam === null ? undefined : cmmsDarkParam === '1';
if (cmmsLoadUrl) {
self.MESH_TOOL_CONFIG = {
loadUrl: cmmsLoadUrl,
@ -173,9 +178,11 @@ function init() {
ownerToken: cmmsParams.get('cmms_owner'),
csrfToken: cmmsParams.get('cmms_csrf'),
originalName: cmmsParams.get('cmms_name'),
dark: cmmsDark,
};
motoClient.on('ready', () => cmms_load_from_url(self.MESH_TOOL_CONFIG));
} else {
self.MESH_TOOL_CONFIG = { dark: cmmsDark };
// reload stored space when worker is ready
motoClient.on('ready', restore_space);
}
@ -263,7 +270,8 @@ async function restore_workspace_from_state(cached = {}, mcache = {}) {
let sklist = api.sketch.list().filter(s => selist.contains(s.id));
api.selection.set([...smodel, ...sgroup, ...sklist], [...tmodel, ...tgroup]);
api.mode[mode]();
set_darkmode();
let bootDark = (self.MESH_TOOL_CONFIG || {}).dark;
set_darkmode(bootDark === undefined ? true : bootDark);
});
});
}
@ -968,22 +976,34 @@ function object_destroy(id) {
}
// listen for changes like dark mode toggle
// CMMS patch: upstream 913977ec hard-wired this to dark (deleting the light
// branch). Restored from 913977ec^ so the Mesh:Tool follows the CMMS light/dark
// theme (boot arg from MESH_TOOL_CONFIG.dark, default dark for non-CMMS use).
function set_darkmode(dark) {
let { prefs, model } = api;
let { sky, platform } = space;
dark = true;
prefs.map.space.dark = true;
materials.wireframe.color.set(0xaaaaaa);
materials.wireline.color.set(0xaaaaaa);
prefs.map.space.dark = dark;
if (dark) {
materials.wireframe.color.set(0xaaaaaa);
materials.wireline.color.set(0xaaaaaa);
$('app')?.classList.add('dark');
} else {
materials.wireframe.color.set(0, 0, 0);
materials.wireline.color.set(0, 0, 0);
$('app')?.classList.remove('dark');
}
sky.set({
color: 0,
ambient: { intensity: 0.55 }
color: dark ? 0 : 0xffffff,
ambient: { intensity: dark ? 0.55 : 1.1 }
});
platform.set({
light: 0.08,
grid: {
grid: dark ? {
colorMajor: 0x666666,
colorMinor: 0x333333,
} : {
colorMajor: 0xcccccc,
colorMinor: 0xeeeeee,
},
});
api.updateFog();

View file

@ -925,3 +925,30 @@ button:hover {
@keyframes spin {
to { transform: rotate(360deg) }
}
/* CMMS patch (not upstream): commit 913977ec made this stylesheet dark-only -
it baked the dark palette into the base rules and deleted every .dark
selector. The 3D scene follows the CMMS light/dark theme via set_darkmode()
(src/main/mesh.js); this re-lights the surrounding chrome when the CMMS
theme is light, keyed on #app NOT carrying the .dark class set_darkmode()
toggles. Additive and scoped - the freestanding app is always dark, so
#app:not(.dark) never matches there. Not exhaustive - transient surfaces
(boot curtain, spinner) stay dark. */
#app:not(.dark) {
--accent: #2563eb;
--menu-blue: #2563eb;
--menu-back: rgba(248,250,252,0.97);
--border: #cbd5e1;
background: #f1f5f9;
color: #1e293b;
}
#app:not(.dark) #container { background: #f1f5f9; }
#app:not(.dark) #top { color: #1e293b; }
#app:not(.dark) #top-doc-name { border-color: #cbd5e1; background-color: #e2e8f0; }
#app:not(.dark) #top-doc-name:hover { background-color: rgba(0,0,0,0.08); }
#app:not(.dark) #modal_frame { background-color: rgba(248,250,252,0.97); color: #1e293b; }
#app:not(.dark) #modal_title { color: #1e293b; background-color: rgba(226,232,240,0.9); }
#app:not(.dark) #modal_title_close { color: #64748b; }
#app:not(.dark) #modal_title_close:hover { color: #1e293b; }
#app:not(.dark) .menu-items > div:hover { color: #1e293b; }
#app:not(.dark) #logger { color: #334155; }