diff --git a/assets/icons/brightness.svg b/assets/icons/brightness.svg new file mode 100644 index 0000000..752d895 --- /dev/null +++ b/assets/icons/brightness.svg @@ -0,0 +1,10 @@ + + + diff --git a/assets/icons/toggle-left.svg b/assets/icons/toggle-left.svg deleted file mode 100644 index c3048d4..0000000 --- a/assets/icons/toggle-left.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/assets/icons/toggle-right.svg b/assets/icons/toggle-right.svg deleted file mode 100644 index d3edd63..0000000 --- a/assets/icons/toggle-right.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/assets/scss/partials/menu.scss b/assets/scss/partials/menu.scss index 9c49b2e..9236291 100644 --- a/assets/scss/partials/menu.scss +++ b/assets/scss/partials/menu.scss @@ -214,28 +214,28 @@ } [data-scheme="dark"] { - #dark-mode-toggle { + #schemeSelectItem { color: var(--accent-color); font-weight: 700; - - .icon-tabler-toggle-left { - display: none; - } - - .icon-tabler-toggle-right { - display: unset; - } } } -#dark-mode-toggle { +#schemeSelectItem { margin-top: auto; color: var(--body-text-color); display: flex; align-items: center; - cursor: pointer; +} - .icon-tabler-toggle-right { - display: none; +#schemeSelect { + background: transparent; + border: 0; + color: var(--body-text-color); + padding: 0; + appearance: none; + + option { + color: var(--card-text-color-main); + background-color: var(--card-background); } } diff --git a/assets/ts/darkmode.ts b/assets/ts/darkmode.ts index 1f2ce53..2b0db49 100644 --- a/assets/ts/darkmode.ts +++ b/assets/ts/darkmode.ts @@ -1,53 +1,64 @@ -export default () => { - const toggleDarkMode = document.getElementById('dark-mode-toggle'); - const darkModeKey = 'StackDarkMode'; - const darkModeItem = localStorage.getItem(darkModeKey); - const darkModeEnabled = localStorage.getItem(darkModeKey) === 'true'; - const supportDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches === true; - const mql = window.matchMedia('(prefers-color-scheme: dark)'); +type colorScheme = 'light' | 'dark' | 'auto'; - let darkMode = false; +const colorSchemeKey = 'StackColorScheme'; +const mql = window.matchMedia('(prefers-color-scheme: dark)'); +const schemeSelect = document.getElementById('schemeSelect') as HTMLSelectElement; - if (darkModeItem && darkModeEnabled || !darkModeItem && supportDarkMode) { - /** - * Enable dark mode if: - * 1. If dark mode is set already (in local storage) - * 2. No color scheme preference is set in localstorage, and user's browser indicates preference for dark mode - */ - darkMode = true; - } +const supportDarkMode = () => { + return window.matchMedia('(prefers-color-scheme: dark)').matches === true; +} - const setBodyClass = () => { - if (darkMode) { +const saveScheme = (scheme: colorScheme) => { + localStorage.setItem(colorSchemeKey, scheme); +} + +const getScheme = () => { + return localStorage.getItem(colorSchemeKey) as colorScheme; +}; + +const setScheme = (scheme: colorScheme) => { + if (scheme === 'auto') { + if (supportDarkMode()) { document.body.dataset.scheme = 'dark'; } else { document.body.dataset.scheme = 'light'; } } - - const mediaQueryListener = (e) => { - darkMode = e.matches; - setBodyClass(); - } - - let listening = false; - if (!darkModeItem) { - /** - * If no dark mode preference is set in local storage, listen to browser color preference change - */ - mql.addEventListener('change', mediaQueryListener); - listening = true; + else { + document.body.dataset.scheme = scheme; } +} +const mediaQueryListener = (e) => { + setScheme('auto'); +} + +export default () => { document.body.style.setProperty('transition', 'background-color .3s ease'); - toggleDarkMode.addEventListener('click', (e) => { - darkMode = !darkMode; - setBodyClass(); - localStorage.setItem(darkModeKey, darkMode.toString()); + if (!getScheme()) { + /// First time visiting + setScheme('auto'); + saveScheme('auto') + mql.addEventListener('change', mediaQueryListener); + } + else { + setScheme(getScheme()); + } - if (listening) { + schemeSelect.value = getScheme(); + + schemeSelect.addEventListener('change', (e) => { + const value = schemeSelect.value as colorScheme; + + setScheme(value); + saveScheme(value); + + if (value === 'auto') { + mql.addEventListener('change', mediaQueryListener); + } + else { /** * Remove listener once user set color preference in website */ diff --git a/layouts/partials/sidebar/left.html b/layouts/partials/sidebar/left.html index de25ee9..26a3431 100644 --- a/layouts/partials/sidebar/left.html +++ b/layouts/partials/sidebar/left.html @@ -46,10 +46,14 @@ {{ end }} -