diff --git a/themes/leela/assets/css/main.css b/themes/leela/assets/css/main.css index edb938a2..ca15a308 100644 --- a/themes/leela/assets/css/main.css +++ b/themes/leela/assets/css/main.css @@ -42,117 +42,93 @@ --alert-header-info: hsl(180, 70%, 35%); } -/* Light theme (default) */ -:root, -.theme-light { - /* Core Colors */ - --color-white: #fff; - --color-black: #000; - --color-black-rgb: 0, 0, 0; - --color-gray-300: #e9ecef; - --color-gray-600: #666; - --color-gray-700: #333; - --black-rgb: 0, 0, 0; - - --color-float-ui: #fafad2; - - --border-color: hsl(223.81 0% 90%); - --border-color-active: hsl(327, 82%, 51%); - - --color-border-primary: var(--border-color); - --color-border-active: var(--border-color-active); - - /* Text colors */ - --color-text-primary: var(--color-black); - --color-text-secondary: var(--color-gray-700); - --color-text-tertiary: var(--color-gray-600); + +:root { + /* --- Light Theme Palette --- */ + --light-color-white: #fff; + --light-color-black: #000; + --light-color-black-rgb: 0, 0, 0; + --light-color-gray-300: #e9ecef; + --light-color-gray-600: #666; + --light-color-gray-700: #333; + --light-color-float-ui: #fafad2; + --light-border-color: hsl(223.81 0% 90%); + --light-color-bg-primary: var(--light-color-white); + --light-color-bg-secondary: hsl(231, 47%, 97%); + --light-color-footer-bg: var(--light-color-bg-secondary); + --light-color-footer-icon: hsl(231, 17%, 60%); + + /* --- Dark Theme Palette --- */ + --dark-color-white: #f8f9fa; + --dark-color-black: #212529; + --dark-color-black-rgb: 33, 37, 41; + --dark-color-gray-300: #74808b; + --dark-color-gray-600: #adb5bd; + --dark-color-gray-700: #e9ecef; + --dark-color-float-ui: #343a40; + --dark-border-color: hsl(210, 14%, 30%); + --dark-color-bg-primary: #121416; + --dark-color-bg-secondary: #2d3239; + --dark-color-footer-bg: var(--dark-color-black); + --dark-color-footer-icon: hsl(231, 17%, 70%); +} + + +/* Should ONLY use these variables. */ +:root { + /* Light theme is the default */ + --color-text-primary: var(--light-color-black); + --color-text-secondary: var(--light-color-gray-700); + --color-text-tertiary: var(--light-color-gray-600); + --color-button-text: var(--light-color-white); --color-link: var(--color-accent); - --color-button-text: var(--color-white); - /* Background colors */ - --color-bg-primary: var(--color-white); - --color-bg-secondary: hsl(231, 47%, 97%); - --color-footer-bg: var(--color-bg-secondary); - --color-footer-icon: hsl(231, 17%, 60%); + --color-bg-primary: var(--light-color-bg-primary); + --color-bg-secondary: var(--light-color-bg-secondary); + --color-footer-bg: var(--light-color-footer-bg); + --color-float-ui: var(--light-color-float-ui); + + --color-border-primary: var(--light-border-color); + --color-border-active: var(--color-accent); - /* Effects */ - --shadow-color: rgba(var(--black-rgb), 0.1); + --shadow-color: rgba(var(--light-color-black-rgb), 0.1); --feature-icon-color: var(--color-accent); + --color-footer-icon: var(--light-color-footer-icon); } -/* Dark theme */ -.theme-dark { - /* Core Colors */ - --color-white: #f8f9fa; - --color-black: #212529; - --color-black-rgb: 33, 37, 41; - --color-gray-300: #74808b; - --color-gray-600: #adb5bd; - --color-gray-700: #e9ecef; - --black-rgb: 33, 37, 41; +[data-theme='dark'] { + --color-text-primary: var(--dark-color-white); + --color-text-secondary: var(--dark-color-gray-600); + --color-text-tertiary: var(--dark-color-gray-300); + --color-button-text: var(--dark-color-white); - --color-float-ui: #343a40; /* A yellow felt too bright */ + --color-bg-primary: var(--dark-color-bg-primary); + --color-bg-secondary: var(--dark-color-bg-secondary); + --color-footer-bg: var(--dark-color-footer-bg); + --color-float-ui: var(--dark-color-float-ui); - --border-color: hsl(210, 14%, 30%); - --border-color-active: hsl(327, 82%, 51%); - - --color-border-primary: var(--border-color); - --color-border-active: var(--border-color-active); - - /* Text colors */ - --color-text-primary: var(--color-white); - --color-text-secondary: var(--color-gray-600); - --color-text-tertiary: var(--color-gray-300); - --color-link: var(--color-accent); - --color-button-text: var(--color-white); - - /* Background colors */ - --color-bg-primary: #121416; - --color-bg-secondary: #2d3239; - --color-footer-bg: var(--color-black); - --color-footer-icon: hsl(231, 17%, 70%); + --color-border-primary: var(--dark-border-color); - /* Effects */ - --shadow-color: rgba(var(--black-rgb), 0.1); - --feature-icon-color: var(--color-accent); + --shadow-color: rgba(var(--dark-color-black-rgb), 0.1); + --color-footer-icon: var(--dark-color-footer-icon); } -/* System theme - respects user's OS preference */ @media (prefers-color-scheme: dark) { - :root:not(.theme-light):not(.theme-dark) { - /* Core Colors */ - --color-white: #f8f9fa; - --color-black: #212529; - --color-black-rgb: 33, 37, 41; - --color-gray-300: #74808b; - --color-gray-600: #adb5bd; - --color-gray-700: #e9ecef; - --black-rgb: 33, 37, 41; - - --color-float-ui: #343a40; /* A yellow felt too bright */ - - --border-color: hsl(210, 14%, 30%); - --border-color-active: hsl(327, 82%, 51%); - - --color-border-primary: var(--border-color); - --color-border-active: var(--border-color-active); - - /* Text colors */ - --color-text-primary: var(--color-white); - --color-text-secondary: var(--color-gray-600); - --color-text-tertiary: var(--color-gray-300); - --color-link: var(--color-accent); - --color-button-text: var(--color-white); - - /* Background colors */ - --color-bg-primary: #121416; - --color-bg-secondary: #2d3239; - --color-footer-bg: var(--color-black); - --color-footer-icon: hsl(231, 17%, 70%); - - /* Effects */ - --shadow-color: rgba(var(--black-rgb), 0.1); - --feature-icon-color: var(--color-accent); + :root:not([data-theme='light']) { + --color-text-primary: var(--dark-color-white); + --color-text-secondary: var(--dark-color-gray-600); + --color-text-tertiary: var(--dark-color-gray-300); + --color-button-text: var(--dark-color-white); + + --color-bg-primary: var(--dark-color-bg-primary); + --color-bg-secondary: var(--dark-color-bg-secondary); + --color-footer-bg: var(--dark-color-footer-bg); + --color-float-ui: var(--dark-color-float-ui); + + --color-border-primary: var(--dark-border-color); + + --shadow-color: rgba(var(--dark-color-black-rgb), 0.1); + --color-footer-icon: var(--dark-color-footer-icon); } } diff --git a/themes/leela/assets/css/syntax.css b/themes/leela/assets/css/syntax.css index 78ab2668..2bbe2339 100644 --- a/themes/leela/assets/css/syntax.css +++ b/themes/leela/assets/css/syntax.css @@ -88,6 +88,7 @@ /* TextWhitespace */ .chroma .w { } @media (prefers-color-scheme: dark) { + :root:not([data-theme='light']) { /* Generated using: hugo gen chromastyles --style=github-dark */ /* Background */ .bg { color:#e6edf3;background-color:#0d1117; } @@ -176,4 +177,5 @@ /* GenericTraceback */ .chroma .gt { color:#ff7b72 } /* GenericUnderline */ .chroma .gl { text-decoration:underline } /* TextWhitespace */ .chroma .w { color:#6e7681 } + } } diff --git a/themes/leela/assets/js/main.js b/themes/leela/assets/js/main.js index d60b7a92..d31b749c 100644 --- a/themes/leela/assets/js/main.js +++ b/themes/leela/assets/js/main.js @@ -76,38 +76,48 @@ document.addEventListener('DOMContentLoaded', () => { const themeToggleBtn = document.getElementById("theme-toggle"); const themeIcon = document.getElementById("theme-icon"); - // Load saved theme from localStorage - const savedTheme = localStorage.getItem("theme"); - if (savedTheme === "light") { - htmlEl.classList.add("theme-light"); - themeIcon.className = "ri--sun-line"; - } else if (savedTheme === "dark") { - htmlEl.classList.add("theme-dark"); - themeIcon.className = "ri--moon-line"; - } else { - htmlEl.classList.remove("theme-light", "theme-dark"); - themeIcon.className = "lucide--sun-moon"; - } + const applyTheme = (theme) => { + if (theme === 'light') { + htmlEl.setAttribute('data-theme', 'light'); + themeIcon.className = "ri--sun-line"; + } else if (theme === 'dark') { + htmlEl.setAttribute('data-theme', 'dark'); + themeIcon.className = "ri--moon-line"; + } else { + // For 'system' theme, we remove the attribute. + // The CSS media query will then automatically apply the correct theme. + htmlEl.removeAttribute('data-theme'); + themeIcon.className = "lucide--sun-moon"; + } + }; + + const saveTheme = (theme) => { + localStorage.setItem("theme", theme); + }; - // Toggle theme on click + // --- Initialize theme on page load --- + const savedTheme = localStorage.getItem("theme") || "system"; + applyTheme(savedTheme); + + // --- Toggle theme on click --- if (themeToggleBtn) { themeToggleBtn.addEventListener("click", () => { - if (htmlEl.classList.contains("theme-light")) { - htmlEl.classList.remove("theme-light"); - htmlEl.classList.add("theme-dark"); - localStorage.setItem("theme", "dark"); - themeIcon.className = "ri--moon-line"; - } else if (htmlEl.classList.contains("theme-dark")) { - htmlEl.classList.remove("theme-light"); - htmlEl.classList.remove("theme-dark"); - localStorage.setItem("theme", "system"); - themeIcon.className = "lucide--sun-moon"; - } else { - htmlEl.classList.remove("theme-dark"); - htmlEl.classList.add("theme-light"); - localStorage.setItem("theme", "light"); - themeIcon.className = "ri--sun-line"; + const currentTheme = htmlEl.getAttribute("data-theme"); + const savedTheme = localStorage.getItem("theme"); + + let nextTheme; + + // The logic for the three-state toggle: light -> dark -> system -> light + if (savedTheme === 'light') { + nextTheme = 'dark'; + } else if (savedTheme === 'dark') { + nextTheme = 'system'; + } else { // This covers 'system' or null + nextTheme = 'light'; } + + applyTheme(nextTheme); + saveTheme(nextTheme); }); } });