yak(theme-explicit-light-is-overridden-on-dark-os-browsers-chip-backgrounds-are-dropped-pku7): theme: explicit light is overridden on dark-OS browsers; chip backgrounds are dropped
This commit is contained in:
@@ -84,7 +84,10 @@ defmodule FirehoseWeb.Layouts do
|
||||
def theme_toggle(assigns) do
|
||||
~H"""
|
||||
<div class="card relative flex flex-row items-center border-2 border-base-300 bg-base-300 rounded-full">
|
||||
<div class="absolute w-1/3 h-full rounded-full border-1 border-base-200 bg-base-100 brightness-200 left-0 [[data-theme=light]_&]:left-1/3 [[data-theme=dark]_&]:left-2/3 transition-[left]" />
|
||||
<%!-- The knob follows the visitor's choice, not the resolved palette: in
|
||||
system mode data-theme may be light or dark, but the system icon stays
|
||||
selected. --%>
|
||||
<div class="absolute w-1/3 h-full rounded-full border-1 border-base-200 bg-base-100 brightness-200 left-0 [[data-theme-choice=light]_&]:left-1/3 [[data-theme-choice=dark]_&]:left-2/3 transition-[left]" />
|
||||
|
||||
<button
|
||||
class="flex p-2 cursor-pointer w-1/3"
|
||||
|
||||
@@ -14,20 +14,37 @@
|
||||
</script>
|
||||
<script>
|
||||
(() => {
|
||||
const setTheme = (theme) => {
|
||||
if (theme === "system") {
|
||||
localStorage.removeItem("phx:theme");
|
||||
document.documentElement.removeAttribute("data-theme");
|
||||
} else {
|
||||
localStorage.setItem("phx:theme", theme);
|
||||
document.documentElement.setAttribute("data-theme", theme);
|
||||
}
|
||||
// Theme selection is always explicit: the document always carries a
|
||||
// data-theme attribute, resolved here before first paint. An explicit
|
||||
// choice therefore always wins in CSS, whatever the OS preference is;
|
||||
// no stylesheet rule follows the OS on its own.
|
||||
//
|
||||
// data-theme-choice records what the visitor actually chose (unset,
|
||||
// system, light, dark) and is what the toggle's knob follows: in
|
||||
// "system" mode the palette may resolve to light or dark, but the
|
||||
// system icon must stay selected.
|
||||
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
const stored = () => localStorage.getItem("phx:theme");
|
||||
const resolve = (theme) =>
|
||||
theme === "system" ? (prefersDark.matches ? "dark" : "light") : theme;
|
||||
const apply = (theme) => {
|
||||
document.documentElement.setAttribute("data-theme", resolve(theme));
|
||||
document.documentElement.setAttribute("data-theme-choice", theme);
|
||||
};
|
||||
const setTheme = (theme) => {
|
||||
localStorage.setItem("phx:theme", theme);
|
||||
apply(theme);
|
||||
};
|
||||
// Light is the default: no stored preference means light, not "follow
|
||||
// the OS". "System" is an explicit choice and is stored as such.
|
||||
if (!document.documentElement.hasAttribute("data-theme")) {
|
||||
setTheme(localStorage.getItem("phx:theme") || "system");
|
||||
apply(stored() || "light");
|
||||
}
|
||||
window.addEventListener("storage", (e) => e.key === "phx:theme" && setTheme(e.newValue || "system"));
|
||||
|
||||
// Follow the OS only while the visitor's recorded choice is "system".
|
||||
prefersDark.addEventListener("change", () => {
|
||||
if (stored() === "system") apply("system");
|
||||
});
|
||||
window.addEventListener("storage", (e) => e.key === "phx:theme" && setTheme(e.newValue || "light"));
|
||||
window.addEventListener("phx:set-theme", (e) => setTheme(e.target.dataset.phxTheme));
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user