- Impressum rewritten with real Austrian business data (ECG instead of German TMG references); UID, Gewerbeberechtigung and Firmenbuchnummer marked as pending until available - Real contact email/phone/address across footer and Impressum - Meta description, Open Graph tags and favicon on all pages - Gallery images now offer both 800w and 1920w srcset candidates - Lightbox traps focus while open and restores it on close - Header/footer extracted into partials/, pages now built from templates/ via `npm run build` (scripts/build.js) to remove duplication across the 4 pages
89 lines
2.6 KiB
JavaScript
89 lines
2.6 KiB
JavaScript
/**
|
||
* Image optimization script for Tischlerei Staffenberger.
|
||
* Generates WebP + JPEG variants at thumbnail (800px) and lightbox (1920px) sizes.
|
||
* Output: images/optimized/{category}/{name}-{size}w.{ext}
|
||
*
|
||
* Run: node scripts/optimize-images.js
|
||
*/
|
||
|
||
'use strict';
|
||
|
||
const sharp = require('sharp');
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
const PROJECT_ROOT = path.join(__dirname, '..');
|
||
const INPUT_ROOT = path.join(PROJECT_ROOT, 'images', 'fotowebsite');
|
||
const OUTPUT_ROOT = path.join(PROJECT_ROOT, 'images', 'optimized');
|
||
|
||
// Gallery categories: [input subdir, output subdir]
|
||
const GALLERY_DIRS = [
|
||
['kitchen', 'kitchen'],
|
||
['outdoor', 'outdoor'],
|
||
['custom', 'custom'],
|
||
];
|
||
|
||
const GALLERY_SIZES = [800, 1920];
|
||
const BANNER_SIZES = [800, 1920];
|
||
|
||
function safeName(filename) {
|
||
return path.basename(filename, path.extname(filename)).replace(/\s+/g, '-');
|
||
}
|
||
|
||
async function processImage(inputPath, outputDir, baseName, sizes) {
|
||
fs.mkdirSync(outputDir, { recursive: true });
|
||
|
||
for (const width of sizes) {
|
||
const jpegOut = path.join(outputDir, `${baseName}-${width}w.jpg`);
|
||
const webpOut = path.join(outputDir, `${baseName}-${width}w.webp`);
|
||
|
||
await sharp(inputPath)
|
||
.resize({ width, withoutEnlargement: true })
|
||
.jpeg({ quality: 85, mozjpeg: true })
|
||
.toFile(jpegOut);
|
||
|
||
await sharp(inputPath)
|
||
.resize({ width, withoutEnlargement: true })
|
||
.webp({ quality: 82 })
|
||
.toFile(webpOut);
|
||
|
||
const jpegSize = (fs.statSync(jpegOut).size / 1024).toFixed(0);
|
||
const webpSize = (fs.statSync(webpOut).size / 1024).toFixed(0);
|
||
console.log(` ${path.basename(jpegOut)}: JPEG ${jpegSize}KB WebP ${webpSize}KB`);
|
||
}
|
||
}
|
||
|
||
async function main() {
|
||
console.log('=== Tischlerei Staffenberger – Image Optimization ===\n');
|
||
|
||
// --- Gallery images ---
|
||
for (const [inputSubdir, outputSubdir] of GALLERY_DIRS) {
|
||
const inputDir = path.join(INPUT_ROOT, inputSubdir);
|
||
const outputDir = path.join(OUTPUT_ROOT, outputSubdir);
|
||
|
||
const files = fs.readdirSync(inputDir)
|
||
.filter(f => /\.(jpe?g)$/i.test(f))
|
||
.sort();
|
||
|
||
console.log(`[${inputSubdir}] – ${files.length} images`);
|
||
|
||
for (const file of files) {
|
||
const inputPath = path.join(inputDir, file);
|
||
const baseName = safeName(file);
|
||
await processImage(inputPath, outputDir, baseName, GALLERY_SIZES);
|
||
}
|
||
}
|
||
|
||
// --- Banner ---
|
||
const bannerInput = path.join(INPUT_ROOT, 'banner.jpg');
|
||
const bannerOutput = OUTPUT_ROOT;
|
||
console.log('\n[banner]');
|
||
await processImage(bannerInput, bannerOutput, 'banner', BANNER_SIZES);
|
||
|
||
console.log('\nDone.');
|
||
}
|
||
|
||
main().catch(err => {
|
||
console.error(err);
|
||
process.exit(1);
|
||
});
|