feat: Set up PWA infrastructure with service worker, offline support, and manifest

- Created service worker (public/sw.js) with caching strategies
  - Cache-first strategy for static assets
  - Stale-while-revalidate for API responses and pages
  - Network-first fallback strategy
- Implemented offline fallback page (/offline)
- Updated manifest.json with complete PWA metadata
- Added service worker registration in app layout
- Created ServiceWorkerRegistration component for client-side registration
- Generated SVG icons for PWA (192x192 and 512x512)
- Added PWA meta tags for iOS Safari support

Validates Requirements: 4.1, 4.3, 4.4
This commit is contained in:
2025-12-01 20:30:07 +00:00
parent 4f29a48ae1
commit ef6a0bf5af
10 changed files with 369 additions and 9 deletions

View File

@@ -1,12 +1,23 @@
import type { Metadata } from 'next'
import './globals.css'
import ServiceWorkerRegistration from '@/components/ServiceWorkerRegistration'
export const metadata: Metadata = {
title: 'Ultimate Lists',
description: 'The ultimate todo list app',
description: 'The ultimate todo list app with advanced task management',
manifest: '/manifest.json',
themeColor: '#3B82F6',
viewport: 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no',
appleWebApp: {
capable: true,
statusBarStyle: 'default',
title: 'Ultimate Lists',
},
applicationName: 'Ultimate Lists',
icons: {
icon: '/icon-192.svg',
apple: '/icon-192.svg',
},
}
export default function RootLayout({
@@ -16,7 +27,17 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body className="bg-gray-50 min-h-screen">{children}</body>
<head>
<link rel="apple-touch-icon" href="/icon-192.svg" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="apple-mobile-web-app-title" content="Ultimate Lists" />
<meta name="mobile-web-app-capable" content="yes" />
</head>
<body className="bg-gray-50 min-h-screen">
<ServiceWorkerRegistration />
{children}
</body>
</html>
)
}

50
app/offline/page.tsx Normal file
View File

@@ -0,0 +1,50 @@
'use client';
import { WifiOff } from 'lucide-react';
export default function OfflinePage() {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 px-4">
<div className="text-center max-w-md">
<div className="flex justify-center mb-6">
<div className="bg-blue-100 p-4 rounded-full">
<WifiOff className="w-12 h-12 text-blue-600" />
</div>
</div>
<h1 className="text-3xl font-bold text-gray-900 mb-4">
You're Offline
</h1>
<p className="text-gray-600 mb-8">
It looks like you've lost your internet connection. Don't worry, your data is safe and will sync when you're back online.
</p>
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 text-left">
<h2 className="font-semibold text-gray-900 mb-3">What you can do:</h2>
<ul className="space-y-2 text-gray-600">
<li className="flex items-start">
<span className="text-blue-600 mr-2">•</span>
<span>View your cached lists and tasks</span>
</li>
<li className="flex items-start">
<span className="text-blue-600 mr-2">•</span>
<span>Make changes that will sync later</span>
</li>
<li className="flex items-start">
<span className="text-blue-600 mr-2">•</span>
<span>Check your connection and try again</span>
</li>
</ul>
</div>
<button
onClick={() => window.location.reload()}
className="mt-8 bg-blue-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors"
>
Try Again
</button>
</div>
</div>
);
}