Added "follow system" option to theme toggle (#2261)
The theme toggle button now has a third option, which follows the user's
system preferences.
- In the code there's now a distinction between the theme setting (which
can be "dark", "light" or "system") and the computed theme.
- The theme setting is now stored as the "theme-setting" local storage
variable. Since this is different from the old variable ("theme"), this
will effectively reset all current user themes to the default "system".
Maybe this is not what you want.
- The "system" theme icon is currently a half circle symbol.
- The toggle button now displays the current theme setting, rather than
the next theme setting (as far as I know this is consistent with other
sites which have three theme options).
- `theme.js` is now loaded regardless of `site.enable_darkmode`. This is
because other scripts which were always loaded relied on being able to
determine the theme. `theme.js` no longer initialises the theme itself
though; this only happens when `site.enable_darkmode`.
- When the theme setting is "system", the theme will change immediately
whenever the user changes their system theme.
#2261
---------
Signed-off-by: George Araujo <george.gcac@gmail.com>
Co-authored-by: George Araujo <george.gcac@gmail.com>
This commit is contained in:
parent
6cf110a682
commit
c788a30202
|
|
@ -1,7 +1,7 @@
|
||||||
<div id="giscus_thread" style="max-width: {{ site.max_width }}; margin: 0 auto;">
|
<div id="giscus_thread" style="max-width: {{ site.max_width }}; margin: 0 auto;">
|
||||||
{% if site.giscus.repo %}
|
{% if site.giscus.repo %}
|
||||||
<script>
|
<script>
|
||||||
let giscusTheme = localStorage.getItem('theme');
|
let giscusTheme = determineComputedTheme();
|
||||||
let giscusAttributes = {
|
let giscusAttributes = {
|
||||||
src: 'https://giscus.app/client.js',
|
src: 'https://giscus.app/client.js',
|
||||||
'data-repo': '{{ site.giscus.repo }}',
|
'data-repo': '{{ site.giscus.repo }}',
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@
|
||||||
<link rel="canonical" href="{{ page.url | replace:'index.html','' | absolute_url }}">
|
<link rel="canonical" href="{{ page.url | replace:'index.html','' | absolute_url }}">
|
||||||
|
|
||||||
<!-- Dark Mode -->
|
<!-- Dark Mode -->
|
||||||
|
<script src="{{ '/assets/js/theme.js' | relative_url | bust_file_cache }}"></script>
|
||||||
{% if site.enable_darkmode %}
|
{% if site.enable_darkmode %}
|
||||||
<link
|
<link
|
||||||
defer
|
defer
|
||||||
|
|
@ -60,7 +61,9 @@
|
||||||
media="none"
|
media="none"
|
||||||
id="highlight_theme_dark"
|
id="highlight_theme_dark"
|
||||||
>
|
>
|
||||||
<script src="{{ '/assets/js/theme.js' | relative_url | bust_file_cache }}"></script>
|
<script>
|
||||||
|
initTheme();
|
||||||
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- GeoJSON support via Leaflet -->
|
<!-- GeoJSON support via Leaflet -->
|
||||||
|
|
|
||||||
|
|
@ -111,8 +111,9 @@
|
||||||
<!-- Toogle theme mode -->
|
<!-- Toogle theme mode -->
|
||||||
<li class="toggle-container">
|
<li class="toggle-container">
|
||||||
<button id="light-toggle" title="Change theme">
|
<button id="light-toggle" title="Change theme">
|
||||||
<i class="fa-solid fa-moon"></i>
|
<i class="ti ti-sun-moon" id="light-toggle-system"></i>
|
||||||
<i class="fa-solid fa-sun"></i>
|
<i class="ti ti-moon-filled" id="light-toggle-dark"></i>
|
||||||
|
<i class="ti ti-sun-filled" id="light-toggle-light"></i>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
></script>
|
></script>
|
||||||
<script>
|
<script>
|
||||||
let theme = localStorage.getItem('theme');
|
let theme = determineComputedTheme();
|
||||||
|
|
||||||
/* Create echarts chart as another node and hide the code block, appending the echarts node after it
|
/* Create echarts chart as another node and hide the code block, appending the echarts node after it
|
||||||
this is done to enable retrieving the code again when changing theme between light/dark */
|
this is done to enable retrieving the code again when changing theme between light/dark */
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
></script>
|
></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script>
|
<script>
|
||||||
let theme = localStorage.getItem('theme');
|
let theme = determineComputedTheme();
|
||||||
|
|
||||||
/* Create echarts chart as another node and hide the code block, appending the echarts node after it
|
/* Create echarts chart as another node and hide the code block, appending the echarts node after it
|
||||||
this is done to enable retrieving the code again when changing theme between light/dark */
|
this is done to enable retrieving the code again when changing theme between light/dark */
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
></script>
|
></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script>
|
<script>
|
||||||
let theme = localStorage.getItem('theme');
|
let theme = determineComputedTheme();
|
||||||
|
|
||||||
/* Create mermaid diagram as another node and hide the code block, appending the mermaid node after it
|
/* Create mermaid diagram as another node and hide the code block, appending the mermaid node after it
|
||||||
this is done to enable retrieving the code again when changing theme between light/dark */
|
this is done to enable retrieving the code again when changing theme between light/dark */
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
></script>
|
></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
let theme = localStorage.getItem('theme');
|
let theme = determineComputedTheme();
|
||||||
|
|
||||||
/* Create vega lite chart as another node and hide the code block, appending the vega lite node after it
|
/* Create vega lite chart as another node and hide the code block, appending the vega lite node after it
|
||||||
this is done to enable retrieving the code again when changing theme between light/dark */
|
this is done to enable retrieving the code again when changing theme between light/dark */
|
||||||
|
|
|
||||||
|
|
@ -30,15 +30,20 @@
|
||||||
--global-danger-block-text: #600;
|
--global-danger-block-text: #600;
|
||||||
--global-danger-block-title: #c00;
|
--global-danger-block-title: #c00;
|
||||||
|
|
||||||
.fa-sun {
|
#light-toggle-system {
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.fa-moon {
|
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#light-toggle-dark {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#light-toggle-light {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.repo-img-light {
|
.repo-img-light {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
@ -75,15 +80,6 @@ html[data-theme="dark"] {
|
||||||
--global-danger-block-text: #600;
|
--global-danger-block-text: #600;
|
||||||
--global-danger-block-title: #c00;
|
--global-danger-block-title: #c00;
|
||||||
|
|
||||||
.fa-sun {
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-top: 12px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.fa-moon {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.repo-img-light {
|
.repo-img-light {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -91,3 +87,35 @@ html[data-theme="dark"] {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html[data-theme-setting="dark"] {
|
||||||
|
#light-toggle-system {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#light-toggle-dark {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-top: 12px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#light-toggle-light {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme-setting="light"] {
|
||||||
|
#light-toggle-system {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#light-toggle-dark {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#light-toggle-light {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-top: 12px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,3 +37,6 @@ $code-bg-color-dark: #2c3237 !default;
|
||||||
|
|
||||||
// Font awesome location
|
// Font awesome location
|
||||||
$fa-font-path: "../webfonts";
|
$fa-font-path: "../webfonts";
|
||||||
|
|
||||||
|
// Tabler icons location
|
||||||
|
$ti-font-path: "../fonts";
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -16,5 +16,8 @@ $max-content-width: {{ site.max_width }};
|
||||||
"font-awesome/fontawesome",
|
"font-awesome/fontawesome",
|
||||||
"font-awesome/brands",
|
"font-awesome/brands",
|
||||||
"font-awesome/solid",
|
"font-awesome/solid",
|
||||||
"font-awesome/regular"
|
"font-awesome/regular",
|
||||||
|
"tabler-icons/tabler-icons.scss",
|
||||||
|
"tabler-icons/tabler-icons-filled.scss",
|
||||||
|
"tabler-icons/tabler-icons-outline.scss"
|
||||||
;
|
;
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -30,13 +30,7 @@ $(document).ready(function () {
|
||||||
cssLink.rel = "stylesheet";
|
cssLink.rel = "stylesheet";
|
||||||
cssLink.type = "text/css";
|
cssLink.type = "text/css";
|
||||||
|
|
||||||
let theme = localStorage.getItem("theme");
|
let theme = determineComputedTheme();
|
||||||
if (theme == null || theme == "null") {
|
|
||||||
const userPref = window.matchMedia;
|
|
||||||
if (userPref && userPref("(prefers-color-scheme: dark)").matches) {
|
|
||||||
theme = "dark";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$(".jupyter-notebook-iframe-container iframe").each(function () {
|
$(".jupyter-notebook-iframe-container iframe").each(function () {
|
||||||
$(this).contents().find("head").append(cssLink);
|
$(this).contents().find("head").append(cssLink);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// add bootstrap classes to tables
|
// add bootstrap classes to tables
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("table").each(function () {
|
$("table").each(function () {
|
||||||
if (document.documentElement.getAttribute("data-theme") == "dark") {
|
if (determineComputedTheme() == "dark") {
|
||||||
$(this).addClass("table-dark");
|
$(this).addClass("table-dark");
|
||||||
} else {
|
} else {
|
||||||
$(this).removeClass("table-dark");
|
$(this).removeClass("table-dark");
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,30 @@
|
||||||
// Has to be in the head tag, otherwise a flicker effect will occur.
|
// Has to be in the head tag, otherwise a flicker effect will occur.
|
||||||
|
|
||||||
let toggleTheme = (theme) => {
|
// Toggle through light, dark, and system theme settings.
|
||||||
if (theme == "dark") {
|
let toggleThemeSetting = () => {
|
||||||
setTheme("light");
|
let themeSetting = determineThemeSetting();
|
||||||
|
if (themeSetting == "system") {
|
||||||
|
setThemeSetting("light");
|
||||||
|
} else if (themeSetting == "light") {
|
||||||
|
setThemeSetting("dark");
|
||||||
} else {
|
} else {
|
||||||
setTheme("dark");
|
setThemeSetting("system");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let setTheme = (theme) => {
|
// Change the theme setting and apply the theme.
|
||||||
|
let setThemeSetting = (themeSetting) => {
|
||||||
|
localStorage.setItem("theme", themeSetting);
|
||||||
|
|
||||||
|
document.documentElement.setAttribute("data-theme-setting", themeSetting);
|
||||||
|
|
||||||
|
applyTheme();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply the computed dark or light theme to the website.
|
||||||
|
let applyTheme = () => {
|
||||||
|
let theme = determineComputedTheme();
|
||||||
|
|
||||||
transTheme();
|
transTheme();
|
||||||
setHighlight(theme);
|
setHighlight(theme);
|
||||||
setGiscusTheme(theme);
|
setGiscusTheme(theme);
|
||||||
|
|
@ -33,7 +49,6 @@ let setTheme = (theme) => {
|
||||||
setVegaLiteTheme(theme);
|
setVegaLiteTheme(theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theme) {
|
|
||||||
document.documentElement.setAttribute("data-theme", theme);
|
document.documentElement.setAttribute("data-theme", theme);
|
||||||
|
|
||||||
// Add class to tables.
|
// Add class to tables.
|
||||||
|
|
@ -58,11 +73,6 @@ let setTheme = (theme) => {
|
||||||
bodyElement.setAttribute("data-jp-theme-name", "JupyterLab Light");
|
bodyElement.setAttribute("data-jp-theme-name", "JupyterLab Light");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
document.documentElement.removeAttribute("data-theme");
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.setItem("theme", theme);
|
|
||||||
|
|
||||||
// Updates the background of medium-zoom overlay.
|
// Updates the background of medium-zoom overlay.
|
||||||
if (typeof medium_zoom !== "undefined") {
|
if (typeof medium_zoom !== "undefined") {
|
||||||
|
|
@ -183,23 +193,48 @@ let transTheme = () => {
|
||||||
}, 500);
|
}, 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
let initTheme = (theme) => {
|
// Determine the expected state of the theme toggle, which can be "dark", "light", or
|
||||||
if (theme == null || theme == "null") {
|
// "system". Default is "system".
|
||||||
const userPref = window.matchMedia;
|
let determineThemeSetting = () => {
|
||||||
if (userPref && userPref("(prefers-color-scheme: dark)").matches) {
|
let themeSetting = localStorage.getItem("theme");
|
||||||
theme = "dark";
|
if (themeSetting != "dark" && themeSetting != "light" && themeSetting != "system") {
|
||||||
|
themeSetting = "system";
|
||||||
}
|
}
|
||||||
}
|
return themeSetting;
|
||||||
|
|
||||||
setTheme(theme);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
initTheme(localStorage.getItem("theme"));
|
// Determine the computed theme, which can be "dark" or "light". If the theme setting is
|
||||||
|
// "system", the computed theme is determined based on the user's system preference.
|
||||||
|
let determineComputedTheme = () => {
|
||||||
|
let themeSetting = determineThemeSetting();
|
||||||
|
if (themeSetting == "system") {
|
||||||
|
const userPref = window.matchMedia;
|
||||||
|
if (userPref && userPref("(prefers-color-scheme: dark)").matches) {
|
||||||
|
return "dark";
|
||||||
|
} else {
|
||||||
|
return "light";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return themeSetting;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let initTheme = () => {
|
||||||
|
let themeSetting = determineThemeSetting();
|
||||||
|
|
||||||
|
setThemeSetting(themeSetting);
|
||||||
|
|
||||||
|
// Add event listener to the theme toggle button.
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
const mode_toggle = document.getElementById("light-toggle");
|
const mode_toggle = document.getElementById("light-toggle");
|
||||||
|
|
||||||
mode_toggle.addEventListener("click", function () {
|
mode_toggle.addEventListener("click", function () {
|
||||||
toggleTheme(localStorage.getItem("theme"));
|
toggleThemeSetting();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add event listener to the system theme preference change.
|
||||||
|
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", ({ matches }) => {
|
||||||
|
applyTheme();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue