Files
KantSites/scripts/seed-maler-drews.php
T
kantarciandClaude Fable 5.1 232e6fe6dc Let a single column sit in a section and give buttons an alignment
A column may now live directly in a section, not only in a row - the way
to centre or narrow a button or a short text without a one-column row.
The align design token applies to buttons; because a button is
inline-flex, auto margins never centred it, so site.css turns an aligned
button into a fit-content block per device. The Drews seed uses the
token for its centred buttons.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 14:49:37 +02:00

1133 lines
102 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Baut die Website „Ihr Malerservice Drews“ (maler-drews.com) als Inhalt dieses CMS auf.
*
* Vorlage ist der laufende Flatsome-Auftritt, am 15.09.2026 Seite für Seite ausgelesen:
* Wortlaut, Reihenfolge der Abschnitte, Farben (Gold #c6a36b, dunkle Bänder, Creme #f7f5f2),
* Schriften (Lato, Cormorant Garamond), Abstände und die Aufteilung der Bilder. Alle 31 Beiträge
* (5 Mitteilungen, 26 Projekte) samt Bildern, Impressum und Datenschutzerklärung sind übernommen;
* die Texte stehen in seed-maler-drews-inhalte.php. Gebaut ist alles aus gewöhnlichen Bausteinen.
*
* Bewusste Abweichungen:
* - Die Videogalerie der Kunstmalerei-Seite und die Google-Karte der Kontaktseite sind eingebettete
* Inhalte, die erst nach Einwilligung geladen werden (Baustein „Eingebettet“). Die Videos liegen
* weiter auf maler-drews.com; für den Livegang brauchen sie einen eigenen Speicherort.
* - Das Kontaktformular verschickt serverseitig; die Rechenaufgabe („5 + 8“) entfällt, der
* Schutz vor Automaten steckt im Formular selbst.
* - /about-us und /innenaustattung der Vorlage sind unfertige Musterseiten (Lorem ipsum) und
* werden auf die Startseite bzw. die Projekte umgeleitet; /little-greene ist auf der Vorlage
* ein 404 und zeigt hier auf die Mitteilung zur Little-Greene-Partnerschaft.
* - Die Wellenform unter dem Startbild ist mit runden Flächen nachgebildet, nicht als SVG.
*
* Das Skript schreibt ausschließlich in die Datenbank aus DATABASE_URL und in MEDIA_DIRECTORY,
* beide müssen auf eine frische, migrierte Installation zeigen (siehe reset-maler-drews.sh).
* Erstes Argument: der Ordner mit den Bildern (var/maler-drews-assets, Dateinamen wie in
* manifest.json).
*/
require dirname(__DIR__).'/config/bootstrap.php';
use App\Content\DocumentValidator;
use App\Content\FormRepository;
use App\Content\MediaLibrary;
use App\Content\MenuRepository;
use App\Content\PageRepository;
use App\Content\PartialRepository;
use App\Content\PostRepository;
use App\Content\RedirectRepository;
use App\Content\SiteSettings;
use App\Content\Theme;
use App\Infrastructure\ConnectionFactory;
use Symfony\Component\HttpFoundation\File\UploadedFile;
$root = dirname(__DIR__);
$assets = $argv[1] ?? null;
if (null === $assets || !is_dir($assets)) {
fwrite(STDERR, "Bitte den Ordner mit den Bildern als Argument angeben.\n");
exit(1);
}
$url = str_replace('%kernel.project_dir%', str_replace('\\', '/', $root), (string) $_SERVER['DATABASE_URL']);
$mediaDirectory = str_replace('%kernel.project_dir%', $root, (string) $_SERVER['MEDIA_DIRECTORY']);
if (!str_contains($url, 'maler-drews')) {
fwrite(STDERR, "Sicherung: DATABASE_URL muss auf die Maler-Drews-Datenbank zeigen.\n");
exit(1);
}
$db = ConnectionFactory::create($url);
if (false !== $db->fetchOne('SELECT id FROM page LIMIT 1')) {
fwrite(STDERR, "Diese Datenbank enthält bereits Seiten. Abbruch, damit nichts überschrieben wird.\n");
exit(1);
}
$inhalte = require __DIR__.'/seed-maler-drews-inhalte.php';
$media = new MediaLibrary($db, $mediaDirectory);
$settings = new SiteSettings($db, $media);
$validator = new DocumentValidator();
$pages = new PageRepository($db, $validator, $settings);
$posts = new PostRepository($db, $media, $settings);
$partials = new PartialRepository($db, $validator);
$menus = new MenuRepository($db, $settings);
$forms = new FormRepository($db);
$theme = new Theme($db);
$redirects = new RedirectRepository($db);
$mail = 'info@maler-drews.com';
$telefon = '+49 7224 40821';
$telHref = 'tel:+49722440821';
$fax = '+49 7224 990503';
$SCHEMA = 23;
$GOLD = '#c6a36b';
// ---------------------------------------------------------------------------------------------
// Bausteine
// ---------------------------------------------------------------------------------------------
$ecken = static fn (string $r): array => ['topLeft' => $r, 'topRight' => $r, 'bottomRight' => $r, 'bottomLeft' => $r];
$seiten = static fn (string $w): array => ['top' => $w, 'right' => $w, 'bottom' => $w, 'left' => $w];
$nurOben = static fn (string $w): array => ['top' => $w, 'right' => '0px', 'bottom' => '0px', 'left' => '0px'];
$nurLinks = static fn (string $w): array => ['top' => '0px', 'right' => '0px', 'bottom' => '0px', 'left' => $w];
$section = static function (string $id, array $children, array $style = [], ?string $anchor = null, array $layout = []): array {
$block = ['id' => $id, 'type' => 'section', 'children' => $children, 'style' => $style];
if (null !== $anchor) {
$block['anchor'] = $anchor;
}
if ([] !== $layout) {
$block['layout'] = $layout;
}
return $block;
};
$row = static function (string $id, array $children, array $design = [], array $style = []): array {
$block = ['id' => $id, 'type' => 'row', 'children' => $children];
if ([] !== $design) {
$block['layout'] = ['design' => $design];
}
if ([] !== $style) {
$block['style'] = $style;
}
return $block;
};
$column = static function (string $id, array $children, array $style = [], string $sichtbarkeit = 'all', string $css = ''): array {
$block = ['id' => $id, 'type' => 'column', 'children' => $children];
if ([] !== $style) {
$block['style'] = $style;
}
if ('all' !== $sichtbarkeit) {
$block['layout'] = ['visibility' => $sichtbarkeit];
}
if ('' !== $css) {
$block['css'] = $css;
}
return $block;
};
$heading = static function (string $id, string $text, int $level, array $style = [], string $css = ''): array {
$block = ['id' => $id, 'type' => 'heading', 'props' => ['text' => $text, 'level' => $level]];
if ([] !== $style) {
$block['style'] = $style;
}
if ('' !== $css) {
$block['css'] = $css;
}
return $block;
};
$text = static function (string $id, string $inhalt, array $style = [], string $css = ''): array {
$block = ['id' => $id, 'type' => 'text', 'props' => ['text' => $inhalt]];
if ([] !== $style) {
$block['style'] = $style;
}
if ('' !== $css) {
$block['css'] = $css;
}
return $block;
};
/** Eine reine Fläche: Linien, die Welle unter dem Startbild. */
$flaeche = static function (string $id, array $style, string $css = ''): array {
$block = ['id' => $id, 'type' => 'spacer', 'props' => ['size' => 'small'], 'style' => $style];
if ('' !== $css) {
$block['css'] = $css;
}
return $block;
};
/**
* Ein Button in einer der vier Farbfassungen der Vorlage: gold, dunkel (#333), weißer Rahmen,
* dunkler Rahmen. Der Pfeil des Bausteins bleibt nur dort, wo die Vorlage einen zeigt.
*/
$button = static function (string $id, string $text, string $href, string $fassung = 'gold', bool $pfeil = false, array $style = [], string $groesse = 'large'): array {
$farben = match ($fassung) {
'dunkel' => '--kb-bg:#333333;--kb-fg:#ffffff;--kb-border:transparent;--kb-hover-bg:#1c1c1c;--kb-hover-fg:#ffffff',
'weiss-rahmen' => '--kb-bg:transparent;--kb-fg:#ffffff;--kb-border:#ffffff;--kb-hover-bg:#ffffff;--kb-hover-fg:#222222',
'dunkel-rahmen' => '--kb-bg:transparent;--kb-fg:#222222;--kb-border:#222222;--kb-hover-bg:#222222;--kb-hover-fg:#ffffff',
'gold-rahmen' => '--kb-bg:transparent;--kb-fg:#c6a36b;--kb-border:#c6a36b;--kb-hover-bg:#c6a36b;--kb-hover-fg:#ffffff',
'gold-pille' => '--kb-bg:#c6a36b;--kb-fg:#2a2a2a;--kb-border:transparent;--kb-hover-bg:#b4966e;--kb-hover-fg:#2a2a2a;--kb-radius:999px',
default => '--kb-bg:#c6a36b;--kb-fg:#222222;--kb-border:transparent;--kb-hover-bg:#ae8c4e;--kb-hover-fg:#222222',
};
$css = ''.$farben.";transition:transform .4s cubic-bezier(.25,.46,.45,.94),box-shadow .4s,background-color .3s,color .3s;\n&:hover{transform:translateY(-2px);box-shadow:0 8px 25px rgba(198,163,107,.35)}";
if (!$pfeil) {
$css .= "\n& span{display:none}";
} else {
$css .= "\n& span{margin-left:6px}";
}
$block = ['id' => $id, 'type' => 'button', 'props' => ['text' => $text, 'href' => $href], 'css' => $css];
// Ein Button zentriert sich nicht über auto-Ränder (er ist inline-flex); dafür gibt es die
// Ausrichtung als Design-Token, dieselbe, die der Editor unter „Ausrichtung“ anbietet.
$rand = $style['desktop']['margin'] ?? [];
if ('auto' === ($rand['left'] ?? '') && 'auto' === ($rand['right'] ?? '')) {
unset($style['desktop']['margin']['left'], $style['desktop']['margin']['right']);
if ([] === $style['desktop']['margin']) {
unset($style['desktop']['margin']);
}
$block['layout'] = ['design' => ['desktop' => ['align' => 'center']]];
}
if ([] !== $style) {
$block['style'] = $style;
}
if ('large' !== $groesse) {
$block['layout'] = [...($block['layout'] ?? []), 'button' => ['desktop' => ['size' => $groesse]]];
}
return $block;
};
$bild = static function (string $id, array $eintrag, string $alt, array $style = [], ?string $href = null, string $css = '', bool $vergroessern = false): array {
$gross = end($eintrag['variants']);
$props = [
'src' => $gross['src'], 'alt' => $alt, 'decorative' => '' === $alt, 'width' => $gross['width'], 'height' => $gross['height'],
'mediaId' => $eintrag['id'],
'sources' => array_map(static fn (array $v): array => ['src' => $v['src'], 'width' => $v['width']], $eintrag['variants']),
];
if (null !== $href) {
$props['href'] = $href;
$props['click'] = 'link';
} elseif ($vergroessern) {
$props['click'] = 'vergroessern';
}
$block = ['id' => $id, 'type' => 'image', 'props' => $props];
if ([] !== $style) {
$block['style'] = $style;
}
if ('' !== $css) {
$block['css'] = $css;
}
return $block;
};
$symbol = static function (string $id, string $name, int $groesse, array $style = []): array {
return ['id' => $id, 'type' => 'icon', 'props' => ['icon' => $name, 'size' => $groesse, 'decorative' => true, 'label' => ''], 'style' => $style];
};
/** Einblendung beim Hereinscrollen, wie Flatsome sie jedem Element anbietet. */
$fx = static function (array $block, string $entrance = 'rise', string $delay = 'none', ?string $hover = null, ?string $shadow = null): array {
$effects = ['entrance' => $entrance, 'delay' => $delay];
if (null !== $hover) {
$effects['hover'] = $hover;
}
if (null !== $shadow) {
$effects['shadow'] = $shadow;
}
$block['layout'] = [...($block['layout'] ?? []), 'effects' => $effects];
return $block;
};
/** Die Kleinzeile über jeder Überschrift: Gold, Versalien, weit gesperrt. */
$kleinzeile = static function (string $id, string $inhalt, string $farbe = '#8a6a2f', string $ausrichtung = 'left', string $abstand = '18px', string $sperrung = '5px'): array {
return ['id' => $id, 'type' => 'text', 'props' => ['text' => $inhalt],
'style' => ['desktop' => ['color' => $farbe, 'fontSize' => '11.5px', 'fontWeight' => '600', 'letterSpacing' => $sperrung, 'textTransform' => 'uppercase', 'lineHeight' => 1.5, 'textAlign' => $ausrichtung, 'margin' => ['bottom' => $abstand]]]];
};
// Wiederkehrende Gestaltungswerte der Vorlage.
$h2Stil = ['desktop' => ['fontSize' => '42px', 'lineHeight' => 1.15, 'fontWeight' => '700', 'letterSpacing' => '0px', 'margin' => ['bottom' => '18px']], 'tablet' => ['fontSize' => '36px'], 'mobile' => ['fontSize' => '32px']];
$h2Mitte = ['desktop' => [...$h2Stil['desktop'], 'textAlign' => 'center'], 'tablet' => $h2Stil['tablet'], 'mobile' => $h2Stil['mobile']];
$h2Hell = ['desktop' => [...$h2Stil['desktop'], 'color' => '#ffffff'], 'tablet' => $h2Stil['tablet'], 'mobile' => $h2Stil['mobile']];
$h2HellMitte = ['desktop' => [...$h2Mitte['desktop'], 'color' => '#ffffff'], 'tablet' => $h2Stil['tablet'], 'mobile' => $h2Stil['mobile']];
$fliess = ['desktop' => ['color' => '#414141', 'fontSize' => '15px', 'lineHeight' => 1.85, 'margin' => ['bottom' => '20px']]];
$introMitte = ['desktop' => ['color' => '#555555', 'fontSize' => '15.5px', 'lineHeight' => 1.8, 'textAlign' => 'center', 'maxWidth' => '720px', 'margin' => ['top' => '0px', 'right' => 'auto', 'bottom' => '0px', 'left' => 'auto']]];
$introHellMitte = ['desktop' => ['color' => '#ffffff99', 'fontSize' => '16px', 'fontWeight' => '400', 'lineHeight' => 1.8, 'textAlign' => 'center', 'maxWidth' => '640px', 'margin' => ['top' => '0px', 'right' => 'auto', 'bottom' => '0px', 'left' => 'auto']]];
$fussTitel = ['desktop' => ['color' => '#c6a36b', 'fontSize' => '11px', 'fontWeight' => '600', 'letterSpacing' => '4px', 'textTransform' => 'uppercase', 'margin' => ['bottom' => '18px']]];
$fussText = ['desktop' => ['color' => '#fffffffc', 'fontSize' => '14.5px', 'fontWeight' => '400', 'lineHeight' => 1.85, 'margin' => ['bottom' => '14px']]];
$bildSchatten = "& img{transition:transform .6s cubic-bezier(.25,.46,.45,.94)}\n&:hover img{transform:scale(1.04)}";
/** Die dunkle Karte der Beitragslisten auf der Startseite: Bild, Verlauf, Titel unten. */
$kartenCss = '& .post-list{display:grid;gap:25px}
& .post-card{position:relative;height:clamp(340px,30vw,420px);border:0;border-radius:4px;background:#2a2a2a;overflow:hidden}
& .post-image{position:absolute;inset:0;margin:0}
& .post-image img{width:100%;height:100%;aspect-ratio:auto;object-fit:cover;opacity:.8;transition:transform .5s ease,opacity .5s ease}
& .post-card:hover .post-image img{opacity:1;transform:scale(1.05)}
& .post-view{display:none}
& .post-body{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:flex-end;padding:25px;background:linear-gradient(180deg,transparent 30%,rgba(42,42,42,.95) 100%);pointer-events:none}
& .post-card h3{font-size:18px;line-height:1.3;color:#fff;font-weight:700;letter-spacing:0}
& .post-card h3 a{color:#fff;pointer-events:auto;text-decoration:none}
& .post-card h3 a:hover{color:#c6a36b}';
// ---------------------------------------------------------------------------------------------
// Website, Gestaltung, Medien, Formular
// ---------------------------------------------------------------------------------------------
$db->insert('website', ['id' => 'default', 'name' => 'Ihr Malerservice Drews', 'default_locale' => 'de', 'theme' => '{}']);
$theme->save(
[
['key' => 'gold', 'name' => 'Gold', 'value' => '#c6a36b'],
['key' => 'gold-dunkel', 'name' => 'Gold dunkel', 'value' => '#ae8c4e'],
// Gold als Schrift auf Weiß erreicht nur 2,4:1; diese Abstufung schafft 5,0:1 und bleibt warm.
['key' => 'gold-text', 'name' => 'Gold, Schrift auf hell', 'value' => '#8a6a2f'],
['key' => 'tinte', 'name' => 'Tinte', 'value' => '#222222'],
['key' => 'dunkel', 'name' => 'Dunkles Band', 'value' => '#232323'],
['key' => 'nacht', 'name' => 'Fußbereich', 'value' => '#111111'],
['key' => 'schwarz', 'name' => 'Schlusszeile', 'value' => '#0a0a0a'],
['key' => 'creme', 'name' => 'Creme', 'value' => '#f7f5f2'],
['key' => 'beige', 'name' => 'Beige', 'value' => '#e3cbaa'],
['key' => 'papier', 'name' => 'Papier', 'value' => '#ffffff'],
['key' => 'gedaempft', 'name' => 'Gedämpft', 'value' => '#555555'],
['key' => 'linie', 'name' => 'Trennlinie', 'value' => '#e6e1d8'],
],
[
// Lato 400/700 trägt den Text, Cormorant Garamond 700 jede Überschrift - beide vom eigenen
// Server. Jeder genannte Schnitt wird vorgeladen; das leichte Lato 300 der Vorlage fehlt
// deshalb bewusst (23 KB weniger vor dem größten Bild), und 900 braucht diese Website nicht.
['key' => 'body', 'name' => 'Fließtext', 'family' => 'Lato', 'source' => 'google', 'weights' => [400, 700], 'fallback' => 'sans-serif'],
['key' => 'heading', 'name' => 'Überschriften', 'family' => 'Cormorant Garamond', 'source' => 'google', 'weights' => [700], 'fallback' => 'serif'],
],
['fontFamily' => 'body', 'headingFontFamily' => 'heading', 'fontSize' => '15px', 'lineHeight' => 1.7, 'color' => '@tinte', 'backgroundColor' => '@papier', 'linkColor' => '@gold-text', 'containerWidth' => '1170px', 'headingScale' => 1.25, 'linkUnderline' => false],
['shape' => 'square', 'appearance' => 'solid', 'size' => 'large', 'fontFamily' => 'inherit', 'fontSize' => 13, 'fontWeight' => 700, 'letterSpacing' => 2, 'textTransform' => 'uppercase', 'backgroundColor' => '@gold', 'color' => '@tinte', 'hoverBackgroundColor' => '@gold-dunkel', 'hoverColor' => '@tinte'],
);
$manifest = json_decode((string) file_get_contents(rtrim($assets, '/\\').'/manifest.json'), true, 512, JSON_THROW_ON_ERROR);
$medien = [];
$hochladen = static function (string $datei, string $alt, string $titel = '') use ($assets, $media, &$medien): array {
if (isset($medien[$datei])) {
return $medien[$datei];
}
$pfad = rtrim($assets, '/\\').'/'.$datei;
if (!is_file($pfad)) {
fwrite(STDERR, "Bild fehlt: $pfad\n");
exit(1);
}
$eintrag = $media->upload(new UploadedFile($pfad, $datei, null, null, true));
$media->update($eintrag['id'], ['title' => '' !== $titel ? $titel : pathinfo($datei, PATHINFO_FILENAME), 'alt' => $alt, 'archived' => false, 'version' => $eintrag['version']]);
$medien[$datei] = $media->find($eintrag['id']);
return $medien[$datei];
};
$seitenbilder = [];
foreach ([
'logo' => 'Ihr Malerservice Drews',
'favicon' => 'Ihr Malerservice Drews – Markenzeichen',
'hero-1' => 'Malermeister Axel Drews prüft eine Wandfläche',
'hero-2' => 'Malermeister Axel Drews bei der Arbeit',
'hero-3' => 'Malermeister Axel Drews beim Planen mit Farbmuster',
'ueber-1' => 'Malermeister Axel Drews prüft eine frisch gestrichene Wand',
'ueber-2' => 'Axel Drews mit Farbmustern in der Werkstatt',
'ueber-3' => 'Malerarbeiten des Teams von Malerservice Drews',
'ueber-4' => 'Das Team von Malerservice Drews bei der Arbeit',
'kunst-bg' => 'Dekorative Wandgestaltung in Steinoptik',
'kunst-1' => 'Wandgestaltung in Steinoptik in einem Rohbau',
'kunst-2' => 'Grün gestrichener Raum mit Tageslicht',
'kunst-3' => 'Farbige Wandgestaltung eines Wohnraums',
'lg-1' => 'Little Greene – Tapete Upper Brook Street',
'lg-2' => 'Little Greene – Farbton Mischief',
'lg-3' => 'Little Greene – Farbton Puck',
'lg-4' => 'Little Greene – Farbkombinationen',
'marke-littlegreene' => 'Little Greene',
'marke-brillux' => 'Brillux',
'marke-gori' => 'Gori',
'marke-keim' => 'Keim',
'marke-sikkens' => 'Sikkens',
'marke-henkel' => 'Henkel',
'partner-eisen' => 'Eisen-Raumausstattung',
'partner-lichtkraus' => 'Licht Kraus Sasbach',
'partner-kant' => 'Kant-IT Solutions',
'kontakt-foto' => 'Axel Drews telefoniert vor dem Firmenwagen',
'projekte-bg' => 'Restaurierte Wandmalerei im Friedrichsbad Baden-Baden',
'aktuelles-cta-bg' => 'Rücken eines Mitarbeiters mit dem Schriftzug Ihr Malerservice Drews',
'kunst-portrait' => 'Treppenhaus mit Unterwasser-Wandmalerei',
] as $schluessel => $alt) {
$seitenbilder[$schluessel] = $hochladen($manifest['pages'][$schluessel], $alt, $schluessel);
echo "Bild übernommen: {$manifest['pages'][$schluessel]}\n";
}
$galerie = [];
foreach ($manifest['galerie'] as $i => $datei) {
$galerie[] = $hochladen($datei, 'Kunstmalerei von Malerservice Drews – Werk '.($i + 1), 'kunstmalerei-'.($i + 1));
}
echo 'Galeriebilder übernommen: '.count($galerie)."\n";
$forms->save('kontakt', 'Kontaktanfrage', [
['name' => 'name', 'type' => 'text', 'label' => 'Ihr Name', 'required' => true],
['name' => 'email', 'type' => 'email', 'label' => 'Ihre E-Mail-Adresse', 'required' => true],
['name' => 'betreff', 'type' => 'text', 'label' => 'Betreff', 'required' => false],
['name' => 'nachricht', 'type' => 'textarea', 'label' => 'Ihre Nachricht', 'required' => false],
['name' => 'datenschutz', 'type' => 'consent', 'label' => 'Ich stimme den Datenschutzrichtlinien zu; meine Daten werden zur Kontaktaufnahme gespeichert.'],
], ['recipient' => $mail, 'subject' => 'Neue Anfrage über maler-drews.com', 'success' => 'Vielen Dank für Ihre Nachricht. Wir melden uns innerhalb von 24 Stunden bei Ihnen.', 'replyToField' => 'email', 'buttonLabel' => 'Senden', 'fieldBorderColor' => '#dddddd', 'fieldBackgroundColor' => '#ffffff', 'buttonColor' => '@gold', 'buttonInk' => '@tinte'], 0);
echo "Formular angelegt: kontakt\n";
// ---------------------------------------------------------------------------------------------
// Kopfbereich: weiß, 90 px hoch, Marke links, Menü in Versalien rechts
// ---------------------------------------------------------------------------------------------
$kopf = [
'schemaVersion' => $SCHEMA, 'title' => 'Kopfbereich', 'description' => 'Erscheint auf jeder Seite über dem Inhalt.',
'blocks' => [
$section('kopf', [
$row('kopf-zeile', [
$column('kopf-marke', [
$bild('kopf-logo', $seitenbilder['logo'], 'Ihr Malerservice Drews – zur Startseite', ['desktop' => ['maxWidth' => '200px', 'margin' => $seiten('0px')], 'mobile' => ['maxWidth' => '150px']], '/'),
], ['desktop' => ['flexShrink' => 0]]),
$column('kopf-navigation', [
['id' => 'kopf-menue', 'type' => 'menu', 'props' => ['slot' => 'header', 'layout' => 'horizontal', 'collapse' => 'tablet', 'burgerLabel' => 'icon'],
'style' => ['desktop' => ['fontSize' => '13px', 'fontWeight' => '700', 'letterSpacing' => '0.8px', 'textTransform' => 'uppercase', 'color' => '@tinte', 'justifyContent' => 'flex-end', 'burgerColor' => '@tinte', 'burgerBorderColor' => '#ffffff00']],
'css' => "& .menu-list{gap:4px 40px;justify-content:flex-end}\n& .menu-list a{padding:8px 0;transition:color .25s}\n& .menu-list a:hover{color:#8a6a2f;text-decoration:none}\n& .menu-list [aria-current=page]{color:#8a6a2f}"],
], ['desktop' => ['display' => 'flex', 'justifyContent' => 'flex-end', 'alignItems' => 'center']]),
], [], ['desktop' => ['display' => 'flex', 'alignItems' => 'center', 'justifyContent' => 'space-between', 'gap' => '30px', 'minHeight' => '90px', 'margin' => ['top' => '0px']], 'mobile' => ['minHeight' => '70px']]),
], ['desktop' => ['backgroundColor' => '@papier', 'padding' => ['top' => '0px', 'bottom' => '0px']]]),
],
];
// ---------------------------------------------------------------------------------------------
// Fußbereich: vier Spalten auf #111, Schlusszeile auf #0a0a0a
// ---------------------------------------------------------------------------------------------
$zeitenZeile = static function (string $id, string $tag, string $zeit, bool $erste = false, bool $kursiv = false) use ($row, $column, $text, $nurOben): array {
return $row($id, [
$column($id.'-tag', [$text($id.'-tag-text', $tag, ['desktop' => ['fontSize' => '14px', 'color' => '#fffffffc', 'margin' => ['bottom' => '0px']]])]),
$column($id.'-zeit', [$text($id.'-zeit-text', $zeit, ['desktop' => ['fontSize' => '14px', 'fontWeight' => $kursiv ? '300' : '400', 'fontStyle' => $kursiv ? 'italic' : 'normal', 'color' => '#fffffffc', 'textAlign' => 'right', 'margin' => ['bottom' => '0px']]])]),
], [], ['desktop' => ['display' => 'flex', 'justifyContent' => 'space-between', 'gap' => '20px', 'margin' => ['top' => '0px'], 'padding' => ['top' => $erste ? '0px' : '9px', 'bottom' => '9px']]
+ ($erste ? [] : ['borderWidth' => $nurOben('1px'), 'borderStyle' => 'solid', 'borderColor' => '#ffffff0f'])]);
};
$fuss = [
'schemaVersion' => $SCHEMA, 'title' => 'Fußbereich', 'description' => 'Erscheint auf jeder Seite unter dem Inhalt.',
'blocks' => [
$section('fuss', [
$row('fuss-zeile', [
$column('fuss-ueber', [
$text('fuss-ueber-text', 'Seit über 60 Jahren steht der Name Drews für erstklassiges Malerhandwerk im Raum Gernsbach und Mittelbaden – mit Leidenschaft, Präzision und einem Auge für das Besondere.', ['desktop' => ['color' => '#fffffffc', 'fontSize' => '14px', 'lineHeight' => 1.85, 'margin' => ['bottom' => '20px']]]),
['id' => 'fuss-sozial', 'type' => 'social', 'props' => ['size' => 16, 'shape' => 'circle', 'layout' => 'horizontal', 'labels' => false, 'networks' => [], 'newTab' => true],
'style' => ['desktop' => ['color' => '#ffffff', 'hover' => ['color' => '@gold']]],
'css' => "& a{border:1px solid rgba(255,255,255,.35);background:transparent;transition:border-color .3s,color .3s}\n& a:hover{border-color:#c6a36b}"],
]),
$column('fuss-navigation', [
$text('fuss-navigation-titel', 'Navigation', $fussTitel),
['id' => 'fuss-menue', 'type' => 'menu', 'props' => ['slot' => 'footer', 'layout' => 'vertical'],
'style' => ['desktop' => ['fontSize' => '14.5px', 'fontWeight' => '400', 'color' => '#fffffffc']],
'css' => "& .menu-list{gap:12px}\n& .menu-list a{padding:0;transition:color .3s}\n& .menu-list a:hover{color:#c6a36b;text-decoration:none}\n& .menu-list [aria-current=page]{font-weight:300}"],
]),
$column('fuss-kontakt', [
$text('fuss-kontakt-titel', 'Kontakt', $fussTitel),
$text('fuss-kontakt-adresse', 'Am Bachgarten 1<br>76593 Gernsbach', $fussText),
$text('fuss-kontakt-daten', '<strong>Tel</strong>&nbsp; <a href="'.$telHref.'">'.$telefon.'</a><br><strong>Fax</strong>&nbsp; '.$fax.'<br><strong>Mail</strong>&nbsp; <a href="mailto:'.$mail.'">'.$mail.'</a>', ['desktop' => [...$fussText['desktop'], 'margin' => ['bottom' => '0px']]], "& strong{font-weight:400;margin-right:6px}\n& a{color:#fff;text-decoration:none}\n& a:hover{color:#c6a36b}"),
]),
$column('fuss-zeiten', [
$text('fuss-zeiten-titel', 'Öffnungszeiten', $fussTitel),
$zeitenZeile('fuss-zeit-1', 'Mo – Do', '07:00 – 16:30', true),
$zeitenZeile('fuss-zeit-2', 'Freitag', '07:00 – 13:00'),
$zeitenZeile('fuss-zeit-3', 'Sa & So', 'nach Vereinbarung', false, true),
$button('fuss-anfrage', 'Projekt anfragen', '/kontakt', 'gold-rahmen', false, ['desktop' => ['margin' => ['top' => '14px']]], 'small'),
]),
], ['desktop' => ['columns' => 'four', 'gap' => 'large'], 'tablet' => ['columns' => 'two'], 'mobile' => ['columns' => 'one']], ['desktop' => ['margin' => ['top' => '0px']]]),
], ['desktop' => ['backgroundColor' => '@nacht', 'color' => '#ffffff', 'padding' => ['top' => '60px', 'bottom' => '50px']], 'mobile' => ['padding' => ['top' => '44px', 'bottom' => '36px']]]),
$section('fuss-schluss', [
$row('fuss-schluss-zeile', [
$column('fuss-schluss-links', [
$text('fuss-copyright', '© 2026 Ihr Malerservice Drews · Webdesign by <a href="https://kant-it.de">Kant-IT Solutions</a>', ['desktop' => ['color' => '#ffffff', 'fontSize' => '12.5px', 'fontWeight' => '400', 'letterSpacing' => '0.5px', 'margin' => ['bottom' => '0px']]], "& a{color:#c6a36b;text-decoration:underline;text-underline-offset:3px}\n& a:hover{text-decoration-thickness:2px}"),
]),
$column('fuss-schluss-rechts', [
['id' => 'fuss-rechtliches', 'type' => 'legal', 'props' => ['label' => 'Rechtliches'],
'style' => ['desktop' => ['color' => '#ffffff', 'fontSize' => '12.5px', 'fontWeight' => '400', 'justifyContent' => 'flex-end', 'gap' => '20px'], 'mobile' => ['justifyContent' => 'flex-start']],
'css' => "& span{display:none}\n& a{transition:color .3s}\n& a:hover{color:#c6a36b}"],
]),
], ['desktop' => ['columns' => 'two', 'gap' => 'medium'], 'mobile' => ['columns' => 'one']], ['desktop' => ['alignItems' => 'center', 'margin' => ['top' => '0px']], 'mobile' => ['gap' => '10px']]),
], ['desktop' => ['backgroundColor' => '@schwarz', 'color' => '#ffffff', 'padding' => ['top' => '22px', 'bottom' => '22px']]]),
],
];
$partials->create('header', 'default', 'Kopfbereich', $kopf);
$partials->create('footer', 'default', 'Fußbereich', $fuss);
echo "Kopf- und Fußbereich angelegt\n";
// ---------------------------------------------------------------------------------------------
// Wiederkehrende Abschnitte
// ---------------------------------------------------------------------------------------------
/** Der dunkle Seitenkopf der Unterseiten: Foto mit Überlagerung, Kleinzeile, Titel, Vorspann. */
$seitenkopf = static function (string $praefix, array $foto, string $label, string $h1, string $intro, string $minHeight = '50vh', string $overlay = '#050505', float $deckung = 0.68, array $zusatz = [], string $position = 'center') use ($section, $column, $kleinzeile, $heading, $text, $fx, $introHellMitte): array {
$kinder = [
$fx($kleinzeile($praefix.'-label', $label, '#c6a36b', 'center', '18px', '6px'), 'fade'),
$fx($heading($praefix.'-h1', $h1, 1, ['desktop' => ['fontSize' => '58px', 'lineHeight' => 1.08, 'letterSpacing' => '-1px', 'fontWeight' => '700', 'color' => '#ffffff', 'textAlign' => 'center', 'margin' => ['bottom' => '20px']], 'tablet' => ['fontSize' => '46px'], 'mobile' => ['fontSize' => '38px']]), 'rise', 'short'),
];
if ('' !== $intro) {
$kinder[] = $fx($text($praefix.'-intro', $intro, $introHellMitte), 'rise', 'medium');
}
foreach ($zusatz as $block) {
$kinder[] = $fx($block, 'rise', 'long');
}
return $section($praefix.'-kopf', [$column($praefix.'-kopf-inhalt', $kinder, ['desktop' => ['maxWidth' => '900px', 'margin' => ['left' => 'auto', 'right' => 'auto']]])], [
'desktop' => ['backgroundImage' => $foto['id'], 'backgroundSize' => 'cover', 'backgroundPosition' => $position, 'overlayColor' => $overlay, 'overlayOpacity' => $deckung,
'color' => '#ffffff', 'minHeight' => $minHeight, 'display' => 'flex', 'alignItems' => 'center', 'padding' => ['top' => '80px', 'bottom' => '80px']],
'mobile' => ['padding' => ['top' => '60px', 'bottom' => '60px']],
]);
};
/** Ein zentrierter Abschnittskopf: Kleinzeile, Überschrift, Vorspann. */
$abschnittskopf = static function (string $praefix, string $label, string $titel, string $intro, bool $hell = false) use ($kleinzeile, $heading, $text, $fx, $h2Mitte, $h2HellMitte, $introMitte, $introHellMitte): array {
return [
$fx($kleinzeile($praefix.'-label', $label, $hell ? '#c6a36b' : '#8a6a2f', 'center', '18px', '6px'), 'fade'),
$fx($heading($praefix.'-titel', $titel, 2, $hell ? $h2HellMitte : $h2Mitte), 'rise'),
$fx($text($praefix.'-intro', $intro, $hell ? $introHellMitte : $introMitte), 'rise', 'short'),
];
};
/** Der dunkle Handlungsaufruf am Ende von Startseite und Aktuelles. */
$aufruf = static function (string $praefix, string $label, string $titel, string $intro, string $knopf, ?array $foto = null) use ($section, $column, $abschnittskopf, $text, $button, $fx, $telHref, $telefon, $mail): array {
$style = ['desktop' => ['backgroundColor' => '@dunkel', 'color' => '#ffffff', 'padding' => ['top' => '130px', 'bottom' => '130px']], 'mobile' => ['padding' => ['top' => '80px', 'bottom' => '80px']]];
if (null !== $foto) {
$style['desktop'] = [...$style['desktop'], 'backgroundImage' => $foto['id'], 'backgroundSize' => 'cover', 'backgroundPosition' => 'center', 'overlayColor' => '#050505', 'overlayOpacity' => 0.6, 'padding' => ['top' => '110px', 'bottom' => '110px']];
}
return $section($praefix, [
$column($praefix.'-inhalt', [
...$abschnittskopf($praefix, $label, $titel, $intro, true),
$fx($text($praefix.'-kontaktzeile', 'Tel. <a href="'.$telHref.'">'.$telefon.'</a> · <a href="mailto:'.$mail.'">'.$mail.'</a>', ['desktop' => ['color' => '#ffffff99', 'fontSize' => '14px', 'letterSpacing' => '2px', 'textAlign' => 'center', 'margin' => ['top' => '24px', 'bottom' => '35px']]], "& a{color:inherit;text-decoration:none}\n& a:hover{color:#c6a36b}"), 'fade', 'medium'),
$fx($button($praefix.'-knopf', $knopf, '/kontakt', 'gold', true, ['desktop' => ['margin' => ['top' => '0px', 'left' => 'auto', 'right' => 'auto']]]), 'rise', 'long'),
], ['desktop' => ['display' => 'flex', 'flexDirection' => 'column', 'alignItems' => 'center', 'maxWidth' => '860px', 'margin' => ['left' => 'auto', 'right' => 'auto']]]),
], $style);
};
// ---------------------------------------------------------------------------------------------
// Startseite
// ---------------------------------------------------------------------------------------------
/** Eine Folie des Startbilds: Foto, dunkle Überlagerung, zentrierter Text, Welle unten. */
$folie = static function (int $n, array $foto, bool $erste) use ($section, $column, $row, $text, $heading, $button, $flaeche, $fx): array {
$titelStil = ['desktop' => ['fontFamily' => 'heading', 'fontSize' => '72px', 'fontWeight' => '700', 'lineHeight' => 1.08, 'letterSpacing' => '-1.5px', 'color' => '#ffffff', 'textAlign' => 'center', 'margin' => ['bottom' => '0px'], 'textShadowY' => '2px', 'textShadowBlur' => '40px', 'textShadowColor' => '#0000004d'], 'tablet' => ['fontSize' => '54px'], 'mobile' => ['fontSize' => '40px', 'letterSpacing' => '-0.5px']];
$titelText = 'Oberflächen,<br>die Eindruck <em>hinterlassen.</em>';
$emCss = '& em{font-style:normal;color:#c6a36b}';
$titel = $erste
? $heading('folie-'.$n.'-titel', $titelText, 1, $titelStil, $emCss)
: $text('folie-'.$n.'-titel', $titelText, $titelStil, $emCss);
$kinder = [
$text('folie-'.$n.'-label', 'Malermeister Axel Drews · Gernsbach', ['desktop' => ['color' => '#ffffffcc', 'fontSize' => '13px', 'fontWeight' => '500', 'letterSpacing' => '6px', 'textTransform' => 'uppercase', 'textAlign' => 'center', 'margin' => ['bottom' => '22px']], 'mobile' => ['fontSize' => '12px', 'letterSpacing' => '4px']]),
$titel,
$text('folie-'.$n.'-intro', 'Saubere Ausführung, präzise Details und hochwertige Materialien –<br>Malerhandwerk für Menschen mit Anspruch.', ['desktop' => ['color' => '#ffffff', 'fontSize' => '15px', 'fontWeight' => '400', 'lineHeight' => 1.8, 'textAlign' => 'center', 'maxWidth' => '680px', 'margin' => ['top' => '18px', 'right' => 'auto', 'bottom' => '26px', 'left' => 'auto']]]),
$row('folie-'.$n.'-aktionen', [
$column('folie-'.$n.'-aktion-1', [$button('folie-'.$n.'-anfrage', 'Projekt anfragen', '/kontakt', 'dunkel', false, ['desktop' => ['margin' => ['top' => '0px']]])]),
$column('folie-'.$n.'-aktion-2', [$button('folie-'.$n.'-referenzen', 'Referenzen ansehen', '/unsere-projekte', 'weiss-rahmen', false, ['desktop' => ['margin' => ['top' => '0px']]])]),
], [], ['desktop' => ['display' => 'flex', 'flexWrap' => 'wrap', 'justifyContent' => 'center', 'gap' => '15px', 'margin' => ['top' => '0px']]]),
];
if ($erste) {
$kinder = [
$fx($kinder[0], 'fade'), $fx($kinder[1], 'rise', 'short'), $fx($kinder[2], 'rise', 'medium'), $fx($kinder[3], 'rise', 'long'),
];
}
return $section('folie-'.$n, [
$column('folie-'.$n.'-text', $kinder, ['desktop' => ['maxWidth' => '60%', 'margin' => ['left' => 'auto', 'right' => 'auto'], 'position' => 'relative', 'zIndex' => 2], 'tablet' => ['maxWidth' => '90%'], 'mobile' => ['maxWidth' => '100%']]),
// Der Pfeil nach unten, wie in der Vorlage am unteren Rand der Folie.
$text('folie-'.$n.'-pfeil', '<a href="#ueber-uns" aria-label="Zum Abschnitt Über uns">⌄</a>', ['desktop' => ['position' => 'absolute', 'left' => '0px', 'right' => '0px', 'bottom' => '58px', 'textAlign' => 'center', 'fontSize' => '29px', 'lineHeight' => 1, 'color' => '#ffffff66', 'zIndex' => 2, 'margin' => ['bottom' => '0px']]], "& a{color:inherit;text-decoration:none;display:inline-block}\n& a:hover{color:#fff}"),
// Die Welle am unteren Rand: zwei runde Flächen in Gold, die hintere halb durchsichtig.
$flaeche('folie-'.$n.'-welle-hinten', ['desktop' => ['position' => 'absolute', 'left' => '-25%', 'right' => '-10%', 'bottom' => '-80px', 'height' => '190px', 'backgroundColor' => '#b4966e', 'opacity' => 0.35, 'zIndex' => 1, 'borderRadius' => ['topLeft' => '55%', 'topRight' => '45%', 'bottomRight' => '0px', 'bottomLeft' => '0px']]], 'border-top-left-radius:55% 100%;border-top-right-radius:45% 100%;'),
$flaeche('folie-'.$n.'-welle-vorn', ['desktop' => ['position' => 'absolute', 'left' => '-10%', 'right' => '-30%', 'bottom' => '-95px', 'height' => '175px', 'backgroundColor' => '#b4966e', 'zIndex' => 1, 'borderRadius' => ['topLeft' => '45%', 'topRight' => '55%', 'bottomRight' => '0px', 'bottomLeft' => '0px']]], 'border-top-left-radius:45% 100%;border-top-right-radius:55% 100%;'),
], [
'desktop' => ['backgroundImage' => $foto['id'], 'backgroundSize' => 'cover', 'backgroundPosition' => 'center', 'overlayColor' => '#050505', 'overlayOpacity' => 0.62,
'color' => '#ffffff', 'minHeight' => '88dvh', 'display' => 'flex', 'alignItems' => 'center', 'position' => 'relative', 'overflow' => 'hidden', 'padding' => ['top' => '90px', 'bottom' => '150px']],
'mobile' => ['minHeight' => '92dvh', 'padding' => ['top' => '70px', 'bottom' => '130px']],
]);
};
$leistungen = [
['innenausbau', '■', 'Innenausbau & Raumgestaltung', 'Wände, Decken, Böden – wir gestalten Räume mit Gespür für Farbe, Material und Proportion.'],
['fassade', '◆', 'Fassadenarbeiten', 'Außenanstriche, Putzarbeiten und Fassadengestaltung – langlebig und witterungsbeständig.'],
['restaurierung', '✦', 'Restaurierung & Denkmalpflege', 'Historische Substanz bewahren und behutsam aufarbeiten – mit handwerklicher Expertise.'],
];
/** Ein Bild mit Rundung, Schatten und Zoom beim Zeigen - das Bildraster der Vorlage. */
$rasterbild = static function (string $id, array $foto, string $alt, string $hoehe = '260px', string $mobil = '220px', string $breite = '300px') use ($bild, $ecken, $seiten, $fx, $bildSchatten): array {
// Die feste Breite ist die Spaltenbreite am Schreibtisch; aus ihr entsteht das sizes-Attribut,
// sonst lud eine 270 px breite Kachel die 2400er Datei.
return $fx($bild($id, $foto, $alt, ['desktop' => ['maxWidth' => $breite, 'imageHeight' => $hoehe, 'objectFit' => 'cover', 'objectPosition' => 'center', 'imageRadius' => $ecken('4px'), 'borderRadius' => $ecken('4px'), 'overflow' => 'hidden', 'margin' => $seiten('0px')], 'mobile' => ['imageHeight' => $mobil]], null, $bildSchatten), 'fade', 'short', null, 'strong');
};
$startseite = [
'schemaVersion' => $SCHEMA,
'title' => 'Ihr Malerservice Drews',
'description' => 'Ihr Malermeister aus Gernsbach und Umgebung. Innen- und Außengestaltung, Fassaden, Anstriche, Restaurierung und Kunstmalerei – Malerservice Drews, seit über 60 Jahren.',
'blocks' => [
// 1 – Das Startbild: drei Folien, dieselbe Botschaft auf drei Fotos.
$section('hero', [
['id' => 'hero-slider', 'type' => 'slider', 'props' => ['desktopVisible' => 1, 'tabletVisible' => 1, 'mobileVisible' => 1, 'snap' => true, 'dots' => true, 'autoplay' => 7],
'children' => [
$folie(1, $seitenbilder['hero-1'], true),
$folie(2, $seitenbilder['hero-2'], false),
$folie(3, $seitenbilder['hero-3'], false),
],
'css' => "gap:0;padding-bottom:0;--slider-dot:rgba(255,255,255,.6);--slider-dot-active:#c6a36b;--slider-bg:rgba(255,255,255,.9);--slider-ink:#222;\n& .slider-slide>.block-section{margin:0}"],
], [
// Dasselbe Foto wie die erste Folie: nur das Hintergrundbild des ersten Abschnitts wird
// vorgeladen, und die Folie liegt eine Ebene tiefer. So ist das größte Bild der Seite
// im HTML angekündigt, statt erst aus dem Stylesheet entdeckt zu werden.
'desktop' => ['backgroundImage' => $seitenbilder['hero-1']['id'], 'backgroundSize' => 'cover', 'backgroundPosition' => 'center', 'padding' => ['top' => '0px', 'bottom' => '0px']],
], 'start', ['width' => 'full']),
// 2 – Über uns: Text links, vier Fotos rechts.
$section('geschichte', [
$row('ueber-uns-zeile', [
$column('ueber-uns-text', [
$fx($kleinzeile('ueber-uns-label', 'Über Uns · Unsere Geschichte'), 'fade'),
$fx($heading('ueber-uns-titel', 'Seit über einem<br>halben Jahrhundert…', 2, $h2Stil), 'rise'),
$fx($text('ueber-uns-1', 'Die Firmengeschichte begann vor 60 Jahren mit einem kleinen Lager von gerade mal 1,5 Quadratmetern am 2. Juni in Calw. Im Herbst 1965 bezog Hans-Jürgen Drews dann seine erste Werkstatt in Loffenau.', $fliess), 'rise', 'short'),
$fx($text('ueber-uns-zitat', '<strong>Heute, ein halbes Jahrhundert später, ist Axel Drews Chef von 16 Mitarbeitern.</strong>', ['desktop' => ['color' => '#222222', 'fontSize' => '15.5px', 'fontStyle' => 'italic', 'lineHeight' => 1.8, 'borderWidth' => $nurLinks('3px'), 'borderStyle' => 'solid', 'borderColor' => '@gold', 'padding' => ['left' => '20px', 'top' => '4px', 'bottom' => '4px'], 'margin' => ['top' => '4px', 'bottom' => '24px']]]), 'rise', 'short'),
$fx($text('ueber-uns-2', 'Im Jahr 2000 hat der Malermeister die Firma von seinem Vater übernommen. Aus dem kleinen Anfang im Milchhäusel in Loffenau ist schnell ein erfolgreiches Malergeschäft geworden. Bereits zwei Jahre nach Firmengründung zog Hans-Jürgen Drews 1967 in die alte Post von Loffenau in der Oberen Dorfstraße um, ehe der Bau eines Wohn- und Geschäftshauses im Kändelweg 27 folgte.', $fliess), 'rise', 'medium'),
$fx($text('ueber-uns-3', '1977 eröffnete Drews eine zweite Werkstatt in der Gernsbacher Amtsstraße, 1979 übernahm er das Malergeschäft Oskar Fieg. Ein wichtiges Jahr in der Firmengeschichte ist 1983: Damals kaufte Hans-Jürgen Drews eine Halle vom Möbelhaus Vogel und baute sie um. Das Anwesen am Bachgarten 1 in Gernsbach mit Werkstatt, Lager und Garage sowie Aufenthaltsräume ist nach wie vor Firmensitz. 2001 wurde das Betriebsgebäude abgerissen und neu aufgebaut.', $fliess), 'rise', 'medium'),
$fx($text('ueber-uns-4', 'In seinen 35 Jahren der Selbstständigkeit hat Diplom-Maler Hans-Jürgen Drews zwölf Lehrlinge ausgebildet, die teilweise heute noch im Betrieb arbeiten.', ['desktop' => [...$fliess['desktop'], 'margin' => ['bottom' => '0px']]]), 'rise', 'long'),
], ['desktop' => ['padding' => ['right' => '55px']], 'tablet' => ['padding' => ['right' => '0px']], 'mobile' => ['padding' => ['right' => '0px']]]),
$column('ueber-uns-bilder', [
$row('ueber-uns-raster', [
$rasterbild('ueber-uns-bild-1', $seitenbilder['ueber-1'], 'Malermeister Axel Drews prüft eine frisch gestrichene Wand'),
$rasterbild('ueber-uns-bild-2', $seitenbilder['ueber-2'], 'Axel Drews mit Farbmustern in der Werkstatt'),
$rasterbild('ueber-uns-bild-3', $seitenbilder['ueber-3'], 'Malerarbeiten des Teams von Malerservice Drews'),
$rasterbild('ueber-uns-bild-4', $seitenbilder['ueber-4'], 'Das Team von Malerservice Drews bei der Arbeit'),
], ['desktop' => ['columns' => 'two'], 'mobile' => ['columns' => 'two']], ['desktop' => ['gap' => '16px', 'margin' => ['top' => '0px']], 'mobile' => ['gap' => '10px']]),
], ['desktop' => ['alignSelf' => 'center']]),
], ['desktop' => ['columns' => 'two', 'gap' => 'medium'], 'mobile' => ['columns' => 'one']], ['desktop' => ['alignItems' => 'center', 'margin' => ['top' => '0px']], 'mobile' => ['gap' => '40px']]),
], ['desktop' => ['padding' => ['top' => '120px', 'bottom' => '120px']], 'mobile' => ['padding' => ['top' => '70px', 'bottom' => '70px']]], 'ueber-uns'),
// 3 – Leistungen: drei weiße Karten auf Creme.
$section('leistungen-abschnitt', [
...$abschnittskopf('leistungen', 'Was wir tun', 'Unsere Leistungen', 'Vom kleinen Detail bis zur kompletten Fassade – alles aus einer Hand, mit der Sorgfalt, die nur echtes Handwerk bieten kann.'),
$row('leistungen-raster', array_map(
static fn (array $l, int $i): array => $fx($column('leistung-'.$l[0], [
$text('leistung-'.$l[0].'-symbol', $l[1], ['desktop' => ['color' => '#a07f45', 'fontSize' => '24px', 'lineHeight' => 1, 'textAlign' => 'center', 'margin' => ['bottom' => '22px']]]),
$heading('leistung-'.$l[0].'-titel', $l[2], 3, ['desktop' => ['fontSize' => '22px', 'fontWeight' => '700', 'lineHeight' => 1.3, 'textAlign' => 'center', 'margin' => ['bottom' => '12px']]]),
$text('leistung-'.$l[0].'-text', $l[3], ['desktop' => ['color' => '#666666', 'fontSize' => '14.5px', 'lineHeight' => 1.75, 'textAlign' => 'center', 'margin' => ['bottom' => '0px']]]),
], ['desktop' => ['backgroundColor' => '@papier', 'padding' => ['top' => '40px', 'right' => '30px', 'bottom' => '40px', 'left' => '30px'], 'borderRadius' => $ecken('4px'), 'borderWidth' => $seiten('1px'), 'borderStyle' => 'solid', 'borderColor' => '#0000000a', 'shadowY' => '2px', 'shadowBlur' => '15px', 'shadowColor' => '#0000000a', 'transition' => 400, 'hover' => ['translateY' => '-6px', 'shadowColor' => '#00000014', 'borderColor' => '#c6a36b33']]]), 'rise', ['none', 'short', 'medium'][$i]),
$leistungen, array_keys($leistungen),
), ['desktop' => ['columns' => 'three', 'gap' => 'medium'], 'tablet' => ['columns' => 'three'], 'mobile' => ['columns' => 'one']], ['desktop' => ['margin' => ['top' => '50px']], 'mobile' => ['margin' => ['top' => '36px']]]),
], ['desktop' => ['backgroundColor' => '@creme', 'padding' => ['top' => '110px', 'bottom' => '110px']], 'mobile' => ['padding' => ['top' => '70px', 'bottom' => '70px']]], 'leistungen'),
// 4 – Aktuelles: vier dunkle Karten auf dunklem Band.
$section('aktuelles-abschnitt', [
...$abschnittskopf('aktuelles', 'News & Projekte', 'Aktuelles aus dem Betrieb', 'Bei Malerservice Drews tut sich immer was! Hier finden Sie Einblicke in aktuelle Projekte, kreative Farbkonzepte und besondere Herausforderungen.', true),
$fx(['id' => 'aktuelles-liste', 'type' => 'postlist', 'props' => ['count' => 4, 'category' => 'aktuelles', 'layout' => 'karten', 'paginate' => false, 'showMeta' => false, 'showExcerpt' => false, 'showTerms' => false],
'style' => ['desktop' => ['maxWidth' => '1400px', 'margin' => ['top' => '40px', 'left' => 'auto', 'right' => 'auto']], 'mobile' => ['margin' => ['top' => '30px']]],
'css' => $kartenCss."\n& .post-list{grid-template-columns:repeat(auto-fit,minmax(min(100%,270px),1fr))}"], 'rise', 'short'),
$fx($button('aktuelles-alle', 'Alle Mitteilungen', '/aktuelles', 'gold', false, ['desktop' => ['margin' => ['top' => '40px', 'left' => 'auto', 'right' => 'auto']]], 'normal'), 'fade', 'medium'),
], ['desktop' => ['backgroundColor' => '@dunkel', 'color' => '#ffffff', 'padding' => ['top' => '110px', 'bottom' => '110px'], 'display' => 'flex', 'flexDirection' => 'column'], 'mobile' => ['padding' => ['top' => '70px', 'bottom' => '70px']]], 'aktuelles', ['width' => 'wide']),
// 5 – Referenzen: drei Projektkarten.
$section('referenzen-abschnitt', [
...$abschnittskopf('referenzen', 'Ausgewählte Arbeiten', 'Referenzen, die für sich sprechen', 'Ein Eindruck sagt mehr als hundert Worte. Hier sehen Sie einige unserer Projekte aus Innenausbau, Fassadenarbeiten und Restaurierung.'),
$fx(['id' => 'referenzen-liste', 'type' => 'postlist', 'props' => ['count' => 3, 'category' => 'projekte', 'layout' => 'karten', 'paginate' => false, 'showMeta' => false, 'showExcerpt' => false, 'showTerms' => false],
'style' => ['desktop' => ['maxWidth' => '900px', 'margin' => ['top' => '40px', 'left' => 'auto', 'right' => 'auto']], 'mobile' => ['margin' => ['top' => '30px']]],
'css' => $kartenCss."\n& .post-list{grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr))}"], 'rise', 'short'),
$fx($button('referenzen-alle', 'Alle Projekte ansehen', '/unsere-projekte', 'dunkel-rahmen', true, ['desktop' => ['margin' => ['top' => '40px', 'left' => 'auto', 'right' => 'auto']]], 'normal'), 'fade', 'medium'),
], ['desktop' => ['backgroundColor' => '@papier', 'padding' => ['top' => '120px', 'bottom' => '120px'], 'display' => 'flex', 'flexDirection' => 'column'], 'mobile' => ['padding' => ['top' => '70px', 'bottom' => '70px']]], 'referenzen'),
// 6 – Kunstmalerei: Foto als Hintergrund, Text links, drei Bilder rechts.
$section('kunstmalerei', [
$row('kunstmalerei-zeile', [
$column('kunstmalerei-text', [
$fx($kleinzeile('kunstmalerei-label', 'Kunst & Gestaltung', '#c6a36b'), 'fade'),
$fx($heading('kunstmalerei-titel', 'Kunstmalerei bei Ihrem<br>Malerservice Drews', 2, $h2Hell), 'rise'),
$fx($text('kunstmalerei-intro', 'Die Malerei ist neben der Grafik eine Kunst der Fläche – wir verbinden traditionelles Können mit kreativer Gestaltung und schaffen Unikate, die Räume verwandeln.', ['desktop' => ['color' => '#ffffffd9', 'fontSize' => '15.5px', 'fontWeight' => '400', 'lineHeight' => 1.8, 'margin' => ['bottom' => '30px']]]), 'rise', 'short'),
$fx($button('kunstmalerei-knopf', 'Galerie ansehen', '/kunstmalerei', 'dunkel', true, ['desktop' => ['margin' => ['top' => '0px']]], 'normal'), 'rise', 'medium'),
], ['desktop' => ['alignSelf' => 'center', 'flexGrow' => 7, 'flexBasis' => '0px', 'minWidth' => '0px', 'padding' => ['right' => '55px']], 'tablet' => ['padding' => ['right' => '0px']], 'mobile' => ['padding' => ['right' => '0px'], 'flexBasis' => 'auto']]),
$column('kunstmalerei-bilder', [
$rasterbild('kunstmalerei-bild-1', $seitenbilder['kunst-1'], 'Wandgestaltung in Steinoptik in einem Rohbau', '330px', '240px', '520px'),
$row('kunstmalerei-raster', [
$rasterbild('kunstmalerei-bild-2', $seitenbilder['kunst-2'], 'Grün gestrichener Raum mit Tageslicht', '150px', '120px'),
$rasterbild('kunstmalerei-bild-3', $seitenbilder['kunst-3'], 'Farbige Wandgestaltung eines Wohnraums', '150px', '120px'),
], ['desktop' => ['columns' => 'two'], 'mobile' => ['columns' => 'two']], ['desktop' => ['gap' => '16px', 'margin' => ['top' => '16px']], 'mobile' => ['gap' => '10px', 'margin' => ['top' => '10px']]]),
], ['desktop' => ['flexGrow' => 5, 'flexBasis' => '0px', 'minWidth' => '0px'], 'mobile' => ['flexBasis' => 'auto', 'width' => '100%']]),
], [], ['desktop' => ['display' => 'flex', 'alignItems' => 'center', 'gap' => '40px', 'margin' => ['top' => '0px']], 'mobile' => ['flexDirection' => 'column', 'gap' => '40px']]),
], [
'desktop' => ['backgroundImage' => $seitenbilder['kunst-bg']['id'], 'backgroundSize' => 'cover', 'backgroundPosition' => 'center', 'overlayColor' => '#050505', 'overlayOpacity' => 0.55, 'color' => '#ffffff', 'padding' => ['top' => '140px', 'bottom' => '140px']],
'mobile' => ['padding' => ['top' => '80px', 'bottom' => '80px']],
], 'kunst'),
// 7 – Little Greene: Text links, vier Produktbilder rechts.
$section('little-greene-abschnitt', [
$row('little-greene-zeile', [
$column('little-greene-text', [
$fx($kleinzeile('little-greene-label', 'Exklusiv in Mittelbaden'), 'fade'),
$fx($heading('little-greene-titel', 'Little Greene', 2, $h2Stil), 'rise'),
$fx($text('little-greene-1', 'Wir sind offizieller Partner von Little Greene – für hochwertige, umweltfreundliche Farben und außergewöhnliche Farbtiefe.', $fliess), 'rise', 'short'),
$fx($text('little-greene-2', 'Als Fachbetrieb beraten wir Sie nicht nur zur Farbwahl, sondern sorgen auch für die perfekte Verarbeitung – von der Vorbereitung bis zum Finish.', ['desktop' => [...$fliess['desktop'], 'margin' => ['bottom' => '30px']]]), 'rise', 'medium'),
$fx($button('little-greene-knopf', 'Mehr über Little Greene', '/exklusiv-in-mittelbaden-wir-sind-offizieller-little-greene-partner', 'dunkel-rahmen', true, ['desktop' => ['margin' => ['top' => '0px']]], 'normal'), 'rise', 'long'),
], ['desktop' => ['alignSelf' => 'center', 'padding' => ['right' => '55px']], 'tablet' => ['padding' => ['right' => '0px']], 'mobile' => ['padding' => ['right' => '0px']]]),
$column('little-greene-bilder', [
$row('little-greene-raster', [
$rasterbild('little-greene-bild-1', $seitenbilder['lg-1'], 'Little Greene – Tapete Upper Brook Street'),
$rasterbild('little-greene-bild-2', $seitenbilder['lg-2'], 'Little Greene – Farbton Mischief'),
$rasterbild('little-greene-bild-3', $seitenbilder['lg-3'], 'Little Greene – Farbton Puck'),
$rasterbild('little-greene-bild-4', $seitenbilder['lg-4'], 'Little Greene – Farbkombinationen'),
], ['desktop' => ['columns' => 'two'], 'mobile' => ['columns' => 'two']], ['desktop' => ['gap' => '16px', 'margin' => ['top' => '0px']], 'mobile' => ['gap' => '10px']]),
]),
], ['desktop' => ['columns' => 'two', 'gap' => 'medium'], 'mobile' => ['columns' => 'one']], ['desktop' => ['alignItems' => 'center', 'margin' => ['top' => '0px']], 'mobile' => ['gap' => '40px']]),
], ['desktop' => ['padding' => ['top' => '120px', 'bottom' => '120px']], 'mobile' => ['padding' => ['top' => '70px', 'bottom' => '70px']]], 'little-greene'),
// 8 – Das Zitat: dunkles Band, goldene Linien links und rechts.
$section('zitat', [
$fx($column('zitat-inhalt', [
$text('zitat-text', '„Qualität ist kein Zufall – sie ist das Ergebnis von Anspruch, Erfahrung und Leidenschaft.“', ['desktop' => ['color' => '#ffffff', 'fontSize' => '24px', 'fontStyle' => 'italic', 'fontWeight' => '400', 'lineHeight' => 1.6, 'textAlign' => 'center', 'margin' => ['bottom' => '22px']], 'mobile' => ['fontSize' => '19px']]),
$kleinzeile('zitat-autor', 'Axel Drews · Malermeister', '#c6a36b', 'center', '0px', '4px'),
], ['desktop' => ['maxWidth' => '780px', 'margin' => ['left' => 'auto', 'right' => 'auto'], 'padding' => ['top' => '24px', 'right' => '40px', 'bottom' => '24px', 'left' => '40px'], 'borderWidth' => ['top' => '0px', 'right' => '1px', 'bottom' => '0px', 'left' => '1px'], 'borderStyle' => 'solid', 'borderColor' => '@gold'], 'mobile' => ['padding' => ['top' => '10px', 'right' => '18px', 'bottom' => '10px', 'left' => '18px']]]), 'fade'),
], ['desktop' => ['backgroundColor' => '@dunkel', 'color' => '#ffffff', 'padding' => ['top' => '100px', 'bottom' => '100px']], 'mobile' => ['padding' => ['top' => '60px', 'bottom' => '60px']]]),
// 9 – Marken: sechs Logos in Graustufen, farbig beim Zeigen.
$section('marken-abschnitt', [
...$abschnittskopf('marken', 'Marken & Partner', 'Qualität beginnt beim Produkt', 'Wir arbeiten ausschließlich mit hochwertigen Marken – für langlebige Ergebnisse, satte Farbtiefe und perfekte Oberflächen.'),
$fx(['id' => 'marken-logos', 'type' => 'logos', 'children' => array_map(
static fn (string $schluessel, string $name): array => $bild('marke-'.$schluessel, $seitenbilder['marke-'.$schluessel], $name, ['desktop' => ['maxWidth' => '150px', 'grayscale' => 1, 'opacity' => 0.6, 'transition' => 400, 'margin' => $seiten('0px'), 'hover' => ['grayscale' => 0, 'opacity' => 1]], 'mobile' => ['maxWidth' => '110px']]),
['littlegreene', 'brillux', 'gori', 'keim', 'sikkens', 'henkel'], ['Little Greene', 'Brillux', 'Gori', 'Keim', 'Sikkens', 'Henkel'],
), 'style' => ['desktop' => ['margin' => ['top' => '50px']], 'mobile' => ['margin' => ['top' => '36px']]],
'css' => "grid-template-columns:repeat(auto-fit,minmax(min(100%,140px),1fr));gap:40px 30px;\n& img{max-height:70px}"], 'fade', 'short'),
], ['desktop' => ['backgroundColor' => '@creme', 'padding' => ['top' => '100px', 'bottom' => '100px']], 'mobile' => ['padding' => ['top' => '60px', 'bottom' => '60px']]], 'marken'),
// 10 – Das beige Band mit drei Partnern.
$section('partner', [
['id' => 'partner-logos', 'type' => 'logos', 'children' => [
$bild('partner-eisen', $seitenbilder['partner-eisen'], 'Eisen-Raumausstattung', ['desktop' => ['maxWidth' => '190px', 'margin' => $seiten('0px')], 'mobile' => ['maxWidth' => '130px']]),
$bild('partner-lichtkraus', $seitenbilder['partner-lichtkraus'], 'Licht Kraus Sasbach', ['desktop' => ['maxWidth' => '120px', 'margin' => $seiten('0px')], 'mobile' => ['maxWidth' => '90px']]),
$bild('partner-kant', $seitenbilder['partner-kant'], 'Kant-IT Solutions', ['desktop' => ['maxWidth' => '210px', 'margin' => $seiten('0px')], 'mobile' => ['maxWidth' => '140px']], 'https://kant-it.de'),
], 'css' => "grid-template-columns:repeat(auto-fit,minmax(150px,max-content));justify-content:center;gap:40px clamp(40px,10vw,150px);\n& img{max-height:80px}"],
], ['desktop' => ['backgroundColor' => '@beige', 'padding' => ['top' => '30px', 'bottom' => '30px']]]),
// 11 – Handlungsaufruf
$aufruf('aufruf', 'Unverbindlich anfragen', 'Bereit für ein Ergebnis,<br>das man sieht?', 'Wir beraten Sie persönlich und erstellen Ihnen ein Angebot, das zu Ihrem Objekt passt – transparent, sauber und professionell.', 'Jetzt Kontakt aufnehmen'),
],
];
// ---------------------------------------------------------------------------------------------
// Seiten anlegen und veröffentlichen
// ---------------------------------------------------------------------------------------------
$erstellt = [];
$anlegen = static function (string $slug, array $dokument, string $seoTitel = '', string $teilbild = '') use ($pages, $db, &$erstellt): string {
$id = $pages->createPage($slug, null, 'page', $dokument);
if ('' !== $seoTitel) {
$db->executeStatement('UPDATE page SET seo_title = ? WHERE id = ?', [$seoTitel, $id]);
}
if ('' !== $teilbild) {
$db->executeStatement('UPDATE page SET og_media_id = ? WHERE id = ?', [$teilbild, $id]);
}
$seite = $db->fetchAssociative('SELECT draft_revision_id, version FROM page WHERE id = ?', [$id]);
$pages->publish($id, $seite['draft_revision_id'], (int) $seite['version']);
$erstellt[$slug] = $id;
echo 'Seite angelegt: /'.$db->fetchOne('SELECT path FROM page WHERE id = ?', [$id])."\n";
return $id;
};
$anlegen('home', $startseite, 'Ihr Malerservice Drews | Malermeister Axel Drews', $seitenbilder['hero-1']['id']);
// Aktuelles: Seitenkopf, Zeitleiste, Handlungsaufruf mit Foto.
$anlegen('aktuelles', [
'schemaVersion' => $SCHEMA, 'title' => 'Aktuelles',
'description' => 'Aktuelles aus dem Betrieb: Einblicke in Projekte, Neuigkeiten und Veranstaltungen von Ihr Malerservice Drews in Gernsbach.',
'blocks' => [
$seitenkopf('aktuelles-seite', $seitenbilder['hero-1'], 'News & Projekte', 'Aktuelles aus dem Betrieb', 'Einblicke in unsere Projekte, Neuigkeiten und Veranstaltungen – erfahren Sie, woran wir gerade arbeiten.', '45vh', '#050505', 0.65, [], 'center'),
$section('aktuelles-liste-abschnitt', [
$heading('aktuelles-liste-titel', 'Alle Mitteilungen im Überblick', 2, ['desktop' => ['position' => 'absolute', 'width' => '1px', 'height' => '1px', 'overflow' => 'hidden', 'margin' => ['bottom' => '0px']]], 'clip-path:inset(50%);white-space:nowrap'),
['id' => 'aktuelles-zeitleiste', 'type' => 'postlist', 'props' => ['count' => 10, 'category' => 'aktuelles', 'layout' => 'liste', 'paginate' => true, 'showMeta' => true, 'showExcerpt' => true, 'showTerms' => false],
'style' => ['desktop' => ['maxWidth' => '1000px', 'margin' => ['left' => 'auto', 'right' => 'auto']]],
'css' => '& .post-list{gap:50px;padding-left:clamp(20px,5vw,60px);border-left:3px solid transparent;border-image:linear-gradient(180deg,#c6a36b 0%,rgba(198,163,107,.3) 100%) 1}
& .post-card{position:relative;border:0;border-radius:16px;background:#fff;box-shadow:0 10px 40px rgba(198,163,107,.15);transition:transform .4s ease,box-shadow .4s ease;flex-wrap:wrap}
& .post-card:hover{transform:translateY(-4px);box-shadow:0 20px 60px rgba(198,163,107,.25)}
& .post-image{flex:1 1 220px;max-width:none}
& .post-image img{min-height:190px;height:100%}
& .post-body{flex:3 1 300px;padding:28px 32px;gap:10px}
& .post-card h3{font-size:22px;font-weight:700;line-height:1.3}
& .post-meta{order:-1;font-size:12px;letter-spacing:2px;text-transform:uppercase;color:#8a6a2f;font-weight:600}
& .post-excerpt{margin:0;color:#555;font-size:15px;line-height:1.7}
& .post-pager{margin-top:50px}', ],
], ['desktop' => ['backgroundColor' => '@creme', 'padding' => ['top' => '100px', 'bottom' => '100px']], 'mobile' => ['padding' => ['top' => '60px', 'bottom' => '60px']]]),
$aufruf('aktuelles-aufruf', 'Ihr nächstes Projekt?', 'Lassen Sie uns über Ihre Ideen sprechen', 'Ob Renovierung, Farbkonzept oder besondere Herausforderung – wir freuen uns auf Ihre Anfrage.', 'Jetzt Kontakt aufnehmen', $seitenbilder['aktuelles-cta-bg']),
],
], 'Aktuelles | Ihr Malerservice Drews', $seitenbilder['hero-1']['id']);
// Unsere Projekte: Seitenkopf, Zickzackliste, dunkler Schluss.
$anlegen('unsere-projekte', [
'schemaVersion' => $SCHEMA, 'title' => 'Unsere Projekte',
'description' => 'Einblicke in ausgewählte Arbeiten von Ihr Malerservice Drews aus dem Bereich Innenausstattung und Außenfassade – Referenzen aus Gernsbach, Baden-Baden und Mittelbaden.',
'blocks' => [
$section('projekte-kopf', [
$column('projekte-kopf-inhalt', [
$fx($kleinzeile('projekte-label', 'Unsere Arbeit', '#ffffffb3', 'center', '20px', '5px'), 'fade'),
$fx($heading('projekte-h1', 'Unsere Projekte', 1, ['desktop' => ['fontSize' => '60px', 'lineHeight' => 1.1, 'fontWeight' => '700', 'color' => '#ffffff', 'textAlign' => 'center', 'margin' => ['bottom' => '0px']], 'tablet' => ['fontSize' => '48px'], 'mobile' => ['fontSize' => '38px']]), 'rise', 'short'),
$flaeche('projekte-linie', ['desktop' => ['width' => '50px', 'height' => '1px', 'backgroundColor' => '#b09066', 'margin' => ['top' => '28px', 'bottom' => '28px', 'left' => 'auto', 'right' => 'auto']]]),
$fx($text('projekte-intro', 'Einblicke in ausgewählte Arbeiten aus dem Bereich Innenaustattung und Außenfassade.', ['desktop' => ['color' => '#ffffff80', 'fontSize' => '14.5px', 'fontWeight' => '400', 'lineHeight' => 1.8, 'textAlign' => 'center', 'maxWidth' => '500px', 'margin' => ['left' => 'auto', 'right' => 'auto', 'bottom' => '0px']]]), 'rise', 'medium'),
], ['desktop' => ['maxWidth' => '900px', 'margin' => ['left' => 'auto', 'right' => 'auto']]]),
], [
'desktop' => ['backgroundImage' => $seitenbilder['projekte-bg']['id'], 'backgroundSize' => 'cover', 'backgroundPosition' => 'center', 'overlayColor' => '#0a0806', 'overlayOpacity' => 0.65, 'color' => '#ffffff', 'padding' => ['top' => '160px', 'bottom' => '160px']],
'mobile' => ['padding' => ['top' => '100px', 'bottom' => '100px']],
]),
$section('projekte-liste-abschnitt', [
$heading('projekte-liste-titel', 'Alle Projekte im Überblick', 2, ['desktop' => ['position' => 'absolute', 'width' => '1px', 'height' => '1px', 'overflow' => 'hidden', 'margin' => ['bottom' => '0px']]], 'clip-path:inset(50%);white-space:nowrap'),
['id' => 'projekte-liste', 'type' => 'postlist', 'props' => ['count' => 8, 'category' => 'projekte', 'layout' => 'wechsel', 'paginate' => true, 'showMeta' => false, 'showExcerpt' => false, 'showTerms' => false],
'style' => ['desktop' => ['maxWidth' => '1360px', 'margin' => ['left' => 'auto', 'right' => 'auto']]],
'css' => '& .post-card{gap:20px 60px;padding:40px 0}
& .post-card + .post-card{border-top:0}
& .post-image{border-radius:16px;box-shadow:0 10px 40px rgba(198,163,107,.15);transition:transform .4s ease,box-shadow .4s ease}
& .post-image:hover{transform:translateY(-8px);box-shadow:0 20px 60px rgba(198,163,107,.25)}
& .post-image img{aspect-ratio:16/11;border-radius:16px;transition:transform .6s ease}
& .post-view{display:none}
& .post-body::before{display:none}
& .post-body{gap:15px;max-width:450px}
& .post-card h3{font-size:clamp(24px,2.3vw,32px);font-weight:700;line-height:1.3;color:#2a2a2a}
& .post-excerpt{color:#333;font-size:15.5px;line-height:1.7}
& .post-more{font-size:15px;font-weight:600;background:#c6a36b;color:#2a2a2a;border-radius:50px;padding:14px 28px;margin-top:10px;transition:transform .3s ease,box-shadow .3s ease,background-color .3s}
& .post-more:hover{background:#b4966e;transform:translateY(-2px);box-shadow:0 8px 25px rgba(198,163,107,.35)}
& .post-pager{margin-top:60px;gap:10px 22px}
& .post-pager a{background:#fff;color:#333;border-radius:50px;padding:14px 24px;text-decoration:none;font-weight:500;transition:background-color .3s,color .3s}
& .post-pager a:hover{background:#c6a36b;color:#fff}', ],
], ['desktop' => ['backgroundColor' => '#f8f6f3', 'padding' => ['top' => '100px', 'bottom' => '100px']], 'mobile' => ['padding' => ['top' => '50px', 'bottom' => '50px']]], null, ['width' => 'wide']),
$section('projekte-schluss', [
$column('projekte-schluss-inhalt', [
$fx($kleinzeile('projekte-schluss-label', 'Ihr Projekt ist das nächste', '#c8a882', 'center', '18px', '4px'), 'fade'),
$fx($heading('projekte-schluss-titel', 'Lassen Sie uns gemeinsam<br>Farbe bekennen.', 2, $h2HellMitte), 'rise'),
$flaeche('projekte-schluss-linie', ['desktop' => ['width' => '50px', 'height' => '1px', 'backgroundColor' => '#b09066', 'margin' => ['top' => '10px', 'bottom' => '25px', 'left' => 'auto', 'right' => 'auto']]]),
$fx($text('projekte-schluss-text', 'Unverbindliche Beratung — wir freuen uns auf Ihre Anfrage.', ['desktop' => ['color' => '#ffffff99', 'fontSize' => '14px', 'fontWeight' => '400', 'textAlign' => 'center', 'margin' => ['bottom' => '40px']]]), 'rise', 'short'),
$fx($button('projekte-schluss-knopf', 'Kontakt aufnehmen', '/kontakt', 'weiss-rahmen', false, ['desktop' => ['margin' => ['top' => '0px', 'left' => 'auto', 'right' => 'auto'], 'letterSpacing' => '3px', 'fontSize' => '11px', 'borderColor' => '#ffffff4d']], 'normal'), 'rise', 'medium'),
], ['desktop' => ['display' => 'flex', 'flexDirection' => 'column', 'alignItems' => 'center', 'maxWidth' => '800px', 'margin' => ['left' => 'auto', 'right' => 'auto']]]),
], ['desktop' => ['backgroundColor' => '#1c1a17', 'color' => '#ffffff', 'padding' => ['top' => '100px', 'bottom' => '100px']], 'mobile' => ['padding' => ['top' => '60px', 'bottom' => '60px']]]),
],
], 'Unsere Projekte | Ihr Malerservice Drews', $seitenbilder['projekte-bg']['id']);
// Kunstmalerei: Kopf, Handschrift, Galerie, Videos, Arbeitsweise, Schluss.
$kunstSchritte = [
['beratung', 'Beratung & Konzept', 'Wir besprechen Ihre Wünsche und erstellen eine individuelle Idee passend zum Raum.'],
['detail', 'Detailarbeit', 'Feine Strukturen, Farbverläufe und Präzision sorgen für Tiefe und Wirkung.'],
['material', 'Hochwertige Materialien', 'Wir verwenden nur professionelle Farben und langlebige Schutzbeschichtungen.'],
['umsetzung', 'Perfekte Umsetzung', 'Sauber, zuverlässig und exakt nach Plan – bis alles perfekt aussieht.'],
];
$kunstKarte = static fn (array $s, string $verzug): array => $fx($column('kunst-schritt-'.$s[0], [
$heading('kunst-schritt-'.$s[0].'-titel', $s[1], 3, ['desktop' => ['fontSize' => '20px', 'fontWeight' => '700', 'margin' => ['bottom' => '10px']]]),
$text('kunst-schritt-'.$s[0].'-text', $s[2], ['desktop' => ['color' => '#000000a6', 'fontSize' => '15px', 'lineHeight' => 1.7, 'margin' => ['bottom' => '0px']]]),
], ['desktop' => ['backgroundColor' => '#f7f7f7', 'padding' => $seiten('28px'), 'borderRadius' => $ecken('16px'), 'shadowY' => '8px', 'shadowBlur' => '22px', 'shadowColor' => '#0000000d', 'height' => '100%']]), 'rise', $verzug);
$videos = [
'2022/12/VIDEO-2022-12-27-19-46-50-2022-12-28-08_33_09.mp4', '2022/12/VIDEO-2022-12-27-20-15-29-2022-12-28-08_33_10.mp4', '2022/04/VIDEO-2022-04-27-09-10-39.mp4',
'2022/04/VIDEO-2022-04-27-09-10-39-video-converter.com_.mp4', '2022/04/VIDEO-2022-04-27-10-32-16-2022-04-27-08_57_30.mp4', '2022/04/VIDEO-2022-04-27-10-29-57-2022-04-27-08_57_29.mp4',
'2022/04/Video_start.mp4', '2022/04/Video_start-online-video-cutter.com-1.mp4', '2022/08/VIDEO-2022-08-29-16-09-21.mp4',
'2022/11/VIDEO-2022-11-07-06-45-45.mp4', '2022/12/VIDEO-2022-12-27-19-49-05-2022-12-28-08_33_09.mp4',
];
$anlegen('kunstmalerei', [
'schemaVersion' => $SCHEMA, 'title' => 'Kunstmalerei',
'description' => 'Kunstmalerei bei Ihrem Malerservice Drews: klassische Motive, moderne Kompositionen und individuelle Kunstwerke, die Räume lebendig machen – mit Galerie und Videos.',
'blocks' => [
$seitenkopf('kunst-seite', $seitenbilder['hero-1'], 'Kunstmalerei', 'Kunst, die Räume lebendig macht', 'Ob klassische Motive, moderne Kompositionen oder individuelle Kunstwerke – wir erschaffen Malerei mit Charakter. Jedes Werk entsteht mit Liebe zum Detail und dem Anspruch, Emotionen sichtbar zu machen.', '40vh', '#000000', 0.55, [
$button('kunst-seite-knopf', 'Jetzt Projekt anfragen', '/kontakt', 'dunkel', false, ['desktop' => ['margin' => ['top' => '14px', 'left' => 'auto', 'right' => 'auto'], 'borderRadius' => $ecken('99px')]], 'normal'),
]),
$section('kunst-handschrift', [
$row('kunst-handschrift-zeile', [
$column('kunst-handschrift-text', [
$fx($kleinzeile('kunst-handschrift-label', 'Unsere Handschrift'), 'fade'),
$fx($heading('kunst-handschrift-titel', 'Kunstmalerei mit Stil & Persönlichkeit', 2, $h2Stil), 'rise'),
$fx($text('kunst-handschrift-1', 'Kunstmalerei ist mehr als Farbe auf Leinwand – sie ist Ausdruck, Stimmung und Atmosphäre. Wir schaffen einzigartige Werke, die nicht nur schön aussehen, sondern Räume aufwerten und Emotionen transportieren.', ['desktop' => ['color' => '#000000b8', 'fontSize' => '16px', 'fontWeight' => '400', 'lineHeight' => 1.8, 'margin' => ['bottom' => '20px']]]), 'rise', 'short'),
$fx($text('kunst-handschrift-2', 'Von detailreichen Naturmotiven bis hin zu modernen abstrakten Elementen: Unsere Arbeiten entstehen individuell, passend zu Ihrem Raum, Ihrer Idee und Ihrem Stil.', ['desktop' => ['color' => '#000000b8', 'fontSize' => '16px', 'fontWeight' => '400', 'lineHeight' => 1.8, 'margin' => ['bottom' => '0px']]]), 'rise', 'medium'),
], ['desktop' => ['alignSelf' => 'center']]),
$column('kunst-handschrift-bild', [
$fx($bild('kunst-handschrift-foto', $seitenbilder['kunst-1'], 'Wandgestaltung in Steinoptik in einem Rohbau', ['desktop' => ['maxWidth' => '560px', 'imageRadius' => $ecken('4px'), 'margin' => $seiten('0px')]], null, $bildSchatten), 'right', 'short', null, 'strong'),
]),
], ['desktop' => ['columns' => 'two', 'gap' => 'large'], 'mobile' => ['columns' => 'one']], ['desktop' => ['alignItems' => 'center', 'margin' => ['top' => '0px']]]),
], ['desktop' => ['padding' => ['top' => '90px', 'bottom' => '90px']], 'mobile' => ['padding' => ['top' => '60px', 'bottom' => '60px']]]),
$section('kunst-galerie-abschnitt', [
...$abschnittskopf('kunst-galerie', 'Galerie', 'Einblicke in unsere Kunstwerke', 'Hier sehen Sie eine Auswahl an Projekten. Jedes Werk ist individuell gefertigt – mit dem Ziel, Räume einzigartig wirken zu lassen.'),
$fx(['id' => 'kunst-galerie', 'type' => 'gallery', 'props' => ['lightbox' => true], 'children' => array_map(
static fn (array $foto, int $i): array => $bild('kunst-werk-'.($i + 1), $foto, 'Kunstmalerei von Malerservice Drews – Werk '.($i + 1), ['desktop' => ['maxWidth' => '360px', 'imageHeight' => '100%', 'objectFit' => 'cover', 'imageRadius' => $ecken('4px'), 'margin' => $seiten('0px')]], null, "& img{aspect-ratio:1/1;transition:transform .5s ease}\n&:hover img{transform:scale(1.04)}", true),
$galerie, array_keys($galerie),
), 'style' => ['desktop' => ['gridColumns' => 4, 'gap' => '15px', 'margin' => ['top' => '60px']], 'tablet' => ['gridColumns' => 3], 'mobile' => ['gridColumns' => 2, 'gap' => '10px', 'margin' => ['top' => '36px']]]], 'fade', 'short'),
], ['desktop' => ['backgroundColor' => '#f7f7f7', 'padding' => ['top' => '90px', 'bottom' => '60px']], 'mobile' => ['padding' => ['top' => '60px', 'bottom' => '40px']]], 'galerie', ['width' => 'wide']),
$section('kunst-videos-abschnitt', [
$heading('kunst-videos-titel', 'Videogalerie', 2, ['desktop' => [...$h2Mitte['desktop'], 'margin' => ['bottom' => '40px']], 'tablet' => $h2Stil['tablet'], 'mobile' => $h2Stil['mobile']]),
$row('kunst-videos', array_map(
static fn (string $datei, int $i): array => ['id' => 'kunst-video-'.($i + 1), 'type' => 'embed', 'props' => ['group' => 'external', 'title' => 'Video '.($i + 1).' aus der Werkstatt von Malerservice Drews', 'provider' => 'maler-drews.com', 'hint' => 'Das Video wird von maler-drews.com geladen.', 'url' => 'https://www.maler-drews.com/wp-content/uploads/'.$datei, 'height' => 240]],
$videos, array_keys($videos),
), ['desktop' => ['columns' => 'three', 'gap' => 'medium'], 'tablet' => ['columns' => 'two'], 'mobile' => ['columns' => 'one']], ['desktop' => ['margin' => ['top' => '0px']]]),
], ['desktop' => ['backgroundColor' => '#f7f7f7', 'padding' => ['top' => '30px', 'bottom' => '90px']], 'mobile' => ['padding' => ['top' => '20px', 'bottom' => '60px']]], null, ['width' => 'wide']),
$section('kunst-arbeitsweise', [
$row('kunst-arbeitsweise-zeile', [
$column('kunst-arbeitsweise-text', [
$fx($kleinzeile('kunst-arbeitsweise-label', 'So arbeiten wir'), 'fade'),
$fx($heading('kunst-arbeitsweise-titel', 'Von der Idee bis zum fertigen Kunstwerk', 2, $h2Stil), 'rise'),
$fx($text('kunst-arbeitsweise-intro', 'Wir beraten Sie persönlich, entwickeln ein Konzept und setzen Ihr Wunschmotiv mit hochwertigen Materialien um. Ob für Privatkunden, Unternehmen oder öffentliche Einrichtungen – wir liefern Kunst, die Eindruck hinterlässt.', ['desktop' => ['color' => '#000000b8', 'fontSize' => '16px', 'fontWeight' => '400', 'lineHeight' => 1.8, 'margin' => ['bottom' => '0px']]]), 'rise', 'short'),
], ['desktop' => ['alignSelf' => 'center']]),
$column('kunst-arbeitsweise-karten', [
$kunstKarte($kunstSchritte[0], 'none'),
$kunstKarte($kunstSchritte[1], 'short'),
], ['desktop' => ['display' => 'flex', 'flexDirection' => 'column', 'gap' => '20px']]),
], ['desktop' => ['columns' => 'two', 'gap' => 'large'], 'mobile' => ['columns' => 'one']], ['desktop' => ['alignItems' => 'center', 'margin' => ['top' => '0px']]]),
$row('kunst-arbeitsweise-raster', [$kunstKarte($kunstSchritte[2], 'none'), $kunstKarte($kunstSchritte[3], 'short')], ['desktop' => ['columns' => 'two', 'gap' => 'medium'], 'mobile' => ['columns' => 'one']], ['desktop' => ['margin' => ['top' => '20px']]]),
], ['desktop' => ['padding' => ['top' => '90px', 'bottom' => '90px']], 'mobile' => ['padding' => ['top' => '60px', 'bottom' => '60px']]]),
$section('kunst-schluss', [
$row('kunst-schluss-zeile', [
$column('kunst-schluss-text', [
$fx($kleinzeile('kunst-schluss-label', 'Interesse?', '#c6a36b'), 'fade'),
$fx($heading('kunst-schluss-titel', 'Lassen Sie uns gemeinsam etwas Einzigartiges erschaffen', 2, ['desktop' => [...$h2Hell['desktop'], 'fontSize' => '46px'], 'tablet' => $h2Stil['tablet'], 'mobile' => $h2Stil['mobile']]), 'rise'),
$fx($text('kunst-schluss-intro', 'Ob Wandgestaltung, Leinwandkunst oder dekorative Malerei – wir freuen uns auf Ihre Anfrage. Gemeinsam entwickeln wir ein Werk, das perfekt zu Ihnen passt.', ['desktop' => ['color' => '#ffffffc7', 'fontSize' => '16px', 'fontWeight' => '400', 'lineHeight' => 1.8, 'margin' => ['bottom' => '0px']]]), 'rise', 'short'),
], ['desktop' => ['flexGrow' => 7, 'flexBasis' => '0px', 'minWidth' => '0px'], 'mobile' => ['flexBasis' => 'auto']]),
$column('kunst-schluss-aktion', [
$fx($button('kunst-schluss-knopf', 'Kontakt aufnehmen', '/kontakt', 'gold', false, ['desktop' => ['margin' => ['top' => '0px', 'left' => 'auto', 'right' => 'auto'], 'borderRadius' => $ecken('99px')]]), 'rise', 'medium'),
$fx($text('kunst-schluss-hinweis', 'Antwort innerhalb von 24 Stunden', ['desktop' => ['color' => '#ffffffa6', 'fontSize' => '14px', 'textAlign' => 'center', 'margin' => ['top' => '14px', 'bottom' => '0px']]]), 'fade', 'long'),
], ['desktop' => ['display' => 'flex', 'flexDirection' => 'column', 'alignItems' => 'center', 'justifyContent' => 'center', 'flexGrow' => 5, 'flexBasis' => '0px'], 'mobile' => ['flexBasis' => 'auto', 'width' => '100%']]),
], [], ['desktop' => ['display' => 'flex', 'alignItems' => 'center', 'gap' => '60px', 'margin' => ['top' => '0px']], 'mobile' => ['flexDirection' => 'column', 'gap' => '36px']]),
], ['desktop' => ['backgroundColor' => '#0f0f0f', 'color' => '#ffffff', 'padding' => ['top' => '90px', 'bottom' => '90px']], 'mobile' => ['padding' => ['top' => '60px', 'bottom' => '60px']]]),
],
], 'Kunstmalerei | Ihr Malerservice Drews', $seitenbilder['kunst-1']['id']);
// Kontakt: Kopf, dunkler Streifen, Formular und Standort, Karte.
$kontaktKachel = static fn (string $id, string $icon, string $label, string $inhalt, string $zusatz = '', bool $letzte = false): array => $column($id, array_values(array_filter([
$symbol($id.'-symbol', $icon, 32, ['desktop' => ['color' => '@gold', 'margin' => ['bottom' => '14px', 'left' => 'auto', 'right' => 'auto']]]),
$text($id.'-label', $label, ['desktop' => ['color' => '#ffffffa6', 'fontSize' => '11px', 'letterSpacing' => '4px', 'textTransform' => 'uppercase', 'fontWeight' => '600', 'textAlign' => 'center', 'margin' => ['bottom' => '10px']]]),
$text($id.'-text', $inhalt, ['desktop' => ['color' => '#ffffffd9', 'fontSize' => '16.5px', 'fontWeight' => '400', 'lineHeight' => 1.7, 'textAlign' => 'center', 'margin' => ['bottom' => '0px']]], "& a{color:inherit;text-decoration:none}\n& a:hover{color:#c6a36b}"),
'' === $zusatz ? null : $text($id.'-zusatz', $zusatz, ['desktop' => ['color' => '#ffffff99', 'fontSize' => '13.5px', 'textAlign' => 'center', 'margin' => ['top' => '5px', 'bottom' => '0px']]]),
])), ['desktop' => ['display' => 'flex', 'flexDirection' => 'column', 'alignItems' => 'center', 'padding' => $seiten('20px')] + ($letzte ? [] : ['borderWidth' => ['top' => '0px', 'right' => '1px', 'bottom' => '0px', 'left' => '0px'], 'borderStyle' => 'solid', 'borderColor' => '#ffffff14']), 'mobile' => $letzte ? [] : ['borderWidth' => ['top' => '0px', 'right' => '0px', 'bottom' => '1px', 'left' => '0px']]]);
$zeitenKarte = static fn (string $id, string $tag, string $zeit, bool $erste = false, bool $kursiv = false): array => $row($id, [
$column($id.'-tag', [$text($id.'-tag-text', $tag, ['desktop' => ['fontSize' => '14.5px', 'color' => '#555555', 'margin' => ['bottom' => '0px']]])]),
$column($id.'-zeit', [$text($id.'-zeit-text', $kursiv ? '<em>'.$zeit.'</em>' : '<strong>'.$zeit.'</strong>', ['desktop' => ['fontSize' => '14.5px', 'color' => '#555555', 'textAlign' => 'right', 'margin' => ['bottom' => '0px']]])]),
], [], ['desktop' => ['display' => 'flex', 'justifyContent' => 'space-between', 'gap' => '20px', 'margin' => ['top' => '0px'], 'padding' => ['top' => $erste ? '0px' : '6px', 'bottom' => '6px']]
+ ($erste ? [] : ['borderWidth' => $nurOben('1px'), 'borderStyle' => 'solid', 'borderColor' => '#f0ece6'])]);
$anlegen('kontakt', [
'schemaVersion' => $SCHEMA, 'title' => 'Kontakt',
'description' => 'Kontakt zu Ihr Malerservice Drews in Gernsbach: Telefon '.$telefon.', Am Bachgarten 1, 76593 Gernsbach. Persönliche Beratung, faire Angebote – wir melden uns innerhalb von 24 Stunden.',
'blocks' => [
$seitenkopf('kontakt-seite', $seitenbilder['hero-1'], 'Malermeister Axel Drews · Gernsbach', 'Sprechen wir über Ihr Projekt', 'Persönliche Beratung, faire Angebote und ein offenes Ohr für Ihre Wünsche – wir sind für Sie da.', '50vh', '#050505', 0.68, [], 'center'),
$section('kontakt-streifen', [
$row('kontakt-streifen-zeile', [
$kontaktKachel('kontakt-kachel-telefon', 'phone', 'Telefon', '<a href="'.$telHref.'">'.$telefon.'</a>', 'Fax: '.$fax),
$kontaktKachel('kontakt-kachel-adresse', 'pin', 'Anschrift', 'Am Bachgarten 1<br>76593 Gernsbach'),
$kontaktKachel('kontakt-kachel-mail', 'mail', 'E-Mail', '<a href="mailto:'.$mail.'">'.$mail.'</a>', '', true),
], ['desktop' => ['columns' => 'three', 'gap' => 'medium'], 'tablet' => ['columns' => 'three'], 'mobile' => ['columns' => 'one']], ['desktop' => ['margin' => ['top' => '0px']]],
),
], ['desktop' => ['backgroundColor' => '#0e0e0e', 'color' => '#ffffff', 'padding' => ['top' => '55px', 'bottom' => '55px']], 'mobile' => ['padding' => ['top' => '40px', 'bottom' => '40px']]]),
$section('kontakt-formular-abschnitt', [
$row('kontakt-formular-zeile', [
$column('kontakt-formular-spalte', [
$fx($kleinzeile('kontakt-formular-label', 'Kontaktformular'), 'fade'),
$fx($heading('kontakt-formular-titel', 'Schreiben Sie uns', 2, ['desktop' => [...$h2Stil['desktop'], 'margin' => ['bottom' => '8px']], 'tablet' => $h2Stil['tablet'], 'mobile' => $h2Stil['mobile']]), 'rise'),
$fx($text('kontakt-formular-intro', 'Beschreiben Sie Ihr Vorhaben in wenigen Worten – wir melden uns innerhalb von 24 Stunden bei Ihnen. Unverbindlich und kostenfrei.', ['desktop' => ['color' => '#666666', 'fontSize' => '15px', 'lineHeight' => 1.8, 'margin' => ['bottom' => '40px']]]), 'rise', 'short'),
$fx($column('kontakt-formular-karte', [
['id' => 'kontakt-formular', 'type' => 'form', 'props' => ['form' => 'kontakt'],
'css' => '& .form-field{margin-bottom:18px}
& .form-field label{font-size:12.5px;letter-spacing:1.5px;text-transform:uppercase;font-weight:600;color:#6b6b6b;margin-bottom:0}
& .form-field input{width:100%;padding:14px 0;border:0;border-bottom:1px solid #ddd;border-radius:0;background:transparent;font-size:15px;color:#222;box-shadow:none;transition:border-color .35s}
& .form-field textarea{width:100%;padding:14px 0;border:0;border-bottom:1px solid #ddd;border-radius:0;background:transparent;font-size:15px;color:#222;box-shadow:none;transition:border-color .35s}
& .form-field input:focus{outline:none;border-bottom-color:#c6a36b;box-shadow:none}
& .form-field textarea:focus{outline:none;border-bottom-color:#c6a36b;box-shadow:none}
& .form-field textarea{min-height:120px;resize:vertical}
& .form-field input[type=checkbox]{width:16px;height:16px;accent-color:#c6a36b;margin-top:4px;padding:0}
& .form-consent label{font-size:13px;text-transform:none;letter-spacing:0;font-weight:400;color:#6b6b6b;line-height:1.55}
& .field-consent label{font-size:13px;text-transform:none;letter-spacing:0;font-weight:400;color:#6b6b6b;line-height:1.55}
& .cms-button{border-radius:0;padding:16px 48px;font-size:12.5px;letter-spacing:3px;margin-top:28px}
& .cms-button span{display:none}', ],
], ['desktop' => ['backgroundColor' => '@papier', 'padding' => ['top' => '40px', 'right' => '38px', 'bottom' => '35px', 'left' => '38px'], 'borderWidth' => $nurOben('3px'), 'borderStyle' => 'solid', 'borderColor' => '@gold', 'shadowY' => '4px', 'shadowBlur' => '25px', 'shadowColor' => '#0000000f'], 'mobile' => ['padding' => ['top' => '28px', 'right' => '22px', 'bottom' => '25px', 'left' => '22px']]]), 'rise', 'medium'),
], ['desktop' => ['flexGrow' => 7, 'flexBasis' => '0px', 'minWidth' => '0px', 'padding' => ['right' => '60px']], 'tablet' => ['padding' => ['right' => '30px']], 'mobile' => ['padding' => ['right' => '0px'], 'flexBasis' => 'auto', 'width' => '100%']]),
$column('kontakt-standort', [
$fx($kleinzeile('kontakt-standort-label', 'Standort'), 'fade'),
$fx($heading('kontakt-standort-titel', 'Gernsbach im Murgtal', 2, ['desktop' => [...$h2Stil['desktop'], 'margin' => ['bottom' => '25px']], 'tablet' => $h2Stil['tablet'], 'mobile' => $h2Stil['mobile']]), 'rise'),
$fx($column('kontakt-anruf', [
$text('kontakt-anruf-label', 'Lieber direkt anrufen?', ['desktop' => ['color' => '@gold', 'fontSize' => '11px', 'letterSpacing' => '4px', 'textTransform' => 'uppercase', 'fontWeight' => '600', 'margin' => ['bottom' => '12px']]]),
$text('kontakt-anruf-text', 'Für dringende Anfragen erreichen Sie uns telefonisch:', ['desktop' => ['color' => '#ffffff99', 'fontSize' => '14.5px', 'lineHeight' => 1.7, 'margin' => ['bottom' => '12px']]]),
$text('kontakt-anruf-nummer', '<a href="'.$telHref.'">'.$telefon.'</a>', ['desktop' => ['color' => '#ffffff', 'fontSize' => '21px', 'fontWeight' => '700', 'letterSpacing' => '0.5px', 'margin' => ['bottom' => '0px']]], "& a{color:#fff;text-decoration:none}\n& a:hover{color:#c6a36b}"),
], ['desktop' => ['backgroundColor' => '#0e0e0e', 'color' => '#ffffff', 'padding' => ['top' => '30px', 'right' => '30px', 'bottom' => '30px', 'left' => '30px']]]), 'rise', 'short'),
$fx($bild('kontakt-foto', $seitenbilder['kontakt-foto'], 'Axel Drews telefoniert vor dem Firmenwagen', ['desktop' => ['imageHeight' => '320px', 'objectFit' => 'cover', 'objectPosition' => 'center', 'margin' => $seiten('0px')], 'mobile' => ['imageHeight' => '240px']]), 'fade', 'medium'),
$fx($column('kontakt-zeiten-karte', [
$text('kontakt-zeiten-label', 'Öffnungszeiten', ['desktop' => ['color' => '@gold-text', 'fontSize' => '11px', 'letterSpacing' => '4px', 'textTransform' => 'uppercase', 'fontWeight' => '600', 'margin' => ['bottom' => '14px']]]),
$zeitenKarte('kontakt-zeit-1', 'Mo – Do', '07:00 – 16:30', true),
$zeitenKarte('kontakt-zeit-2', 'Freitag', '07:00 – 13:00'),
$zeitenKarte('kontakt-zeit-3', 'Sa & So', 'nach Vereinbarung', false, true),
], ['desktop' => ['backgroundColor' => '@papier', 'padding' => ['top' => '25px', 'right' => '28px', 'bottom' => '25px', 'left' => '28px'], 'borderWidth' => $nurLinks('3px'), 'borderStyle' => 'solid', 'borderColor' => '@gold', 'shadowY' => '2px', 'shadowBlur' => '12px', 'shadowColor' => '#0000000a', 'margin' => ['top' => '30px']]]), 'rise', 'long'),
], ['desktop' => ['flexGrow' => 5, 'flexBasis' => '0px', 'minWidth' => '0px'], 'mobile' => ['flexBasis' => 'auto', 'width' => '100%']]),
], [], ['desktop' => ['display' => 'flex', 'alignItems' => 'flex-start', 'gap' => '0px', 'margin' => ['top' => '0px']], 'mobile' => ['flexDirection' => 'column', 'gap' => '50px']]),
], ['desktop' => ['backgroundColor' => '@creme', 'padding' => ['top' => '110px', 'bottom' => '110px']], 'mobile' => ['padding' => ['top' => '70px', 'bottom' => '70px']]], 'kontakt'),
$section('kontakt-karte-abschnitt', [
['id' => 'kontakt-karte', 'type' => 'embed', 'props' => ['group' => 'external', 'title' => 'Google-Karte: Ihr Malerservice Drews, Am Bachgarten 1, Gernsbach', 'provider' => 'Google Maps', 'hint' => 'Die Karte wird von Google geladen. Dabei erfährt Google Ihre IP-Adresse.', 'url' => 'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d4465.340405747277!2d8.329596477683358!3d48.7648255713197!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4797184150f38e7b%3A0x77b609b6d2aa14ae!2sIhr%20Malerservice%20Drews!5e1!3m2!1sde!2sde!4v1770799998354!5m2!1sde!2sde', 'height' => 500],
'css' => "& iframe{border-radius:0;filter:grayscale(85%) contrast(1.05) brightness(1.02);transition:filter .5s ease}\n&:hover iframe{filter:grayscale(15%) contrast(1.05)}\n&.embed-blocked{border-radius:0;padding:60px 24px}"],
], ['desktop' => ['padding' => ['top' => '0px', 'bottom' => '0px']]], null, ['width' => 'full']),
],
], 'Kontakt | Ihr Malerservice Drews Gernsbach', $seitenbilder['kontakt-foto']['id']);
/** Eine Rechtsseite: heller Kopf mit Titel, darunter der übernommene Text in Absätzen. */
$rechtsseite = static function (string $praefix, string $titel, array $abschnitte) use ($section, $column, $heading, $text, $fx): array {
$bloecke = [];
foreach ($abschnitte as $i => $inhalt) {
$bloecke[] = $text($praefix.'-text-'.($i + 1), $inhalt, ['desktop' => ['color' => '#414141', 'fontSize' => '15px', 'lineHeight' => 1.85, 'margin' => ['bottom' => '0px']]], "& p{margin:0 0 18px}\n& strong{color:#222}\n& ol{margin:0 0 18px;padding-left:24px}\n& ul{margin:0 0 18px;padding-left:24px}\n& li{margin-bottom:8px}\n& a{color:#8a6a2f;text-decoration:none;border-bottom:1px solid rgba(138,106,47,.45);overflow-wrap:anywhere}\n& a:hover{border-bottom-color:#8a6a2f}");
}
return [
$section($praefix.'-kopf', [
$fx($heading($praefix.'-h1', $titel, 1, ['desktop' => ['fontSize' => '54px', 'fontWeight' => '700', 'lineHeight' => 1.1, 'textAlign' => 'center', 'margin' => ['bottom' => '0px']], 'mobile' => ['fontSize' => '38px']]), 'rise'),
], ['desktop' => ['backgroundColor' => '@creme', 'padding' => ['top' => '70px', 'bottom' => '70px']], 'mobile' => ['padding' => ['top' => '50px', 'bottom' => '50px']]]),
$section($praefix.'-inhalt', [$column($praefix.'-spalte', $bloecke, ['desktop' => ['maxWidth' => '860px', 'margin' => ['left' => 'auto', 'right' => 'auto']]])], ['desktop' => ['padding' => ['top' => '70px', 'bottom' => '100px']], 'mobile' => ['padding' => ['top' => '50px', 'bottom' => '70px']]]),
];
};
$anlegen('impressum', [
'schemaVersion' => $SCHEMA, 'title' => 'Impressum',
'description' => 'Impressum von Ihr Malerservice Drews, Axel Drews, Am Bachgarten 1, 76593 Gernsbach – Anbieterkennzeichnung, Umsatzsteuer-ID und rechtliche Hinweise.',
'blocks' => $rechtsseite('impressum', 'Impressum', [$inhalte['impressum']]),
], 'Impressum | Ihr Malerservice Drews');
$anlegen('datenschutz', [
'schemaVersion' => $SCHEMA, 'title' => 'Datenschutz',
'description' => 'Datenschutzerklärung von Ihr Malerservice Drews: Art, Umfang und Zweck der Verarbeitung personenbezogener Daten auf dieser Website und Ihre Rechte.',
'blocks' => $rechtsseite('datenschutz', 'Datenschutz', $inhalte['datenschutz']),
], 'Datenschutz | Ihr Malerservice Drews');
$fehlerId = $anlegen('404', [
'schemaVersion' => $SCHEMA, 'title' => 'Seite nicht gefunden',
'description' => 'Die gesuchte Seite gibt es nicht oder sie wurde verschoben.',
'blocks' => [
$seitenkopf('fehler', $seitenbilder['hero-1'], 'Fehler 404', 'Hoppla! Diese Seite wurde nicht gefunden.', 'Es sieht so aus, als ob an dieser Stelle nichts gefunden wurde. Über die Startseite finden Sie zurück.', '60vh', '#050505', 0.68, [
$button('fehler-knopf', 'Zur Startseite', '/', 'gold', false, ['desktop' => ['margin' => ['top' => '14px', 'left' => 'auto', 'right' => 'auto']]]),
]),
],
]);
$db->executeStatement('UPDATE page SET robots = ? WHERE id = ?', ['noindex', $fehlerId]);
// ---------------------------------------------------------------------------------------------
// Beiträge: 5 Mitteilungen und 26 Projekte, jeweils mit Bildkopf, Text, Galerie, Nachbarn, Aufruf
// ---------------------------------------------------------------------------------------------
$beitragAnlegen = static function (array $b, int $nummer) use ($pages, $posts, $db, $redirects, $hochladen, $section, $column, $heading, $text, $bild, $button, $fx, $ecken, $seiten, $SCHEMA, $h2Mitte, &$erstellt): void {
// Block-IDs müssen mit einem Buchstaben beginnen und kurz bleiben - die Adresse eines Beitrags tut beides nicht immer.
$p = 'beitrag-'.$nummer;
// Beiträge ohne Text bekommen einen Satz für Suche und Vorschau; leere Absätze zählen nicht als Text.
$inhalt = '' === trim(strip_tags($b['content'])) ? '' : $b['content'];
$beschreibung = '' !== $b['description'] ? $b['description'] : sprintf('„%s“ – ein Projekt von Ihr Malerservice Drews, Malermeister Axel Drews in Gernsbach.', $b['title']);
$bilder = [];
foreach ($b['images'] as $i => $datei) {
$bilder[] = $hochladen($datei, $b['title'].(0 === $i ? '' : ' – Bild '.($i + 1)), $b['slug'].(0 === $i ? '' : '-'.($i + 1)));
}
$kopfbild = $bilder[0];
$bloecke = [
$section($p.'-kopf', [
$column($p.'-kopf-inhalt', [
$fx($heading($p.'-h1', $b['title'], 1, ['desktop' => ['fontSize' => '46px', 'fontWeight' => '700', 'lineHeight' => 1.15, 'color' => '#ffffff', 'margin' => ['bottom' => '0px'], 'textShadowY' => '2px', 'textShadowBlur' => '20px', 'textShadowColor' => '#00000066'], 'tablet' => ['fontSize' => '36px'], 'mobile' => ['fontSize' => '30px']]), 'rise'),
], ['desktop' => ['maxWidth' => '1100px']]),
], [
'desktop' => ['backgroundImage' => $kopfbild['id'], 'backgroundSize' => 'cover', 'backgroundPosition' => 'center', 'gradientFrom' => '#0a0a0a33', 'gradientTo' => '#0a0a0ad9', 'gradientAngle' => 180, 'color' => '#ffffff', 'minHeight' => '62vh', 'display' => 'flex', 'alignItems' => 'flex-end', 'padding' => ['top' => '120px', 'bottom' => '50px']],
'mobile' => ['minHeight' => '48vh', 'padding' => ['top' => '90px', 'bottom' => '36px']],
]),
];
if ('' !== $inhalt) {
$bloecke[] = $section($p.'-text', [
$column($p.'-text-spalte', [
$text($p.'-inhalt', $inhalt, ['desktop' => ['color' => '#333333', 'fontSize' => '17px', 'lineHeight' => 1.85]], "& p{margin:0 0 20px}\n& p:last-child{margin-bottom:0}\n& strong{color:#2a2a2a}\n& a{color:#8a6a2f;text-decoration:underline}"),
], ['desktop' => ['maxWidth' => '900px', 'margin' => ['left' => 'auto', 'right' => 'auto']]]),
], ['desktop' => ['padding' => ['top' => '80px', 'bottom' => '80px']], 'mobile' => ['padding' => ['top' => '50px', 'bottom' => '50px']]]);
}
$bloecke[] = $section($p.'-galerie-abschnitt', [
$heading($p.'-galerie-titel', 'news' === $b['kind'] ? 'Bilder' : 'Projektbilder', 2, ['desktop' => [...$h2Mitte['desktop'], 'fontSize' => '30px', 'margin' => ['bottom' => '50px']], 'mobile' => ['fontSize' => '26px', 'margin' => ['bottom' => '30px']]]),
['id' => $p.'-galerie', 'type' => 'gallery', 'props' => ['lightbox' => true], 'children' => array_map(
static fn (array $foto, int $i): array => $bild($p.'-bild-'.($i + 1), $foto, $b['title'].(0 === $i ? '' : ' – Bild '.($i + 1)), ['desktop' => ['maxWidth' => 0 === $i ? '920px' : '450px', 'imageHeight' => '100%', 'objectFit' => 'cover', 'imageRadius' => $ecken('12px'), 'margin' => $seiten('0px')]], null, "& img{aspect-ratio:1/1;transition:transform .5s ease}\n&:hover img{transform:scale(1.05)}", true),
$bilder, array_keys($bilder),
), 'style' => ['desktop' => ['gridColumns' => 3, 'gap' => '20px', 'maxWidth' => '1400px', 'margin' => ['left' => 'auto', 'right' => 'auto']], 'mobile' => ['gridColumns' => 2, 'gap' => '10px']],
'css' => '& > :first-child{grid-column:span 2;grid-row:span 2}'],
], ['desktop' => ['backgroundColor' => '#f8f9fa', 'padding' => ['top' => '80px', 'bottom' => '80px']], 'mobile' => ['padding' => ['top' => '50px', 'bottom' => '50px']]], null, ['width' => 'wide']);
$bloecke[] = $section($p.'-nachbarn', [
['id' => $p.'-navigation', 'type' => 'postnav', 'props' => ['previousLabel' => '← Vorheriges Projekt', 'nextLabel' => 'Nächstes Projekt →'], 'css' => "& .post-nav-link{border-radius:12px;box-shadow:0 4px 20px rgba(0,0,0,.05);border:0}\n& .post-nav-label{color:#8a6a2f}"],
], ['desktop' => ['padding' => ['top' => '40px', 'bottom' => '40px']], 'mobile' => ['padding' => ['top' => '30px', 'bottom' => '30px']]], null, ['width' => 'wide']);
$bloecke[] = $section($p.'-aufruf', [
$column($p.'-aufruf-inhalt', [
$heading($p.'-aufruf-titel', 'Haben Sie ein ähnliches Projekt?', 2, ['desktop' => [...$h2Mitte['desktop'], 'color' => '#ffffff', 'fontSize' => '36px', 'margin' => ['bottom' => '16px']], 'mobile' => ['fontSize' => '28px']]),
$text($p.'-aufruf-text', 'Wir freuen uns darauf, mehr über Ihre Wünsche zu erfahren und Ihr Projekt professionell umzusetzen.', ['desktop' => ['color' => '#ffffffb3', 'fontSize' => '16px', 'lineHeight' => 1.8, 'textAlign' => 'center', 'maxWidth' => '600px', 'margin' => ['left' => 'auto', 'right' => 'auto', 'bottom' => '32px']]]),
$button($p.'-aufruf-knopf', 'Jetzt Kontakt aufnehmen', '/kontakt', 'gold-pille', false, ['desktop' => ['margin' => ['top' => '0px', 'left' => 'auto', 'right' => 'auto']]], 'normal'),
], ['desktop' => ['display' => 'flex', 'flexDirection' => 'column', 'alignItems' => 'center']]),
], ['desktop' => ['backgroundColor' => '#2a2a2a', 'color' => '#ffffff', 'padding' => ['top' => '90px', 'bottom' => '90px']], 'mobile' => ['padding' => ['top' => '60px', 'bottom' => '60px']]]);
// Adressen sind auf 80 Zeichen begrenzt; die eine längere der Vorlage wird gekürzt und umgeleitet.
$slug = strlen($b['slug']) > 80 ? substr($b['slug'], 0, strrpos(substr($b['slug'], 0, 80), '-')) : $b['slug'];
$id = $pages->createPage($slug, null, 'post', [
'schemaVersion' => $SCHEMA, 'title' => $b['title'], 'description' => $beschreibung,
'blocks' => $bloecke,
]);
$seite = $db->fetchAssociative('SELECT version FROM page WHERE id = ?', [$id]);
$posts->saveMetadata($id, [
'excerpt' => $b['excerpt'], 'author' => '', 'publishedAt' => $b['date'], 'featuredMediaId' => $kopfbild['id'], 'ogMediaId' => $kopfbild['id'],
'seoTitle' => $b['title'].' | Ihr Malerservice Drews', 'robots' => 'index',
], ['news' === $b['kind'] ? 'Aktuelles' : 'Projekte'], [], (int) $seite['version']);
$seite = $db->fetchAssociative('SELECT draft_revision_id, version FROM page WHERE id = ?', [$id]);
$pages->publish($id, $seite['draft_revision_id'], (int) $seite['version']);
$erstellt[$b['slug']] = $id;
if ($slug !== $b['slug']) {
$redirects->save('/'.$b['slug'], '/'.$slug, 301);
}
echo 'Beitrag angelegt: /'.$slug.' ('.count($bilder)." Bilder)\n";
};
foreach ($inhalte['beitraege'] as $i => $beitrag) {
$beitragAnlegen($beitrag, $i + 1);
}
// ---------------------------------------------------------------------------------------------
// Menüs, Einstellungen, Weiterleitungen, Konto
// ---------------------------------------------------------------------------------------------
$seite = static fn (string $label, string $slug, string $anchor = ''): array => ['label' => $label, 'type' => 'page', 'pageId' => $erstellt[$slug], 'anchor' => $anchor, 'children' => []];
$hauptmenue = [
$seite('Home', 'home'),
$seite('Über Uns', 'home', 'ueber-uns'),
$seite('Aktuelles', 'aktuelles'),
$seite('Unsere Projekte', 'unsere-projekte'),
$seite('Kunstmalerei', 'kunstmalerei'),
$seite('Kontakt', 'kontakt'),
];
$menus->save('header', 'Hauptnavigation', $hauptmenue, 0);
$menus->save('footer', 'Fußzeile', $hauptmenue, 0);
$menus->save('legal', 'Rechtliches', [$seite('Impressum', 'impressum'), $seite('Datenschutz', 'datenschutz')], 0);
echo "Menüs angelegt\n";
$settings->assignNotFoundPage($fehlerId, '');
$settings->save([
'legalName' => 'Ihr Malerservice Drews',
'description' => 'Malermeister Axel Drews in Gernsbach: Innenausbau und Raumgestaltung, Fassadenarbeiten, Restaurierung und Denkmalpflege sowie Kunstmalerei. Seit über 60 Jahren erstklassiges Malerhandwerk in Gernsbach und Mittelbaden, offizieller Little-Greene-Partner.',
'phone' => $telefon, 'email' => $mail,
'street' => 'Am Bachgarten 1', 'postalCode' => '76593', 'city' => 'Gernsbach', 'country' => 'DE',
'social' => ['instagram' => 'https://www.instagram.com/malerservicedrews/'],
'hours' => [...array_fill_keys(['Monday', 'Tuesday', 'Wednesday', 'Thursday'], ['opens' => '07:00', 'closes' => '16:30']), 'Friday' => ['opens' => '07:00', 'closes' => '13:00']],
'areaServed' => implode("\n", ['Gernsbach', 'Loffenau', 'Gaggenau', 'Baden-Baden', 'Rastatt', 'Kuppenheim', 'Bühl', 'Murgtal', 'Mittelbaden']),
'localBusiness' => true, 'llmsTxt' => true,
'faviconMediaId' => $seitenbilder['favicon']['id'],
'stickyHeader' => true, 'headerOverlay' => false,
'motion' => 'always',
'homePath' => 'home', 'privacyPath' => 'datenschutz', 'imprintPath' => 'impressum',
// Karte und Videos laden erst nach Einwilligung; deshalb die Frage als Leiste im Zuschnitt der Website.
'consentBanner' => true, 'consentGroups' => ['external'], 'consentLayout' => 'leiste', 'consentShape' => 'eckig',
'consentTitle' => 'Externe Inhalte', 'consentText' => 'Die Google-Karte auf der Kontaktseite und die Videos der Kunstmalerei werden von anderen Anbietern geladen. Sie entscheiden, ob das geschehen darf.',
'consentColor' => '#111111', 'consentInk' => '#ffffff', 'consentAccent' => '@gold', 'consentAccentInk' => '#111111',
'scrollTop' => true, 'scrollTopShape' => 'eckig', 'scrollTopColor' => '@gold', 'scrollTopInk' => '@tinte',
'postMetaHeader' => false,
]);
echo "Einstellungen gespeichert\n";
foreach (['/about-us' => '/home', '/innenaustattung' => '/unsere-projekte', '/little-greene' => '/exklusiv-in-mittelbaden-wir-sind-offizieller-little-greene-partner', '/blocks/footer' => '/home'] as $von => $nach) {
$redirects->save($von, $nach, 301);
}
echo "Weiterleitungen angelegt\n";
$passwort = bin2hex(random_bytes(12));
$db->insert('cms_user', ['id' => bin2hex(random_bytes(16)), 'username' => 'umut', 'password_hash' => password_hash($passwort, PASSWORD_BCRYPT), 'roles' => '["ROLE_ADMIN"]']);
echo "\nFertig.\nVerwaltung: Benutzer „umut“, Passwort: $passwort\n";