From d8b6ae3688192f3e2a2b816f903c8a3af918d89c Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Date: Sat, 13 Jun 2026 08:25:57 -0300 Subject: [PATCH] fix(dashboard): self-host Material Symbols icon font (#3695) (#3764) The dashboard loaded the Material Symbols icon font only from the Google Fonts CDN (fonts.googleapis.com). On networks where that CDN is blocked (e.g. mainland China) the ligature font never loaded, so every icon rendered as its literal text name and the layout broke. Bundle the font locally via the material-symbols package so icons render without a runtime CDN dependency. Closes #3695 --- CHANGELOG.md | 2 + package-lock.json | 9 ++- package.json | 1 + src/app/globals.css | 7 +++ src/app/layout.tsx | 10 +--- .../material-icons-self-hosted.test.ts | 58 +++++++++++++++++++ 6 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 tests/unit/dashboard/material-icons-self-hosted.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 09349db1c9..60e0d1826b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ### 🐛 Fixed +- fix(dashboard): self-host the Material Symbols icon font instead of loading it from the Google Fonts CDN. On networks where `fonts.googleapis.com` is unreachable (e.g. mainland China), the icon ligature font never loaded, so every icon rendered as its literal text name (`smart_toy`, `visibility`, …) and the layout broke — especially after importing many models. The font is now bundled locally via the `material-symbols` package (`@import "material-symbols/outlined.css"` in `globals.css`), removing the runtime CDN dependency. ([#3695](https://github.com/diegosouzapw/OmniRoute/issues/3695) — thanks @lqyiwwx) + - fix(antigravity): skip Google One AI credits retry on `full_quota_exhausted` verdict — antigravity executor now calls `decide429()` before attempting the credits retry so that a quota-exhausted account (24h cooldown) bypasses the extra upstream HTTP call instead of hanging for up to ~41s. Also persists the cooldown in the DB via `setConnectionRateLimitUntil` so post-restart routing skips exhausted connections without re-learning the hard way. Bonus: `antigravity429Engine` now recognises the real Antigravity "Individual quota reached. Contact your administrator to enable overages." error message as `quota_exhausted`. ([#3707](https://github.com/diegosouzapw/OmniRoute/issues/3707) — thanks @andrea-kingautomation) - fix(cli): `ServerSupervisor.handleExit` now coerces the exit code to a number before calling `process.exit()` — Node.js v24 throws `TypeError [ERR_INVALID_ARG_TYPE]` when `process.exit()` receives a string (e.g. `'ENOENT'` from a spawn `error` event's `err.code`). The `error` callback also now passes `-1` instead of the raw `err.code`, which is an OS error string rather than a meaningful exit code. ([#3748](https://github.com/diegosouzapw/OmniRoute/issues/3748)) diff --git a/package-lock.json b/package-lock.json index 057d2a036f..bd60689b4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,6 +50,7 @@ "lucide-react": "^1.16.0", "marked": "^18.0.4", "marked-terminal": "^7.3.0", + "material-symbols": "^0.45.1", "mermaid": "^11.15.0", "monaco-editor": "^0.55.1", "next": "^16.2.6", @@ -93,7 +94,7 @@ "@testing-library/react": "^16.3.2", "@types/bcryptjs": "^3.0.0", "@types/better-sqlite3": "^7.6.13", - "@types/bun": "*", + "@types/bun": "latest", "@types/keytar": "^4.4.2", "@types/node": "^25.9.1", "@types/react": "^19.2.15", @@ -14876,6 +14877,12 @@ "node": ">=10" } }, + "node_modules/material-symbols": { + "version": "0.45.1", + "resolved": "https://registry.npmjs.org/material-symbols/-/material-symbols-0.45.1.tgz", + "integrity": "sha512-iQibeoKymxHthNqTjYg/jCN2pRySFQ+DAD0sYK9FS7rUpf38i1qR3N4I1jfi/bLS5qdEKvkkJAvf2mE89amSZw==", + "license": "Apache-2.0" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", diff --git a/package.json b/package.json index 470f74c0c7..604d44958b 100644 --- a/package.json +++ b/package.json @@ -201,6 +201,7 @@ "lucide-react": "^1.16.0", "marked": "^18.0.4", "marked-terminal": "^7.3.0", + "material-symbols": "^0.45.1", "mermaid": "^11.15.0", "monaco-editor": "^0.55.1", "next": "^16.2.6", diff --git a/src/app/globals.css b/src/app/globals.css index b95cb1a1f9..a7701be7e0 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,6 +1,13 @@ @import "tailwindcss"; @import "fumadocs-ui/css/neutral.css"; @import "fumadocs-ui/css/preset.css"; +/* Self-hosted Material Symbols icon font (#3695): the Google Fonts CDN + (fonts.googleapis.com) is blocked in some networks (e.g. mainland China), + which made every icon ligature fall back to its literal text name and broke + the layout. Bundling the font locally removes that runtime CDN dependency. + The bundled @font-face uses family "Material Symbols Outlined", matching the + .material-symbols-outlined rule defined later in this file. */ +@import "material-symbols/outlined.css"; @source "../../node_modules/fumadocs-ui/css/generated/*.css"; /* Tailwind v4 auto-detection cannot scan directories with parentheses diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 2d4d23e3b5..f88989df76 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -59,13 +59,9 @@ export default async function RootLayout({ children }) { return (
- - - {/* eslint-disable-next-line @next/next/no-page-custom-font */} - + {/* Material Symbols icon font is self-hosted via globals.css + (@import "material-symbols/outlined.css") so icons render even when + the Google Fonts CDN is unreachable (#3695). */}