summaryrefslogtreecommitdiff
path: root/static/js
diff options
context:
space:
mode:
Diffstat (limited to 'static/js')
-rw-r--r--static/js/theme.js75
1 files changed, 75 insertions, 0 deletions
diff --git a/static/js/theme.js b/static/js/theme.js
new file mode 100644
index 0000000..3d2b25c
--- /dev/null
+++ b/static/js/theme.js
@@ -0,0 +1,75 @@
+(function () {
+ "use strict";
+
+ var root = document.documentElement;
+ root.classList.add("theme-ready");
+ var toggle = document.querySelector("[data-theme-toggle]");
+ var syntaxLight = document.getElementById("syntax-light");
+ var syntaxDark = document.getElementById("syntax-dark");
+ var media = window.matchMedia("(prefers-color-scheme: dark)");
+ var storedTheme = null;
+
+ try {
+ storedTheme = window.localStorage.getItem("theme");
+ } catch (error) {
+ storedTheme = null;
+ }
+
+ function activeTheme() {
+ if (root.dataset.theme === "light" || root.dataset.theme === "dark") {
+ return root.dataset.theme;
+ }
+ return media.matches ? "dark" : "light";
+ }
+
+ function syncSyntax(theme) {
+ if (!syntaxLight || !syntaxDark) {
+ return;
+ }
+ syntaxLight.media = theme === "light" ? "all" : "not all";
+ syntaxDark.media = theme === "dark" ? "all" : "not all";
+ }
+
+ function updateToggle() {
+ if (!toggle) {
+ return;
+ }
+ var dark = activeTheme() === "dark";
+ toggle.setAttribute("aria-pressed", String(dark));
+ toggle.setAttribute("aria-label", dark ? "ライトテーマに切り替える" : "ダークテーマに切り替える");
+ toggle.textContent = dark ? "Light" : "Dark";
+ }
+
+ function applyTheme(theme, persist) {
+ root.dataset.theme = theme;
+ syncSyntax(theme);
+ updateToggle();
+ if (persist) {
+ try {
+ window.localStorage.setItem("theme", theme);
+ } catch (error) {
+ // Storageが利用できなくても、現在のpageではthemeを維持する。
+ }
+ }
+ }
+
+ if (storedTheme === "light" || storedTheme === "dark") {
+ applyTheme(storedTheme, false);
+ } else {
+ syncSyntax(activeTheme());
+ updateToggle();
+ }
+
+ if (toggle) {
+ toggle.addEventListener("click", function () {
+ applyTheme(activeTheme() === "dark" ? "light" : "dark", true);
+ });
+ }
+
+ media.addEventListener("change", function () {
+ if (!root.dataset.theme) {
+ syncSyntax(activeTheme());
+ updateToggle();
+ }
+ });
+})();