my website built with vue, plus lexicon definitions for moe.wlo.gallery.* vt3e.cat
at develop 4.4 kB view raw
1import { html } from "../html"; 2 3const themes = { 4 light: ["latte"], 5 dark: ["frappe", "macchiato", "mocha"], 6}; 7 8const allThemes = [...themes.dark, ...themes.light]; 9const defaultTheme = "mocha"; 10 11function getCurrentTheme(): string { 12 const stored = localStorage.getItem("theme"); 13 if (stored && allThemes.includes(stored)) return stored; 14 return defaultTheme; 15} 16 17function getCurrentBoxyMode(): boolean { 18 const stored = localStorage.getItem("boxyMode"); 19 return stored === "true"; 20} 21 22function applyBoxyMode(isEnabled: boolean) { 23 if (isEnabled) document.documentElement.classList.add("boxy"); 24 else document.documentElement.classList.remove("boxy"); 25 26 localStorage.setItem("boxyMode", isEnabled.toString()); 27} 28 29function applyTheme(theme: string) { 30 for (const t of allThemes) document.body.classList.remove(`theme-${t}`); 31 document.body.classList.add(`theme-${theme}`); 32 localStorage.setItem("theme", theme); 33} 34 35type DropdownOptionItem = { 36 value: string; 37 label: string; 38 selected?: boolean; 39}; 40type DropdownOption = 41 | { 42 type: "optgroup"; 43 name: string; 44 children: DropdownOptionItem[]; 45 } 46 | DropdownOptionItem; 47type DropdownOptions = { 48 options: DropdownOption[]; 49 selectedValue?: string; 50 onChange: (value: string) => void; 51 label?: string; 52}; 53 54function Dropdown({ 55 options, 56 selectedValue, 57 onChange, 58 label = "select an option", 59}: DropdownOptions) { 60 const id = `${Math.random().toString(36).substring(2, 15)}`; 61 62 (window as Window)[`handleDropdownChange_${id}`] = (event: Event) => { 63 const select = event.target as HTMLSelectElement; 64 onChange(select.value); 65 }; 66 67 const renderOption = (option: DropdownOptionItem) => { 68 const isSelected = selectedValue === option.value; 69 const _ = html` 70 <option 71 value=${option.value} 72 selected=${isSelected ? "" : undefined} 73 > 74 ${option.label} 75 </option> 76 `; 77 return _; 78 }; 79 80 const renderDropdownOption = (option: DropdownOption) => { 81 if ("type" in option && option.type === "optgroup") { 82 return html` 83 <optgroup label="${option.name}"> 84 ${option.children.map(renderOption)} 85 </optgroup> 86 `; 87 } else { 88 return renderOption(option as DropdownOptionItem); 89 } 90 }; 91 92 return html` 93 <div class="dropdown input-container"> 94 <label for="${id}" class="dropdown__label">${label}</label> 95 <select 96 id="${id}" 97 class="dropdown__select" 98 onchange="window.handleDropdownChange_${id}(event)" 99 > 100 ${options.map(renderDropdownOption)} 101 </select> 102 </div> 103 `; 104} 105 106type CheckboxOptions = { 107 label: string; 108 checked: boolean; 109 onChange: (checked: boolean) => void; 110}; 111function Checkbox({ label, checked, onChange }: CheckboxOptions) { 112 const id = `${Math.random().toString(36).substring(2, 15)}`; 113 114 (window as Window)[`handleCheckboxChange_${id}`] = (event: Event) => { 115 const checkbox = event.target as HTMLInputElement; 116 onChange(checkbox.checked); 117 }; 118 119 return html` 120 <div class="input-container checkbox-container"> 121 <span class="checkbox-label" aria-hidden="true">${label}</span> 122 <label class="sr-only" for="${id}">${label}</label> 123 <input 124 type="checkbox" 125 id="${id}" 126 class="checkbox" 127 checked=${checked ? "checked" : ""} 128 onchange="window.handleCheckboxChange_${id}(event)" 129 /> 130 </div> 131 `; 132} 133 134export const OptionsSection = () => { 135 const currentTheme = getCurrentTheme(); 136 const isBoxyMode = getCurrentBoxyMode(); 137 138 applyTheme(currentTheme); 139 applyBoxyMode(isBoxyMode); 140 141 const dropdownOptions: DropdownOptions = { 142 options: [ 143 { 144 type: "optgroup", 145 name: "light themes", 146 children: themes.light.map((t) => ({ 147 value: t, 148 label: t, 149 selected: t === currentTheme, 150 })), 151 }, 152 { 153 type: "optgroup", 154 name: "dark themes", 155 children: themes.dark.map((t) => ({ 156 value: t, 157 label: t, 158 selected: t === currentTheme, 159 })), 160 }, 161 ], 162 selectedValue: currentTheme, 163 onChange: applyTheme, 164 label: "theme", 165 }; 166 const checkboxOptions: CheckboxOptions = { 167 label: "boxy mode", 168 checked: isBoxyMode, 169 onChange: applyBoxyMode, 170 }; 171 172 return html` 173 <div class="theme-picker"> 174 ${Dropdown(dropdownOptions)} 175 ${Checkbox(checkboxOptions)} 176 </div> 177 `; 178}; 179 180document.addEventListener("DOMContentLoaded", () => { 181 applyTheme(getCurrentTheme()); 182 applyBoxyMode(getCurrentBoxyMode()); 183});