57 lines
1.6 KiB
TypeScript
57 lines
1.6 KiB
TypeScript
import {effect, Injectable, signal, WritableSignal} from '@angular/core';
|
|
import {Theme} from "../models/theme";
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class ThemeSwitchService {
|
|
private readonly THEME_KEY = 'app-theme-mode';
|
|
|
|
public theme: WritableSignal<Theme> = signal(Theme.DEFAULT_THEME);
|
|
|
|
constructor() {
|
|
effect(() => {
|
|
const currentTheme = this.theme();
|
|
localStorage.setItem(this.THEME_KEY, currentTheme.code);
|
|
|
|
const html = document.querySelector('html')!;
|
|
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
|
|
const isDark = currentTheme.code === 'dark' || (currentTheme.code === 'system' && systemPrefersDark);
|
|
|
|
html.classList.toggle('dark', isDark);
|
|
});
|
|
|
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
|
if (this.theme().code === 'system') {
|
|
this.theme.update(t => t);
|
|
}
|
|
});
|
|
}
|
|
|
|
initialize() {
|
|
console.info('initializing dark mode service');
|
|
const stored = Theme.THEMES.find(theme => theme.code === localStorage.getItem(this.THEME_KEY));
|
|
|
|
if (stored === undefined) {
|
|
this.theme.set(Theme.DEFAULT_THEME);
|
|
return;
|
|
}
|
|
|
|
if (stored.code === 'dark' || stored.code === 'light' || stored.code === 'system') {
|
|
this.theme.set(stored);
|
|
} else {
|
|
this.theme.set(Theme.DEFAULT_THEME);
|
|
}
|
|
}
|
|
|
|
switchToTheme(theme: Theme) {
|
|
console.info(`switching to theme: ${theme.name}`);
|
|
this.theme.set(theme);
|
|
}
|
|
|
|
isDarkMode(): boolean {
|
|
return this.theme().code === 'dark' || (this.theme().code === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
}
|
|
}
|