feat: Add PWA support

- PWA_MOBILE_SPEC.md documentation
- manifest.json with app metadata
- Service Worker with caching strategies
- Offline page
- PWA registration in layout
- App icons (placeholder)
This commit is contained in:
Apple
2025-11-26 13:56:22 -08:00
parent e0d534ea87
commit a3e632b9e7
12 changed files with 655 additions and 10 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,61 @@
const fs = require('fs');
const { createCanvas } = require('canvas');
function generateIcon(size, filename) {
const canvas = createCanvas(size, size);
const ctx = canvas.getContext('2d');
// Background
ctx.fillStyle = '#0f172a';
ctx.beginPath();
ctx.roundRect(0, 0, size, size, size * 0.18);
ctx.fill();
// Gradient for sparkle
const gradient = ctx.createLinearGradient(0, 0, size, size);
gradient.addColorStop(0, '#22d3ee');
gradient.addColorStop(1, '#3b82f6');
// Draw sparkle
const cx = size / 2;
const cy = size / 2;
const s = size * 0.23; // sparkle size
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.moveTo(cx, cy - s);
ctx.lineTo(cx + s * 0.12, cy - s * 0.12);
ctx.lineTo(cx + s, cy);
ctx.lineTo(cx + s * 0.12, cy + s * 0.12);
ctx.lineTo(cx, cy + s);
ctx.lineTo(cx - s * 0.12, cy + s * 0.12);
ctx.lineTo(cx - s, cy);
ctx.lineTo(cx - s * 0.12, cy - s * 0.12);
ctx.closePath();
ctx.fill();
// Small sparkles
ctx.fillStyle = '#22d3ee';
ctx.globalAlpha = 0.7;
ctx.beginPath();
ctx.arc(cx + size * 0.15, cy - size * 0.15, size * 0.023, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#3b82f6';
ctx.globalAlpha = 0.6;
ctx.beginPath();
ctx.arc(cx - size * 0.14, cy + size * 0.14, size * 0.015, 0, Math.PI * 2);
ctx.fill();
const buffer = canvas.toBuffer('image/png');
fs.writeFileSync(filename, buffer);
console.log(`Generated ${filename}`);
}
try {
generateIcon(192, 'icon-192x192.png');
generateIcon(512, 'icon-512x512.png');
generateIcon(180, 'apple-touch-icon.png');
} catch (e) {
console.error('Error:', e.message);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="none">
<rect width="512" height="512" rx="96" fill="#0f172a"/>
<defs>
<linearGradient id="sparkle" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#22d3ee"/>
<stop offset="100%" style="stop-color:#3b82f6"/>
</linearGradient>
</defs>
<g transform="translate(256, 256)">
<path d="M0 -120 L15 -15 L120 0 L15 15 L0 120 L-15 15 L-120 0 L-15 -15 Z" fill="url(#sparkle)" opacity="0.9"/>
<circle cx="80" cy="-80" r="12" fill="#22d3ee" opacity="0.7"/>
<circle cx="-70" cy="70" r="8" fill="#3b82f6" opacity="0.6"/>
<circle cx="60" cy="90" r="6" fill="#22d3ee" opacity="0.5"/>
<circle cx="-90" cy="-50" r="10" fill="#3b82f6" opacity="0.6"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 785 B