feat(darkmode): dark mode toggle (#82)
* feat(darkmode): initial support for dark mode toggle * fix(darkmode): add svg icons * feat(darkmode): dispatch onColorSchemeChange event * add head/darkmode * feat(darkmode); add colorScheme config * style: remove empty line * refactor(darkmode): simplify code * style: add comment for darkmode config * i18n support for dark mode toggle * Some renaming
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
type colorScheme = 'light' | 'dark' | 'auto';
|
||||
|
||||
class StackColorScheme {
|
||||
private localStorageKey = 'StackColorScheme';
|
||||
private currentScheme: colorScheme;
|
||||
private systemPreferScheme: colorScheme;
|
||||
|
||||
constructor(toggleEl: HTMLElement) {
|
||||
this.bindMatchMedia();
|
||||
this.currentScheme = this.getSavedScheme();
|
||||
|
||||
if (toggleEl)
|
||||
this.bindClick(toggleEl);
|
||||
|
||||
if (document.body.style.transition == '')
|
||||
document.body.style.setProperty('transition', 'background-color .3s ease');
|
||||
}
|
||||
|
||||
private saveScheme() {
|
||||
localStorage.setItem(this.localStorageKey, this.currentScheme);
|
||||
}
|
||||
|
||||
private bindClick(toggleEl) {
|
||||
toggleEl.addEventListener('click', (e) => {
|
||||
if (this.isDark()) {
|
||||
/// Disable dark mode
|
||||
this.currentScheme = 'light';
|
||||
}
|
||||
else {
|
||||
this.currentScheme = 'dark';
|
||||
}
|
||||
|
||||
this.setBodyClass();
|
||||
|
||||
if (this.currentScheme == this.systemPreferScheme) {
|
||||
/// Set to auto
|
||||
this.currentScheme = 'auto';
|
||||
}
|
||||
|
||||
this.saveScheme();
|
||||
})
|
||||
}
|
||||
|
||||
private isDark() {
|
||||
return (this.currentScheme == 'dark' || this.currentScheme == 'auto' && this.systemPreferScheme == 'dark');
|
||||
}
|
||||
|
||||
private dispatchEvent(colorScheme: colorScheme) {
|
||||
const event = new CustomEvent('onColorSchemeChange', {
|
||||
detail: colorScheme
|
||||
});
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
|
||||
private setBodyClass() {
|
||||
if (this.isDark()) {
|
||||
document.body.dataset.scheme = 'dark';
|
||||
}
|
||||
else {
|
||||
document.body.dataset.scheme = 'light';
|
||||
}
|
||||
|
||||
this.dispatchEvent(document.body.dataset.scheme as colorScheme);
|
||||
}
|
||||
|
||||
private getSavedScheme(): colorScheme {
|
||||
const savedScheme = localStorage.getItem(this.localStorageKey);
|
||||
|
||||
if (savedScheme == 'light' || savedScheme == 'dark' || savedScheme == 'auto') return savedScheme;
|
||||
else return 'auto';
|
||||
}
|
||||
|
||||
private bindMatchMedia() {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
||||
if (e.matches) {
|
||||
this.systemPreferScheme = 'dark';
|
||||
}
|
||||
else {
|
||||
this.systemPreferScheme = 'light';
|
||||
}
|
||||
this.setBodyClass();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default StackColorScheme;
|
||||
@@ -9,6 +9,7 @@ import StackGallery from "ts/gallery";
|
||||
import { getColor } from 'ts/color';
|
||||
import menu from 'ts/menu';
|
||||
import createElement from 'ts/createElement';
|
||||
import StackColorScheme from 'ts/colorScheme';
|
||||
|
||||
let Stack = {
|
||||
init: () => {
|
||||
@@ -52,6 +53,8 @@ let Stack = {
|
||||
|
||||
observer.observe(articleTile)
|
||||
}
|
||||
|
||||
new StackColorScheme(document.getElementById('dark-mode-toggle'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user