From bce9f8663df6b5695f3cc8ae62812f69e540beec Mon Sep 17 00:00:00 2001 From: kfj001 Date: Fri, 26 Jun 2026 06:23:38 +0000 Subject: [PATCH] Pro firefox enhancements --- src/app/interceptors/auth.interceptor.ts | 7 ++++- src/app/schedule/schedule.component.scss | 9 +++++++ src/app/services/auth.service.ts | 34 +++++++++++++++++++++--- src/styles/_mixins.scss | 6 +++++ 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/app/interceptors/auth.interceptor.ts b/src/app/interceptors/auth.interceptor.ts index 4a68207..579694a 100644 --- a/src/app/interceptors/auth.interceptor.ts +++ b/src/app/interceptors/auth.interceptor.ts @@ -1,7 +1,12 @@ import { HttpInterceptorFn, HttpRequest, HttpHandlerFn } from '@angular/common/http'; export const authInterceptor: HttpInterceptorFn = (req: HttpRequest, next: HttpHandlerFn) => { - const token = localStorage.getItem('kmtn_access_token'); + let token: string | null = null; + try { + token = localStorage.getItem('kmtn_access_token'); + } catch { + // Storage blocked (e.g. Mullvad Browser strict mode) + } if (token) { const cloned = req.clone({ diff --git a/src/app/schedule/schedule.component.scss b/src/app/schedule/schedule.component.scss index 2e4431c..380ce54 100644 --- a/src/app/schedule/schedule.component.scss +++ b/src/app/schedule/schedule.component.scss @@ -165,14 +165,21 @@ margin: 0 0 $spacing-md; line-height: 1.5; + // WebKit line-clamp (Chrome, Safari) display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; + + // Standard line-clamp (Firefox 122+) — overrides display for supporting browsers + display: block; + line-clamp: 3; + transition: max-height $transition-slow ease, opacity $transition-normal; &.expanded { -webkit-line-clamp: unset; + line-clamp: unset; overflow: visible; } } @@ -241,6 +248,7 @@ .show-description { -webkit-line-clamp: 2; + line-clamp: 2; font-size: 0.88rem; } } @@ -263,5 +271,6 @@ .show-description { -webkit-line-clamp: 2; + line-clamp: 2; } } diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index 2cb0841..e8aba12 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -7,6 +7,32 @@ import { AppUser, AuthTokenResponse } from '../interfaces/auth'; const TOKEN_KEY = 'kmtn_access_token'; +// ── Safe localStorage helpers (privacy browsers may throw SecurityError) ── + +function safeLocalStorageGet(key: string): string | null { + try { + return localStorage.getItem(key); + } catch { + return null; + } +} + +function safeLocalStorageSet(key: string, value: string): void { + try { + localStorage.setItem(key, value); + } catch { + // Storage blocked — silently ignore + } +} + +function safeLocalStorageRemove(key: string): void { + try { + localStorage.removeItem(key); + } catch { + // Storage blocked — silently ignore + } +} + @Injectable({ providedIn: 'root', }) @@ -30,7 +56,7 @@ export class AuthService { username, password, }).pipe( - tap((resp) => localStorage.setItem(TOKEN_KEY, resp.access_token)), + tap((resp) => safeLocalStorageSet(TOKEN_KEY, resp.access_token)), ); } @@ -39,13 +65,13 @@ export class AuthService { return this.http.post(`${this.baseUrl}/google`, { id_token: idToken, }).pipe( - tap((resp) => localStorage.setItem(TOKEN_KEY, resp.access_token)), + tap((resp) => safeLocalStorageSet(TOKEN_KEY, resp.access_token)), ); } /** Clear stored token and reset auth state. */ logout(): void { - localStorage.removeItem(TOKEN_KEY); + safeLocalStorageRemove(TOKEN_KEY); this.authStateSubject.next(null); } @@ -83,7 +109,7 @@ export class AuthService { // ── Private ────────────────────────────────────────────── private _getToken(): string | null { - return localStorage.getItem(TOKEN_KEY); + return safeLocalStorageGet(TOKEN_KEY); } private async _initAuth(): Promise { diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss index 504b57b..679f547 100644 --- a/src/styles/_mixins.scss +++ b/src/styles/_mixins.scss @@ -19,6 +19,12 @@ -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; + + // Firefox fallback: solid color when gradient text is unsupported + @supports not ((-webkit-background-clip: text) or (background-clip: text)) { + background: none; + color: $from; + } } @mixin card-style {