- Ordnerstruktur mit public/-Docroot, Deny-.htaccess für app/bin/config/data/storage - CLAUDE.md mit Leitplanken (self-hosted only, Single Source of Truth, Component-first) - Design-Tokens aus alter Seite extrahiert (Akzent #e20612, Coolvetica/Abel als woff2) - Front Controller mit Routen-Register, Sitemap, Canonical, JSON-LD (SportsClub) - Startseite: Hero, Instagram-Feed (lokaler Cache), Historie/Sportheim, Stats, Partner, Kontakt - Kontaktformular via PHPMailer/Brevo mit Honeypot + HMAC-Time-Trap (kein reCAPTCHA) - bin/instagram-sync.php: Scraper mit Strategie-Kette, flock, atomarem Cache, lokalen Bildern Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
42 lines
1.4 KiB
PHP
42 lines
1.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Responsives Bild aus Varianten-Set. Props:
|
|
* $image array{base: string, widths: int[], alt: string} — base relativ zu assets/, Dateien: <base>-<w>.jpg
|
|
* $sizes string (optional, default '100vw')
|
|
* $eager bool (optional) — above the fold: eager + fetchpriority high
|
|
* $class string (optional)
|
|
*/
|
|
$sizes = $sizes ?? '100vw';
|
|
$eager = $eager ?? false;
|
|
$class = $class ?? '';
|
|
|
|
$widths = $image['widths'];
|
|
$largest = max($widths);
|
|
$srcset = implode(', ', array_map(
|
|
static fn (int $w): string => asset("{$image['base']}-{$w}.jpg") . " {$w}w",
|
|
$widths
|
|
));
|
|
|
|
// Maße der größten Variante für width/height (CLS-Vermeidung).
|
|
[$w, $h] = (function () use ($image, $largest): array {
|
|
static $dims = [];
|
|
$file = PUBLIC_PATH . "/assets/{$image['base']}-{$largest}.jpg";
|
|
$key = $file;
|
|
if (!isset($dims[$key])) {
|
|
$size = is_file($file) ? (getimagesize($file) ?: [0, 0]) : [0, 0];
|
|
$dims[$key] = [$size[0], $size[1]];
|
|
}
|
|
return $dims[$key];
|
|
})();
|
|
?>
|
|
<img<?= $class !== '' ? ' class="' . e($class) . '"' : '' ?>
|
|
src="<?= e(asset("{$image['base']}-{$largest}.jpg")) ?>"
|
|
srcset="<?= e($srcset) ?>"
|
|
sizes="<?= e($sizes) ?>"
|
|
alt="<?= e($image['alt']) ?>"
|
|
width="<?= e($w) ?>" height="<?= e($h) ?>"
|
|
<?= $eager ? 'loading="eager" fetchpriority="high"' : 'loading="lazy" decoding="async"' ?>>
|