1import { Controller } from "@hotwired/stimulus" 2 3const STORAGE_KEY = "hackorum-theme" 4const DEFAULT_THEME = "light" 5 6export default class extends Controller { 7 static targets = ["icon", "label", "button"] 8 9 connect() { 10 this.applyInitialTheme() 11 } 12 13 toggle(event) { 14 if (event && event.type !== "change") { 15 event.preventDefault() 16 } 17 const nextTheme = this.currentTheme === "dark" ? "light" : "dark" 18 this.setTheme(nextTheme) 19 } 20 21 select(event) { 22 event.preventDefault() 23 const { themeValue } = event.currentTarget.dataset 24 this.setTheme(themeValue) 25 } 26 27 applyInitialTheme() { 28 const storedTheme = window.localStorage.getItem(STORAGE_KEY) 29 const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches 30 const initialTheme = storedTheme || (prefersDark ? "dark" : DEFAULT_THEME) 31 32 this.setTheme(initialTheme, { persist: false }) 33 } 34 35 setTheme(theme, { persist = true } = {}) { 36 const normalizedTheme = theme === "dark" ? "dark" : "light" 37 document.documentElement.dataset.theme = normalizedTheme 38 39 if (persist) { 40 window.localStorage.setItem(STORAGE_KEY, normalizedTheme) 41 } 42 43 this.updateToggle(normalizedTheme) 44 } 45 46 updateToggle(theme) { 47 if (this.hasLabelTarget) { 48 this.labelTarget.textContent = theme === "dark" ? "Dark" : "Light" 49 } 50 51 if (this.hasIconTarget) { 52 this.iconTarget.classList.remove("fa-regular", "fa-solid", "fa-moon", "fa-sun") 53 this.iconTarget.classList.add("fa-solid") 54 this.iconTarget.classList.add(theme === "dark" ? "fa-sun" : "fa-moon") 55 } 56 57 this.element.setAttribute("aria-pressed", theme === "dark") 58 this.element.setAttribute("aria-label", `Switch to ${theme === "dark" ? "light" : "dark"} mode`) 59 this.element.setAttribute("title", `Switch to ${theme === "dark" ? "light" : "dark"} mode`) 60 61 if (this.hasButtonTarget) { 62 this.buttonTargets.forEach((button) => { 63 button.classList.toggle("is-active", button.dataset.themeValue === theme) 64 }) 65 } 66 } 67 68 get currentTheme() { 69 return document.documentElement.dataset.theme || DEFAULT_THEME 70 } 71}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.