From dac6f171e38b212e370ea94926efe7bbacedfe2e Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Tue, 5 May 2026 21:50:31 +0300 Subject: [PATCH] feat(app): add font cache management hooks --- desktop/capabilities/default.json | 4 +++ .../editor/{font-cache.ts => fonts/cache.ts} | 25 +++++++++++++++++++ src/app/editor/{fonts.ts => fonts/index.ts} | 20 ++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) rename src/app/editor/{font-cache.ts => fonts/cache.ts} (78%) rename src/app/editor/{fonts.ts => fonts/index.ts} (82%) diff --git a/desktop/capabilities/default.json b/desktop/capabilities/default.json index c668295c9..e33eac910 100644 --- a/desktop/capabilities/default.json +++ b/desktop/capabilities/default.json @@ -23,6 +23,10 @@ "identifier": "fs:allow-mkdir", "allow": [{ "path": "**" }] }, + { + "identifier": "fs:allow-remove", + "allow": [{ "path": "**" }] + }, { "identifier": "fs:allow-watch", "allow": [{ "path": "**" }] diff --git a/src/app/editor/font-cache.ts b/src/app/editor/fonts/cache.ts similarity index 78% rename from src/app/editor/font-cache.ts rename to src/app/editor/fonts/cache.ts index b97e8ffc1..d8740113c 100644 --- a/src/app/editor/font-cache.ts +++ b/src/app/editor/fonts/cache.ts @@ -14,6 +14,12 @@ type FontCacheManifest = { entries: Partial> } +export interface DownloadedFontCacheSummary { + count: number + byteLength: number + updatedAt: number | null +} + const CACHE_DIR = 'font-cache/v1' const MANIFEST_PATH = `${CACHE_DIR}/manifest.json` const EMPTY_MANIFEST: FontCacheManifest = { version: 1, entries: {} } @@ -59,6 +65,25 @@ async function writeManifest(manifest: FontCacheManifest) { }) } +export async function downloadedFontCacheSummary(): Promise { + const manifest = await readManifest() + const entries = Object.values(manifest.entries).filter((entry): entry is FontCacheEntry => !!entry) + return { + count: entries.length, + byteLength: entries.reduce((sum, entry) => sum + entry.byteLength, 0), + updatedAt: entries.length > 0 ? Math.max(...entries.map((entry) => entry.updatedAt)) : null + } +} + +export async function clearDownloadedFontCache(): Promise { + const { BaseDirectory, remove } = await import('@tauri-apps/plugin-fs') + try { + await remove(CACHE_DIR, { baseDir: BaseDirectory.AppLocalData, recursive: true }) + } catch (error) { + console.warn('Downloaded font cache clear skipped:', error) + } +} + export function createTauriDownloadedFontCache(): DownloadedFontCache { return { async read(family, style) { diff --git a/src/app/editor/fonts.ts b/src/app/editor/fonts/index.ts similarity index 82% rename from src/app/editor/fonts.ts rename to src/app/editor/fonts/index.ts index 8f7c5bc03..6ab22ba65 100644 --- a/src/app/editor/fonts.ts +++ b/src/app/editor/fonts/index.ts @@ -1,7 +1,11 @@ import { IS_TAURI } from '@open-pencil/core/constants' import { fontManager, styleToWeight, type LocalFontAccessState } from '@open-pencil/core/text' -import { createTauriDownloadedFontCache } from '@/app/editor/font-cache' +import { + clearDownloadedFontCache as clearTauriDownloadedFontCache, + createTauriDownloadedFontCache, + downloadedFontCacheSummary as tauriDownloadedFontCacheSummary +} from '@/app/editor/fonts/cache' if (typeof navigator !== 'undefined') { fontManager.setFallbackUserAgent(navigator.userAgent) @@ -49,6 +53,20 @@ export async function requestLocalFontAccess(): Promise { return fontManager.listFamilies() } +export async function downloadedFontCacheSummary() { + if (!IS_TAURI) return { count: 0, byteLength: 0, updatedAt: null } + return tauriDownloadedFontCacheSummary() +} + +export async function clearDownloadedFontCache(): Promise { + if (!IS_TAURI) return + await clearTauriDownloadedFontCache() +} + +export async function predownloadFallbackFonts() { + return fontManager.ensureFallbackPack() +} + function registerFontFaces(fonts: TauriFontFamily[]): void { if (typeof document === 'undefined') return for (const { family } of fonts) {