feat(pwa): add icon generation script and generated PWA icons
This commit is contained in:
parent
ab38e8115b
commit
6d5f78aecf
7 changed files with 74 additions and 0 deletions
BIN
apps/main/public/pwa-icons/apple-touch-icon-180x180.png
Normal file
BIN
apps/main/public/pwa-icons/apple-touch-icon-180x180.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
apps/main/public/pwa-icons/favicon-16x16.png
Normal file
BIN
apps/main/public/pwa-icons/favicon-16x16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 600 B |
BIN
apps/main/public/pwa-icons/favicon-32x32.png
Normal file
BIN
apps/main/public/pwa-icons/favicon-32x32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
apps/main/public/pwa-icons/pwa-192x192.png
Normal file
BIN
apps/main/public/pwa-icons/pwa-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
apps/main/public/pwa-icons/pwa-512x512-maskable.png
Normal file
BIN
apps/main/public/pwa-icons/pwa-512x512-maskable.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
BIN
apps/main/public/pwa-icons/pwa-512x512.png
Normal file
BIN
apps/main/public/pwa-icons/pwa-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
74
apps/main/scripts/generate-pwa-icons.ts
Normal file
74
apps/main/scripts/generate-pwa-icons.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import sharp from "sharp";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
|
||||
const PUBLIC_DIR = path.resolve(import.meta.dirname, "../public");
|
||||
const OUTPUT_DIR = path.join(PUBLIC_DIR, "pwa-icons");
|
||||
|
||||
const ICON_SIZES = [
|
||||
{ size: 16, name: "favicon-16x16.png" },
|
||||
{ size: 32, name: "favicon-32x32.png" },
|
||||
{ size: 180, name: "apple-touch-icon-180x180.png" },
|
||||
{ size: 192, name: "pwa-192x192.png" },
|
||||
{ size: 512, name: "pwa-512x512.png" },
|
||||
{ size: 512, name: "pwa-512x512-maskable.png", maskable: true },
|
||||
];
|
||||
|
||||
// Maskable icons need 10% safe zone padding (per spec).
|
||||
// We add a colored background and shrink the source to 80% to stay within the safe zone.
|
||||
const MASKABLE_PADDING_RATIO = 0.1;
|
||||
const MASKABLE_BG_COLOR = "#ffffff";
|
||||
|
||||
async function generateIcons(sourceFile: string) {
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
for (const icon of ICON_SIZES) {
|
||||
const outputPath = path.join(OUTPUT_DIR, icon.name);
|
||||
|
||||
if (icon.maskable) {
|
||||
// Create maskable icon with padding and background
|
||||
const innerSize = Math.round(icon.size * (1 - MASKABLE_PADDING_RATIO * 2));
|
||||
const offset = Math.round(icon.size * MASKABLE_PADDING_RATIO);
|
||||
|
||||
const resizedIcon = await sharp(sourceFile)
|
||||
.resize(innerSize, innerSize, { fit: "contain" })
|
||||
.toBuffer();
|
||||
|
||||
await sharp({
|
||||
create: {
|
||||
width: icon.size,
|
||||
height: icon.size,
|
||||
channels: 4,
|
||||
background: MASKABLE_BG_COLOR,
|
||||
},
|
||||
})
|
||||
.composite([{ input: resizedIcon, left: offset, top: offset }])
|
||||
.png()
|
||||
.toFile(outputPath);
|
||||
} else {
|
||||
await sharp(sourceFile)
|
||||
.resize(icon.size, icon.size, { fit: "contain" })
|
||||
.png()
|
||||
.toFile(outputPath);
|
||||
}
|
||||
|
||||
console.log(`Generated: ${icon.name} (${icon.size}x${icon.size})`);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine source: pass "staging" as first arg for staging icons
|
||||
const variant = process.argv[2];
|
||||
const sourceFile =
|
||||
variant === "staging"
|
||||
? path.join(PUBLIC_DIR, "staging_icon.jpg")
|
||||
: path.join(PUBLIC_DIR, "icon.jpg");
|
||||
|
||||
if (!fs.existsSync(sourceFile)) {
|
||||
console.error(`Source icon not found: ${sourceFile}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Generating PWA icons from: ${sourceFile}`);
|
||||
generateIcons(sourceFile).then(() => console.log("Done!"));
|
||||
Loading…
Reference in a new issue