initial commit
Deploy to Dev Server / deploy (push) Has been cancelled

This commit is contained in:
2026-03-26 16:10:45 +01:00
commit ae33874ae0
406 changed files with 72867 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
/**
* PWA Icon Generator Script
* Generiert Placeholder-Icons für die PWA
*
* Verwendung: node tools/generate-pwa-icons.mjs
*
* Für echte Icons: Ersetze die generierten Dateien mit deinen
* eigenen Icons oder nutze https://www.pwabuilder.com/imageGenerator
*/
import { writeFileSync, mkdirSync, existsSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ICONS_DIR = join(__dirname, '../public/assets/icons');
const SIZES = [72, 96, 128, 144, 152, 192, 384, 512];
const BRAND_COLOR = '#C2410C';
const BG_COLOR = '#ffffff';
// Stelle sicher dass der Ordner existiert
if (!existsSync(ICONS_DIR)) {
mkdirSync(ICONS_DIR, { recursive: true });
}
/**
* Generiert ein einfaches SVG-Icon als Placeholder
*/
function generateSvgIcon(size) {
const padding = size * 0.15;
const innerSize = size - (padding * 2);
const fontSize = size * 0.35;
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">
<rect width="${size}" height="${size}" fill="${BG_COLOR}" rx="${size * 0.15}"/>
<rect x="${padding}" y="${padding}" width="${innerSize}" height="${innerSize}" fill="${BRAND_COLOR}" rx="${innerSize * 0.1}"/>
<text x="50%" y="52%" dominant-baseline="middle" text-anchor="middle"
font-family="Arial, sans-serif" font-weight="bold" font-size="${fontSize}px" fill="white">
L&amp;B
</text>
</svg>`;
}
/**
* Konvertiert SVG zu PNG mit Canvas (vereinfachte Base64 Version)
* Hinweis: Für echte PNG-Generierung würde man sharp oder canvas npm packages verwenden
*/
function generatePlaceholderPng(size) {
// Da wir keine externen Dependencies haben, generieren wir eine Info-Datei
const infoContent = `PWA Icon Placeholder - ${size}x${size}px
WICHTIG: Ersetze diese Datei mit einem echten PNG-Icon!
Empfohlene Tools:
- PWA Builder: https://www.pwabuilder.com/imageGenerator
- Maskable App: https://maskable.app/editor
- Real Favicon Generator: https://realfavicongenerator.net/
Icon-Anforderungen:
- Größe: ${size}x${size} Pixel
- Format: PNG mit Transparenz
- Safe Zone für Maskable: 80% des Icons sollte im inneren Kreis sein
`;
return infoContent;
}
// Generiere SVG Icons (können direkt verwendet werden)
console.log('🎨 Generiere PWA Icons...\n');
SIZES.forEach(size => {
const svgPath = join(ICONS_DIR, `icon-${size}x${size}.svg`);
const svg = generateSvgIcon(size);
writeFileSync(svgPath, svg);
console.log(` ✓ icon-${size}x${size}.svg`);
});
// Erstelle eine README
const readme = `# PWA Icons
Diese SVG-Icons wurden automatisch generiert und dienen als Placeholder.
## Für die Produktion:
1. Erstelle ein quadratisches Logo (mindestens 512x512px)
2. Gehe zu https://www.pwabuilder.com/imageGenerator
3. Lade dein Logo hoch
4. Lade die generierten Icons herunter
5. Ersetze die SVG-Dateien hier mit den PNG-Dateien
## Benötigte Größen:
${SIZES.map(s => `- icon-${s}x${s}.png`).join('\n')}
## Icon-Tipps:
- Verwende PNG mit Transparenz
- Halte wichtige Elemente in der "Safe Zone" (innere 80%)
- Teste mit https://maskable.app/editor
## Schnelle Alternative:
Die SVG-Icons funktionieren auch, aber PNGs sind kompatibler.
Ändere in manifest.webmanifest die Endungen von .png zu .svg.
`;
writeFileSync(join(ICONS_DIR, 'README.md'), readme);
console.log('\n✅ PWA Icons generiert!\n');
console.log('📝 Nächste Schritte:');
console.log(' 1. Öffne public/assets/icons/README.md für Anweisungen');
console.log(' 2. Ersetze die SVGs mit echten PNGs für beste Kompatibilität');
console.log(' 3. Oder ändere manifest.webmanifest zu .svg Endungen\n');
+125
View File
@@ -0,0 +1,125 @@
import { writeFileSync, existsSync, readFileSync, mkdirSync } from "node:fs";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
/**
* Domain setzen per ENV überschreibbar:
* BASE_URL=https://Leonards & Brandenburger IT.de npm run build
*/
const BASE_URL = (process.env.BASE_URL || "https://Leonards & Brandenburger IT.de").replace(/\/+$/, "");
/**
* Statische, öffentliche Routen (aus deiner Liste, aber ohne Admin/Auth/Preview).
* Passe diese Liste an, falls du noch mehr veröffentlichen willst.
*/
const STATIC_ROUTES = [
"/", // Home
"/services",
"/about",
"/contact",
"/imprint",
"/process",
"/faq",
"/policy",
"/booking",
"/survey",
"/it-services"
];
/**
* Dynamische Services: /services/:slug
* Lies optionale Slugs aus src/data/service-slugs.json
* Formatbeispiel:
* { "slugs": ["one-pager","all-in-one","large-website","seo-optimization","full-stack-development"] }
*/
function readServiceSlugs() {
try {
const p = "src/data/service-slugs.json";
if (!existsSync(p)) return [];
const json = JSON.parse(readFileSync(p, "utf8"));
const arr = Array.isArray(json) ? json : json.slugs;
return Array.isArray(arr) ? arr.filter(Boolean) : [];
} catch {
return [];
}
}
const serviceSlugs = readServiceSlugs();
const DYNAMIC_ROUTES = serviceSlugs.map(slug => `/services/${slug}`);
/**
* Final: Alle URLs, doppelte raus, sortiert
*/
const allPaths = Array.from(new Set([...STATIC_ROUTES, ...DYNAMIC_ROUTES]));
allPaths.sort((a, b) => a.localeCompare(b));
/**
* lastmod: heute im YYYY-MM-DD
*/
const today = new Date().toISOString().slice(0, 10);
/**
* Prioritäten & changefreq: simple Heuristik
*/
function getMeta(path) {
if (path === "/") return { priority: "1.0", changefreq: "weekly" };
if (path.startsWith("/services/")) return { priority: "0.7", changefreq: "monthly" };
if (path === "/services") return { priority: "0.8", changefreq: "weekly" };
return { priority: "0.6", changefreq: "monthly" };
}
/**
* sitemap.xml bauen (ohne externes Paket)
*/
function buildSitemapXml() {
const urlsXml = allPaths.map(p => {
const { priority, changefreq } = getMeta(p);
const loc = `${BASE_URL}${p === "/" ? "/" : p}`;
return [
" <url>",
` <loc>${loc}</loc>`,
` <changefreq>${changefreq}</changefreq>`,
` <priority>${priority}</priority>`,
` <lastmod>${today}</lastmod>`,
" </url>"
].join("\n");
}).join("\n");
return [
`<?xml version="1.0" encoding="UTF-8"?>`,
`<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`,
urlsXml,
`</urlset>`
].join("\n");
}
/**
* robots.txt bauen (mit absoluter Sitemap-URL)
*/
function buildRobotsTxt() {
return [
`User-agent: *`,
`Allow: /`,
``,
`Sitemap: ${BASE_URL}/sitemap.xml`
].join("\n");
}
/**
* Dateien nach src/ schreiben (werden per assets ins Webroot kopiert)
*/
function ensureDirFor(filePath) {
const dir = filePath.split("/").slice(0, -1).join("/");
if (dir && !existsSync(dir)) mkdirSync(dir, { recursive: true });
}
function writeFile(path, content) {
ensureDirFor(path);
writeFileSync(path, content, "utf8");
console.log(`${path} geschrieben`);
}
writeFile("src/sitemap.xml", buildSitemapXml());
writeFile("src/robots.txt", buildRobotsTxt());