From 01deafa5bf5b68784d434d6f361c21d72cf89069 Mon Sep 17 00:00:00 2001 From: GDWR Date: Tue, 8 Feb 2022 00:43:03 +0000 Subject: Add initial dark theme --- pydis_site/static/js/base/navbar.js | 87 +++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 pydis_site/static/js/base/navbar.js (limited to 'pydis_site/static/js/base') diff --git a/pydis_site/static/js/base/navbar.js b/pydis_site/static/js/base/navbar.js new file mode 100644 index 00000000..f0bd94b9 --- /dev/null +++ b/pydis_site/static/js/base/navbar.js @@ -0,0 +1,87 @@ +"use strict"; + +const defaultCssElement = $("#bulma-css")[0]; +const darkCssElement = $("#bulma-css-dark")[0]; + +function getCurrentTheme() { + return document.cookie + .split('; ') + .find(row => row.startsWith('theme=')) + .split('=')[1]; +} + +function displayThemedElements() { + const defaultElements = Array.from($(".show-default-mode")); + const darkElements = Array.from($(".show-dark-mode")); + + switch (getCurrentTheme()) { + case "": + case "default": + defaultElements.forEach(e => e.style.display = null); + darkElements.forEach(e => e.style.display = 'none'); + break; + case "dark": + defaultElements.forEach(e => e.style.display = 'none'); + darkElements.forEach(e => e.style.display = null); + break; + } +} + +function setStyleSheets() { + switch (getCurrentTheme()) { + case "": + case "default": + defaultCssElement.disabled = false; + darkCssElement.disabled = true; + break; + case "dark": + defaultCssElement.disabled = true; + darkCssElement.disabled = false; + break; + } +} + + +// Executed when the page has finished loading. +document.addEventListener("DOMContentLoaded", () => { + + setStyleSheets(); + displayThemedElements(); + + $('#theme-switch').on("click", () => { + + // Update cookie + if (getCurrentTheme() === "dark") { + document.cookie = "theme=default"; + } else { + document.cookie = "theme=dark"; + } + + setStyleSheets(); + displayThemedElements(); + + // Animations + let switchToggle = $(".switch")[0]; + let knob = $(".knob")[0]; + + if (knob.classList.contains("dark")) { + knob.classList.remove("dark"); + knob.classList.add("light"); + + // After 500ms, switch the icons + setTimeout(function() { + switchToggle.classList.remove("dark"); + switchToggle.classList.add("light"); + }, 100); + } else { + knob.classList.remove("light"); + knob.classList.add("dark"); + + // After 500ms, switch the icons + setTimeout(function() { + switchToggle.classList.remove("light"); + switchToggle.classList.add("dark"); + }, 100); + } + }); +}); \ No newline at end of file -- cgit v1.2.3 From 47be83e4c7924109acce52a00b7135147c28244e Mon Sep 17 00:00:00 2001 From: GDWR Date: Tue, 8 Feb 2022 08:44:45 +0000 Subject: getCurrentTheme returns "default" if empty --- pydis_site/static/js/base/navbar.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'pydis_site/static/js/base') diff --git a/pydis_site/static/js/base/navbar.js b/pydis_site/static/js/base/navbar.js index f0bd94b9..23ddfd7c 100644 --- a/pydis_site/static/js/base/navbar.js +++ b/pydis_site/static/js/base/navbar.js @@ -4,6 +4,9 @@ const defaultCssElement = $("#bulma-css")[0]; const darkCssElement = $("#bulma-css-dark")[0]; function getCurrentTheme() { + if (document.cookie === "") + return "default"; + return document.cookie .split('; ') .find(row => row.startsWith('theme=')) -- cgit v1.2.3 From d2d98a1a3ce7a0def73e75be6e305e03b1af864e Mon Sep 17 00:00:00 2001 From: GDWR Date: Tue, 8 Feb 2022 23:44:26 +0000 Subject: Determine current theme and set switch --- pydis_site/static/js/base/navbar.js | 52 ++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 24 deletions(-) (limited to 'pydis_site/static/js/base') diff --git a/pydis_site/static/js/base/navbar.js b/pydis_site/static/js/base/navbar.js index 23ddfd7c..b49c86b1 100644 --- a/pydis_site/static/js/base/navbar.js +++ b/pydis_site/static/js/base/navbar.js @@ -44,6 +44,30 @@ function setStyleSheets() { } } +function toggleThemeSwitch() { + let switchToggle = $(".switch")[0]; + let knob = $(".knob")[0]; + + if (knob.classList.contains("dark")) { + knob.classList.remove("dark"); + knob.classList.add("light"); + + // After 500ms, switch the icons + setTimeout(function() { + switchToggle.classList.remove("dark"); + switchToggle.classList.add("light"); + }, 100); + } else { + knob.classList.remove("light"); + knob.classList.add("dark"); + + // After 500ms, switch the icons + setTimeout(function() { + switchToggle.classList.remove("light"); + switchToggle.classList.add("dark"); + }, 100); + } +} // Executed when the page has finished loading. document.addEventListener("DOMContentLoaded", () => { @@ -51,6 +75,9 @@ document.addEventListener("DOMContentLoaded", () => { setStyleSheets(); displayThemedElements(); + if (getCurrentTheme() === "default") + toggleThemeSwitch(); + $('#theme-switch').on("click", () => { // Update cookie @@ -62,29 +89,6 @@ document.addEventListener("DOMContentLoaded", () => { setStyleSheets(); displayThemedElements(); - - // Animations - let switchToggle = $(".switch")[0]; - let knob = $(".knob")[0]; - - if (knob.classList.contains("dark")) { - knob.classList.remove("dark"); - knob.classList.add("light"); - - // After 500ms, switch the icons - setTimeout(function() { - switchToggle.classList.remove("dark"); - switchToggle.classList.add("light"); - }, 100); - } else { - knob.classList.remove("light"); - knob.classList.add("dark"); - - // After 500ms, switch the icons - setTimeout(function() { - switchToggle.classList.remove("light"); - switchToggle.classList.add("dark"); - }, 100); - } + toggleThemeSwitch(); }); }); \ No newline at end of file -- cgit v1.2.3 From 1177f0d442a40e603b5d4d06dfe6590133724dbf Mon Sep 17 00:00:00 2001 From: hedy Date: Thu, 14 Dec 2023 20:29:27 +0800 Subject: Automatically fix lint --- pydis_site/static/css/base/navbar.css | 2 +- pydis_site/static/js/base/navbar.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'pydis_site/static/js/base') diff --git a/pydis_site/static/css/base/navbar.css b/pydis_site/static/css/base/navbar.css index bf8913ab..9d71e799 100644 --- a/pydis_site/static/css/base/navbar.css +++ b/pydis_site/static/css/base/navbar.css @@ -62,4 +62,4 @@ .switch.light .theme-icon.dark { opacity: 0; -} \ No newline at end of file +} diff --git a/pydis_site/static/js/base/navbar.js b/pydis_site/static/js/base/navbar.js index b49c86b1..a4b8a0aa 100644 --- a/pydis_site/static/js/base/navbar.js +++ b/pydis_site/static/js/base/navbar.js @@ -91,4 +91,4 @@ document.addEventListener("DOMContentLoaded", () => { displayThemedElements(); toggleThemeSwitch(); }); -}); \ No newline at end of file +}); -- cgit v1.2.3 From 058b562304a96055a57f8daee80db07c596684ec Mon Sep 17 00:00:00 2001 From: hedy Date: Fri, 5 Jan 2024 09:16:47 +0800 Subject: Dark: Refactor toggle handling JS - Use localstorage. Advantages: - One key=value for the entire site, without needing to specify `path=/` - No need for string splitting to parse the `key=value; ...` data - Suggested more widely in tutorials Pretty good support: https://caniuse.com/?search=localstorage - Remove the need for JQuery, use IDs for switch and knob elements. - This also makes the code more robust if the page has other switch & knob classes! --- pydis_site/static/js/base/navbar.js | 114 +++++++++++++--------------------- pydis_site/templates/base/navbar.html | 6 +- 2 files changed, 45 insertions(+), 75 deletions(-) (limited to 'pydis_site/static/js/base') diff --git a/pydis_site/static/js/base/navbar.js b/pydis_site/static/js/base/navbar.js index a4b8a0aa..9a1641aa 100644 --- a/pydis_site/static/js/base/navbar.js +++ b/pydis_site/static/js/base/navbar.js @@ -1,94 +1,64 @@ "use strict"; -const defaultCssElement = $("#bulma-css")[0]; -const darkCssElement = $("#bulma-css-dark")[0]; +const defaultTheme = "light"; +const lightCssElement = document.getElementById("bulma-css"); +const darkCssElement = document.getElementById("bulma-css-dark"); function getCurrentTheme() { - if (document.cookie === "") - return "default"; - - return document.cookie - .split('; ') - .find(row => row.startsWith('theme=')) - .split('=')[1]; + const theme = localStorage.getItem("theme"); + if (theme === null || theme === "") + return defaultTheme; + return theme; } -function displayThemedElements() { - const defaultElements = Array.from($(".show-default-mode")); - const darkElements = Array.from($(".show-dark-mode")); - - switch (getCurrentTheme()) { - case "": - case "default": - defaultElements.forEach(e => e.style.display = null); - darkElements.forEach(e => e.style.display = 'none'); +function setStyleSheets(newTheme) { + switch (newTheme) { + case "light": + lightCssElement.disabled = false; + darkCssElement.disabled = true; break; case "dark": - defaultElements.forEach(e => e.style.display = 'none'); - darkElements.forEach(e => e.style.display = null); + lightCssElement.disabled = true; + darkCssElement.disabled = false; break; } } -function setStyleSheets() { - switch (getCurrentTheme()) { - case "": - case "default": - defaultCssElement.disabled = false; - darkCssElement.disabled = true; +function toggleThemeSwitch(newTheme) { + const switchToggle = document.getElementById("theme-switch"); + const knob = document.getElementById("theme-knob"); + switch (newTheme) { + case "light": + knob.classList.remove("dark"); + knob.classList.add("light"); + setTimeout(function() { + switchToggle.classList.remove("dark"); + switchToggle.classList.add("light"); + }, 100); break; case "dark": - defaultCssElement.disabled = true; - darkCssElement.disabled = false; + knob.classList.remove("light"); + knob.classList.add("dark"); + setTimeout(function() { + switchToggle.classList.remove("light"); + switchToggle.classList.add("dark"); + }, 100); break; } } -function toggleThemeSwitch() { - let switchToggle = $(".switch")[0]; - let knob = $(".knob")[0]; - - if (knob.classList.contains("dark")) { - knob.classList.remove("dark"); - knob.classList.add("light"); - - // After 500ms, switch the icons - setTimeout(function() { - switchToggle.classList.remove("dark"); - switchToggle.classList.add("light"); - }, 100); - } else { - knob.classList.remove("light"); - knob.classList.add("dark"); - - // After 500ms, switch the icons - setTimeout(function() { - switchToggle.classList.remove("light"); - switchToggle.classList.add("dark"); - }, 100); - } -} - // Executed when the page has finished loading. document.addEventListener("DOMContentLoaded", () => { - - setStyleSheets(); - displayThemedElements(); - - if (getCurrentTheme() === "default") - toggleThemeSwitch(); - - $('#theme-switch').on("click", () => { - - // Update cookie - if (getCurrentTheme() === "dark") { - document.cookie = "theme=default"; - } else { - document.cookie = "theme=dark"; - } - - setStyleSheets(); - displayThemedElements(); - toggleThemeSwitch(); + const theme = getCurrentTheme() + setStyleSheets(theme); + toggleThemeSwitch(theme); + + const switchToggle = document.getElementById("theme-switch"); + switchToggle.addEventListener("click", () => { + const newTheme = getCurrentTheme() === "light" ? "dark" : "light"; + console.log(newTheme); + localStorage.setItem("theme", newTheme); + setStyleSheets(newTheme); + toggleThemeSwitch(newTheme); }); }); diff --git a/pydis_site/templates/base/navbar.html b/pydis_site/templates/base/navbar.html index f6a1bc26..57fdbf6a 100644 --- a/pydis_site/templates/base/navbar.html +++ b/pydis_site/templates/base/navbar.html @@ -3,7 +3,6 @@ {% block head %} - {% endblock %} @@ -104,17 +103,18 @@ + {# Theme toggle #} - {# Desktop Nav Discord #} + {# Desktop Nav Discord #} -- cgit v1.2.3 From eaaf1efff1f5d9b47658541496fb948a3292fe48 Mon Sep 17 00:00:00 2001 From: hedy Date: Fri, 5 Jan 2024 13:57:44 +0800 Subject: Dark: Support system color scheme preference Added features - When no preference already stored when page loads, we'll take into account the system setting and set the theme automatically. - When the system setting is modified while the site is active, switch theme automatically. - The system preference takes lower precedence than saved preference from the switch toggle, unless the setting is modified while the site is active. Miscellaneous refactor. --- pydis_site/static/js/base/navbar.js | 49 ++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 12 deletions(-) (limited to 'pydis_site/static/js/base') diff --git a/pydis_site/static/js/base/navbar.js b/pydis_site/static/js/base/navbar.js index 9a1641aa..04850add 100644 --- a/pydis_site/static/js/base/navbar.js +++ b/pydis_site/static/js/base/navbar.js @@ -1,32 +1,42 @@ "use strict"; const defaultTheme = "light"; -const lightCssElement = document.getElementById("bulma-css"); -const darkCssElement = document.getElementById("bulma-css-dark"); +const lightStylesheet = document.getElementById("bulma-css"); +const darkStylesheet = document.getElementById("bulma-css-dark"); -function getCurrentTheme() { +// Get saved preference for the site in local storage, optionally accounting +// for system preference used when a page loads. +function getCurrentTheme(systemPrefers) { const theme = localStorage.getItem("theme"); - if (theme === null || theme === "") - return defaultTheme; - return theme; + + if (theme !== null && theme !== "") + return theme; + + if (systemPrefers !== undefined) + return systemPrefers; + + return defaultTheme; } +// Disable & enable the correct CSS stylesheets based on chosen theme. function setStyleSheets(newTheme) { switch (newTheme) { case "light": - lightCssElement.disabled = false; - darkCssElement.disabled = true; + lightStylesheet.disabled = false; + darkStylesheet.disabled = true; break; case "dark": - lightCssElement.disabled = true; - darkCssElement.disabled = false; + lightStylesheet.disabled = true; + darkStylesheet.disabled = false; break; } } +// Reflect chosen theme on the switch toggle. function toggleThemeSwitch(newTheme) { const switchToggle = document.getElementById("theme-switch"); const knob = document.getElementById("theme-knob"); + switch (newTheme) { case "light": knob.classList.remove("dark"); @@ -49,14 +59,29 @@ function toggleThemeSwitch(newTheme) { // Executed when the page has finished loading. document.addEventListener("DOMContentLoaded", () => { - const theme = getCurrentTheme() + let theme; + const systemPrefersDark = window.matchMedia("(prefers-color-scheme: dark)"); + + if (systemPrefersDark.matches) + theme = getCurrentTheme("dark"); + else + theme = getCurrentTheme(); + setStyleSheets(theme); toggleThemeSwitch(theme); + systemPrefersDark.addEventListener("change", ({matches: isDark}) => { + const newTheme = isDark ? "dark" : "light"; + // Let the new system preference take precedence over toggle preference + // on page reloads. + localStorage.removeItem("theme"); + setStyleSheets(newTheme); + toggleThemeSwitch(newTheme); + }) + const switchToggle = document.getElementById("theme-switch"); switchToggle.addEventListener("click", () => { const newTheme = getCurrentTheme() === "light" ? "dark" : "light"; - console.log(newTheme); localStorage.setItem("theme", newTheme); setStyleSheets(newTheme); toggleThemeSwitch(newTheme); -- cgit v1.2.3 From 7b5435a9855111dd34422ff0067c1955c43875eb Mon Sep 17 00:00:00 2001 From: hedy Date: Fri, 5 Jan 2024 17:31:11 +0800 Subject: Dark: Fix hero colors on homepage We can now use `[data-theme="dark"]` selector in CSS to defined styles specifically for dark mode. This follows common web dev patterns and gives little overhead. - Hero - Added `wave_black` SVG which copies `wave_white` as is but uses the site's dark mode background color. --- pydis_site/static/css/home/index.css | 10 ++++ pydis_site/static/images/waves/wave_black.svg | 77 +++++++++++++++++++++++++++ pydis_site/static/js/base/navbar.js | 2 + 3 files changed, 89 insertions(+) create mode 100644 pydis_site/static/images/waves/wave_black.svg (limited to 'pydis_site/static/js/base') diff --git a/pydis_site/static/css/home/index.css b/pydis_site/static/css/home/index.css index e117a35b..23e27be1 100644 --- a/pydis_site/static/css/home/index.css +++ b/pydis_site/static/css/home/index.css @@ -91,6 +91,11 @@ h1 { height: 26px; z-index: 3; } +[data-theme="dark"] { + #bottom-wave { + background: url(../../images/waves/wave_black.svg) repeat-x !important; + } +} @keyframes wave { 0% { @@ -176,6 +181,11 @@ h1 { #projects .card:hover .card-header-title { color: #363636; } +[data-theme="dark"] { + #projects .card:hover .card-header-title { + color: #CAD6FF; + } +} #projects .card-content { padding-top: 8px; diff --git a/pydis_site/static/images/waves/wave_black.svg b/pydis_site/static/images/waves/wave_black.svg new file mode 100644 index 00000000..899fe2f9 --- /dev/null +++ b/pydis_site/static/images/waves/wave_black.svg @@ -0,0 +1,77 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/pydis_site/static/js/base/navbar.js b/pydis_site/static/js/base/navbar.js index 04850add..2a57cad4 100644 --- a/pydis_site/static/js/base/navbar.js +++ b/pydis_site/static/js/base/navbar.js @@ -30,6 +30,8 @@ function setStyleSheets(newTheme) { darkStylesheet.disabled = false; break; } + + document.querySelector("html").setAttribute("data-theme", newTheme); } // Reflect chosen theme on the switch toggle. -- cgit v1.2.3 From 7559cb72da7e8b84dd81b33d54ba6c6abd156fd7 Mon Sep 17 00:00:00 2001 From: hedy Date: Fri, 5 Jan 2024 20:55:34 +0800 Subject: Dark: Name JS & CSS files according to their content We have the CSS for the navbar in base.css, the relevant files only contain code for the theme toggle, so they should be named as such. If we ever implement CSS variables per-theme, they could then be done in `themes.css`. --- pydis_site/static/css/base/navbar.css | 65 ------------------------- pydis_site/static/css/base/themes.css | 67 ++++++++++++++++++++++++++ pydis_site/static/js/base/navbar.js | 91 ----------------------------------- pydis_site/static/js/base/themes.js | 91 +++++++++++++++++++++++++++++++++++ pydis_site/templates/base/navbar.html | 4 +- 5 files changed, 160 insertions(+), 158 deletions(-) delete mode 100644 pydis_site/static/css/base/navbar.css create mode 100644 pydis_site/static/css/base/themes.css delete mode 100644 pydis_site/static/js/base/navbar.js create mode 100644 pydis_site/static/js/base/themes.js (limited to 'pydis_site/static/js/base') diff --git a/pydis_site/static/css/base/navbar.css b/pydis_site/static/css/base/navbar.css deleted file mode 100644 index 9d71e799..00000000 --- a/pydis_site/static/css/base/navbar.css +++ /dev/null @@ -1,65 +0,0 @@ -.switch { - position: relative; - height: 2em; - width: 4em; - cursor: pointer; -} - -.switch-outer { - position: absolute; - height: 100%; - width: 100%; - border-radius: 2em; - transition: background-color 0.3s ease-out; -} - -.switch.dark .switch-outer { - background-color: #22272E; -} - -.switch.light .switch-outer { - background-color: #3f61d9; -} - -.knob { - position: absolute; - padding-top: 20%; - height: 70%; - width: 37.5%; - border-radius: 10em; - transition: all 0.5s ease-out; -} - -.knob.dark { - background-color: #586282; - margin: 7% auto auto 8%; -} - -.knob.light { - background-color: #364c94; - margin: 7% auto auto 56%; -} - -.theme-icon { - position: absolute !important; - --ggs: 0.75; - transition: opacity 0.3s ease-out; -} - -.theme-icon.light { - left: 10%; - top: 15% -} - -.theme-icon.dark { - right: 10%; - top: 20% -} - -.switch.dark .theme-icon.light { - opacity: 0; -} - -.switch.light .theme-icon.dark { - opacity: 0; -} diff --git a/pydis_site/static/css/base/themes.css b/pydis_site/static/css/base/themes.css new file mode 100644 index 00000000..35273d44 --- /dev/null +++ b/pydis_site/static/css/base/themes.css @@ -0,0 +1,67 @@ +/* Theme switch toggle */ + +.switch { + position: relative; + height: 2em; + width: 4em; + cursor: pointer; +} + +.switch-outer { + position: absolute; + height: 100%; + width: 100%; + border-radius: 2em; + transition: background-color 0.3s ease-out; +} + +.switch.dark .switch-outer { + background-color: #22272E; +} + +.switch.light .switch-outer { + background-color: #3f61d9; +} + +.knob { + position: absolute; + padding-top: 20%; + height: 70%; + width: 37.5%; + border-radius: 10em; + transition: all 0.5s ease-out; +} + +.knob.dark { + background-color: #586282; + margin: 7% auto auto 8%; +} + +.knob.light { + background-color: #364c94; + margin: 7% auto auto 56%; +} + +.theme-icon { + position: absolute !important; + --ggs: 0.75; + transition: opacity 0.3s ease-out; +} + +.theme-icon.light { + left: 10%; + top: 15% +} + +.theme-icon.dark { + right: 10%; + top: 20% +} + +.switch.dark .theme-icon.light { + opacity: 0; +} + +.switch.light .theme-icon.dark { + opacity: 0; +} diff --git a/pydis_site/static/js/base/navbar.js b/pydis_site/static/js/base/navbar.js deleted file mode 100644 index 2a57cad4..00000000 --- a/pydis_site/static/js/base/navbar.js +++ /dev/null @@ -1,91 +0,0 @@ -"use strict"; - -const defaultTheme = "light"; -const lightStylesheet = document.getElementById("bulma-css"); -const darkStylesheet = document.getElementById("bulma-css-dark"); - -// Get saved preference for the site in local storage, optionally accounting -// for system preference used when a page loads. -function getCurrentTheme(systemPrefers) { - const theme = localStorage.getItem("theme"); - - if (theme !== null && theme !== "") - return theme; - - if (systemPrefers !== undefined) - return systemPrefers; - - return defaultTheme; -} - -// Disable & enable the correct CSS stylesheets based on chosen theme. -function setStyleSheets(newTheme) { - switch (newTheme) { - case "light": - lightStylesheet.disabled = false; - darkStylesheet.disabled = true; - break; - case "dark": - lightStylesheet.disabled = true; - darkStylesheet.disabled = false; - break; - } - - document.querySelector("html").setAttribute("data-theme", newTheme); -} - -// Reflect chosen theme on the switch toggle. -function toggleThemeSwitch(newTheme) { - const switchToggle = document.getElementById("theme-switch"); - const knob = document.getElementById("theme-knob"); - - switch (newTheme) { - case "light": - knob.classList.remove("dark"); - knob.classList.add("light"); - setTimeout(function() { - switchToggle.classList.remove("dark"); - switchToggle.classList.add("light"); - }, 100); - break; - case "dark": - knob.classList.remove("light"); - knob.classList.add("dark"); - setTimeout(function() { - switchToggle.classList.remove("light"); - switchToggle.classList.add("dark"); - }, 100); - break; - } -} - -// Executed when the page has finished loading. -document.addEventListener("DOMContentLoaded", () => { - let theme; - const systemPrefersDark = window.matchMedia("(prefers-color-scheme: dark)"); - - if (systemPrefersDark.matches) - theme = getCurrentTheme("dark"); - else - theme = getCurrentTheme(); - - setStyleSheets(theme); - toggleThemeSwitch(theme); - - systemPrefersDark.addEventListener("change", ({matches: isDark}) => { - const newTheme = isDark ? "dark" : "light"; - // Let the new system preference take precedence over toggle preference - // on page reloads. - localStorage.removeItem("theme"); - setStyleSheets(newTheme); - toggleThemeSwitch(newTheme); - }) - - const switchToggle = document.getElementById("theme-switch"); - switchToggle.addEventListener("click", () => { - const newTheme = getCurrentTheme() === "light" ? "dark" : "light"; - localStorage.setItem("theme", newTheme); - setStyleSheets(newTheme); - toggleThemeSwitch(newTheme); - }); -}); diff --git a/pydis_site/static/js/base/themes.js b/pydis_site/static/js/base/themes.js new file mode 100644 index 00000000..2a57cad4 --- /dev/null +++ b/pydis_site/static/js/base/themes.js @@ -0,0 +1,91 @@ +"use strict"; + +const defaultTheme = "light"; +const lightStylesheet = document.getElementById("bulma-css"); +const darkStylesheet = document.getElementById("bulma-css-dark"); + +// Get saved preference for the site in local storage, optionally accounting +// for system preference used when a page loads. +function getCurrentTheme(systemPrefers) { + const theme = localStorage.getItem("theme"); + + if (theme !== null && theme !== "") + return theme; + + if (systemPrefers !== undefined) + return systemPrefers; + + return defaultTheme; +} + +// Disable & enable the correct CSS stylesheets based on chosen theme. +function setStyleSheets(newTheme) { + switch (newTheme) { + case "light": + lightStylesheet.disabled = false; + darkStylesheet.disabled = true; + break; + case "dark": + lightStylesheet.disabled = true; + darkStylesheet.disabled = false; + break; + } + + document.querySelector("html").setAttribute("data-theme", newTheme); +} + +// Reflect chosen theme on the switch toggle. +function toggleThemeSwitch(newTheme) { + const switchToggle = document.getElementById("theme-switch"); + const knob = document.getElementById("theme-knob"); + + switch (newTheme) { + case "light": + knob.classList.remove("dark"); + knob.classList.add("light"); + setTimeout(function() { + switchToggle.classList.remove("dark"); + switchToggle.classList.add("light"); + }, 100); + break; + case "dark": + knob.classList.remove("light"); + knob.classList.add("dark"); + setTimeout(function() { + switchToggle.classList.remove("light"); + switchToggle.classList.add("dark"); + }, 100); + break; + } +} + +// Executed when the page has finished loading. +document.addEventListener("DOMContentLoaded", () => { + let theme; + const systemPrefersDark = window.matchMedia("(prefers-color-scheme: dark)"); + + if (systemPrefersDark.matches) + theme = getCurrentTheme("dark"); + else + theme = getCurrentTheme(); + + setStyleSheets(theme); + toggleThemeSwitch(theme); + + systemPrefersDark.addEventListener("change", ({matches: isDark}) => { + const newTheme = isDark ? "dark" : "light"; + // Let the new system preference take precedence over toggle preference + // on page reloads. + localStorage.removeItem("theme"); + setStyleSheets(newTheme); + toggleThemeSwitch(newTheme); + }) + + const switchToggle = document.getElementById("theme-switch"); + switchToggle.addEventListener("click", () => { + const newTheme = getCurrentTheme() === "light" ? "dark" : "light"; + localStorage.setItem("theme", newTheme); + setStyleSheets(newTheme); + toggleThemeSwitch(newTheme); + }); +}); diff --git a/pydis_site/templates/base/navbar.html b/pydis_site/templates/base/navbar.html index 57fdbf6a..64518146 100644 --- a/pydis_site/templates/base/navbar.html +++ b/pydis_site/templates/base/navbar.html @@ -1,9 +1,9 @@ {% load static %} {% block head %} - + - + {% endblock %}