feat: add unified Settings dialog (#18)
This commit is contained in:
1 parent
bdb1e3e230
commit
5a34160ab2
29 files changed
+420
-453
No files matched your search
@@ -33,7 +33,7 @@ export class CalendarSettingsService {
|
||||
constructor() {
|
||||
for (const [id, def] of this.definitions) {
|
||||
const storageKey = `calendarSettings.${id}`;
|
||||
this.signals.set(id, storedSignal(storageKey, def.defaultValue, this.injector));
|
||||
this.signals.set(id, storedSignal(storageKey, def.defaultValue, this.injector, 0));
|
||||
}
|
||||
|
||||
this.settingsArray = Array.from(this.definitions.entries()).map(([id, def]) => ({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { computed, Injectable, signal } from '@angular/core';
|
||||
import { computed, inject, Injectable, Injector, signal } from '@angular/core';
|
||||
import { storedSignal } from '../shared/utils/stored-signal';
|
||||
|
||||
export type ThemePreference = 'system' | 'light' | 'dark';
|
||||
export type EffectiveTheme = 'light' | 'dark';
|
||||
@@ -7,15 +8,23 @@ export type EffectiveTheme = 'light' | 'dark';
|
||||
export class ThemeService {
|
||||
private readonly lightModeMedia = window.matchMedia('(prefers-color-scheme: light)');
|
||||
private readonly systemIsLight = signal(this.lightModeMedia.matches);
|
||||
private readonly selectedPreference = signal<ThemePreference>('system');
|
||||
private readonly selectedPreference = storedSignal<ThemePreference>(
|
||||
'theme.preference',
|
||||
'system',
|
||||
inject(Injector),
|
||||
0,
|
||||
);
|
||||
readonly themePreference = this.selectedPreference.asReadonly();
|
||||
readonly effectiveTheme = computed<EffectiveTheme>(() => {
|
||||
const preference = this.selectedPreference();
|
||||
return preference === 'system' ? (this.systemIsLight() ? 'light' : 'dark') : preference;
|
||||
});
|
||||
readonly nextThemePreference = computed(() => this.nextPreference(this.selectedPreference()));
|
||||
|
||||
constructor() {
|
||||
const preference = this.selectedPreference();
|
||||
if (preference !== 'system' && preference !== 'light' && preference !== 'dark') {
|
||||
this.selectedPreference.set('system');
|
||||
}
|
||||
this.applyEffectiveTheme();
|
||||
this.lightModeMedia.addEventListener('change', (e) => {
|
||||
this.systemIsLight.set(e.matches);
|
||||
@@ -25,19 +34,11 @@ export class ThemeService {
|
||||
});
|
||||
}
|
||||
|
||||
toggleTheme(): void {
|
||||
this.setThemePreference(this.nextThemePreference());
|
||||
}
|
||||
|
||||
private setThemePreference(preference: ThemePreference): void {
|
||||
setThemePreference(preference: ThemePreference): void {
|
||||
this.selectedPreference.set(preference);
|
||||
this.applyEffectiveTheme();
|
||||
}
|
||||
|
||||
private nextPreference(preference: ThemePreference): ThemePreference {
|
||||
return preference === 'system' ? 'light' : preference === 'light' ? 'dark' : 'system';
|
||||
}
|
||||
|
||||
private applyEffectiveTheme(): void {
|
||||
const isLight = this.effectiveTheme() === 'light';
|
||||
document.body.classList.toggle('light-mode', isLight);
|
||||
|
||||
@@ -50,6 +50,13 @@ export interface AppTranslations {
|
||||
showWeekNumbers: string;
|
||||
close: string;
|
||||
selectLanguage: string;
|
||||
selectTheme: string;
|
||||
themeOptions: {
|
||||
system: string;
|
||||
light: string;
|
||||
dark: string;
|
||||
};
|
||||
systemAppearance: string;
|
||||
};
|
||||
rules: {
|
||||
title: string;
|
||||
@@ -307,6 +314,7 @@ export class TranslationService {
|
||||
'app.language',
|
||||
this.getBrowserLanguage(),
|
||||
this.injector,
|
||||
0,
|
||||
);
|
||||
|
||||
public readonly tr = computed<AppTranslations>(() => {
|
||||
|
||||
Reference in new issue
Block a user