From 9593ebb6b48ba9d8043f97431f2d9dfe0bc855e2 Mon Sep 17 00:00:00 2001
From: Shota FUJI
Date: Thu, 30 Jul 2026 19:09:50 +0900
Subject: [PATCH] Add theme color preferences (JS)
I hate the default blue convention.
---
embed/static/global.css | 91 +++++++++++++++++++++++++++
embed/static/preferences.js | 33 ++++++++++
embed/templates/site-footer.html.tmpl | 16 +++++
3 files changed, 140 insertions(+)
diff --git a/embed/static/global.css b/embed/static/global.css
index 6477a92..db19a87 100644
--- a/embed/static/global.css
+++ b/embed/static/global.css
@@ -53,6 +53,42 @@
--radii-sm: 3px;
--radii-md: 6px;
}
+:root[data-theme-color="purple"] {
+ --color-link: var(--uchu-purple-8);
+ --color-decoration: var(--uchu-purple-6);
+}
+:root[data-theme-color="pink"] {
+ --color-link: var(--uchu-pink-9);
+ --color-decoration: var(--uchu-pink-6);
+}
+:root[data-theme-color="red"] {
+ --color-link: var(--uchu-red-8);
+ --color-decoration: var(--uchu-red-6);
+}
+:root[data-theme-color="orange"] {
+ --color-link: var(--uchu-orange-9);
+ --color-decoration: var(--uchu-orange-6);
+}
+:root[data-theme-color="yellow"] {
+ --color-link: var(--uchu-yellow-9);
+ --color-decoration: var(--uchu-yellow-6);
+}
+:root[data-theme-color="green"] {
+ --color-link: var(--uchu-green-9);
+ --color-decoration: var(--uchu-green-6);
+}
+:root[data-theme-color="gray"] {
+ --color-link: var(--uchu-yin-7);
+ --color-decoration: var(--uchu-gray-6);
+}
+@supports (color: color-mix(in oklab, var(--uchu-pink-6) 50%, var(--color-fg) 40%)) {
+ :root[data-theme-color="pink"] {
+ --color-link: color-mix(in oklab, var(--uchu-pink-6) 60%, var(--color-fg) 40%);
+ }
+ :root[data-theme-color="yellow"] {
+ --color-link: color-mix(in oklab, var(--uchu-yellow-5) 45%, var(--color-fg) 55%);
+ }
+}
@media (prefers-contrast: more) {
:root {
@@ -61,6 +97,12 @@
--color-fg-subtle: var(--uchu-yin-8);
--color-link: var(--uchu-blue-9);
}
+ :root[data-theme-color="purple"] {
+ --color-link: var(--uchu-purple-9);
+ }
+ :root[data-theme-color="red"] {
+ --color-link: var(--uchu-red-9);
+ }
}
@media (prefers-color-scheme: dark) {
@@ -74,6 +116,34 @@
--color-decoration: var(--uchu-blue-4);
--color-backdrop: oklch(var(--uchu-yin-9-raw) / 90%);
}
+ :root[data-theme-color="purple"] {
+ --color-link: var(--uchu-purple-2);
+ --color-decoration: var(--uchu-purple-4);
+ }
+ :root[data-theme-color="pink"] {
+ --color-link: var(--uchu-pink-3);
+ --color-decoration: var(--uchu-pink-4);
+ }
+ :root[data-theme-color="red"] {
+ --color-link: var(--uchu-red-2);
+ --color-decoration: var(--uchu-red-4);
+ }
+ :root[data-theme-color="orange"] {
+ --color-link: var(--uchu-orange-2);
+ --color-decoration: var(--uchu-orange-4);
+ }
+ :root[data-theme-color="yellow"] {
+ --color-link: var(--uchu-yellow-2);
+ --color-decoration: var(--uchu-yellow-4);
+ }
+ :root[data-theme-color="green"] {
+ --color-link: var(--uchu-green-2);
+ --color-decoration: var(--uchu-green-4);
+ }
+ :root[data-theme-color="gray"] {
+ --color-link: var(--uchu-gray-2);
+ --color-decoration: var(--uchu-gray-4);
+ }
}
@media (prefers-color-scheme: dark) and (prefers-contrast: more) {
@@ -82,6 +152,27 @@
--color-fg-subtle: var(--uchu-yin-2);
--color-link: var(--uchu-blue-1);
}
+ :root[data-theme-color="purple"] {
+ --color-link: var(--uchu-purple-1);
+ }
+ :root[data-theme-color="pink"] {
+ --color-link: var(--uchu-pink-1);
+ }
+ :root[data-theme-color="red"] {
+ --color-link: var(--uchu-red-1);
+ }
+ :root[data-theme-color="orange"] {
+ --color-link: var(--uchu-orange-1);
+ }
+ :root[data-theme-color="yellow"] {
+ --color-link: var(--uchu-yellow-1);
+ }
+ :root[data-theme-color="green"] {
+ --color-link: var(--uchu-green-1);
+ }
+ :root[data-theme-color="gray"] {
+ --color-link: var(--uchu-gray-1);
+ }
}
*, *::before, *::after {
diff --git a/embed/static/preferences.js b/embed/static/preferences.js
index 1cd94b8..1c37d16 100644
--- a/embed/static/preferences.js
+++ b/embed/static/preferences.js
@@ -37,6 +37,38 @@ function setupTabWidthSelector() {
}
}
+function setupThemeColor() {
+ const LOCAL_STORAGE_KEY = "legit_theme_color";
+ const VALID_COLORS = ["red", "orange", "green", "gray", "pink", "purple", "yellow"];
+
+ function applyThemeColor(color) {
+ if (color) {
+ localStorage.setItem(LOCAL_STORAGE_KEY, color);
+ document.documentElement.dataset.themeColor = color;
+ } else {
+ localStorage.removeItem(LOCAL_STORAGE_KEY);
+ document.documentElement.dataset.themeColor = "";
+ }
+ }
+
+ const saved = localStorage.getItem(LOCAL_STORAGE_KEY) || "";
+ applyThemeColor(saved);
+
+ const selector = document.getElementById("theme-color");
+ if (selector) {
+ selector.value = saved;
+
+ selector.addEventListener("change", event => {
+ const value = event.currentTarget.value;
+ if (value && !VALID_COLORS.includes(value)) {
+ return;
+ }
+
+ applyThemeColor(value);
+ });
+ }
+}
+
function setupPreferencesDialog() {
const preferences = document.getElementById("preferences-dialog");
document.getElementById("preferences-dialog-trigger")?.addEventListener("click", (event) => {
@@ -48,4 +80,5 @@ function setupPreferencesDialog() {
}
setupTabWidthSelector();
+setupThemeColor();
setupPreferencesDialog();
diff --git a/embed/templates/site-footer.html.tmpl b/embed/templates/site-footer.html.tmpl
index e31e15f..aae21a3 100644
--- a/embed/templates/site-footer.html.tmpl
+++ b/embed/templates/site-footer.html.tmpl
@@ -31,6 +31,22 @@ SPDX-License-Identifier: MIT
Changes the size of a tab character in code blocks and code previews.
+
+
+
+
+ Changes the primary color to use for links, buttons, and icons.
+
+
{{- if .Config.UI.Footer.PoweredBy }}
--
2.51.2