From 6f65836a227a9876a59d148286d342e0e66ec27c Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 12 Mar 2025 15:10:26 +0100 Subject: [PATCH] [ADD] runbot_merge: color theme switcher Uses localStorage rather than the odoo backend cookie because Odoo *requires* the cookie, it can't fallback on the system theme, and we might want a different color theme on the frontend and backend since the frontend dark theme is pretty half-assed. Also load the file by hand, as adding it to `assets_frontend` causes a flash of system color theme. It would probably be possible to create an asset which is not deferred or lazy (but wouldn't be async either which is a shame), but I can't be arsed. Part of #1088 --- runbot_merge/static/scss/revariable.scss | 15 ++++++-- runbot_merge/static/src/js/runbot_merge.js | 42 ++++++++++++++++++++++ runbot_merge/views/templates.xml | 16 +++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 runbot_merge/static/src/js/runbot_merge.js diff --git a/runbot_merge/static/scss/revariable.scss b/runbot_merge/static/scss/revariable.scss index e813ed71..0a327d15 100644 --- a/runbot_merge/static/scss/revariable.scss +++ b/runbot_merge/static/scss/revariable.scss @@ -1,6 +1,6 @@ // resets a bunch of CSS rules to either `inherit` color or use CSS variables, // such that they properly follow CSS variables -:root { +:root, :root.light { color-scheme: light dark; // dunno why it's not global @@ -17,11 +17,11 @@ // adjusting the conversion just set the value we want --danger-bg-rgb: 242, 222, 222; } + @function invlight($value) { @return hsl(hue($value), saturation($value), 100% - lightness($value)); } -@media (prefers-color-scheme: dark) { - :root { +@mixin darkrules { $ibc: invlight($body-color); --body-color: #{$ibc}; --body-color-rgb: #{to-rgb($ibc)}; @@ -41,8 +41,17 @@ ))}; } --danger-bg-rgb: 41, 10, 10; +} + +:root.dark { + @include darkrules; +} +@media (prefers-color-scheme: dark) { + :root:not(.light) { + @include darkrules; } } + body { font-family: inherit; } diff --git a/runbot_merge/static/src/js/runbot_merge.js b/runbot_merge/static/src/js/runbot_merge.js new file mode 100644 index 00000000..fa258f5e --- /dev/null +++ b/runbot_merge/static/src/js/runbot_merge.js @@ -0,0 +1,42 @@ +function setColorScheme(t) { + const classes = document.documentElement.classList; + classes.remove('light', 'dark'); + + const buttons = document.querySelectorAll('.theme-toggle button'); + for(const button of buttons) { + button.classList.toggle( + 'active', + (t === 'light' && button.classList.contains('fa-sun-o')) + || (t === 'dark' && button.classList.contains('fa-moon-o')) + || (t !== 'light' && t !== 'dark' && button.classList.contains('fa-ban')) + ); + } + + switch (t) { + case 'light': case 'dark': + classes.add(t); + window.localStorage.setItem('color-scheme', t); + break; + default: + window.localStorage.removeItem('color-scheme'); + } +} + +window.addEventListener("click", (e) => { + const target = e.target; + if (target.matches(".btn-group.theme-toggle button")) { + setColorScheme( + target.classList.contains('fa-sun-o') ? 'light' : + target.classList.contains('fa-moon-o') ? 'dark' : + null + ); + } +}); + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", (e) => { + setColorScheme(window.localStorage.getItem('color-scheme')); + }); +} else { + setColorScheme(window.localStorage.getItem('color-scheme')); +} diff --git a/runbot_merge/views/templates.xml b/runbot_merge/views/templates.xml index a01ac998..30430c23 100644 --- a/runbot_merge/views/templates.xml +++ b/runbot_merge/views/templates.xml @@ -640,4 +640,20 @@ action = batches +