All files / app/layout/services font-scale.service.ts

100% Statements 45/45
92.3% Branches 12/13
100% Functions 14/14
100% Lines 38/38

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 755x 5x 5x   5x 5x 5x 5x 5x 5x         5x 56x 56x 56x 56x   56x 56x   56x 56x 56x 56x     56x 44x 44x 44x 44x           27x 22x         7x 6x         4x       56x 56x 1x   55x       44x       44x 41x   3x        
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
import { computed, effect, inject, Injectable, PLATFORM_ID, signal } from '@angular/core';
import { StorageService } from '@drevo-web/core';
 
export const FONT_SCALE_KEY = 'drevo-font-scale';
const DEFAULT_SCALE = 1;
const MIN_SCALE = 0.8;
const MAX_SCALE = 1.5;
const SCALE_STEP = 0.1;
const BASE_FONT_SIZE = 14;
 
@Injectable({
    providedIn: 'root',
})
export class FontScaleService {
    private readonly platformId = inject(PLATFORM_ID);
    private readonly isBrowser = isPlatformBrowser(this.platformId);
    private readonly storage = inject(StorageService);
    private readonly document = inject(DOCUMENT);
 
    private readonly _scale = signal<number>(this.getInitialScale());
    readonly scale = this._scale.asReadonly();
 
    readonly scalePercent = computed(() => Math.round(this._scale() * 100));
    readonly canIncrease = computed(() => this._scale() < MAX_SCALE);
    readonly canDecrease = computed(() => this._scale() > MIN_SCALE);
    readonly isDefault = computed(() => this._scale() === DEFAULT_SCALE);
 
    constructor() {
        effect(() => {
            const currentScale = this._scale();
            Eif (this.isBrowser) {
                this.applyScale(currentScale);
                this.saveScale(currentScale);
            }
        });
    }
 
    increase(): void {
        if (this.canIncrease()) {
            this._scale.update(current => Math.min(MAX_SCALE, Math.round((current + SCALE_STEP) * 10) / 10));
        }
    }
 
    decrease(): void {
        if (this.canDecrease()) {
            this._scale.update(current => Math.max(MIN_SCALE, Math.round((current - SCALE_STEP) * 10) / 10));
        }
    }
 
    reset(): void {
        this._scale.set(DEFAULT_SCALE);
    }
 
    private getInitialScale(): number {
        const savedScale = this.storage.get<number>(FONT_SCALE_KEY);
        if (savedScale !== undefined && savedScale >= MIN_SCALE && savedScale <= MAX_SCALE) {
            return savedScale;
        }
        return DEFAULT_SCALE;
    }
 
    private applyScale(scale: number): void {
        this.document.documentElement.style.fontSize = `${BASE_FONT_SIZE * scale}px`;
    }
 
    private saveScale(scale: number): void {
        if (scale === DEFAULT_SCALE) {
            this.storage.remove(FONT_SCALE_KEY);
        } else {
            this.storage.set(FONT_SCALE_KEY, scale);
        }
    }
}