feat(pwa): installable PWA + mobile responsive chrome
PWA対応とモバイルUX改善。 - app/manifest.ts: Nextファイルベースでマニフェスト生成(name/short_name/display:standalone/icons 192+512 any+maskable + svg) - public/icon.svg + 生成PNG(192/512): scripts/generate-icons.mjs で sharp を用いてSVGをラスタライズ - public/sw.js: アプリシェルのプリキャッシュ、ナビゲーションはネットワーク優先(オフラインはキャッシュ/'/'にフォールバック)、静的アセットはキャッシュ優先。API/非GET/クロスオリジンはキャッシュせず、res.ok&&basic でエラー/リダイレクト結果を弾く - components/pwa/ServiceWorkerRegister: 本番のみ /sw.js を登録(開発HMRとの衝突回避) - app/layout.tsx: export const viewport(device-width, cover, themeColor) + metadata.icons/appleWebApp - middleware: sw.js/manifest/icon を認証ガードから除外(ログイン前でも取得可能) - ProjectNav: 横スクロールStrip(折り返さない)、Header: モバイルでダッシュボードテキストリンクを非表示
This commit is contained in:
26
scripts/generate-icons.mjs
Normal file
26
scripts/generate-icons.mjs
Normal file
@ -0,0 +1,26 @@
|
||||
// One-off: rasterize public/icon.svg into 512 and 192 PNGs (any/maskable).
|
||||
// Uses sharp (already a transitive dependency in this project). Run: node scripts/generate-icons.mjs
|
||||
import sharp from 'sharp';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const ROOT = process.cwd();
|
||||
const SVG = path.join(ROOT, 'public/icon.svg');
|
||||
|
||||
async function main() {
|
||||
const svgBuf = fs.readFileSync(SVG);
|
||||
const sizes = [512, 192];
|
||||
for (const size of sizes) {
|
||||
const out = path.join(ROOT, `public/icon-${size}.png`);
|
||||
await sharp(svgBuf, { density: 384 })
|
||||
.resize(size, size, { fit: 'contain' })
|
||||
.png()
|
||||
.toFile(out);
|
||||
console.log(`wrote ${out} (${size}x${size})`);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user