feat: add PWA support with manifest and service worker

This commit is contained in:
2025-10-01 13:46:51 +08:00
parent cad2885cc2
commit 091e130021
10 changed files with 2639 additions and 2 deletions

View File

@@ -3,7 +3,9 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="manifest" href="/manifest.webmanifest" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#0f172a" />
<title>Traveling Around The World</title>
</head>
<body class="bg-slate-100 text-slate-900">

2551
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -45,6 +45,7 @@
"tailwindcss": "^3.4.3",
"typescript": "^5.4.2",
"vite": "^5.1.4",
"vite-plugin-pwa": "^0.17.5",
"autoprefixer": "^10.4.20"
}
}

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<circle cx="32" cy="32" r="30" fill="#0b7285"/>
<path d="M20 26c4-8 16-10 24 0s-8 20-8 20l-4-8-8 8" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="32" cy="24" r="4" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 310 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<circle cx="32" cy="32" r="30" fill="#0b7285"/>
<path d="M20 26c4-8 16-10 24 0s-8 20-8 20l-4-8-8 8" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="32" cy="24" r="4" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 310 B

View File

@@ -0,0 +1,25 @@
{
"name": "Traveling Around The World",
"short_name": "Travel Map",
"description": "記錄旅程、管理旅遊分類並在地圖上標記足跡的 PWA。",
"lang": "zh-Hant",
"start_url": "/",
"scope": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#0f172a",
"icons": [
{
"src": "/icons/icon-192.svg",
"sizes": "192x192",
"type": "image/svg+xml",
"purpose": "any"
},
{
"src": "/icons/icon-512.svg",
"sizes": "512x512",
"type": "image/svg+xml",
"purpose": "any maskable"
}
]
}

View File

@@ -3,6 +3,7 @@ import { createRoot } from 'react-dom/client';
import { App } from './app/App';
import './i18n';
import './styles/global.css';
import { registerSW } from 'virtual:pwa-register';
const container = document.getElementById('root');
@@ -17,3 +18,7 @@ root.render(
<App />
</StrictMode>
);
if (typeof window !== 'undefined' && 'serviceWorker' in navigator) {
registerSW({ immediate: true });
}

View File

@@ -1,4 +1,5 @@
/// <reference types="vite/client" />
/// <reference types="vite-plugin-pwa/client" />
declare module '*.png?url' {
const url: string;

View File

@@ -1,9 +1,47 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import { fileURLToPath, URL } from 'node:url';
import { VitePWA } from 'vite-plugin-pwa';
const pwaManifest = {
name: 'Traveling Around The World',
short_name: 'Travel Map',
description: '記錄旅程、管理旅遊分類並在地圖上標記足跡的 PWA。',
lang: 'zh-Hant',
start_url: '/',
scope: '/',
display: 'standalone',
background_color: '#ffffff',
theme_color: '#0f172a',
icons: [
{
src: '/icons/icon-192.svg',
sizes: '192x192',
type: 'image/svg+xml',
purpose: 'any'
},
{
src: '/icons/icon-512.svg',
sizes: '512x512',
type: 'image/svg+xml',
purpose: 'any maskable'
}
]
};
export default defineConfig({
plugins: [react()],
plugins: [
react(),
VitePWA({
registerType: 'autoUpdate',
includeAssets: ['favicon.svg', 'icons/icon-192.svg', 'icons/icon-512.svg'],
manifest: pwaManifest,
workbox: {
navigateFallback: '/index.html',
globPatterns: ['**/*.{js,css,html,svg,png,ico,json}']
}
})
],
resolve: {
alias: {
'@shared': fileURLToPath(new URL('../shared', import.meta.url))