Replace the Astro placeholder favicon (white L on indigo) with the larpaso "la" mark from the prototype, in SVG/ICO/PNG sizes plus an Apple touch icon, and add Open Graph tags with a 1200x630 preview image so shared links show the logo. Icons are rebuilt with scripts/icons-bauen.mjs. Clicking or tapping the laptop or phone in the hero and the portfolio now opens a full-page capture of the example site in a dialog, scrollable and switchable between desktop and mobile. The scroll videos stay as they were. New content fields mappe.items[].fullImage / fullMobileImage, also in the admin schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
56 lines
2.3 KiB
JavaScript
56 lines
2.3 KiB
JavaScript
// Baut Favicon, App-Icons und das Vorschaubild für geteilte Links aus den
|
|
// Marken-SVGs in public/. Aufruf: node scripts/icons-bauen.mjs
|
|
// Quelle des Favicons: das "la" auf Petrol aus dem Prototyp lara-webdesign.html.
|
|
import sharp from 'sharp';
|
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
|
|
const pub = (f) => new URL(`../public/${f}`, import.meta.url);
|
|
const papier = { r: 252, g: 250, b: 246, alpha: 1 };
|
|
|
|
const favicon = readFileSync(pub('favicon.svg'));
|
|
const logo = readFileSync(pub('logo.svg'));
|
|
|
|
const png = (svg, size) =>
|
|
sharp(svg, { density: 72 * Math.ceil(size / 100) * 4 }).resize(size, size).png().toBuffer();
|
|
|
|
// Transparente Icons
|
|
for (const size of [48, 96, 192, 512]) {
|
|
writeFileSync(pub(`icon-${size}.png`), await png(favicon, size));
|
|
}
|
|
|
|
// Apple-Icon braucht deckenden Grund (iOS füllt Transparenz schwarz)
|
|
const appleInner = await png(favicon, 148);
|
|
await sharp({ create: { width: 180, height: 180, channels: 4, background: papier } })
|
|
.composite([{ input: appleInner, gravity: 'center' }])
|
|
.png()
|
|
.toFile(new URL('../public/apple-touch-icon.png', import.meta.url).pathname.replace(/^\/(\w:)/, '$1'));
|
|
|
|
// favicon.ico mit 16/32/48 als PNG-Einträge
|
|
const sizes = [16, 32, 48];
|
|
const bufs = await Promise.all(sizes.map((s) => png(favicon, s)));
|
|
const header = Buffer.alloc(6 + 16 * sizes.length);
|
|
header.writeUInt16LE(0, 0);
|
|
header.writeUInt16LE(1, 2);
|
|
header.writeUInt16LE(sizes.length, 4);
|
|
let offset = header.length;
|
|
sizes.forEach((s, i) => {
|
|
const e = 6 + 16 * i;
|
|
header.writeUInt8(s, e);
|
|
header.writeUInt8(s, e + 1);
|
|
header.writeUInt16LE(1, e + 4);
|
|
header.writeUInt16LE(32, e + 6);
|
|
header.writeUInt32LE(bufs[i].length, e + 8);
|
|
header.writeUInt32LE(offset, e + 12);
|
|
offset += bufs[i].length;
|
|
});
|
|
writeFileSync(pub('favicon.ico'), Buffer.concat([header, ...bufs]));
|
|
|
|
// Vorschaubild für WhatsApp, Signal, Facebook, LinkedIn & Co. (1200 x 630)
|
|
const logoPng = await sharp(logo, { density: 300 }).resize({ width: 860 }).png().toBuffer();
|
|
await sharp({ create: { width: 1200, height: 630, channels: 4, background: papier } })
|
|
.composite([{ input: logoPng, gravity: 'center' }])
|
|
.flatten({ background: papier })
|
|
.jpeg({ quality: 88 })
|
|
.toFile(new URL('../public/og-image.jpg', import.meta.url).pathname.replace(/^\/(\w:)/, '$1'));
|
|
|
|
console.log('Icons gebaut.');
|