diff --git a/app/favicon.ico b/app/favicon.ico deleted file mode 100644 index 718d6fe..0000000 Binary files a/app/favicon.ico and /dev/null differ diff --git a/app/layout.tsx b/app/layout.tsx index 97b0956..56d94e4 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,6 +1,7 @@ -import type { Metadata } from "next"; +import type { Metadata, Viewport } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; +import { RegisterSW } from "./register-sw"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -15,6 +16,21 @@ const geistMono = Geist_Mono({ export const metadata: Metadata = { title: "屏幕截图监控系统", description: "Windows更新监控系统", + manifest: "/manifest.json", + icons: [ + { + rel: "icon", + url: "/favicon.png", + }, + { + rel: "apple-touch-icon", + url: "/favicon.png", + }, + ], +}; + +export const viewport: Viewport = { + themeColor: "#F9FAFB", }; export default function RootLayout({ @@ -27,6 +43,7 @@ export default function RootLayout({ + {children} diff --git a/app/register-sw.tsx b/app/register-sw.tsx new file mode 100644 index 0000000..f1c08ea --- /dev/null +++ b/app/register-sw.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { useEffect } from "react"; + +export function RegisterSW() { + useEffect(() => { + if (typeof window === "undefined") return; + if (!("serviceWorker" in navigator)) return; + + const register = async () => { + try { + const swUrl = "/sw.js"; + await navigator.serviceWorker.register(swUrl); + } catch (error) { + console.error("Service worker registration failed", error); + } + }; + + register(); + }, []); + + return null; +} diff --git a/envtests/test-file-operations.ts b/envtests/test-file-operations.ts index 4b2ddcb..7416414 100644 --- a/envtests/test-file-operations.ts +++ b/envtests/test-file-operations.ts @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { storeFile, getFileByObjectName, deleteFile, getStorageStats } from './lib/fileStorage' +import { storeFile, getFileByObjectName, deleteFile, getStorageStats } from '../lib/fileStorage' async function testMinIOFileOperations() { console.log('🚀 开始测试 MinIO 文件操作...') diff --git a/middleware.ts b/middleware.ts index 0fae1a3..69507f8 100644 --- a/middleware.ts +++ b/middleware.ts @@ -9,11 +9,13 @@ export function middleware(req: NextRequest) { url.pathname.startsWith('/api/') || url.pathname.startsWith('/screenshots/') || url.pathname.startsWith('/downloads/') || + url.pathname.startsWith('/manifest.json') || + url.pathname.startsWith('/sw.js') || + url.pathname.includes('favicon.png') || url.pathname.includes('install') || url.pathname.includes('WinupdateCore') || req.method === 'POST' || url.pathname.startsWith('/_next/') || // Next.js static files - url.pathname.startsWith('/favicon.ico') || // Favicon url.pathname.startsWith('/api-test') // API test page (for development) ) { return NextResponse.next() @@ -65,6 +67,6 @@ export const config_middleware = { * - _next/image (image optimization files) * - favicon.ico (favicon file) */ - '/((?!_next/static|_next/image|favicon.ico).*)', + '/((?!_next/static|_next/image|favicon.ico|manifest.json|sw.js).*)', ], } diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000..e4a63ec Binary files /dev/null and b/public/favicon.png differ diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..8f58d0d --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,15 @@ +{ + "name": "Winupdate Neo", + "short_name": "Winupdate", + "start_url": "/", + "display": "standalone", + "background_color": "#F9FAFB", + "theme_color": "#F9FAFB", + "icons": [ + { + "src": "/favicon.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/public/sw.js b/public/sw.js new file mode 100644 index 0000000..478ae31 --- /dev/null +++ b/public/sw.js @@ -0,0 +1,23 @@ +// Minimal PWA service worker with no API caching + +self.addEventListener("install", (event) => { + // Skip waiting so updated SW takes control faster + // but we do not pre-cache anything to keep behavior minimal + // @ts-ignore + self.skipWaiting(); +}); + +self.addEventListener("activate", (event) => { + // Claim clients so the SW starts controlling pages immediately + // @ts-ignore + event.waitUntil(self.clients.claim()); +}); + +self.addEventListener("fetch", (event) => { + const request = event.request; + + // Do not cache anything; just let the request pass through. + // Especially do not touch API requests. + // If needed in future, add logic here, but keep it disabled for now. + return; +});