1 line
5.1 KiB
JavaScript
1 line
5.1 KiB
JavaScript
const themeToggle=document.createElement("template");themeToggle.innerHTML='\n <style>\n *{\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n }\n :host{\n cursor: pointer;\n --height: 2.5rem;\n --width: 2.5rem;\n }\n .theme-toggle {\n display: flex;\n position: relative;\n width: 1.4rem;\n height: 1.4rem;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n .theme-toggle::after{\n content: \'\';\n position: absolute;\n height: var(--height);\n width: var(--width);\n top: 50%;\n left: 50%;\n opacity: 0;\n border-radius: 50%;\n pointer-events: none;\n transition: transform 0.3s, opacity 0.3s;\n transform: translate(-50%, -50%) scale(1.2);\n background-color: rgba(var(--text-color), 0.12);\n }\n :host(:focus-within) .theme-toggle{\n outline: none;\n }\n :host(:focus-within) .theme-toggle::after{\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n .icon {\n position: absolute;\n height: 100%;\n width: 100%;\n fill: rgba(var(--text-color), 1);\n transition: transform 0.6s;\n }\n \n .theme-switcher__checkbox {\n display: none;\n }\n :host([checked]) .moon-icon {\n transform: scale(0) rotate(90deg);\n }\n :host(:not([checked])) .sun-icon {\n transform: scale(0) rotate(-90deg);\n }\n </style>\n <label class="theme-toggle" title="Change theme" tabindex="0">\n <slot name="light-mode-icon">\n <svg class="icon moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24"\n height="24">\n <path fill="none" d="M0 0h24v24H0z" />\n <path\n d="M10 6a8 8 0 0 0 11.955 6.956C21.474 18.03 17.2 22 12 22 6.477 22 2 17.523 2 12c0-5.2 3.97-9.474 9.044-9.955A7.963 7.963 0 0 0 10 6zm-6 6a8 8 0 0 0 8 8 8.006 8.006 0 0 0 6.957-4.045c-.316.03-.636.045-.957.045-5.523 0-10-4.477-10-10 0-.321.015-.64.045-.957A8.006 8.006 0 0 0 4 12zm14.164-9.709L19 2.5v1l-.836.209a2 2 0 0 0-1.455 1.455L16.5 6h-1l-.209-.836a2 2 0 0 0-1.455-1.455L13 3.5v-1l.836-.209A2 2 0 0 0 15.29.836L15.5 0h1l.209.836a2 2 0 0 0 1.455 1.455zm5 5L24 7.5v1l-.836.209a2 2 0 0 0-1.455 1.455L21.5 11h-1l-.209-.836a2 2 0 0 0-1.455-1.455L18 8.5v-1l.836-.209a2 2 0 0 0 1.455-1.455L20.5 5h1l.209.836a2 2 0 0 0 1.455 1.455z" />\n </svg>\n </slot>\n <slot name="dark-mode-icon">\n <svg class="icon sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">\n <path fill="none" d="M0 0h24v24H0z" />\n <path\n d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z" />\n </svg>\n </slot>\n </label>\n';class ThemeToggle extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(themeToggle.content.cloneNode(!0)),this.isChecked=!1,this.hasTheme="light",this.toggleState=this.toggleState.bind(this),this.fireEvent=this.fireEvent.bind(this),this.handleThemeChange=this.handleThemeChange.bind(this)}static get observedAttributes(){return["checked"]}daylight(){this.hasTheme="light",document.body.dataset.theme="light",this.setAttribute("aria-checked","false")}nightlight(){this.hasTheme="dark",document.body.dataset.theme="dark",this.setAttribute("aria-checked","true")}toggleState(){this.toggleAttribute("checked"),this.fireEvent()}handleKeyDown(e){"Space"===e.code&&this.toggleState()}handleThemeChange(e){e.detail.theme!==this.hasTheme&&("dark"===e.detail.theme?this.setAttribute("checked",""):this.removeAttribute("checked"))}fireEvent(){this.dispatchEvent(new CustomEvent("themechange",{bubbles:!0,composed:!0,detail:{theme:this.hasTheme}}))}connectedCallback(){this.setAttribute("role","switch"),this.setAttribute("aria-label","theme toggle"),"dark"===localStorage.theme?(this.nightlight(),this.setAttribute("checked","")):"light"===localStorage.theme?(this.daylight(),this.removeAttribute("checked")):window.matchMedia("(prefers-color-scheme: dark)").matches?(this.nightlight(),this.setAttribute("checked","")):(this.daylight(),this.removeAttribute("checked")),this.addEventListener("click",this.toggleState),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("themechange",this.handleThemeChange)}disconnectedCallback(){this.removeEventListener("click",this.toggleState),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("themechange",this.handleThemeChange)}attributeChangedCallback(e,t,n){"checked"===e&&(this.hasAttribute("checked")?(this.nightlight(),localStorage.setItem("theme","dark")):(this.daylight(),localStorage.setItem("theme","light")))}}window.customElements.define("theme-toggle",ThemeToggle); |