aboutsummaryrefslogtreecommitdiff
path: root/themes/hugo-theme-stack/assets/ts/colorScheme.ts
diff options
context:
space:
mode:
Diffstat (limited to 'themes/hugo-theme-stack/assets/ts/colorScheme.ts')
-rw-r--r--themes/hugo-theme-stack/assets/ts/colorScheme.ts92
1 files changed, 92 insertions, 0 deletions
diff --git a/themes/hugo-theme-stack/assets/ts/colorScheme.ts b/themes/hugo-theme-stack/assets/ts/colorScheme.ts
new file mode 100644
index 0000000..978e98e
--- /dev/null
+++ b/themes/hugo-theme-stack/assets/ts/colorScheme.ts
@@ -0,0 +1,92 @@
+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 (window.matchMedia('(prefers-color-scheme: dark)').matches === true)
+ this.systemPreferScheme = 'dark'
+ else
+ this.systemPreferScheme = 'light';
+
+ this.dispatchEvent(document.documentElement.dataset.scheme as colorScheme);
+
+ 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: HTMLElement) {
+ 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.documentElement.dataset.scheme = 'dark';
+ }
+ else {
+ document.documentElement.dataset.scheme = 'light';
+ }
+
+ this.dispatchEvent(document.documentElement.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;