From 5c3b11d4c20a37d1fff980965cf037564e5887b6 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Wed, 1 Apr 2026 19:08:04 +0200 Subject: [PATCH] [fix](trx-frontend-http): vendor DSEG14 font locally to avoid CDN content blockers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same issue as Leaflet — content blockers block the jsdelivr CDN request, causing the seven-segment font to fail loading and fall back to monospace. Also replace preload-to-stylesheet swap with media="print" onload swap for themes.css and leaflet.css to eliminate Safari preload warnings. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Stan Grams --- .../trx-frontend-http/assets/web/index.html | 4 ++-- .../trx-frontend-http/assets/web/style.css | 2 +- .../vendor/dseg14-classic-latin-400-normal.woff2 | Bin 0 -> 5804 bytes .../trx-frontend-http/src/api/assets.rs | 15 +++++++++++++++ .../trx-frontend-http/src/api/mod.rs | 2 ++ .../trx-frontend/trx-frontend-http/src/status.rs | 4 ++++ 6 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/trx-client/trx-frontend/trx-frontend-http/assets/web/vendor/dseg14-classic-latin-400-normal.woff2 diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html index 2ea7152..d44cf43 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html @@ -8,9 +8,9 @@ - + - + diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css index 3a6e727..8167dbb 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css @@ -77,7 +77,7 @@ font-style: normal; font-weight: 400; font-display: swap; - src: url('https://cdn.jsdelivr.net/npm/@fontsource/dseg14-classic/files/dseg14-classic-latin-400-normal.woff2') format('woff2'); + src: url('/vendor/dseg14-classic-latin-400-normal.woff2') format('woff2'); unicode-range: U+0030-0039, U+002E, U+002D, U+0020, U+002B; } diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/vendor/dseg14-classic-latin-400-normal.woff2 b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/vendor/dseg14-classic-latin-400-normal.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..ba7cd028aa974ad9c53191dfbeffa353d92805ce GIT binary patch literal 5804 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 P^UwS9{h~xM0|Ns9{eBly literal 0 HcmV?d00001 diff --git a/src/trx-client/trx-frontend/trx-frontend-http/src/api/assets.rs b/src/trx-client/trx-frontend/trx-frontend-http/src/api/assets.rs index 6539b5c..611844d 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/src/api/assets.rs +++ b/src/trx-client/trx-frontend/trx-frontend-http/src/api/assets.rs @@ -70,6 +70,9 @@ define_gz_cache!( define_gz_cache!(gz_vchan_js, status::VCHAN_JS, "vchan.js"); define_gz_cache!(gz_bandplan_json, status::BANDPLAN_JSON, "bandplan.json"); +// Vendored DSEG14 Classic font +// (binary woff2 — served directly, not through gz_cache) + // Vendored Leaflet 1.9.4 define_gz_cache!(gz_leaflet_js, status::LEAFLET_JS, "leaflet.js"); define_gz_cache!(gz_leaflet_css, status::LEAFLET_CSS, "leaflet.css"); @@ -378,6 +381,18 @@ pub(crate) async fn bandplan_json(req: HttpRequest) -> impl Responder { static_asset_response(&req, "application/json; charset=utf-8", c) } +// --------------------------------------------------------------------------- +// Vendored DSEG14 Classic font +// --------------------------------------------------------------------------- + +#[get("/vendor/dseg14-classic-latin-400-normal.woff2")] +pub(crate) async fn dseg14_classic_woff2() -> impl Responder { + HttpResponse::Ok() + .insert_header((header::CONTENT_TYPE, "font/woff2")) + .insert_header((header::CACHE_CONTROL, "public, max-age=604800, immutable")) + .body(status::DSEG14_CLASSIC_WOFF2) +} + // --------------------------------------------------------------------------- // Vendored Leaflet 1.9.4 // --------------------------------------------------------------------------- diff --git a/src/trx-client/trx-frontend/trx-frontend-http/src/api/mod.rs b/src/trx-client/trx-frontend/trx-frontend-http/src/api/mod.rs index 08be84c..9d0c9cc 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/src/api/mod.rs +++ b/src/trx-client/trx-frontend/trx-frontend-http/src/api/mod.rs @@ -667,6 +667,8 @@ pub fn configure(cfg: &mut web::ServiceConfig) { .service(assets::background_decode_js) .service(assets::vchan_js) .service(assets::bandplan_json) + // Vendored DSEG14 Classic font + .service(assets::dseg14_classic_woff2) // Vendored Leaflet 1.9.4 .service(assets::leaflet_js) .service(assets::leaflet_css) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/src/status.rs b/src/trx-client/trx-frontend/trx-frontend-http/src/status.rs index 180aea3..2f5fe24 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/src/status.rs +++ b/src/trx-client/trx-frontend/trx-frontend-http/src/status.rs @@ -35,6 +35,10 @@ pub const BACKGROUND_DECODE_JS: &str = include_str!("../assets/web/plugins/backg pub const VCHAN_JS: &str = include_str!("../assets/web/plugins/vchan.js"); pub const BANDPLAN_JSON: &str = include_str!("../assets/web/bandplan.json"); +// Vendored DSEG14 Classic font +pub const DSEG14_CLASSIC_WOFF2: &[u8] = + include_bytes!("../assets/web/vendor/dseg14-classic-latin-400-normal.woff2"); + // Vendored Leaflet 1.9.4 pub const LEAFLET_JS: &str = include_str!("../assets/web/vendor/leaflet.js"); pub const LEAFLET_CSS: &str = include_str!("../assets/web/vendor/leaflet.css");