From c343ca6cf7abdf5d5305e24bac4f844fe7160b9d Mon Sep 17 00:00:00 2001 From: nymkappa Date: Tue, 6 Jan 2026 10:25:42 +0100 Subject: [PATCH 1/4] [theme] if css fails to load, revert to default --- frontend/src/app/services/theme.service.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/services/theme.service.ts b/frontend/src/app/services/theme.service.ts index 6ed9c1027..492fb8d24 100644 --- a/frontend/src/app/services/theme.service.ts +++ b/frontend/src/app/services/theme.service.ts @@ -8,7 +8,7 @@ import { StateService } from '@app/services/state.service'; providedIn: 'root' }) export class ThemeService { - style: HTMLLinkElement; + style: HTMLLinkElement | null = null; theme: string = 'default'; themeChanged$: Subject = new Subject(); mempoolFeeColors: string[] = defaultMempoolFeeColors; @@ -21,16 +21,19 @@ export class ThemeService { this.apply(theme); } - apply(theme) { + apply(theme: string): void { this.theme = theme; if (theme !== 'default') { - theme === 'contrast' || theme === 'bukele' ? this.mempoolFeeColors = contrastMempoolFeeColors : this.mempoolFeeColors = defaultMempoolFeeColors; + this.mempoolFeeColors = (theme === 'contrast' || theme === 'bukele') ? contrastMempoolFeeColors : defaultMempoolFeeColors; try { if (!this.style) { this.style = document.createElement('link'); this.style.rel = 'stylesheet'; this.style.href = `${theme}.css`; - document.head.appendChild(this.style); + this.style.onerror = (): void => { // something went wrong (eg the css resource does not exist, revert to default) + this.apply('default'); + }; + document.head.appendChild(this.style); // load the css now } else { this.style.href = `${theme}.css`; } From b758926ca427cefaea95eac7418e7b125df8b82b Mon Sep 17 00:00:00 2001 From: nymkappa Date: Tue, 6 Jan 2026 10:30:17 +0100 Subject: [PATCH 2/4] [theme] add infinite recursion guard --- frontend/src/app/services/theme.service.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/app/services/theme.service.ts b/frontend/src/app/services/theme.service.ts index 492fb8d24..95dbee0ba 100644 --- a/frontend/src/app/services/theme.service.ts +++ b/frontend/src/app/services/theme.service.ts @@ -22,6 +22,10 @@ export class ThemeService { } apply(theme: string): void { + if (this.theme === theme) { + return; + } + this.theme = theme; if (theme !== 'default') { this.mempoolFeeColors = (theme === 'contrast' || theme === 'bukele') ? contrastMempoolFeeColors : defaultMempoolFeeColors; From 1d00a3e6659c8423201e49544d02d5427d02742a Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 6 Jan 2026 10:10:54 +0000 Subject: [PATCH 3/4] fix fees box theme pipe race condition error --- frontend/src/app/components/fees-box/fees-box.component.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/fees-box/fees-box.component.ts b/frontend/src/app/components/fees-box/fees-box.component.ts index a1c8e7698..b0686ab2e 100644 --- a/frontend/src/app/components/fees-box/fees-box.component.ts +++ b/frontend/src/app/components/fees-box/fees-box.component.ts @@ -44,10 +44,13 @@ export class FeesBoxComponent implements OnInit, OnDestroy { ); this.themeSubscription = this.themeService.themeChanged$.subscribe(() => { this.setFeeGradient(); - }) + }); } setFeeGradient() { + if (!this.fees || !this.themeService.mempoolFeeColors) { + return; + } let feeLevelIndex = feeLevels.slice().reverse().findIndex((feeLvl) => this.fees.minimumFee >= feeLvl); feeLevelIndex = feeLevelIndex >= 0 ? feeLevels.length - feeLevelIndex : feeLevelIndex; const startColor = '#' + (this.themeService.mempoolFeeColors[feeLevelIndex - 1] || this.themeService.mempoolFeeColors[this.themeService.mempoolFeeColors.length - 1]); From 8626467df322ed92d7c9576a91b923fdbde91281 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 6 Jan 2026 10:11:12 +0000 Subject: [PATCH 4/4] override unknown theme preferences with defaults --- frontend/src/app/services/theme.service.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/services/theme.service.ts b/frontend/src/app/services/theme.service.ts index 95dbee0ba..2453acf05 100644 --- a/frontend/src/app/services/theme.service.ts +++ b/frontend/src/app/services/theme.service.ts @@ -17,7 +17,12 @@ export class ThemeService { private storageService: StorageService, private stateService: StateService, ) { - const theme = this.stateService.env.customize?.theme || this.storageService.getValue('theme-preference') || 'default'; + let theme = this.stateService.env.customize?.theme || this.storageService.getValue('theme-preference') || 'default'; + // theme preference must be a valid known public theme + if (!this.stateService.env.customize?.theme && !['default', 'contrast', 'softsimon'].includes(theme)) { + theme = 'default'; + this.storageService.setValue('theme-preference', 'default'); + } this.apply(theme); }