فهرست منبع

Self-host fonts and icons for offline/hotspot mode

Replace Google Fonts CDN imports with bundled npm packages:
- @fontsource/plus-jakarta-sans (400-700)
- @fontsource/noto-sans (400-700)
- material-icons (filled + outlined)

Font files are now included in the Vite build output, so the
app renders correctly in hotspot mode with no internet.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tuanchris 4 ماه پیش
والد
کامیت
d9b8cdc4e1
4فایلهای تغییر یافته به همراه44 افزوده شده و 5 حذف شده
  1. 27 0
      frontend/package-lock.json
  2. 3 0
      frontend/package.json
  3. 1 5
      frontend/src/index.css
  4. 13 0
      frontend/src/main.tsx

+ 27 - 0
frontend/package-lock.json

@@ -11,6 +11,8 @@
         "@dnd-kit/core": "^6.3.1",
         "@dnd-kit/sortable": "^10.0.0",
         "@dnd-kit/utilities": "^3.2.2",
+        "@fontsource/noto-sans": "^5.2.10",
+        "@fontsource/plus-jakarta-sans": "^5.2.8",
         "@radix-ui/react-accordion": "^1.2.12",
         "@radix-ui/react-dialog": "^1.1.15",
         "@radix-ui/react-label": "^2.1.8",
@@ -26,6 +28,7 @@
         "@radix-ui/react-tooltip": "^1.2.8",
         "@tailwindcss/postcss": "^4.1.18",
         "@tanstack/react-query": "^5.90.16",
+        "material-icons": "^1.13.14",
         "motion": "^12.27.1",
         "next-themes": "^0.4.6",
         "react": "^19.2.0",
@@ -2826,6 +2829,24 @@
       "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
       "license": "MIT"
     },
+    "node_modules/@fontsource/noto-sans": {
+      "version": "5.2.10",
+      "resolved": "https://registry.npmjs.org/@fontsource/noto-sans/-/noto-sans-5.2.10.tgz",
+      "integrity": "sha512-J58RVfS/C0Z2VBF+PoU260Tx8cdRGYuS+e3yQe4hYaIYDl0sEVn5CzlLo5zVRvQD0HaIUTV8AZMfqR7rtdEpqQ==",
+      "license": "OFL-1.1",
+      "funding": {
+        "url": "https://github.com/sponsors/ayuhito"
+      }
+    },
+    "node_modules/@fontsource/plus-jakarta-sans": {
+      "version": "5.2.8",
+      "resolved": "https://registry.npmjs.org/@fontsource/plus-jakarta-sans/-/plus-jakarta-sans-5.2.8.tgz",
+      "integrity": "sha512-P5qE49fqdeD+7DXH1KBxmMPlB17LTz1zvBhFH0tFzfnYTKVJVyb0pR6plh0ZGXxcB+Oayb54FZZw3V42/DawTw==",
+      "license": "OFL-1.1",
+      "funding": {
+        "url": "https://github.com/sponsors/ayuhito"
+      }
+    },
     "node_modules/@hono/node-server": {
       "version": "1.19.9",
       "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz",
@@ -10483,6 +10504,12 @@
       "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==",
       "license": "ISC"
     },
+    "node_modules/material-icons": {
+      "version": "1.13.14",
+      "resolved": "https://registry.npmjs.org/material-icons/-/material-icons-1.13.14.tgz",
+      "integrity": "sha512-kZOfc7xCC0rAT8Q3DQixYAeT+tBqZnxkseQtp2bxBxz7q5pMAC+wmit7vJn1g/l7wRU+HEPq23gER4iPjGs5Cg==",
+      "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",

+ 3 - 0
frontend/package.json

@@ -19,6 +19,8 @@
     "@dnd-kit/core": "^6.3.1",
     "@dnd-kit/sortable": "^10.0.0",
     "@dnd-kit/utilities": "^3.2.2",
+    "@fontsource/noto-sans": "^5.2.10",
+    "@fontsource/plus-jakarta-sans": "^5.2.8",
     "@radix-ui/react-accordion": "^1.2.12",
     "@radix-ui/react-dialog": "^1.1.15",
     "@radix-ui/react-label": "^2.1.8",
@@ -34,6 +36,7 @@
     "@radix-ui/react-tooltip": "^1.2.8",
     "@tailwindcss/postcss": "^4.1.18",
     "@tanstack/react-query": "^5.90.16",
+    "material-icons": "^1.13.14",
     "motion": "^12.27.1",
     "next-themes": "^0.4.6",
     "react": "^19.2.0",

+ 1 - 5
frontend/src/index.css

@@ -1,10 +1,6 @@
 @import "tailwindcss";
 
-/* Import fonts */
-@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=Noto+Sans:wght@400;500;600;700&display=swap');
-
-/* Material Icons */
-@import url('https://fonts.googleapis.com/icon?family=Material+Icons|Material+Icons+Outlined');
+/* Fonts imported in main.tsx (self-hosted, no CDN dependency) */
 
 /* Theme configuration using CSS variables */
 @theme {

+ 13 - 0
frontend/src/main.tsx

@@ -2,6 +2,19 @@ import { StrictMode } from 'react'
 import { createRoot } from 'react-dom/client'
 import { BrowserRouter } from 'react-router-dom'
 import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+
+// Self-hosted fonts (no CDN — works offline / hotspot mode)
+import '@fontsource/plus-jakarta-sans/400.css'
+import '@fontsource/plus-jakarta-sans/500.css'
+import '@fontsource/plus-jakarta-sans/600.css'
+import '@fontsource/plus-jakarta-sans/700.css'
+import '@fontsource/noto-sans/400.css'
+import '@fontsource/noto-sans/500.css'
+import '@fontsource/noto-sans/600.css'
+import '@fontsource/noto-sans/700.css'
+import 'material-icons/iconfont/filled.css'
+import 'material-icons/iconfont/outlined.css'
+
 import './index.css'
 import App from './App.tsx'