Adds what iOS/Android need to treat the site as an installable app from Safari's "Add to Home Screen": a manifest.json, apple-touch-icon set generated from the existing logo mark (scripts/generate-icons.mjs, sharp as a dev dependency), and the apple-mobile-web-app-* meta tags iOS Safari requires since it ignores manifest.json entirely. The service worker is deliberately minimal — this app shows live financial data, so navigations always hit the network first. It only caches enough to serve offline.html when there's no connection, not a full offline-first app shell. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
41 lines
1.6 KiB
JavaScript
41 lines
1.6 KiB
JavaScript
import sharp from 'sharp';
|
|
import { mkdirSync } from 'fs';
|
|
|
|
const BRAND = '#c67139';
|
|
const MARK = '#fff8ee';
|
|
|
|
function svgIcon({ size, markScale }) {
|
|
const r = (316 / 2) * markScale;
|
|
const cx = size / 2;
|
|
const cy = size / 2;
|
|
const scale = (size * markScale) / 316;
|
|
|
|
return `
|
|
<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
|
|
<rect width="${size}" height="${size}" fill="${BRAND}"/>
|
|
<g transform="translate(${cx - 158 * scale}, ${cy - 158 * scale}) scale(${scale})">
|
|
<circle cx="158" cy="158" r="140" stroke="${MARK}" stroke-width="16" fill="none"/>
|
|
<path d="M90 196 L134 142 L172 174 L238 96" stroke="${MARK}" stroke-width="18" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
<path d="M238 96 L238 138 M238 96 L196 96" stroke="${MARK}" stroke-width="18" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
</g>
|
|
</svg>`;
|
|
}
|
|
|
|
mkdirSync('public/icons', { recursive: true });
|
|
|
|
const targets = [
|
|
{ file: 'public/icons/apple-touch-icon.png', size: 180, markScale: 0.68 },
|
|
{ file: 'public/icons/apple-touch-icon-152.png', size: 152, markScale: 0.68 },
|
|
{ file: 'public/icons/apple-touch-icon-167.png', size: 167, markScale: 0.68 },
|
|
{ file: 'public/icons/icon-192.png', size: 192, markScale: 0.68 },
|
|
{ file: 'public/icons/icon-512.png', size: 512, markScale: 0.68 },
|
|
{ file: 'public/icons/icon-maskable-512.png', size: 512, markScale: 0.55 },
|
|
];
|
|
|
|
for (const t of targets) {
|
|
await sharp(Buffer.from(svgIcon(t)))
|
|
.png()
|
|
.toFile(t.file);
|
|
console.log(`wrote ${t.file}`);
|
|
}
|