Forms gained steps, conditions, image choices, number fields with units and a summary step; the DEEG price finder uses all of it. Plugins are manifest plus Twig: blocks, settings, containers, routes, presets and theme packs, switched per installation. The review backlog is done: archive pages render through the normal page pipeline, forms and post lists work inside areas and sections, repeated sections get their own ids, breakpoints and colours come from the palette, backup and update work on MySQL and lock each other out. The task worker no longer shortens a process that has no time limit: set_time_limit() sets the limit instead of extending it, which turned an unlimited CLI run into eighty seconds and killed the full test suite far away from the scheduler. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
997 lines
76 KiB
PHP
997 lines
76 KiB
PHP
<?php
|
||
|
||
/**
|
||
* Baut die Website „DEEG – Immobilien & Hausverwaltung in Freudenstadt“ als Inhalt dieses CMS auf.
|
||
*
|
||
* Vorlage ist das gelieferte Paket „Immobilien-DEEG-Website.zip“ (15.09.2026): ein Onepager aus
|
||
* index.html, style.css und main.js mit dem unveränderten DEEG-Logo. Wortlaut, Farben (Logo-Blau
|
||
* #0081c7, Anthrazit #343a40, helle Fläche #f5fafd), Schriftgrößen, Abstände und die Reihenfolge
|
||
* der Abschnitte sind daraus übernommen. Gebaut ist alles aus gewöhnlichen Bausteinen – kein
|
||
* eigener Baustein, kein Plugin, kein eigenes Skript, keine externe Schrift (Arial wie die Vorlage).
|
||
*
|
||
* Bewusste Abweichungen:
|
||
* - Kontakt und Bewertungsanfrage sind zwei serverseitige Formulare dieses CMS („kontakt“ und
|
||
* „bewertung“ – ein Preisfinder in drei Schritten mit Feldern je Objektart und einer
|
||
* Zusammenfassung). Die Vorlage verlinkt dafür noch auf die bisherigen Seiten unter
|
||
* www.immobiliendeeg.de; hier landen die Anfragen in der Verwaltung und per E-Mail.
|
||
* - Nur „Aktuelle Angebote ansehen“ zeigt weiter auf www.immobiliendeeg.de/immobilien/: die
|
||
* Immobilien-Datenbank ist nicht Teil des Pakets.
|
||
* - Impressum und Datenschutz sind eigene Seiten. Register und Vertretung stammen vom Impressum
|
||
* der laufenden Website (15.09.2026); was nur DEEG beantworten kann, steht als „NOCH ZU PRÜFEN“.
|
||
* - Blau als Fläche mit weißer Schrift trägt #0076b6 statt #0081c7 (4,9:1 statt 4,2:1), kleine
|
||
* blaue Schrift auf Weiß #006aa3. Das Logo-Blau bleibt für Linien und große Überschriften.
|
||
*
|
||
* 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-immobilien-deeg.sh).
|
||
* Erstes Argument: der Ordner mit logo-deeg.png, architecture.jpg und architecture-detail.jpg.
|
||
*/
|
||
|
||
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\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, 'immobilien-deeg')) {
|
||
fwrite(STDERR, "Sicherung: DATABASE_URL muss auf die DEEG-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);
|
||
}
|
||
|
||
$media = new MediaLibrary($db, $mediaDirectory);
|
||
$settings = new SiteSettings($db, $media);
|
||
$pages = new PageRepository($db, new DocumentValidator(), $settings);
|
||
$partials = new PartialRepository($db, new DocumentValidator());
|
||
$menus = new MenuRepository($db, $settings);
|
||
$forms = new FormRepository($db);
|
||
$theme = new Theme($db);
|
||
|
||
$firma = 'Deeg Hausverwaltung und Immobilien GmbH';
|
||
$mail = 'deeg@immobiliendeeg.de';
|
||
$telefon = '07441 84542';
|
||
$telHref = 'tel:+49744184542';
|
||
$angebote = 'https://www.immobiliendeeg.de/immobilien/';
|
||
$route = 'https://www.google.com/maps/search/?api=1&query=Ringstra%C3%9Fe+30+72250+Freudenstadt';
|
||
$SCHEMA = 23;
|
||
|
||
// ---------------------------------------------------------------------------------------------
|
||
// Bausteine
|
||
// ---------------------------------------------------------------------------------------------
|
||
|
||
$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'];
|
||
$nurUnten = static fn (string $w): array => ['top' => '0px', 'right' => '0px', 'bottom' => $w, 'left' => '0px'];
|
||
$nurLinks = static fn (string $w): array => ['top' => '0px', 'right' => '0px', 'bottom' => '0px', 'left' => $w];
|
||
$obenUnten = static fn (string $w): array => ['top' => $w, 'right' => '0px', 'bottom' => $w, 'left' => '0px'];
|
||
|
||
$section = static function (string $id, array $children, array $style = [], ?string $anchor = null): array {
|
||
$block = ['id' => $id, 'type' => 'section', 'children' => $children, 'style' => $style];
|
||
if (null !== $anchor) {
|
||
$block['anchor'] = $anchor;
|
||
}
|
||
|
||
return $block;
|
||
};
|
||
|
||
/** Der Rhythmus der Vorlage: 108 px am Schreibtisch, 80 auf dem Tablet, 65 auf dem Telefon. */
|
||
$abschnitt = static function (string $id, array $children, array $style = [], ?string $anchor = null) use ($section): array {
|
||
$basis = [
|
||
'desktop' => ['padding' => ['top' => '108px', 'bottom' => '108px']],
|
||
'tablet' => ['padding' => ['top' => '80px', 'bottom' => '80px']],
|
||
'mobile' => ['padding' => ['top' => '65px', 'bottom' => '65px']],
|
||
];
|
||
foreach ($style as $device => $values) {
|
||
$basis[$device] = [...($basis[$device] ?? []), ...$values];
|
||
}
|
||
|
||
return $section($id, $children, $basis, $anchor);
|
||
};
|
||
|
||
$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;
|
||
};
|
||
|
||
/** Eine Zeile, die nebeneinander stellt statt zu rastern – Kleinzeile, Aktionen, Leiste, Fuß. */
|
||
$zeile = static function (string $id, array $children, string $gap, array $extra = [], array $mobil = [], array $tablet = []) use ($row): array {
|
||
$style = ['desktop' => ['display' => 'flex', 'alignItems' => 'center', 'gap' => $gap, 'margin' => ['top' => '0px'], ...$extra]];
|
||
if ([] !== $tablet) {
|
||
$style['tablet'] = $tablet;
|
||
}
|
||
if ([] !== $mobil) {
|
||
$style['mobile'] = $mobil;
|
||
}
|
||
|
||
return $row($id, $children, [], $style);
|
||
};
|
||
|
||
$column = static function (string $id, array $children, array $style = [], string $sichtbarkeit = 'all', ?string $anchor = null, string $css = ''): array {
|
||
$block = ['id' => $id, 'type' => 'column', 'children' => $children];
|
||
if ([] !== $style) {
|
||
$block['style'] = $style;
|
||
}
|
||
if ('all' !== $sichtbarkeit) {
|
||
$block['layout'] = ['visibility' => $sichtbarkeit];
|
||
}
|
||
if (null !== $anchor) {
|
||
$block['anchor'] = $anchor;
|
||
}
|
||
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: der kurze Strich vor der Kleinzeile, der Verlauf über 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 ohne den Pfeil des Bausteins: die Vorlage kommt ausdrücklich ohne Pfeile aus. */
|
||
$button = static function (string $id, string $text, string $href, array $style = []): array {
|
||
return ['id' => $id, 'type' => 'button', 'props' => ['text' => $text, 'href' => $href], 'style' => $style, 'css' => '& span{display:none}'];
|
||
};
|
||
|
||
$bild = static function (string $id, array $eintrag, string $alt, array $style = [], ?string $href = null, string $css = ''): 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';
|
||
}
|
||
|
||
$block = ['id' => $id, 'type' => 'image', 'props' => $props, '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];
|
||
};
|
||
|
||
/**
|
||
* Setzt die Einblendungen nach einer Liste, statt sie über das ganze Dokument zu streuen.
|
||
*
|
||
* @param array<string, array{0: string, 1?: string}> $plan Block-ID => [Art, Verzögerung]
|
||
*/
|
||
$einblenden = static function (array $dokument, array $plan): array {
|
||
$gehen = function (array $bloecke) use (&$gehen, $plan): array {
|
||
foreach ($bloecke as $i => $block) {
|
||
if (isset($plan[$block['id'] ?? ''])) {
|
||
[$art, $verzug] = [...$plan[$block['id']], 'none'];
|
||
$bloecke[$i]['layout'] = [...($block['layout'] ?? []), 'effects' => ['entrance' => $art, 'delay' => $verzug]];
|
||
}
|
||
if (isset($block['children'])) {
|
||
$bloecke[$i]['children'] = $gehen($block['children']);
|
||
}
|
||
}
|
||
|
||
return $bloecke;
|
||
};
|
||
$dokument['blocks'] = $gehen($dokument['blocks']);
|
||
|
||
return $dokument;
|
||
};
|
||
|
||
// Wiederkehrende Gestaltungswerte der Vorlage.
|
||
$h2Stil = ['desktop' => ['fontWeight' => '400', 'fontSize' => '45px', 'lineHeight' => 1.16, 'letterSpacing' => '-0.045em', 'margin' => ['bottom' => '26px']], 'tablet' => ['fontSize' => '38px'], 'mobile' => ['fontSize' => '35px']];
|
||
$h3Stil = ['desktop' => ['fontWeight' => '400', 'fontSize' => '24px', 'lineHeight' => 1.3, 'letterSpacing' => '-0.035em', 'margin' => ['bottom' => '18px']], 'tablet' => ['fontSize' => '22px']];
|
||
$fliess = ['desktop' => ['color' => '@text', 'fontSize' => '16px', 'lineHeight' => 1.85, 'margin' => ['bottom' => '20px']]];
|
||
$kleinStil = ['desktop' => ['fontSize' => '12px', 'fontWeight' => '700', 'letterSpacing' => '0.14em', 'lineHeight' => 1.6, 'margin' => ['bottom' => '25px']], 'mobile' => ['fontSize' => '11px', 'margin' => ['bottom' => '18px']]];
|
||
$linkCss = "& a{color:#006aa3;text-decoration:underline;text-underline-offset:3px}\n& a:hover{color:#343a40}";
|
||
$textLinkCss = "& a{display:inline-flex;align-items:center;font-size:14px;font-weight:600;border-bottom:1px solid #8d9a9f;padding-bottom:4px;text-decoration:none}\n& a:hover{color:#006aa3;border-color:#006aa3}";
|
||
$formularCss = '& .form-field label{font-size:14px;font-weight:600;color:#343a40}
|
||
& .form-field input{background:#fff;border:1px solid #c8dce8;padding:12px 13px;font-size:16px;color:#343a40}
|
||
& .form-field select{background:#fff;border:1px solid #c8dce8;padding:12px 13px;font-size:16px;color:#343a40}
|
||
& .form-field textarea{background:#fff;border:1px solid #c8dce8;padding:12px 13px;font-size:16px;color:#343a40;min-height:120px}
|
||
& .field-note{font-size:13px;color:#58666d}
|
||
& .check-row label{font-weight:400;font-size:14px;line-height:1.6}
|
||
& .cms-button{width:100%;justify-content:center;margin-top:4px}';
|
||
|
||
/** Die Kleinzeile in Versalien; im Hero mit dem kurzen blauen Strich davor. */
|
||
$kleinzeile = static fn (string $id, string $inhalt, string $farbe = '@anthrazit', string $abstand = '25px'): array => $text($id, $inhalt, [
|
||
'desktop' => [...$kleinStil['desktop'], 'color' => $farbe, 'margin' => ['bottom' => $abstand]],
|
||
'mobile' => $kleinStil['mobile'],
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------------------------
|
||
// Website, Gestaltung, Medien, Formulare
|
||
// ---------------------------------------------------------------------------------------------
|
||
|
||
$db->insert('website', ['id' => 'default', 'name' => 'DEEG Immobilien & Hausverwaltung', 'default_locale' => 'de', 'theme' => '{}']);
|
||
|
||
$theme->save(
|
||
[
|
||
['key' => 'blau', 'name' => 'Logo-Blau', 'value' => '#0081c7'],
|
||
['key' => 'blau-tief', 'name' => 'Blau als Fläche', 'value' => '#0076b6'],
|
||
['key' => 'blau-dunkel', 'name' => 'Blau dunkel', 'value' => '#006aa3'],
|
||
['key' => 'anthrazit', 'name' => 'Anthrazit', 'value' => '#343a40'],
|
||
['key' => 'text', 'name' => 'Fließtext', 'value' => '#58666d'],
|
||
['key' => 'meta', 'name' => 'Nebentext', 'value' => '#66747b'],
|
||
['key' => 'hell', 'name' => 'Helle Fläche', 'value' => '#f5fafd'],
|
||
['key' => 'linie', 'name' => 'Trennlinie', 'value' => '#dbe1e3'],
|
||
['key' => 'linie-hell', 'name' => 'Trennlinie hell', 'value' => '#e0ebf1'],
|
||
['key' => 'kante', 'name' => 'Kopfkante', 'value' => '#e9edef'],
|
||
['key' => 'papier', 'name' => 'Papier', 'value' => '#ffffff'],
|
||
],
|
||
[
|
||
// Die Vorlage lädt bewusst keine Webschrift; Arial steht auf jedem Gerät bereit.
|
||
['key' => 'body', 'name' => 'Fließtext', 'family' => 'Arial', 'source' => 'system', 'weights' => [400, 600, 700], 'fallback' => 'sans-serif'],
|
||
['key' => 'heading', 'name' => 'Überschriften', 'family' => 'Arial', 'source' => 'system', 'weights' => [400, 700], 'fallback' => 'sans-serif'],
|
||
],
|
||
['fontFamily' => 'body', 'headingFontFamily' => 'heading', 'fontSize' => '16px', 'lineHeight' => 1.6, 'color' => '@anthrazit', 'backgroundColor' => '@papier', 'linkColor' => '@anthrazit', 'containerWidth' => '1320px', 'headingScale' => 1.25, 'linkUnderline' => false],
|
||
['shape' => 'square', 'appearance' => 'solid', 'size' => 'normal', 'fontFamily' => 'inherit', 'fontSize' => 14, 'fontWeight' => 600, 'letterSpacing' => 0, 'textTransform' => 'none', 'backgroundColor' => '@blau-tief', 'color' => '@papier', 'hoverBackgroundColor' => '@blau-dunkel', 'hoverColor' => '@papier'],
|
||
);
|
||
echo "Farben, Schriften und Buttons gesetzt\n";
|
||
|
||
$medien = [];
|
||
foreach ([
|
||
'logo' => ['logo-deeg.png', 'DEEG Hausverwaltung und Immobilien'],
|
||
'hero' => ['architecture.jpg', 'Moderne Wohnarchitektur mit klaren Linien und großzügigen Fenstern'],
|
||
'detail' => ['architecture-detail.jpg', 'Wohngebäude mit charaktervoller Architektur'],
|
||
// Die Bildauswahl der Objektart im Preisfinder: einfache Piktogramme als Platzhalter,
|
||
// in der Mediathek jederzeit gegen Fotos tauschbar.
|
||
'opt-wohnung' => ['option-wohnung.png', 'Piktogramm: Wohnung in einem Gebäude'],
|
||
'opt-haus' => ['option-haus.png', 'Piktogramm: Haus'],
|
||
'opt-mfh' => ['option-mehrfamilienhaus.png', 'Piktogramm: Mehrfamilienhaus'],
|
||
'opt-grund' => ['option-grundstueck.png', 'Piktogramm: Grundstück mit Baum'],
|
||
] as $schluessel => [$datei, $alt]) {
|
||
$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' => pathinfo($datei, PATHINFO_FILENAME), 'alt' => $alt, 'archived' => false, 'version' => $eintrag['version']]);
|
||
$medien[$schluessel] = $media->find($eintrag['id']);
|
||
echo "Bild übernommen: $datei\n";
|
||
}
|
||
|
||
$einwilligung = 'Ich habe die Datenschutzhinweise gelesen. Meine Angaben werden verwendet, um meine Anfrage zu beantworten.';
|
||
|
||
$forms->save('kontakt', 'Kontaktanfrage', [
|
||
['name' => 'name', 'type' => 'text', 'label' => 'Ihr Name', 'required' => true],
|
||
['name' => 'email', 'type' => 'email', 'label' => 'E-Mail-Adresse', 'required' => true],
|
||
['name' => 'telefon', 'type' => 'phone', 'label' => 'Telefon', 'required' => false, 'help' => 'Für einen persönlichen Rückruf'],
|
||
['name' => 'anliegen', 'type' => 'select', 'label' => 'Worum geht es?', 'required' => false, 'options' => ['Verkauf', 'Vermietung', 'Verwaltung', 'Etwas anderes']],
|
||
['name' => 'nachricht', 'type' => 'textarea', 'label' => 'Ihre Nachricht', 'required' => true],
|
||
['name' => 'datenschutz', 'type' => 'consent', 'label' => $einwilligung],
|
||
], ['recipient' => $mail, 'subject' => 'Neue Nachricht über immobiliendeeg.de', 'success' => 'Vielen Dank. Ihre Nachricht ist angekommen – wir melden uns bei Ihnen.', 'replyToField' => 'email', 'buttonLabel' => 'Nachricht senden'], 0);
|
||
echo "Formular angelegt: kontakt\n";
|
||
|
||
// Die Bewertungsanfrage als Preisfinder in drei Schritten, nach dem Vorbild der laufenden
|
||
// Website: Objektart und Anlass, dann die Eckdaten je Objektart (Felder hinter Bedingungen), dann
|
||
// Lage und Kontakt, zum Schluss die Zusammenfassung. Bewusst kein Plugin - ein Formular mit
|
||
// Schritten und Bedingungen reicht, und die Anfrage liegt wie jede andere in der Verwaltung.
|
||
$wohnen = ['Wohnung', 'Haus', 'Mehrfamilienhaus'];
|
||
$bedingt = static fn (array $feld, array $werte): array => [...$feld, 'showIf' => ['field' => 'immobilienart', 'values' => $werte]];
|
||
$forms->save('bewertung', 'Bewertungsanfrage', [
|
||
['name' => 'schritt_objekt', 'type' => 'step', 'label' => 'Ihre Immobilie', 'help' => 'Womit können wir Ihnen helfen?'],
|
||
['name' => 'immobilienart', 'type' => 'radio', 'label' => 'Um welche Immobilie geht es?', 'required' => true, 'options' => ['Wohnung', 'Haus', 'Mehrfamilienhaus', 'Grundstück'],
|
||
'images' => ['Wohnung' => $medien['opt-wohnung']['id'], 'Haus' => $medien['opt-haus']['id'], 'Mehrfamilienhaus' => $medien['opt-mfh']['id'], 'Grundstück' => $medien['opt-grund']['id']]],
|
||
['name' => 'anlass', 'type' => 'radio', 'label' => 'Was haben Sie vor?', 'required' => true, 'options' => ['Verkaufen', 'Vermieten']],
|
||
|
||
['name' => 'schritt_eckdaten', 'type' => 'step', 'label' => 'Eckdaten', 'help' => 'Was wir über die Immobilie wissen sollten. Schätzwerte genügen.'],
|
||
$bedingt(['name' => 'wohnflaeche', 'type' => 'number', 'label' => 'Wohnfläche', 'required' => true, 'min' => 10, 'max' => 2000, 'unit' => 'm²'], $wohnen),
|
||
$bedingt(['name' => 'grundstueck', 'type' => 'number', 'label' => 'Grundstücksfläche', 'required' => false, 'min' => 10, 'max' => 100000, 'unit' => 'm²'], ['Haus', 'Mehrfamilienhaus']),
|
||
$bedingt(['name' => 'flaeche_grundstueck', 'type' => 'number', 'label' => 'Grundstücksfläche', 'required' => true, 'min' => 10, 'max' => 100000, 'unit' => 'm²'], ['Grundstück']),
|
||
$bedingt(['name' => 'zimmer', 'type' => 'select', 'label' => 'Zimmer', 'required' => false, 'options' => ['1', '2', '3', '4', '5', '6', '7', '8 oder mehr']], ['Wohnung', 'Haus']),
|
||
$bedingt(['name' => 'einheiten', 'type' => 'number', 'label' => 'Wohneinheiten', 'required' => true, 'min' => 2, 'max' => 200], ['Mehrfamilienhaus']),
|
||
$bedingt(['name' => 'baujahr', 'type' => 'number', 'label' => 'Baujahr', 'required' => false, 'min' => 1800, 'max' => 2026], $wohnen),
|
||
$bedingt(['name' => 'zustand', 'type' => 'select', 'label' => 'Zustand', 'required' => false, 'options' => ['Neuwertig', 'Gepflegt', 'Renovierungsbedürftig', 'Sanierungsbedürftig']], $wohnen),
|
||
$bedingt(['name' => 'einbaukueche', 'type' => 'select', 'label' => 'Einbauküche', 'required' => false, 'options' => ['ja (neuwertig)', 'ja (gebraucht)', 'keine vorhanden']], ['Wohnung']),
|
||
$bedingt(['name' => 'aufzug', 'type' => 'select', 'label' => 'Aufzug', 'required' => false, 'options' => ['ja', 'nein']], ['Wohnung']),
|
||
$bedingt(['name' => 'parken', 'type' => 'select', 'label' => 'Parkmöglichkeit', 'required' => false, 'options' => ['Tiefgarage', 'Garage', 'Doppelgarage', 'Carport', 'Stellplatz', 'mehrere', 'keine']], $wohnen),
|
||
$bedingt(['name' => 'bebaubar', 'type' => 'select', 'label' => 'Ist das Grundstück bebaubar?', 'required' => false, 'options' => ['ja', 'nein', 'unklar']], ['Grundstück']),
|
||
|
||
['name' => 'schritt_kontakt', 'type' => 'step', 'label' => 'Lage und Kontakt', 'help' => 'Damit wir die Lage einordnen und Sie erreichen können.'],
|
||
['name' => 'strasse', 'type' => 'text', 'label' => 'Straße und Hausnummer der Immobilie', 'required' => true],
|
||
['name' => 'ort', 'type' => 'text', 'label' => 'PLZ und Ort', 'required' => true],
|
||
['name' => 'name', 'type' => 'text', 'label' => 'Ihr Name', 'required' => true],
|
||
['name' => 'email', 'type' => 'email', 'label' => 'E-Mail-Adresse', 'required' => true],
|
||
['name' => 'telefon', 'type' => 'phone', 'label' => 'Telefon', 'required' => false, 'help' => 'Für Rückfragen zur Immobilie'],
|
||
['name' => 'hinweise', 'type' => 'textarea', 'label' => 'Was sollten wir noch wissen?', 'required' => false],
|
||
['name' => 'datenschutz', 'type' => 'consent', 'label' => $einwilligung],
|
||
], ['recipient' => $mail, 'subject' => 'Bewertungsanfrage über immobiliendeeg.de', 'success' => 'Vielen Dank. Ihre Bewertungsanfrage ist angekommen – wir melden uns persönlich bei Ihnen.', 'replyToField' => 'email', 'buttonLabel' => 'Bewertung anfragen', 'summary' => true], 0);
|
||
echo "Formular angelegt: bewertung\n";
|
||
|
||
// ---------------------------------------------------------------------------------------------
|
||
// Kopfbereich: helle Leiste, darunter der weiße Kopf, der beim Scrollen oben bleibt
|
||
// ---------------------------------------------------------------------------------------------
|
||
|
||
$logo = static fn (string $id, string $breite, string $mobil) => $bild($id, $medien['logo'], 'DEEG Hausverwaltung und Immobilien', [
|
||
'desktop' => ['maxWidth' => $breite, 'margin' => $seiten('0px')],
|
||
'mobile' => ['maxWidth' => $mobil],
|
||
], '/');
|
||
|
||
$kopf = [
|
||
'schemaVersion' => $SCHEMA, 'title' => 'Kopfbereich', 'description' => 'Erscheint auf jeder Seite über dem Inhalt.',
|
||
'blocks' => [
|
||
$section('kopf-leiste', [
|
||
$zeile('kopf-leiste-zeile', [
|
||
$column('kopf-leiste-ort', [
|
||
$text('kopf-leiste-ort-text', 'In Freudenstadt zuhause. Seit 1994.', ['desktop' => ['fontSize' => '13px', 'letterSpacing' => '0.02em', 'lineHeight' => 1.6, 'margin' => ['bottom' => '0px']]]),
|
||
], [], 'hide-mobile'),
|
||
$zeile('kopf-leiste-kontakt', [
|
||
$text('kopf-leiste-telefon', '<a href="'.$telHref.'">'.$telefon.'</a>', [
|
||
'desktop' => ['fontSize' => '13px', 'letterSpacing' => '0.02em', 'lineHeight' => 1.6, 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['fontSize' => '12px'],
|
||
], '& a:hover{text-decoration:underline}'),
|
||
$column('kopf-leiste-label', [
|
||
$text('kopf-leiste-label-text', '· Wir sind für Sie da', ['desktop' => ['fontSize' => '13px', 'letterSpacing' => '0.02em', 'lineHeight' => 1.6, 'color' => '@text', 'margin' => ['bottom' => '0px']]]),
|
||
], [], 'hide-mobile'),
|
||
], '5px'),
|
||
], '20px', ['justifyContent' => 'space-between'], ['justifyContent' => 'center']),
|
||
], [
|
||
'desktop' => ['backgroundColor' => '@hell', 'color' => '@anthrazit', 'borderWidth' => $nurUnten('1px'), 'borderStyle' => 'solid', 'borderColor' => '@linie-hell', 'padding' => ['top' => '9px', 'bottom' => '9px']],
|
||
]),
|
||
$section('kopf-haupt', [
|
||
$row('kopf-haupt-zeile', [
|
||
$column('kopf-marke', [$logo('kopf-logo', '113px', '100px')], ['desktop' => ['flexShrink' => 0]]),
|
||
$column('kopf-navigation', [
|
||
['id' => 'kopf-menue', 'type' => 'menu', 'props' => ['slot' => 'header', 'layout' => 'horizontal', 'collapse' => 'mobile', 'burgerLabel' => 'both'],
|
||
'style' => ['desktop' => [
|
||
'fontSize' => '14px', 'fontWeight' => '600', 'justifyContent' => 'flex-end', 'display' => 'flex',
|
||
// Der Menü-Knopf im Zuschnitt der Vorlage: feiner Rahmen, keine Rundung.
|
||
'burgerColor' => '@anthrazit', 'burgerBorderColor' => '#cbd4d6', 'burgerBorderRadius' => '0px', 'burgerFontSize' => '14px',
|
||
]],
|
||
// Der letzte Eintrag ist der blaue Knopf „Immobilie bewerten“.
|
||
'css' => "& .menu-list{gap:4px 30px;justify-content:flex-end;align-items:center}\n& .menu-list a{transition:color .2s,background .2s}\n& .menu-list a:hover{color:#006aa3;text-decoration:none}\n& .menu-list>li:last-child>a{background:#0076b6;color:#fff;padding:13px 18px}\n& .menu-list>li:last-child>a:hover{background:#006aa3;color:#fff}",
|
||
],
|
||
], ['desktop' => ['display' => 'flex', 'justifyContent' => 'flex-end', 'alignItems' => 'center']]),
|
||
], [], [
|
||
'desktop' => ['display' => 'flex', 'alignItems' => 'center', 'justifyContent' => 'space-between', 'gap' => '30px', 'minHeight' => '99px', 'margin' => ['top' => '0px']],
|
||
'tablet' => ['minHeight' => '86px'],
|
||
'mobile' => ['minHeight' => '80px'],
|
||
]),
|
||
], [
|
||
'desktop' => ['backgroundColor' => '#fffffff5', 'borderWidth' => $nurUnten('1px'), 'borderStyle' => 'solid', 'borderColor' => '@kante', 'padding' => ['top' => '0px', 'bottom' => '0px']],
|
||
]),
|
||
],
|
||
];
|
||
|
||
// ---------------------------------------------------------------------------------------------
|
||
// Fußbereich
|
||
// ---------------------------------------------------------------------------------------------
|
||
|
||
$fuss = [
|
||
'schemaVersion' => $SCHEMA, 'title' => 'Fußbereich', 'description' => 'Erscheint auf jeder Seite unter dem Inhalt.',
|
||
'blocks' => [
|
||
$section('fuss', [
|
||
$zeile('fuss-oben', [
|
||
$column('fuss-marke', [$logo('fuss-logo', '113px', '100px')], ['desktop' => ['flexShrink' => 0]]),
|
||
$column('fuss-spruch', [
|
||
$text('fuss-spruch-text', 'Gut beraten. Persönlich begleitet.', [
|
||
'desktop' => ['fontSize' => '15px', 'color' => '@text', 'textAlign' => 'center', 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['fontSize' => '13px', 'textAlign' => 'left'],
|
||
]),
|
||
], ['mobile' => ['order' => 3, 'flexBasis' => '100%']]),
|
||
$column('fuss-nachoben', [
|
||
$text('fuss-nachoben-text', '<a href="#start">Nach oben</a>', [
|
||
'desktop' => ['fontSize' => '14px', 'color' => '@blau-dunkel', 'textAlign' => 'right', 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['margin' => ['left' => 'auto']],
|
||
], "& a{color:#006aa3}\n& a:hover{text-decoration:underline}"),
|
||
]),
|
||
], '30px', ['justifyContent' => 'space-between', 'borderWidth' => $nurUnten('1px'), 'borderStyle' => 'solid', 'borderColor' => '#dce7ed', 'padding' => ['top' => '45px', 'bottom' => '36px']], ['flexWrap' => 'wrap', 'gap' => '25px', 'padding' => ['top' => '30px', 'bottom' => '25px']]),
|
||
$zeile('fuss-unten', [
|
||
$column('fuss-recht', [
|
||
// Die Farbe steht am Block selbst: der Fuß hellt kleinen Text sonst auf 3,8:1 auf.
|
||
$text('fuss-copyright', '© 2026 '.$firma, ['desktop' => ['fontSize' => '11px', 'color' => '@text', 'margin' => ['bottom' => '0px']], 'mobile' => ['fontSize' => '10px']]),
|
||
]),
|
||
$zeile('fuss-links', [
|
||
// Impressum und Datenschutz kommen aus den Einstellungen, nicht aus einem Menü.
|
||
['id' => 'fuss-rechtliches', 'type' => 'legal', 'props' => ['label' => 'Rechtliches'],
|
||
'style' => ['desktop' => ['fontSize' => '11px', 'gap' => '4px']],
|
||
'css' => '& a:hover{color:#006aa3}'],
|
||
$text('fuss-agentur', '<a href="https://kant-it.de">Website by Kant-IT Solutions</a>', ['desktop' => ['fontSize' => '11px', 'margin' => ['bottom' => '0px']]], '& a:hover{color:#006aa3}'),
|
||
], '25px', ['flexWrap' => 'wrap'], ['rowGap' => '12px', 'columnGap' => '18px', 'justifyContent' => 'flex-start']),
|
||
], '30px', ['justifyContent' => 'space-between', 'alignItems' => 'center', 'padding' => ['top' => '23px', 'bottom' => '23px'], 'color' => '@text'], ['flexDirection' => 'column', 'alignItems' => 'flex-start', 'gap' => '12px', 'padding' => ['top' => '22px', 'bottom' => '28px']]),
|
||
], [
|
||
'desktop' => ['backgroundColor' => '@hell', 'borderWidth' => $nurOben('1px'), 'borderStyle' => 'solid', 'borderColor' => '#dce7ed', 'padding' => ['top' => '0px', 'bottom' => '0px']],
|
||
]),
|
||
],
|
||
];
|
||
|
||
$partials->create('header', 'default', 'Kopfbereich', $kopf);
|
||
$partials->create('footer', 'default', 'Fußbereich', $fuss);
|
||
echo "Kopf- und Fußbereich angelegt\n";
|
||
|
||
/**
|
||
* Eine Rechtsseite: Kleinzeile, Titel, Vorspann auf heller Fläche, dann Absätze mit
|
||
* Zwischenüberschriften. Was nur DEEG beantworten kann, steht als „NOCH ZU PRÜFEN“ im Text.
|
||
*/
|
||
$rechtsseite = static function (string $praefix, string $label, string $titel, string $vorspann, array $absaetze) use ($section, $abschnitt, $row, $column, $kleinzeile, $heading, $text, $nurOben, $nurUnten, $linkCss): array {
|
||
$kopf = $section($praefix.'-kopf', [
|
||
[...$kleinzeile($praefix.'-label', $label), 'layout' => ['effects' => ['entrance' => 'fade', 'delay' => 'none']]],
|
||
[...$heading($praefix.'-h1', $titel, 1, [
|
||
'desktop' => ['fontWeight' => '400', 'fontSize' => '56px', 'lineHeight' => 1.1, 'letterSpacing' => '-0.05em', 'margin' => ['bottom' => '22px']],
|
||
'tablet' => ['fontSize' => '44px'],
|
||
'mobile' => ['fontSize' => '38px', 'margin' => ['bottom' => '16px']],
|
||
]), 'layout' => ['effects' => ['entrance' => 'rise', 'delay' => 'short']]],
|
||
[...$text($praefix.'-vorspann', $vorspann, [
|
||
'desktop' => ['maxWidth' => '640px', 'fontSize' => '18px', 'lineHeight' => 1.7, 'color' => '@text', 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['fontSize' => '16px'],
|
||
]), 'layout' => ['effects' => ['entrance' => 'rise', 'delay' => 'medium']]],
|
||
], [
|
||
'desktop' => ['backgroundColor' => '@hell', 'borderWidth' => $nurUnten('1px'), 'borderStyle' => 'solid', 'borderColor' => '@linie-hell', 'padding' => ['top' => '84px', 'bottom' => '72px']],
|
||
'tablet' => ['padding' => ['top' => '64px', 'bottom' => '56px']],
|
||
'mobile' => ['padding' => ['top' => '48px', 'bottom' => '40px']],
|
||
]);
|
||
|
||
$punkte = [];
|
||
foreach ($absaetze as $i => [$zwischentitel, $inhalt]) {
|
||
$punkte[] = $row($praefix.'-punkt-'.$i, [
|
||
$column($praefix.'-punkt-'.$i.'-titel', '' === $zwischentitel ? [] : [
|
||
$heading($praefix.'-h2-'.$i, $zwischentitel, 2, [
|
||
'desktop' => ['fontSize' => '17px', 'fontWeight' => '700', 'letterSpacing' => '-0.01em', 'lineHeight' => 1.5, 'color' => '@anthrazit', 'margin' => ['bottom' => '0px']],
|
||
]),
|
||
], [
|
||
'desktop' => ['flexBasis' => '280px', 'flexShrink' => 0],
|
||
'tablet' => ['flexBasis' => '220px'],
|
||
'mobile' => ['flexBasis' => 'auto'],
|
||
]),
|
||
$column($praefix.'-punkt-'.$i.'-text', [
|
||
$text($praefix.'-p-'.$i, $inhalt, [
|
||
'desktop' => ['fontSize' => '16px', 'lineHeight' => 1.75, 'color' => '@text', 'margin' => ['bottom' => '0px']],
|
||
], $linkCss),
|
||
], ['desktop' => ['flexGrow' => 1, 'flexBasis' => '0', 'minWidth' => '0']]),
|
||
], [], [
|
||
'desktop' => ['display' => 'flex', 'alignItems' => 'flex-start', 'gap' => '48px', 'margin' => ['top' => '0px'],
|
||
'borderWidth' => $nurOben('1px'), 'borderStyle' => 'solid', 'borderColor' => '@linie', 'padding' => ['top' => '28px', 'bottom' => '28px']],
|
||
'tablet' => ['gap' => '32px'],
|
||
'mobile' => ['flexDirection' => 'column', 'gap' => '8px', 'padding' => ['top' => '22px', 'bottom' => '22px']],
|
||
]);
|
||
}
|
||
|
||
$inhalt = $abschnitt($praefix, [
|
||
$column($praefix.'-inhalt', $punkte, ['desktop' => ['maxWidth' => '960px']]),
|
||
], ['desktop' => ['padding' => ['top' => '56px', 'bottom' => '108px']], 'mobile' => ['padding' => ['top' => '28px', 'bottom' => '65px']]]);
|
||
|
||
return [$kopf, $inhalt];
|
||
};
|
||
|
||
// ---------------------------------------------------------------------------------------------
|
||
// Startseite
|
||
// ---------------------------------------------------------------------------------------------
|
||
|
||
// Nummer, Sprungziel, Symbol, Titel, Text, Titel des Aufklappers, dessen Inhalt – die drei Karten.
|
||
$leistungen = [
|
||
['01 / VERKAUF', 'verkauf', 'home', 'Ein guter Verkauf<br>beginnt mit Vertrauen.',
|
||
'Wir kennen die Region und beobachten den Markt. Gemeinsam finden wir einen realistischen Angebotspreis und bringen Ihre Immobilie überzeugend zur Geltung.',
|
||
'So begleiten wir Ihren Verkauf',
|
||
'<ol><li><strong>Wert einschätzen.</strong> Lage, Zustand und Marktsituation bilden die Grundlage.</li><li><strong>Passend präsentieren.</strong> Wir stellen Ihre Immobilie in den passenden Angebotsmedien vor.</li><li><strong>Persönlich begleiten.</strong> Sie bleiben über die Schritte informiert – bis zum Notartermin und zur Übergabe.</li></ol><p><a href="#kontakt">Verkauf besprechen</a></p>'],
|
||
['02 / VERMIETUNG', 'vermietung', 'people', 'Die richtigen Menschen.<br>Für Ihre Immobilie.',
|
||
'Eine gute Vermietung braucht Zeit und Erfahrung. Wir unterstützen Sie dabei, passende Mietinteressenten zu finden und nehmen Ihnen Arbeit ab.',
|
||
'Mehr zur Vermietung',
|
||
'<p>Wir vermitteln seit vielen Jahren Wohnungen und kennen die Fragen, die Eigentümer beschäftigen. Wir begleiten die Suche nach geeigneten Mietern und stimmen das Vorgehen mit Ihnen ab.</p><p><a href="#kontakt">Vermietung anfragen</a></p>'],
|
||
['03 / VERWALTUNG', 'verwaltung', 'shield', 'Werte erhalten.<br>Mit Weitblick verwalten.',
|
||
'Ihr Eigentum verdient Aufmerksamkeit. Wir betreuen Wohn- und Gewerbeimmobilien zuverlässig – mit Sachkenntnis, Transparenz und persönlichem Einsatz.',
|
||
'Unsere Verwaltungsleistungen',
|
||
'<ul><li>WEG-Verwaltung für Gemeinschaften unterschiedlicher Größe</li><li>Sondereigentumsverwaltung einzelner Wohnungen und Gewerbeeinheiten</li><li>Mietverwaltung für Ihre vermieteten Immobilien</li></ul><p><a href="#kontakt">Verwaltungsangebot anfragen</a></p>'],
|
||
];
|
||
|
||
$startseite = [
|
||
'schemaVersion' => $SCHEMA,
|
||
'title' => 'DEEG Immobilien & Hausverwaltung',
|
||
'description' => 'Immobilien verkaufen, vermieten und verwalten in Freudenstadt. DEEG begleitet Eigentümer persönlich – seit 1994. Jetzt Kontakt aufnehmen.',
|
||
'blocks' => [
|
||
// 1 – Hero: Text links, das Foto rechts mit Schild, Bildzeile und blauem Aufruf.
|
||
$section('hero', [
|
||
$row('hero-zeile', [
|
||
$column('hero-text', [
|
||
$zeile('hero-label', [
|
||
$flaeche('hero-label-strich', ['desktop' => ['width' => '29px', 'height' => '1px', 'backgroundColor' => '@blau', 'flexShrink' => 0]], 'min-height:0'),
|
||
$text('hero-label-text', 'IMMOBILIEN. VERTRAUEN. DEEG.', ['desktop' => [...$kleinStil['desktop'], 'margin' => ['bottom' => '0px']], 'mobile' => ['fontSize' => '11px']]),
|
||
], '11px', ['margin' => ['top' => '0px', 'bottom' => '25px']], ['margin' => ['top' => '0px', 'bottom' => '22px']]),
|
||
$heading('hero-titel', 'Für Ihr Eigentum.<br>Für Ihr Zuhause.<br><em>Für Sie.</em>', 1, [
|
||
'desktop' => ['fontWeight' => '400', 'fontSize' => '66px', 'lineHeight' => 1.075, 'letterSpacing' => '-0.057em', 'margin' => ['bottom' => '25px']],
|
||
'tablet' => ['fontSize' => '52px'],
|
||
'mobile' => ['fontSize' => '46px', 'margin' => ['bottom' => '23px']],
|
||
], '& em{color:#0081c7;font-style:normal}'),
|
||
$text('hero-intro', 'Eine Immobilie ist mehr als ein Gebäude. Wir begleiten Sie beim Verkauf, bei der Vermietung und in der Verwaltung – persönlich und mit einem klaren Blick für Ihre Ziele.', [
|
||
'desktop' => ['maxWidth' => '440px', 'color' => '@text', 'fontSize' => '16px', 'lineHeight' => 1.85, 'margin' => ['bottom' => '30px']],
|
||
'mobile' => ['fontSize' => '15px', 'lineHeight' => 1.8, 'maxWidth' => '450px', 'margin' => ['bottom' => '24px']],
|
||
]),
|
||
$zeile('hero-aktionen', [
|
||
$column('hero-aktion-knopf', [
|
||
$button('hero-knopf', 'Lassen Sie uns sprechen', '#kontakt', ['desktop' => ['margin' => ['top' => '0px']]]),
|
||
], ['desktop' => ['flexShrink' => 0]]),
|
||
$column('hero-aktion-link', [
|
||
$text('hero-textlink', '<a href="#leistungen">DEEG kennenlernen</a>', ['desktop' => ['margin' => ['bottom' => '0px']]], $textLinkCss),
|
||
], ['desktop' => ['flexShrink' => 0]]),
|
||
], '24px', ['flexWrap' => 'wrap'], ['rowGap' => '14px', 'columnGap' => '22px']),
|
||
$zeile('hero-notiz', [
|
||
$text('hero-notiz-zahl', '30<em>+</em>', [
|
||
'desktop' => ['fontSize' => '46px', 'fontWeight' => '400', 'lineHeight' => 1, 'letterSpacing' => '-0.055em', 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['fontSize' => '38px'],
|
||
], '& em{font-size:26px;vertical-align:top;line-height:1.4;color:#0081c7;font-style:normal}'),
|
||
$text('hero-notiz-text', 'Jahre Erfahrung.<br><strong>Und immer persönlich für Sie da.</strong>', [
|
||
'desktop' => ['fontSize' => '12px', 'lineHeight' => 1.6, 'color' => '@text', 'borderWidth' => $nurLinks('1px'), 'borderStyle' => 'solid', 'borderColor' => '#d1d8da', 'padding' => ['left' => '20px'], 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['fontSize' => '11px', 'padding' => ['left' => '12px']],
|
||
], '& strong{font-weight:400;color:#343a40}'),
|
||
], '20px', ['margin' => ['top' => 'auto'], 'padding' => ['top' => '38px']], ['gap' => '12px', 'padding' => ['top' => '29px']]),
|
||
], [
|
||
'desktop' => ['display' => 'flex', 'flexDirection' => 'column', 'alignItems' => 'flex-start', 'padding' => ['top' => '41px', 'bottom' => '12px']],
|
||
'tablet' => ['padding' => ['top' => '14px', 'bottom' => '0px']],
|
||
'mobile' => ['padding' => ['top' => '10px', 'bottom' => '0px']],
|
||
]),
|
||
$column('hero-visual', [
|
||
$bild('hero-bild', $medien['hero'], 'Moderne Wohnarchitektur mit klaren Linien und großzügigen Fenstern', [
|
||
'desktop' => ['imageHeight' => '580px', 'objectFit' => 'cover', 'objectPosition' => 'center', 'margin' => $seiten('0px')],
|
||
'tablet' => ['imageHeight' => '565px'],
|
||
'mobile' => ['imageHeight' => '420px'],
|
||
], null, '& img{display:block;width:100%}'),
|
||
// Der dunkle Verlauf über der unteren Bildhälfte, damit die Bildzeile lesbar bleibt.
|
||
$flaeche('hero-verlauf', ['desktop' => ['position' => 'absolute', 'left' => '0px', 'right' => '0px', 'bottom' => '0px', 'width' => 'auto', 'height' => 'auto', 'zIndex' => 1]], 'top:50%;min-height:0;background:linear-gradient(transparent,rgba(5,23,32,.6));pointer-events:none'),
|
||
$text('hero-schild', 'RAUM FÜR NEUE PERSPEKTIVEN', [
|
||
'desktop' => ['position' => 'absolute', 'top' => '24px', 'left' => '24px', 'zIndex' => 2, 'padding' => ['top' => '8px', 'right' => '12px', 'bottom' => '8px', 'left' => '12px'], 'fontSize' => '10px', 'fontWeight' => '700', 'letterSpacing' => '0.12em', 'color' => '@papier', 'backgroundColor' => '#12272d8c', 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['top' => '20px', 'left' => '20px', 'fontSize' => '9px'],
|
||
], 'backdrop-filter:blur(8px)'),
|
||
$zeile('hero-bildzeile', [
|
||
$text('hero-bildzeile-ort', 'Freudenstadt & Umgebung', ['desktop' => ['fontSize' => '11px', 'letterSpacing' => '0.04em', 'color' => '@papier', 'margin' => ['bottom' => '0px']]]),
|
||
$text('hero-bildzeile-lage', '48° N · 8° O', ['desktop' => ['fontSize' => '11px', 'letterSpacing' => '0.04em', 'color' => '@papier', 'margin' => ['bottom' => '0px']]]),
|
||
], '20px', ['position' => 'absolute', 'left' => '27px', 'right' => '27px', 'bottom' => '27px', 'zIndex' => 2, 'justifyContent' => 'space-between'], ['left' => '20px', 'right' => '20px', 'bottom' => '20px']),
|
||
$text('hero-aufruf', '<a href="#bewertung">Was ist Ihre<br><strong>Immobilie wert?</strong></a>', [
|
||
'desktop' => ['position' => 'absolute', 'right' => '0px', 'bottom' => '83px', 'zIndex' => 3, 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['bottom' => '64px'],
|
||
], "& a{display:flex;align-items:center;gap:36px;background:#0076b6;color:#fff;padding:24px 28px;font-size:15px;line-height:1.5;text-decoration:none;transition:background .2s}\n& a:hover{background:#006aa3}\n& strong{font-weight:600}"),
|
||
], [
|
||
'desktop' => ['position' => 'relative', 'overflow' => 'hidden', 'backgroundColor' => '#d7dee0', 'minHeight' => '580px'],
|
||
'tablet' => ['minHeight' => '565px'],
|
||
'mobile' => ['minHeight' => '420px'],
|
||
]),
|
||
], ['desktop' => ['columns' => 'two'], 'mobile' => ['columns' => 'one']], [
|
||
'desktop' => ['gap' => '42px', 'alignItems' => 'stretch', 'margin' => ['top' => '0px']],
|
||
'tablet' => ['gap' => '22px'],
|
||
'mobile' => ['gap' => '27px'],
|
||
]),
|
||
], [
|
||
'desktop' => ['padding' => ['top' => '36px', 'bottom' => '42px']],
|
||
'tablet' => ['padding' => ['top' => '24px', 'bottom' => '42px']],
|
||
'mobile' => ['padding' => ['top' => '14px', 'bottom' => '27px']],
|
||
], 'start'),
|
||
|
||
// 2 – Die Leiste mit den drei Leistungen.
|
||
$section('leiste', [
|
||
$zeile('leiste-zeile', [
|
||
$column('leiste-satz', [
|
||
$text('leiste-satz-text', 'Ihr Eigentum in guten Händen.', ['desktop' => ['fontSize' => '13px', 'color' => '@meta', 'margin' => ['bottom' => '0px']]]),
|
||
], ['desktop' => ['flexGrow' => 1.5, 'flexBasis' => '0']], 'hide-mobile'),
|
||
...array_map(
|
||
static fn (array $l, int $i): array => $column('leiste-'.($i + 1), [
|
||
$text('leiste-'.($i + 1).'-link', '<a href="#'.$l[1].'">'.$l[0].' <em>0'.($i + 1).'</em></a>', [
|
||
'desktop' => ['fontSize' => '14px', 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['fontSize' => '13px'],
|
||
], "& a{display:flex;justify-content:space-between;align-items:center;gap:10px;font-weight:600;text-decoration:none;transition:color .2s}\n& a:hover{color:#0076b6}\n& em{font-style:normal;font-size:11px;font-weight:400;color:#66747b}"),
|
||
], [
|
||
'desktop' => ['flexGrow' => 1, 'flexBasis' => '0', 'borderWidth' => $nurLinks('1px'), 'borderStyle' => 'solid', 'borderColor' => '@linie', 'padding' => ['top' => '4px', 'right' => '27px', 'bottom' => '4px', 'left' => '27px']],
|
||
'tablet' => ['padding' => ['top' => '4px', 'right' => '17px', 'bottom' => '4px', 'left' => '17px']],
|
||
'mobile' => ['padding' => ['top' => '5px', 'right' => '12px', 'bottom' => '5px', 'left' => '12px']],
|
||
]),
|
||
[['Verkaufen', 'verkauf'], ['Vermieten', 'vermietung'], ['Verwalten', 'verwaltung']], [0, 1, 2],
|
||
),
|
||
], '0px', ['alignItems' => 'stretch']),
|
||
], [
|
||
'desktop' => ['borderWidth' => $obenUnten('1px'), 'borderStyle' => 'solid', 'borderColor' => '@linie', 'padding' => ['top' => '21px', 'bottom' => '21px']],
|
||
'mobile' => ['padding' => ['top' => '16px', 'bottom' => '16px']],
|
||
]),
|
||
|
||
// 3 – Leistungen: Kopfzeile, darunter drei Karten mit Aufklapper.
|
||
$abschnitt('leistungen-abschnitt', [
|
||
$zeile('leistungen-kopf', [
|
||
$column('leistungen-kopf-titel', [
|
||
$kleinzeile('leistungen-label', 'WAS WIR FÜR SIE TUN'),
|
||
$heading('leistungen-h2', 'Drei Leistungen.<br>Ein verlässlicher Partner.', 2, [...$h2Stil, 'desktop' => [...$h2Stil['desktop'], 'margin' => ['bottom' => '0px']]]),
|
||
]),
|
||
$column('leistungen-kopf-text', [
|
||
$text('leistungen-intro', 'Ob neue Pläne oder bestehendes Eigentum: Wir kümmern uns um Ihre Immobilie, damit Sie sich auf das Wesentliche konzentrieren können.', [
|
||
'desktop' => ['maxWidth' => '360px', 'fontSize' => '16px', 'lineHeight' => 1.85, 'color' => '@text', 'margin' => ['bottom' => '4px']],
|
||
'tablet' => ['maxWidth' => '280px'],
|
||
'mobile' => ['maxWidth' => '100%', 'margin' => ['top' => '23px', 'bottom' => '0px']],
|
||
]),
|
||
]),
|
||
], '45px', ['alignItems' => 'flex-end', 'justifyContent' => 'space-between', 'margin' => ['top' => '0px', 'bottom' => '44px']], ['flexDirection' => 'column', 'alignItems' => 'flex-start', 'gap' => '0px', 'margin' => ['top' => '0px', 'bottom' => '30px']], ['gap' => '28px']),
|
||
$row('leistungen-raster', array_map(
|
||
static function (array $l, int $i) use ($column, $zeile, $text, $symbol, $heading, $h3Stil, $linkCss, $nurOben): array {
|
||
$n = $i + 1;
|
||
|
||
return $column('leistung-'.$n, [
|
||
$zeile('leistung-'.$n.'-kopf', [
|
||
$text('leistung-'.$n.'-nummer', $l[0], ['desktop' => ['fontSize' => '11px', 'fontWeight' => '700', 'letterSpacing' => '0.11em', 'margin' => ['bottom' => '0px']]]),
|
||
$symbol('leistung-'.$n.'-symbol', $l[2], 40, ['desktop' => ['color' => '@anthrazit', 'flexShrink' => 0], 'mobile' => ['width' => '34px', 'height' => '34px']]),
|
||
], '12px', ['justifyContent' => 'space-between', 'margin' => ['top' => '0px', 'bottom' => '34px']], ['margin' => ['top' => '0px', 'bottom' => '24px']]),
|
||
$heading('leistung-'.$n.'-titel', $l[3], 3, $h3Stil),
|
||
$text('leistung-'.$n.'-text', $l[4], [
|
||
'desktop' => ['fontSize' => '16px', 'lineHeight' => 1.85, 'color' => '@text', 'minHeight' => '155px', 'margin' => ['bottom' => '0px']],
|
||
'tablet' => ['minHeight' => '0px'],
|
||
'mobile' => ['minHeight' => '0px'],
|
||
]),
|
||
['id' => 'leistung-'.$n.'-mehr', 'type' => 'accordion', 'props' => ['faq' => false],
|
||
'style' => ['desktop' => ['borderWidth' => $nurOben('1px'), 'borderStyle' => 'solid', 'borderColor' => '#dce7ed', 'margin' => ['top' => '22px']]],
|
||
'children' => [
|
||
['id' => 'leistung-'.$n.'-punkt', 'type' => 'accordionitem', 'props' => ['title' => $l[5], 'open' => false],
|
||
'css' => "& summary{border:0;border-radius:0;background:transparent;padding:17px 0;font-size:14px;font-weight:600}\n& .accordion-body{padding:0 0 12px}",
|
||
'children' => [
|
||
$text('leistung-'.$n.'-details', $l[6], ['desktop' => ['fontSize' => '14px', 'lineHeight' => 1.75, 'color' => '@text', 'margin' => ['bottom' => '0px']]], "& li{margin:12px 0}\n& ol{padding-left:18px}\n& ul{padding-left:18px}\n& strong{color:#343a40}\n".$linkCss),
|
||
],
|
||
],
|
||
],
|
||
],
|
||
], [
|
||
'desktop' => ['backgroundColor' => '@hell', 'borderWidth' => $nurOben('2px'), 'borderStyle' => 'solid', 'borderColor' => '#dce7ed', 'padding' => ['top' => '32px', 'right' => '29px', 'bottom' => '18px', 'left' => '29px']],
|
||
'tablet' => ['padding' => ['top' => '26px', 'right' => '26px', 'bottom' => '12px', 'left' => '26px']],
|
||
'mobile' => ['padding' => ['top' => '28px', 'right' => '25px', 'bottom' => '12px', 'left' => '25px']],
|
||
], 'all', $l[1], "transition:border-color .3s\n&:hover{border-color:#0081c7}");
|
||
},
|
||
$leistungen, array_keys($leistungen),
|
||
), ['desktop' => ['columns' => 'three'], 'tablet' => ['columns' => 'one'], 'mobile' => ['columns' => 'one']], [
|
||
'desktop' => ['gap' => '24px', 'margin' => ['top' => '0px']],
|
||
'tablet' => ['gap' => '12px'],
|
||
'mobile' => ['gap' => '17px'],
|
||
]),
|
||
], [], 'leistungen'),
|
||
|
||
// 4 – Bewertung: blaue Fläche, rechts die weiße Karte mit der Bewertungsanfrage.
|
||
$section('bewertung-abschnitt', [
|
||
$row('bewertung-zeile', [
|
||
$column('bewertung-text', [
|
||
$kleinzeile('bewertung-label', 'EINE GUTE ENTSCHEIDUNG BEGINNT MIT KLARHEIT', '@papier'),
|
||
$heading('bewertung-h2', 'Was steckt in<br>Ihrer Immobilie?', 2, [
|
||
'desktop' => ['fontWeight' => '400', 'fontSize' => '53px', 'lineHeight' => 1.16, 'letterSpacing' => '-0.045em', 'color' => '@papier', 'margin' => ['bottom' => '26px']],
|
||
'tablet' => ['fontSize' => '42px'],
|
||
'mobile' => ['fontSize' => '40px'],
|
||
]),
|
||
$text('bewertung-intro', 'Lage, Zustand und Ausstattung machen den Unterschied. Geben Sie uns die Eckdaten – wir helfen Ihnen, den Wert Ihrer Immobilie einzuschätzen.', [
|
||
'desktop' => ['maxWidth' => '425px', 'color' => '@papier', 'fontSize' => '16px', 'lineHeight' => 1.8, 'margin' => ['bottom' => '0px']],
|
||
]),
|
||
$zeile('bewertung-punkte', [
|
||
$text('bewertung-punkt-1', '✓ Kostenlose Ersteinschätzung', ['desktop' => ['fontSize' => '12px', 'color' => '@papier', 'margin' => ['bottom' => '0px']]]),
|
||
$text('bewertung-punkt-2', '✓ Persönliche Beratung', ['desktop' => ['fontSize' => '12px', 'color' => '@papier', 'margin' => ['bottom' => '0px']]]),
|
||
], '24px', ['flexWrap' => 'wrap', 'margin' => ['top' => '28px']], ['rowGap' => '8px', 'columnGap' => '20px']),
|
||
]),
|
||
$column('bewertung-karte', [
|
||
$text('bewertung-karte-label', 'IHRE BEWERTUNGSANFRAGE IN DREI SCHRITTEN', ['desktop' => ['fontSize' => '14px', 'letterSpacing' => '0.12em', 'color' => '@blau-dunkel', 'margin' => ['bottom' => '0px']], 'mobile' => ['fontSize' => '12px']]),
|
||
$heading('bewertung-karte-titel', 'Um welche Immobilie geht es?', 3, [
|
||
'desktop' => ['fontWeight' => '400', 'fontSize' => '22px', 'letterSpacing' => '-0.02em', 'lineHeight' => 1.3, 'margin' => ['top' => '18px', 'bottom' => '24px']],
|
||
]),
|
||
['id' => 'bewertung-formular', 'type' => 'form', 'props' => ['form' => 'bewertung'], 'css' => $formularCss],
|
||
$text('bewertung-karte-hinweis', 'Kostenlos und unverbindlich. Vor dem Absenden sehen Sie alle Angaben noch einmal – mehr zum Umgang damit in den <a href="/datenschutz">Datenschutzhinweisen</a>.', [
|
||
'desktop' => ['fontSize' => '14px', 'lineHeight' => 1.65, 'color' => '@text', 'margin' => ['top' => '20px', 'bottom' => '0px']],
|
||
], $linkCss),
|
||
], [
|
||
'desktop' => ['backgroundColor' => '@papier', 'color' => '@anthrazit', 'borderWidth' => $seiten('1px'), 'borderStyle' => 'solid', 'borderColor' => '@linie-hell', 'padding' => $seiten('36px')],
|
||
'tablet' => ['padding' => ['top' => '25px', 'right' => '20px', 'bottom' => '25px', 'left' => '20px']],
|
||
'mobile' => ['padding' => ['top' => '27px', 'right' => '22px', 'bottom' => '27px', 'left' => '22px']],
|
||
]),
|
||
], ['desktop' => ['columns' => 'two'], 'mobile' => ['columns' => 'one']], [
|
||
'desktop' => ['gap' => '100px', 'alignItems' => 'center', 'margin' => ['top' => '0px']],
|
||
'tablet' => ['gap' => '30px'],
|
||
'mobile' => ['gap' => '25px'],
|
||
]),
|
||
], [
|
||
'desktop' => ['backgroundColor' => '@blau-tief', 'color' => '@papier', 'padding' => ['top' => '76px', 'bottom' => '76px']],
|
||
'mobile' => ['padding' => ['top' => '55px', 'bottom' => '55px']],
|
||
], 'bewertung'),
|
||
|
||
// 5 – Über uns: Foto mit Jahreszahl links, Text rechts.
|
||
$abschnitt('ueber-uns-abschnitt', [
|
||
$row('ueber-uns-zeile', [
|
||
$column('ueber-uns-visual', [
|
||
$bild('ueber-uns-bild', $medien['detail'], 'Wohngebäude mit charaktervoller Architektur', [
|
||
'desktop' => ['imageHeight' => '500px', 'objectFit' => 'cover', 'objectPosition' => 'center', 'margin' => $seiten('0px')],
|
||
'tablet' => ['imageHeight' => '480px'],
|
||
'mobile' => ['imageHeight' => '390px'],
|
||
], null, '& img{display:block;width:100%}'),
|
||
$column('ueber-uns-seit', [
|
||
$text('ueber-uns-seit-oben', 'SEIT', ['desktop' => ['fontSize' => '10px', 'fontWeight' => '700', 'letterSpacing' => '0.14em', 'lineHeight' => 1.6, 'margin' => ['bottom' => '0px']]]),
|
||
$text('ueber-uns-seit-jahr', '1994', ['desktop' => ['fontSize' => '61px', 'fontWeight' => '400', 'letterSpacing' => '-0.06em', 'lineHeight' => 1.3, 'margin' => ['bottom' => '0px']], 'mobile' => ['fontSize' => '48px']]),
|
||
$text('ueber-uns-seit-ort', 'IN FREUDENSTADT', ['desktop' => ['fontSize' => '10px', 'fontWeight' => '700', 'letterSpacing' => '0.14em', 'lineHeight' => 1.6, 'margin' => ['bottom' => '0px']]]),
|
||
], [
|
||
'desktop' => ['position' => 'absolute', 'right' => '-24px', 'bottom' => '-23px', 'zIndex' => 1, 'backgroundColor' => '@blau-tief', 'color' => '@papier', 'display' => 'flex', 'flexDirection' => 'column', 'alignItems' => 'center', 'padding' => ['top' => '29px', 'right' => '37px', 'bottom' => '29px', 'left' => '37px']],
|
||
'tablet' => ['right' => '-12px', 'padding' => ['top' => '20px', 'right' => '27px', 'bottom' => '20px', 'left' => '27px']],
|
||
'mobile' => ['right' => '-13px', 'bottom' => '-25px', 'padding' => ['top' => '20px', 'right' => '27px', 'bottom' => '20px', 'left' => '27px']],
|
||
]),
|
||
], [
|
||
'desktop' => ['position' => 'relative', 'backgroundColor' => '#eef1f1', 'margin' => ['right' => '24px', 'bottom' => '23px']],
|
||
'tablet' => ['margin' => ['right' => '12px', 'bottom' => '23px']],
|
||
'mobile' => ['margin' => ['right' => '13px', 'bottom' => '25px']],
|
||
]),
|
||
$column('ueber-uns-text', [
|
||
$kleinzeile('ueber-uns-label', 'IN DER REGION VERWURZELT'),
|
||
$heading('ueber-uns-h2', 'Immobilien verstehen.<br>Menschen kennen.', 2, $h2Stil),
|
||
$text('ueber-uns-lead', 'Hinter jeder Immobilie stehen Menschen und persönliche Pläne. Genau dort beginnt unsere Arbeit.', [
|
||
'desktop' => ['fontSize' => '18px', 'lineHeight' => 1.6, 'color' => '@anthrazit', 'margin' => ['bottom' => '20px']],
|
||
]),
|
||
$text('ueber-uns-p1', 'Seit 1994 ist DEEG in Freudenstadt für Eigentümer von Wohn- und Gewerbeimmobilien da. Von der einzelnen Wohnung bis zur Eigentümergemeinschaft: Sie erhalten die gleiche Aufmerksamkeit und einen Ansprechpartner, der sich kümmert.', $fliess),
|
||
$text('ueber-uns-p2', 'Unser Ziel ist, den Wert Ihrer Immobilie zu erhalten und weiterzuentwickeln. Dabei zählen für uns nachvollziehbare Entscheidungen, ein gutes Miteinander und eine Zusammenarbeit auf Augenhöhe.', $fliess),
|
||
$text('ueber-uns-link', '<a href="#kontakt">Lernen wir uns kennen</a>', ['desktop' => ['margin' => ['top' => '10px', 'bottom' => '0px']]], $textLinkCss),
|
||
]),
|
||
], ['desktop' => ['columns' => 'two'], 'mobile' => ['columns' => 'one']], [
|
||
'desktop' => ['gap' => '95px', 'alignItems' => 'center', 'margin' => ['top' => '0px']],
|
||
'tablet' => ['gap' => '40px'],
|
||
'mobile' => ['gap' => '60px'],
|
||
]),
|
||
], [], 'ueber-uns'),
|
||
|
||
// 6 – Angebote: ein helles Band mit Aufruf zu den aktuellen Angeboten.
|
||
$section('angebote-abschnitt', [
|
||
$column('angebote-band', [
|
||
$zeile('angebote-zeile', [
|
||
$column('angebote-text', [
|
||
$kleinzeile('angebote-label', 'IMMOBILIENANGEBOTE', '@anthrazit', '20px'),
|
||
$heading('angebote-h2', 'Vielleicht beginnt hier<br>Ihr nächstes Kapitel.', 2, [...$h2Stil, 'desktop' => [...$h2Stil['desktop'], 'fontSize' => '40px'], 'tablet' => ['fontSize' => '34px'], 'mobile' => ['fontSize' => '32px']]),
|
||
$text('angebote-intro', 'Entdecken Sie unsere aktuellen Immobilienangebote.<br>Wir helfen Ihnen gerne bei der Suche.', [
|
||
'desktop' => ['fontSize' => '16px', 'lineHeight' => 1.8, 'color' => '@text', 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['fontSize' => '15px'],
|
||
]),
|
||
]),
|
||
$column('angebote-aktion', [
|
||
// Die Angebotsliste liegt weiter auf der laufenden Website; ein Textlink im Zuschnitt
|
||
// des hellen Buttons der Vorlage.
|
||
$text('angebote-knopf', '<a href="'.$angebote.'">Aktuelle Angebote ansehen</a>', ['desktop' => ['margin' => ['bottom' => '0px']], 'mobile' => ['width' => '100%']],
|
||
"& a{display:inline-flex;justify-content:center;align-items:center;width:100%;border:1px solid #006aa3;color:#006aa3;padding:18px 24px;font-size:14px;font-weight:600;line-height:1.4;text-decoration:none;transition:background .2s,color .2s,transform .2s}\n& a:hover{background:#0076b6;color:#fff;border-color:#0076b6;transform:translateY(-2px)}"),
|
||
], ['desktop' => ['flexShrink' => 0], 'mobile' => ['width' => '100%']]),
|
||
], '40px', ['justifyContent' => 'space-between'], ['flexDirection' => 'column', 'alignItems' => 'flex-start', 'gap' => '28px'], ['flexDirection' => 'column', 'alignItems' => 'flex-start', 'gap' => '26px']),
|
||
], [
|
||
'desktop' => ['backgroundColor' => '@hell', 'padding' => ['top' => '55px', 'right' => '60px', 'bottom' => '55px', 'left' => '60px']],
|
||
'tablet' => ['padding' => $seiten('40px')],
|
||
'mobile' => ['padding' => ['top' => '32px', 'right' => '25px', 'bottom' => '32px', 'left' => '25px']],
|
||
]),
|
||
], ['desktop' => ['padding' => ['top' => '0px', 'bottom' => '0px']]], 'angebote'),
|
||
|
||
// 7 – Kontakt: Gespräch links mit Adresse und Bürozeiten, rechts die Formularkarte.
|
||
$abschnitt('kontakt-abschnitt', [
|
||
$row('kontakt-zeile', [
|
||
$column('kontakt-text', [
|
||
$kleinzeile('kontakt-label', 'WIR FREUEN UNS AUF SIE'),
|
||
$heading('kontakt-h2', 'Ihre Immobilie.<br>Unser nächstes Gespräch.', 2, $h2Stil),
|
||
$text('kontakt-intro', 'Verkaufen, vermieten oder verwalten?<br>Erzählen Sie uns, was Sie vorhaben.', [
|
||
'desktop' => ['fontSize' => '16px', 'lineHeight' => 1.8, 'color' => '@text', 'margin' => ['bottom' => '0px']],
|
||
]),
|
||
$text('kontakt-telefon', '<a href="'.$telHref.'">'.$telefon.'</a>', [
|
||
'desktop' => ['fontSize' => '43px', 'letterSpacing' => '-0.04em', 'lineHeight' => 1.4, 'margin' => ['top' => '26px', 'bottom' => '0px']],
|
||
'tablet' => ['fontSize' => '36px'],
|
||
'mobile' => ['fontSize' => '36px'],
|
||
], "& a{text-decoration:none}\n& a:hover{color:#006aa3}"),
|
||
$text('kontakt-mail', '<a href="mailto:'.$mail.'">'.$mail.'</a>', [
|
||
'desktop' => ['fontSize' => '17px', 'color' => '#61717a', 'margin' => ['top' => '6px', 'bottom' => '0px']],
|
||
], "& a{overflow-wrap:anywhere;text-decoration:none}\n& a:hover{color:#006aa3;text-decoration:underline}"),
|
||
$zeile('kontakt-info', [
|
||
$column('kontakt-adresse', [
|
||
$text('kontakt-adresse-label', 'BESUCHEN SIE UNS', ['desktop' => [...$kleinStil['desktop'], 'margin' => ['bottom' => '12px']]]),
|
||
$text('kontakt-adresse-text', $firma.'<br>Ringstraße 30<br>72250 Freudenstadt', ['desktop' => ['fontSize' => '16px', 'lineHeight' => 1.85, 'margin' => ['bottom' => '14px']]]),
|
||
$text('kontakt-route', '<a href="'.$route.'">Route planen</a>', ['desktop' => ['margin' => ['bottom' => '0px']]], $textLinkCss),
|
||
], ['desktop' => ['flexBasis' => '0', 'flexGrow' => 1, 'minWidth' => '220px']]),
|
||
$column('kontakt-zeiten', [
|
||
$text('kontakt-zeiten-label', 'UNSERE BÜROZEITEN', ['desktop' => [...$kleinStil['desktop'], 'margin' => ['bottom' => '12px']]]),
|
||
$text('kontakt-zeiten-1', 'Montag – Freitag<br><strong>08:00 – 12:00</strong>', ['desktop' => ['fontSize' => '14px', 'lineHeight' => 1.7, 'color' => '@text', 'margin' => ['bottom' => '12px']]], '& strong{font-weight:600;color:#343a40}'),
|
||
$text('kontakt-zeiten-2', 'Montag, Dienstag & Donnerstag<br><strong>14:00 – 17:00</strong>', ['desktop' => ['fontSize' => '14px', 'lineHeight' => 1.7, 'color' => '@text', 'margin' => ['bottom' => '0px']]], '& strong{font-weight:600;color:#343a40}'),
|
||
], ['desktop' => ['flexBasis' => '0', 'flexGrow' => 1, 'minWidth' => '220px']]),
|
||
], '40px', ['alignItems' => 'flex-start', 'flexWrap' => 'wrap', 'borderWidth' => $nurOben('1px'), 'borderStyle' => 'solid', 'borderColor' => '@linie', 'padding' => ['top' => '30px'], 'margin' => ['top' => '40px']], ['gap' => '28px', 'margin' => ['top' => '30px']]),
|
||
]),
|
||
$column('kontakt-karte', [
|
||
$text('kontakt-karte-label', 'SCHREIBEN SIE UNS', ['desktop' => ['fontSize' => '11px', 'fontWeight' => '700', 'letterSpacing' => '0.14em', 'color' => '@meta', 'margin' => ['bottom' => '18px']]]),
|
||
$heading('kontakt-karte-titel', 'Was können wir<br>für Sie tun?', 3, [
|
||
'desktop' => ['fontWeight' => '400', 'fontSize' => '28px', 'lineHeight' => 1.25, 'letterSpacing' => '-0.03em', 'margin' => ['bottom' => '25px']],
|
||
]),
|
||
['id' => 'kontakt-formular', 'type' => 'form', 'props' => ['form' => 'kontakt'], 'css' => $formularCss],
|
||
$text('kontakt-formular-hinweis', 'Ihre Nachricht geht direkt an DEEG. Wir verwenden Ihre Angaben ausschließlich, um Ihre Anfrage zu beantworten – mehr dazu in den <a href="/datenschutz">Datenschutzhinweisen</a>.', [
|
||
'desktop' => ['fontSize' => '13px', 'lineHeight' => 1.65, 'color' => '@text', 'margin' => ['top' => '19px', 'bottom' => '0px']],
|
||
], $linkCss),
|
||
], [
|
||
'desktop' => ['alignSelf' => 'flex-start', 'backgroundColor' => '@papier', 'borderWidth' => ['top' => '3px', 'right' => '1px', 'bottom' => '1px', 'left' => '1px'], 'borderStyle' => 'solid', 'borderColor' => '@linie-hell', 'padding' => ['top' => '32px', 'right' => '35px', 'bottom' => '32px', 'left' => '35px'], 'shadowY' => '10px', 'shadowBlur' => '40px', 'shadowColor' => '#343a4012'],
|
||
'tablet' => ['padding' => ['top' => '28px', 'right' => '25px', 'bottom' => '28px', 'left' => '25px']],
|
||
'mobile' => ['padding' => ['top' => '28px', 'right' => '22px', 'bottom' => '28px', 'left' => '22px']],
|
||
], 'all', null, 'border-top-color:#0081c7'),
|
||
], ['desktop' => ['columns' => 'two'], 'mobile' => ['columns' => 'one']], [
|
||
'desktop' => ['gap' => '100px', 'alignItems' => 'flex-start', 'margin' => ['top' => '0px']],
|
||
'tablet' => ['gap' => '35px'],
|
||
'mobile' => ['gap' => '35px'],
|
||
]),
|
||
], [], 'kontakt'),
|
||
],
|
||
];
|
||
|
||
// ---------------------------------------------------------------------------------------------
|
||
// 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;
|
||
};
|
||
|
||
// Der Hero spielt beim Laden, alles Weitere beim Hereinscrollen – wie die Vorlage, die die
|
||
// Abschnittsköpfe, Bewertung, Über-uns-Text und Kontaktkarte einblendet.
|
||
$startseite = $einblenden($startseite, [
|
||
'hero-label' => ['fade'],
|
||
'hero-titel' => ['rise', 'short'],
|
||
'hero-intro' => ['rise', 'medium'],
|
||
'hero-aktionen' => ['rise', 'long'],
|
||
'hero-notiz' => ['fade', 'long'],
|
||
// Kein Hereinschieben von rechts: das ragt für einen Moment über den Rand hinaus.
|
||
'hero-visual' => ['fade', 'short'],
|
||
'leistungen-kopf' => ['rise'],
|
||
'leistung-1' => ['rise'],
|
||
'leistung-2' => ['rise', 'short'],
|
||
'leistung-3' => ['rise', 'medium'],
|
||
'bewertung-text' => ['rise'],
|
||
'bewertung-karte' => ['rise', 'short'],
|
||
'ueber-uns-visual' => ['fade'],
|
||
'ueber-uns-text' => ['rise', 'short'],
|
||
'angebote-band' => ['rise'],
|
||
'kontakt-text' => ['rise'],
|
||
'kontakt-karte' => ['rise', 'short'],
|
||
]);
|
||
|
||
$anlegen('home', $startseite, 'DEEG · Immobilien & Hausverwaltung in Freudenstadt', $medien['hero']['id']);
|
||
|
||
$anlegen('impressum', [
|
||
'schemaVersion' => $SCHEMA, 'title' => 'Impressum',
|
||
'description' => 'Anbieterangaben der Deeg Hausverwaltung und Immobilien GmbH in Freudenstadt.',
|
||
'blocks' => [
|
||
...$rechtsseite('impressum', 'Rechtliche Angaben', 'Impressum', 'Angaben gemäß § 5 DDG und § 18 Abs. 2 MStV.', [
|
||
['Anbieterin', $firma.'<br>Ringstraße 30<br>72250 Freudenstadt'],
|
||
['Vertreten durch', 'Furkan Kurt, Geschäftsführer'],
|
||
['Registereintrag', 'Handelsregister: HRB 430747<br>Registergericht: Amtsgericht Stuttgart'],
|
||
['Kontakt', "Telefon: <a href=\"$telHref\">$telefon</a><br>E-Mail: <a href=\"mailto:$mail\">$mail</a>"],
|
||
['Umsatzsteuer', 'NOCH ZU PRÜFEN: Umsatzsteuer-Identifikationsnummer nach § 27a UStG eintragen.'],
|
||
['Aufsichtsbehörde', 'NOCH ZU PRÜFEN: Die Vermittlung und Verwaltung von Immobilien braucht eine Erlaubnis nach § 34c GewO. Erlaubnisbehörde und Aufsicht (in der Regel die Stadt Freudenstadt oder das Landratsamt Freudenstadt) hier eintragen.'],
|
||
['Verantwortlich für den Inhalt', 'Furkan Kurt, Anschrift wie oben.'],
|
||
['Verbraucherstreitbeilegung', 'Wir sind nicht bereit und nicht verpflichtet, an einem Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen.'],
|
||
['Haftung für Inhalte', 'Als Diensteanbieter sind wir für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Wir sind jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Bei Bekanntwerden von Rechtsverletzungen entfernen wir diese Inhalte umgehend.'],
|
||
['Haftung für Links', 'Unser Angebot enthält Links zu externen Websites Dritter, auf deren Inhalte wir keinen Einfluss haben. Für diese Inhalte ist stets die jeweilige Anbieterin oder der jeweilige Anbieter verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Bei Bekanntwerden von Rechtsverletzungen entfernen wir solche Links umgehend.'],
|
||
['Urheberrecht', 'Die von uns erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechts bedürfen der schriftlichen Zustimmung. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet.'],
|
||
['Bildnachweis', 'Titelbild: Unsplash (Unsplash-Lizenz), illustrative Architekturaufnahme, kein Objekt aus unserem Angebot. Zweites Gebäudefoto: aus der bisherigen Website übernommen – NOCH ZU PRÜFEN: Urheber und Lizenz eintragen. Logo: '.$firma.'.'],
|
||
]),
|
||
],
|
||
], 'Impressum | '.$firma);
|
||
|
||
$anlegen('datenschutz', [
|
||
'schemaVersion' => $SCHEMA, 'title' => 'Datenschutz',
|
||
'description' => 'Wie die Deeg Hausverwaltung und Immobilien GmbH Daten beim Besuch der Website und bei einer Anfrage verarbeitet.',
|
||
'blocks' => [
|
||
...$rechtsseite('datenschutz', 'Ihre Daten', 'Datenschutzhinweise', 'Hier erfahren Sie, welche Daten beim Besuch dieser Website und bei Ihrer Anfrage verarbeitet werden – und welche Rechte Sie haben.', [
|
||
['1. Verantwortliche', "$firma, Ringstraße 30, 72250 Freudenstadt, vertreten durch Furkan Kurt. Telefon <a href=\"$telHref\">$telefon</a>, E-Mail <a href=\"mailto:$mail\">$mail</a>.<br><br>NOCH ZU PRÜFEN: Ob eine Datenschutzbeauftragte oder ein Datenschutzbeauftragter zu benennen ist, hängt von der Zahl der ständig mit der Verarbeitung beschäftigten Personen ab; gegebenenfalls hier die Kontaktdaten ergänzen."],
|
||
['2. Besuch dieser Website', 'Beim Aufruf verarbeitet der Hostingdienst technisch erforderliche Verbindungsdaten: IP-Adresse, Zeitpunkt, angeforderte Adresse, Browserangaben und HTTP-Status. Das dient der sicheren Bereitstellung und der Fehlersuche. Rechtsgrundlage ist unser berechtigtes Interesse an einem störungsfreien Betrieb, Art. 6 Abs. 1 lit. f DSGVO.<br><br>NOCH ZU PRÜFEN: Hostinganbieter benennen, Auftragsverarbeitungsvertrag abschließen, Verarbeitungsländer und die konkrete Speicherdauer der Serverprotokolle eintragen.'],
|
||
['3. Cookies, Schriften, externe Dienste', 'Diese Website setzt keine Analyse- oder Werbecookies. Bilder, Schriften und Gestaltung kommen vom eigenen Server; es werden keine Karten, Videos oder Schriften von Dritten nachgeladen. Deshalb gibt es auch keinen Einwilligungsdialog. Der Link „Route planen“ führt zu Google Maps; erst mit dem Klick verlassen Sie unsere Website, und es gelten die Datenschutzbestimmungen von Google. Unsere aktuellen Immobilienangebote sind auf unserer bisherigen Website unter www.immobiliendeeg.de verlinkt.'],
|
||
['4. Kontaktanfrage und Bewertungsanfrage', 'Wenn Sie uns über eines der Formulare schreiben, verarbeiten wir die von Ihnen angegebenen Kontakt- und Inhaltsdaten – bei der Bewertungsanfrage auch die Angaben zur Immobilie –, um Ihre Anfrage zu beantworten und Ihnen ein Angebot zu unterbreiten. Rechtsgrundlage ist Art. 6 Abs. 1 lit. b DSGVO (Anbahnung eines Vertrags), sonst Art. 6 Abs. 1 lit. f DSGVO. Die Formulare speichern den Zeitpunkt Ihrer Einwilligung und schützen sich gegen automatisierte Eingaben, ohne dafür Dienste Dritter zu laden.'],
|
||
['5. Wie lange wir speichern', 'Anfragedaten löschen wir, sobald sie für die Beantwortung nicht mehr nötig sind und keine gesetzliche Aufbewahrungspflicht entgegensteht. Entsteht aus Ihrer Anfrage ein Auftrag, gelten für die dann anfallenden Unterlagen die handels- und steuerrechtlichen Fristen.'],
|
||
['6. Empfänger', 'Ihre Angaben erreichen uns per E-Mail und liegen in der Verwaltung dieser Website. Darüber hinaus geben wir sie nicht weiter, außer wir sind dazu gesetzlich verpflichtet oder Sie wünschen es, etwa bei der Weitergabe eines Angebots an Interessenten.<br><br>NOCH ZU PRÜFEN: E-Mail-Anbieter und Hostingdienst als Auftragsverarbeiter benennen.'],
|
||
['7. Ihre Rechte', 'Sie haben unter den gesetzlichen Voraussetzungen das Recht auf Auskunft, Berichtigung, Löschung, Einschränkung der Verarbeitung und Datenübertragbarkeit. Einer Verarbeitung auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO können Sie widersprechen. Eine erteilte Einwilligung können Sie jederzeit mit Wirkung für die Zukunft widerrufen.'],
|
||
['8. Beschwerderecht', 'Sie können sich bei einer Datenschutz-Aufsichtsbehörde beschweren, für uns beim Landesbeauftragten für den Datenschutz und die Informationsfreiheit Baden-Württemberg.'],
|
||
['', "Fragen zum Datenschutz beantworten wir gern unter <a href=\"mailto:$mail\">$mail</a>."],
|
||
]),
|
||
],
|
||
], 'Datenschutz | '.$firma);
|
||
|
||
$fehlerId = $anlegen('404', [
|
||
'schemaVersion' => $SCHEMA, 'title' => 'Seite nicht gefunden',
|
||
'description' => 'Die gesuchte Seite gibt es nicht oder sie wurde verschoben.',
|
||
'blocks' => [
|
||
$abschnitt('fehler', [
|
||
[...$kleinzeile('fehler-label', 'FEHLER 404'), 'layout' => ['effects' => ['entrance' => 'fade', 'delay' => 'none']]],
|
||
$heading('fehler-titel', 'Diese Seite<br><em>haben wir nicht.</em>', 1, [
|
||
'desktop' => ['fontWeight' => '400', 'fontSize' => '56px', 'lineHeight' => 1.1, 'letterSpacing' => '-0.05em', 'margin' => ['bottom' => '25px']],
|
||
'mobile' => ['fontSize' => '38px'],
|
||
], '& em{color:#0081c7;font-style:normal}'),
|
||
$text('fehler-text', 'Vielleicht hat sich ein Tippfehler in die Adresse geschlichen. Über die Startseite finden Sie zurück.', [
|
||
'desktop' => ['maxWidth' => '465px', 'color' => '@text', 'fontSize' => '17px', 'lineHeight' => 1.8, 'margin' => ['bottom' => '28px']],
|
||
]),
|
||
$button('fehler-knopf', 'Zur Startseite', '/', ['desktop' => ['margin' => ['top' => '0px']]]),
|
||
], ['desktop' => ['padding' => ['top' => '120px', 'bottom' => '140px']]]),
|
||
],
|
||
]);
|
||
$db->executeStatement('UPDATE page SET robots = ? WHERE id = ?', ['noindex', $fehlerId]);
|
||
|
||
// ---------------------------------------------------------------------------------------------
|
||
// Menü, Einstellungen, Konto
|
||
// ---------------------------------------------------------------------------------------------
|
||
|
||
$sprung = static fn (string $label, string $anchor): array => ['label' => $label, 'type' => 'page', 'pageId' => $erstellt['home'], 'anchor' => $anchor, 'children' => []];
|
||
|
||
$menus->save('header', 'Hauptnavigation', [
|
||
$sprung('Leistungen', 'leistungen'),
|
||
$sprung('Über uns', 'ueber-uns'),
|
||
$sprung('Immobilien', 'angebote'),
|
||
$sprung('Kontakt', 'kontakt'),
|
||
$sprung('Immobilie bewerten', 'bewertung'),
|
||
], 0);
|
||
echo "Menü angelegt\n";
|
||
|
||
$settings->assignNotFoundPage($fehlerId, '');
|
||
$settings->save([
|
||
'legalName' => $firma,
|
||
'description' => 'Immobilien verkaufen, vermieten und verwalten in Freudenstadt. DEEG begleitet Eigentümer von Wohn- und Gewerbeimmobilien persönlich – seit 1994.',
|
||
'phone' => $telefon, 'email' => $mail,
|
||
'street' => 'Ringstraße 30', 'postalCode' => '72250', 'city' => 'Freudenstadt', 'country' => 'DE',
|
||
'localBusiness' => true, 'llmsTxt' => true,
|
||
'stickyHeader' => true, 'headerOverlay' => false,
|
||
'motion' => 'always',
|
||
'faviconMediaId' => $medien['logo']['id'],
|
||
'homePath' => 'home', 'imprintPath' => 'impressum', 'privacyPath' => 'datenschutz',
|
||
'consentBanner' => false, 'scrollTop' => false, 'postMetaHeader' => true,
|
||
]);
|
||
echo "Einstellungen gespeichert\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";
|