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

45
scripts/generate-icons.js Normal file
View File

@@ -0,0 +1,45 @@
// Icon generation script
// This script creates placeholder icon files for the PWA
// In production, you should replace these with proper high-quality icons
const fs = require('fs');
const path = require('path');
// Create a simple data URL for a blue icon with a checkmark
function createIconDataURL(size) {
// Simple SVG icon
const svg = `
<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
<rect width="${size}" height="${size}" rx="${size * 0.25}" fill="#3B82F6"/>
<path d="M${size * 0.3} ${size * 0.5}L${size * 0.45} ${size * 0.65}L${size * 0.7} ${size * 0.35}"
stroke="white" stroke-width="${size * 0.08}" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
`;
return `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`;
}
// For now, we'll create SVG files that browsers can use
function createSVGIcon(size, outputPath) {
const svg = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
<rect width="${size}" height="${size}" rx="${size * 0.25}" fill="#3B82F6"/>
<path d="M${size * 0.3} ${size * 0.5}L${size * 0.45} ${size * 0.65}L${size * 0.7} ${size * 0.35}"
stroke="white" stroke-width="${size * 0.08}" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="${size * 0.25}" y="${size * 0.6}" width="${size * 0.5}" height="${size * 0.08}" rx="${size * 0.02}" fill="white"/>
<rect x="${size * 0.25}" y="${size * 0.72}" width="${size * 0.4}" height="${size * 0.08}" rx="${size * 0.02}" fill="white"/>
</svg>`;
fs.writeFileSync(outputPath, svg);
console.log(`Created ${outputPath}`);
}
// Create icons
const publicDir = path.join(__dirname, '..', 'public');
createSVGIcon(192, path.join(publicDir, 'icon-192.svg'));
createSVGIcon(512, path.join(publicDir, 'icon-512.svg'));
console.log('\nNote: SVG icons created. For production, convert these to PNG using:');
console.log(' - Online tools like https://cloudconvert.com/svg-to-png');
console.log(' - ImageMagick: convert icon-192.svg icon-192.png');
console.log(' - Or use a design tool like Figma/Sketch to export PNG versions');