diff --git a/src/app/core/services/display-mode.service.ts b/src/app/core/services/display-mode.service.ts index adfd71c..61e30f6 100644 --- a/src/app/core/services/display-mode.service.ts +++ b/src/app/core/services/display-mode.service.ts @@ -1,19 +1,21 @@ import { Injectable, inject } from '@angular/core'; import { DOCUMENT } from '@angular/common'; -import { DISPLAY_MODES, LinkParserSettingsService } from '../../link-parser/data-access/link-parser-settings.service'; +import { LinkParserSettingsService } from '../../link-parser/data-access/link-parser-settings.service'; +import { DISPLAY_MODES, ThemeService } from '../../shared/data-access/theme.service'; @Injectable({ providedIn: 'root' }) export class DisplayModeService { private doc = inject(DOCUMENT); private setts = inject(LinkParserSettingsService); + private theme = inject(ThemeService) update() { - if (this.setts.displayMode == undefined) return; + if (this.theme.displayMode == undefined) return; for (const mode of DISPLAY_MODES) { this.doc.documentElement.classList.remove(mode); } - this.doc.documentElement.classList.add(this.setts.displayMode() + 'mode'); + this.doc.documentElement.classList.add(this.theme.displayMode() + 'mode'); } } \ No newline at end of file diff --git a/src/app/file/data-access/file-history.service.ts b/src/app/file/data-access/file-history.service.ts index d22f445..9a3b73a 100644 --- a/src/app/file/data-access/file-history.service.ts +++ b/src/app/file/data-access/file-history.service.ts @@ -19,7 +19,7 @@ export class FileHistoryService { private createDatabase() { this.db = new Dexie(HISTORY_DB_NAME); - this.db.version(1).stores({ + this.db.version(2).stores({ filehistory: '++id,sha256,pages,size,title,format,page,cover,arrayBuffer,created,updated' }); } diff --git a/src/app/history/data-access/history.service.ts b/src/app/history/data-access/history.service.ts index 959e596..1f30f47 100644 --- a/src/app/history/data-access/history.service.ts +++ b/src/app/history/data-access/history.service.ts @@ -20,7 +20,7 @@ export class HistoryService { private createDatabase() { this.db = new Dexie(HISTORY_DB_NAME); - this.db.version(1).stores({ + this.db.version(2).stores({ history: '++id,site,post_id,title,cover,episode,pages,page,created,updated' }); } diff --git a/src/app/link-parser/data-access/link-parser-settings.service.ts b/src/app/link-parser/data-access/link-parser-settings.service.ts index 1908af3..b100e1f 100644 --- a/src/app/link-parser/data-access/link-parser-settings.service.ts +++ b/src/app/link-parser/data-access/link-parser-settings.service.ts @@ -1,11 +1,7 @@ -import { isPlatformBrowser } from '@angular/common'; -import { Injectable, PLATFORM_ID, WritableSignal, computed, inject, signal } from '@angular/core'; -import { ToggleBarOption } from '../../shared/ui/toggle-bar'; +import { isPlatformServer } from '@angular/common'; +import { Injectable, PLATFORM_ID, WritableSignal, inject, signal } from '@angular/core'; -export const DISPLAY_MODES = ['softmode', 'truemode']; -const NAME_DISPLAY_MODE = 'displayMode'; const NAME_AUTO_PASTE_LINK = 'autoPasteLink'; -const NAME_SEASONAL_THEME = 'seasonalTheme'; @Injectable({ providedIn: 'root' @@ -17,80 +13,19 @@ export class LinkParserSettingsService { constructor() { this.initAutoPasteLink() - this.initSeasonalTheme() - this.initDisplayMode() } initAutoPasteLink() { - if (!isPlatformBrowser(this.platformId)) return; + if (isPlatformServer(this.platformId)) return; - const n = Boolean(localStorage.getItem('autoPasteLink') == 'true'); + const n = Boolean(localStorage.getItem(NAME_AUTO_PASTE_LINK) == 'true'); this.autoPasteLink = signal(n); } setAutoPasteLink(n: boolean) { - if (!isPlatformBrowser(this.platformId)) return; + if (isPlatformServer(this.platformId)) return; this.autoPasteLink.set(n); - localStorage.setItem('autoPasteLink', n.toString()) + localStorage.setItem(NAME_AUTO_PASTE_LINK, n.toString()) } - - displayMode!: WritableSignal; - - displayModeOptions: ToggleBarOption[] = [ - { value: 'true', emoji: '👑', label: 'trueMode' }, - { value: 'soft', emoji: '🧸', label: 'softMode' } - ] - - initDisplayMode() { - if (!isPlatformBrowser(this.platformId)) return; - - const n = localStorage.getItem(NAME_DISPLAY_MODE) === null ? 'soft' : localStorage.getItem(NAME_DISPLAY_MODE) as string; - this.displayMode = signal(n); - this.setDisplayMode(n); - } - - setDisplayMode(n: string) { - if (!isPlatformBrowser(this.platformId)) return; - - this.displayMode.update(v => n); - localStorage.setItem(NAME_DISPLAY_MODE, n) - } - - /** - * - */ - seasonalTheme: WritableSignal = signal(false); - - initSeasonalTheme() { - if (!isPlatformBrowser(this.platformId)) return; - - const n = localStorage.getItem('seasonalTheme') === null ? true : Boolean(localStorage.getItem('seasonalTheme') == 'true'); - this.seasonalTheme.set(n); - this.setSeasonalTheme(n); - } - - setSeasonalTheme(n: boolean) { - if (!isPlatformBrowser(this.platformId)) return; - - this.seasonalTheme.set(n); - localStorage.setItem('seasonalTheme', n.toString()) - } - - getSeasonalTheme(): string { - const now = new Date(); - const month = now.getMonth(); // 0-11 - const day = now.getDate(); - - if (month === 5) return 'pride'; // June - if (month === 9 && day > 15) return 'halloween'; // second half of Oct - if (month === 11 || (month === 0 && day < 10)) return 'newyear'; - if (month === 1 && day <= 15) return 'valentine'; - return 'default'; - } - - theme = computed(() => { - if (!this.seasonalTheme) return ''; - return this.seasonalTheme() ? this.getSeasonalTheme() : '' - }) } diff --git a/src/app/link-parser/link-parser/link-parser.component.html b/src/app/link-parser/link-parser/link-parser.component.html index c92121b..12e3afa 100644 --- a/src/app/link-parser/link-parser/link-parser.component.html +++ b/src/app/link-parser/link-parser/link-parser.component.html @@ -3,7 +3,7 @@ @defer (on immediate) { diff --git a/src/app/link-parser/link-parser/link-parser.component.ts b/src/app/link-parser/link-parser/link-parser.component.ts index 30719f7..2059b99 100644 --- a/src/app/link-parser/link-parser/link-parser.component.ts +++ b/src/app/link-parser/link-parser/link-parser.component.ts @@ -4,6 +4,7 @@ import { MetaTagsService } from '../../shared/data-access/meta-tags.service'; import { LinkParserService } from '../data-access/link-parser.service'; import { LinkParserSettingsService } from '../data-access/link-parser-settings.service'; import { FileService } from '../../file/data-access/file.service'; +import { ThemeService } from '../../shared/data-access/theme.service'; @Component({ selector: 'app-link-parser', @@ -19,7 +20,7 @@ import { FileService } from '../../file/data-access/file.service'; standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, host: { - '[class]': 'this.setts.theme()' + '[class]': 'this.theme.theme()' } }) export class LinkParserComponent { @@ -28,6 +29,7 @@ export class LinkParserComponent { public parser: LinkParserService = inject(LinkParserService) public setts = inject(LinkParserSettingsService) public file = inject(FileService) + protected theme = inject(ThemeService); constructor() { effect(() => { diff --git a/src/app/link-parser/ui/parser-form/parser-form.component.html b/src/app/link-parser/ui/parser-form/parser-form.component.html index 87f690e..a5763b9 100644 --- a/src/app/link-parser/ui/parser-form/parser-form.component.html +++ b/src/app/link-parser/ui/parser-form/parser-form.component.html @@ -8,7 +8,7 @@ }

- +

@if (online) {
diff --git a/src/app/link-parser/ui/parser-form/parser-form.component.ts b/src/app/link-parser/ui/parser-form/parser-form.component.ts index 496888f..ac9238e 100644 --- a/src/app/link-parser/ui/parser-form/parser-form.component.ts +++ b/src/app/link-parser/ui/parser-form/parser-form.component.ts @@ -1,6 +1,7 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { LangService } from '../../../shared/data-access/lang.service'; import { FileNetFacade, LinkInitFacade, LinkParserFacade, NavigationFacade } from './facades'; +import { ThemeService } from '../../../shared/data-access/theme.service'; @Component({ selector: 'app-parser-form', @@ -15,6 +16,7 @@ export class ParserFormComponent { protected navFacade = inject(NavigationFacade); protected fileNetFacade = inject(FileNetFacade); protected linkInit = inject(LinkInitFacade); + protected theme = inject(ThemeService); ngOnInit() { this.linkFacade.setLink(''); diff --git a/src/app/link-parser/ui/settings/settings.component.html b/src/app/link-parser/ui/settings/settings.component.html index ea504ab..1f08833 100644 --- a/src/app/link-parser/ui/settings/settings.component.html +++ b/src/app/link-parser/ui/settings/settings.component.html @@ -54,21 +54,21 @@

🖥️ {{lang.ph().displayMode}} - {{setts.displayMode() | titlecase}} + {{theme.displayMode() | titlecase}}

{{lang.ph().displayModeDesc}}

- +
-
+

- @if(setts.seasonalTheme()) { + @if(theme.seasonalTheme()) { ON } @else { OFF @@ -78,7 +78,7 @@ {{lang.ph().seasonalThemeDesc}}

-
diff --git a/src/app/link-parser/ui/settings/settings.component.ts b/src/app/link-parser/ui/settings/settings.component.ts index 2b0450c..d8652e0 100644 --- a/src/app/link-parser/ui/settings/settings.component.ts +++ b/src/app/link-parser/ui/settings/settings.component.ts @@ -4,6 +4,7 @@ import { LangService } from '../../../shared/data-access/lang.service'; import { FileSettingsService } from '../../../file/data-access/file-settings.service'; import { VibrationService } from '../../../shared/data-access/vibration.service'; import { ToggleBarOption } from '../../../shared/ui/toggle-bar'; +import { ThemeService } from '../../../shared/data-access/theme.service'; @Component({ selector: 'app-settings', @@ -16,6 +17,7 @@ export class SettingsComponent { lang = inject(LangService) fileSetts = inject(FileSettingsService) vibro = inject(VibrationService) + theme = inject(ThemeService) getLangValue(lang: string) { @@ -28,7 +30,7 @@ export class SettingsComponent { } setSeasonalTheme(e: Event) { - this.setts.setSeasonalTheme((e.target as HTMLInputElement).checked) + this.theme.setSeasonalTheme((e.target as HTMLInputElement).checked) } setSaveFileToHistory(e: Event) { diff --git a/src/app/shared/data-access/theme.service.ts b/src/app/shared/data-access/theme.service.ts new file mode 100644 index 0000000..6861d78 --- /dev/null +++ b/src/app/shared/data-access/theme.service.ts @@ -0,0 +1,99 @@ +import { computed, inject, Injectable, PLATFORM_ID, signal, WritableSignal } from '@angular/core'; +import { ToggleBarOption } from '../ui/toggle-bar'; +import { DOCUMENT, isPlatformServer } from '@angular/common'; + +export const DISPLAY_MODES = ['softmode', 'truemode']; +const NAME_DISPLAY_MODE = 'displayMode'; +const NAME_SEASONAL_THEME = 'seasonalTheme'; + +@Injectable({ + providedIn: 'root' +}) +export class ThemeService { + private readonly document = inject(DOCUMENT); + private platformId = inject(PLATFORM_ID) + + constructor() { + this.initDisplayMode() + this.initSeasonalTheme() + } + + //#region Display Mode + + displayMode!: WritableSignal; + private _lightMetaElement = signal(this.document.querySelector('meta[name="theme-color"][media="(prefers-color-scheme: light)"]') as HTMLMetaElement); + private _darkMetaElement = signal(this.document.querySelector('meta[name="theme-color"][media="(prefers-color-scheme: dark)"]') as HTMLMetaElement); + + readonly displayModeOptions: ToggleBarOption[] = [ + { value: 'true', emoji: '👑', label: 'trueMode' }, + { value: 'soft', emoji: '🧸', label: 'softMode' } + ] + + readonly displayModeMetaThemeColors: Record = { + 'soft': { light: '#166496', dark: '#002741' }, + 'true': { light: '#ffffff', dark: '#000000' } + } + + private initDisplayMode() { + if (isPlatformServer(this.platformId)) return; + + const n = localStorage.getItem(NAME_DISPLAY_MODE) === null ? 'soft' : localStorage.getItem(NAME_DISPLAY_MODE) as string; + this.displayMode = signal(n); + this.setDisplayMode(n); + } + + private setMetaThemeColors(mode: string) { + const colors = this.displayModeMetaThemeColors[mode]; + if (!colors) return; + + if (this._lightMetaElement()) this._lightMetaElement()!.content = colors.light; + if (this._darkMetaElement()) this._darkMetaElement()!.content = colors.dark; + } + + setDisplayMode(n: string) { + if (isPlatformServer(this.platformId)) return; + + this.displayMode.update(v => n); + localStorage.setItem(NAME_DISPLAY_MODE, n) + + this.setMetaThemeColors(n); + } + + //#endregion + + //#region Seasonal Theme + seasonalTheme: WritableSignal = signal(false); + + private initSeasonalTheme() { + if (isPlatformServer(this.platformId)) return; + + const n = localStorage.getItem(NAME_SEASONAL_THEME) === null ? true : Boolean(localStorage.getItem(NAME_SEASONAL_THEME) == 'true'); + this.seasonalTheme.set(n); + this.setSeasonalTheme(n); + } + + setSeasonalTheme(n: boolean) { + if (isPlatformServer(this.platformId)) return; + + this.seasonalTheme.set(n); + localStorage.setItem(NAME_SEASONAL_THEME, n.toString()) + } + + getSeasonalTheme(): string { + const now = new Date(); + const month = now.getMonth(); // 0-11 + const day = now.getDate(); + + if (month === 5) return 'pride'; // June + if (month === 9 && day > 15) return 'halloween'; // second half of Oct + if (month === 11 || (month === 0 && day < 10)) return 'newyear'; + if (month === 1 && day <= 15) return 'valentine'; + return 'default'; + } + + theme = computed(() => { + if (!this.seasonalTheme) return ''; + return this.seasonalTheme() ? this.getSeasonalTheme() : '' + }) + //#endregion +} diff --git a/src/app/shared/ui/slogan/slogan.component.ts b/src/app/shared/ui/slogan/slogan.component.ts index f1bdaa1..6e1a0b1 100644 --- a/src/app/shared/ui/slogan/slogan.component.ts +++ b/src/app/shared/ui/slogan/slogan.component.ts @@ -1,6 +1,7 @@ import { Component, computed, inject, signal } from '@angular/core'; import { LinkParserSettingsService } from '../../../link-parser/data-access/link-parser-settings.service'; import { LangService } from '../../data-access'; +import { ThemeService } from '../../data-access/theme.service'; @Component({ selector: 'slogan', @@ -11,6 +12,7 @@ import { LangService } from '../../data-access'; }) export class SloganComponent { private setts = inject(LinkParserSettingsService) + private theme = inject(ThemeService) private lang = inject(LangService); private seasonalTheme = signal(new Map([ @@ -27,9 +29,9 @@ export class SloganComponent { emoji: '🌻' }; - if (!this.setts.seasonalTheme()) return defaultSlogan; + if (!this.theme.seasonalTheme()) return defaultSlogan; - const theme = this.seasonalTheme().get(this.setts.theme()); + const theme = this.seasonalTheme().get(this.theme.theme()); if (!theme) return defaultSlogan; diff --git a/src/index.html b/src/index.html index 320a99b..e37e559 100644 --- a/src/index.html +++ b/src/index.html @@ -10,7 +10,9 @@ - + + +