From 1aedcaf314827dfdaaab911b466e379cc2d4f910 Mon Sep 17 00:00:00 2001 From: Claw Date: Tue, 19 May 2026 14:38:38 +0000 Subject: [PATCH] refactor: Umstellung auf Mini-MVC-Architektur (Issue #46) - Front Controller Pattern mit public/index.php als Einstiegspunkt - Eigenes Routing (App\Core\Router) ohne externes Framework - Controller: HomeController, ImpressumController, DatenschutzController - Views mit gemeinsamem Layout (app/views/layouts/main.php) - PSR-4 Autoloading - Statische Assets nach public/ verschoben - Alte Dateien (index.php, impressum.html, datenschutz.html) geloescht - 301-Redirects fuer alte URLs - PHP 8.5 kompatibel - Apache DocumentRoot auf public/ gesetzt --- .continue/mcpServers/new-mcp-server.yaml | 0 .dockerignore | 0 .gitea/workflows/deploy-test.yml | 0 .gitignore | 0 .htaccess | 8 + .htmlhintrc | 0 .husky/pre-commit | 0 .prettierignore | 0 .prettierrc | 0 .stylelintrc.json | 0 AGENTS.md | 0 Dockerfile | 0 README.md | 0 app/controllers/Controller.php | 25 + app/controllers/DatenschutzController.php | 18 + app/controllers/HomeController.php | 174 ++++ app/controllers/ImpressumController.php | 18 + app/core/Router.php | 60 ++ app/core/View.php | 46 + .../views/datenschutz/index.php | 116 +-- app/views/home/index.php | 504 +++++++++++ .../views/impressum/index.php | 116 +-- app/views/layouts/main.php | 51 ++ docker-preview.png | Bin eslint.config.js | 1 - index.php | 828 ------------------ js/haus-schleusingen.js | 131 --- nginx.conf | 0 package.json | 0 page-preview.png | Bin public/.htaccess | 15 + .../bilder}/Außenansicht-2-small.png | Bin .../bilder}/Außenansicht-2-small.webp | Bin {bilder => public/bilder}/Außenansicht-2.png | Bin {bilder => public/bilder}/Außenansicht-2.webp | Bin {bilder => public/bilder}/Bad-2-small.jpg | Bin {bilder => public/bilder}/Bad-2-small.webp | Bin {bilder => public/bilder}/Bad-2.jpeg | Bin {bilder => public/bilder}/Bad-2.webp | Bin {bilder => public/bilder}/Bad-3-small.jpg | Bin {bilder => public/bilder}/Bad-3-small.webp | Bin {bilder => public/bilder}/Bad-3.jpeg | Bin {bilder => public/bilder}/Bad-3.webp | Bin {bilder => public/bilder}/Bad-4-small.jpg | Bin {bilder => public/bilder}/Bad-4-small.webp | Bin {bilder => public/bilder}/Bad-4.jpeg | Bin {bilder => public/bilder}/Bad-4.webp | Bin {bilder => public/bilder}/Bad-small.jpg | Bin {bilder => public/bilder}/Bad-small.webp | Bin {bilder => public/bilder}/Bad.jpg | Bin {bilder => public/bilder}/Bad.webp | Bin .../bilder}/Kinderzimmer 2-small.png | Bin .../bilder}/Kinderzimmer 2-small.webp | Bin {bilder => public/bilder}/Kinderzimmer 2.jpg | Bin {bilder => public/bilder}/Kinderzimmer 2.webp | Bin .../bilder}/Kinderzimmer 3-small.png | Bin .../bilder}/Kinderzimmer 3-small.webp | Bin {bilder => public/bilder}/Kinderzimmer 3.jpg | Bin {bilder => public/bilder}/Kinderzimmer 3.webp | Bin .../bilder}/Kinderzimmer-small.png | Bin .../bilder}/Kinderzimmer-small.webp | Bin {bilder => public/bilder}/Kinderzimmer.png | Bin {bilder => public/bilder}/Kinderzimmer.webp | Bin {bilder => public/bilder}/Küche 1-small.jpg | Bin {bilder => public/bilder}/Küche 1-small.webp | Bin {bilder => public/bilder}/Küche 1.jpg | Bin {bilder => public/bilder}/Küche 1.webp | Bin public/bilder/favicon/apple-touch-icon.png | Bin 0 -> 55489 bytes public/bilder/favicon/favicon-16x16.png | Bin 0 -> 851 bytes public/bilder/favicon/favicon-32x32.png | Bin 0 -> 2440 bytes public/bilder/favicon/favicon.ico | Bin 0 -> 3329 bytes public/bilder/favicon/site.webmanifest | 10 + .../grundrisse/Dachboden unten 2-small.jpg | Bin .../grundrisse/Dachboden unten 2-small.webp | Bin .../bilder}/grundrisse/Dachboden unten 2.png | Bin .../bilder}/grundrisse/Dachboden unten 2.webp | Bin .../grundrisse/Dachboden unten-small.jpg | Bin .../grundrisse/Dachboden unten-small.webp | Bin .../bilder}/grundrisse/Dachboden unten.png | Bin .../bilder}/grundrisse/Dachboden unten.webp | Bin .../bilder}/grundrisse/EG 3D-small.jpg | Bin .../bilder}/grundrisse/EG 3D-small.webp | Bin .../bilder}/grundrisse/EG 3D.png | Bin .../bilder}/grundrisse/EG 3D.webp | Bin .../bilder}/grundrisse/EG-small.jpg | Bin .../bilder}/grundrisse/EG-small.webp | Bin {bilder => public/bilder}/grundrisse/EG.png | Bin {bilder => public/bilder}/grundrisse/EG.webp | Bin .../bilder}/grundrisse/OG 1 2-small.jpg | Bin .../bilder}/grundrisse/OG 1 2-small.webp | Bin .../bilder}/grundrisse/OG 1 2.png | Bin .../bilder}/grundrisse/OG 1 2.webp | Bin .../bilder}/grundrisse/OG 1 3D-small.jpg | Bin .../bilder}/grundrisse/OG 1 3D-small.webp | Bin .../bilder}/grundrisse/OG 1 3D.png | Bin .../bilder}/grundrisse/OG 1 3D.webp | Bin .../bilder}/grundrisse/OG 2 3D-small.jpg | Bin .../bilder}/grundrisse/OG 2 3D-small.webp | Bin .../bilder}/grundrisse/OG 2 3D.png | Bin .../bilder}/grundrisse/OG 2 3D.webp | Bin .../grundrisse/OG 2 grundriss-small.jpg | Bin .../grundrisse/OG 2 grundriss-small.webp | Bin .../bilder}/grundrisse/OG 2 grundriss.png | Bin .../bilder}/grundrisse/OG 2 grundriss.webp | Bin .../bilder}/kinderzimmer 2 2-small.png | Bin .../bilder}/kinderzimmer 2 2-small.webp | Bin .../bilder}/kinderzimmer 2 2.jpeg | Bin .../bilder}/kinderzimmer 2 2.webp | Bin .../bilder}/schlafzimmer-small.png | Bin .../bilder}/schlafzimmer-small.webp | Bin {bilder => public/bilder}/schlafzimmer.png | Bin {bilder => public/bilder}/schlafzimmer.webp | Bin .../bilder}/wohnzimmer2-small.png | Bin .../bilder}/wohnzimmer2-small.webp | Bin {bilder => public/bilder}/wohnzimmer2.png | Bin {bilder => public/bilder}/wohnzimmer2.webp | Bin {css => public/css}/haus-schleusingen.css | 55 +- .../fonts}/CormorantGaramond-Light.ttf | Bin .../fonts}/CormorantGaramond-Regular.ttf | Bin .../fonts}/CormorantGaramond-SemiBold.ttf | Bin {fonts => public/fonts}/DMSans-Light.ttf | Bin {fonts => public/fonts}/DMSans-Medium.ttf | Bin {fonts => public/fonts}/DMSans-Regular.ttf | Bin {fonts => public/fonts}/fonts.css | 0 public/index.php | 44 + public/js/haus-schleusingen.js | 259 ++++++ public/robots.txt | 3 + robots.txt | 0 screenshot-landingpage-thumb.png | Bin screenshot-landingpage.png | Bin 130 files changed, 1303 insertions(+), 1179 deletions(-) mode change 100644 => 100755 .continue/mcpServers/new-mcp-server.yaml mode change 100644 => 100755 .dockerignore mode change 100644 => 100755 .gitea/workflows/deploy-test.yml mode change 100644 => 100755 .gitignore create mode 100644 .htaccess mode change 100644 => 100755 .htmlhintrc mode change 100644 => 100755 .husky/pre-commit mode change 100644 => 100755 .prettierignore mode change 100644 => 100755 .prettierrc mode change 100644 => 100755 .stylelintrc.json mode change 100644 => 100755 AGENTS.md mode change 100644 => 100755 Dockerfile mode change 100644 => 100755 README.md create mode 100644 app/controllers/Controller.php create mode 100644 app/controllers/DatenschutzController.php create mode 100644 app/controllers/HomeController.php create mode 100644 app/controllers/ImpressumController.php create mode 100644 app/core/Router.php create mode 100644 app/core/View.php rename datenschutz.html => app/views/datenschutz/index.php (60%) create mode 100644 app/views/home/index.php rename impressum.html => app/views/impressum/index.php (53%) create mode 100644 app/views/layouts/main.php mode change 100644 => 100755 docker-preview.png mode change 100644 => 100755 eslint.config.js delete mode 100644 index.php delete mode 100644 js/haus-schleusingen.js mode change 100644 => 100755 nginx.conf mode change 100644 => 100755 package.json mode change 100644 => 100755 page-preview.png create mode 100644 public/.htaccess rename {bilder => public/bilder}/Außenansicht-2-small.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Außenansicht-2-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Außenansicht-2.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Außenansicht-2.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-2-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-2-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-2.jpeg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-2.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-3-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-3-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-3.jpeg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-3.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-4-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-4-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-4.jpeg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-4.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Bad.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer 2-small.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer 2-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer 2.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer 2.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer 3-small.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer 3-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer 3.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer 3.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer-small.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Kinderzimmer.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Küche 1-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Küche 1-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Küche 1.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/Küche 1.webp (100%) mode change 100644 => 100755 create mode 100755 public/bilder/favicon/apple-touch-icon.png create mode 100755 public/bilder/favicon/favicon-16x16.png create mode 100755 public/bilder/favicon/favicon-32x32.png create mode 100755 public/bilder/favicon/favicon.ico create mode 100755 public/bilder/favicon/site.webmanifest rename {bilder => public/bilder}/grundrisse/Dachboden unten 2-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/Dachboden unten 2-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/Dachboden unten 2.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/Dachboden unten 2.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/Dachboden unten-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/Dachboden unten-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/Dachboden unten.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/Dachboden unten.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/EG 3D-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/EG 3D-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/EG 3D.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/EG 3D.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/EG-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/EG-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/EG.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/EG.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 1 2-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 1 2-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 1 2.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 1 2.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 1 3D-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 1 3D-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 1 3D.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 1 3D.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 2 3D-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 2 3D-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 2 3D.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 2 3D.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 2 grundriss-small.jpg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 2 grundriss-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 2 grundriss.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/grundrisse/OG 2 grundriss.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/kinderzimmer 2 2-small.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/kinderzimmer 2 2-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/kinderzimmer 2 2.jpeg (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/kinderzimmer 2 2.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/schlafzimmer-small.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/schlafzimmer-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/schlafzimmer.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/schlafzimmer.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/wohnzimmer2-small.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/wohnzimmer2-small.webp (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/wohnzimmer2.png (100%) mode change 100644 => 100755 rename {bilder => public/bilder}/wohnzimmer2.webp (100%) mode change 100644 => 100755 rename {css => public/css}/haus-schleusingen.css (95%) mode change 100644 => 100755 rename {fonts => public/fonts}/CormorantGaramond-Light.ttf (100%) mode change 100644 => 100755 rename {fonts => public/fonts}/CormorantGaramond-Regular.ttf (100%) mode change 100644 => 100755 rename {fonts => public/fonts}/CormorantGaramond-SemiBold.ttf (100%) mode change 100644 => 100755 rename {fonts => public/fonts}/DMSans-Light.ttf (100%) mode change 100644 => 100755 rename {fonts => public/fonts}/DMSans-Medium.ttf (100%) mode change 100644 => 100755 rename {fonts => public/fonts}/DMSans-Regular.ttf (100%) mode change 100644 => 100755 rename {fonts => public/fonts}/fonts.css (100%) mode change 100644 => 100755 create mode 100644 public/index.php create mode 100755 public/js/haus-schleusingen.js create mode 100755 public/robots.txt mode change 100644 => 100755 robots.txt mode change 100644 => 100755 screenshot-landingpage-thumb.png mode change 100644 => 100755 screenshot-landingpage.png diff --git a/.continue/mcpServers/new-mcp-server.yaml b/.continue/mcpServers/new-mcp-server.yaml old mode 100644 new mode 100755 diff --git a/.dockerignore b/.dockerignore old mode 100644 new mode 100755 diff --git a/.gitea/workflows/deploy-test.yml b/.gitea/workflows/deploy-test.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..cb7276d --- /dev/null +++ b/.htaccess @@ -0,0 +1,8 @@ +# Legacy redirects for old URLs pointing to root +RewriteEngine On +RewriteRule ^impressum\.html$ /impressum [R=301,L] +RewriteRule ^datenschutz\.html$ /datenschutz [R=301,L] +RewriteRule ^haus-schleusingen\.html$ / [R=301,L] + +# Everything else goes to public/ +RewriteRule ^(.*)$ public/$1 [L] diff --git a/.htmlhintrc b/.htmlhintrc old mode 100644 new mode 100755 diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755 diff --git a/.prettierignore b/.prettierignore old mode 100644 new mode 100755 diff --git a/.prettierrc b/.prettierrc old mode 100644 new mode 100755 diff --git a/.stylelintrc.json b/.stylelintrc.json old mode 100644 new mode 100755 diff --git a/AGENTS.md b/AGENTS.md old mode 100644 new mode 100755 diff --git a/Dockerfile b/Dockerfile old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/app/controllers/Controller.php b/app/controllers/Controller.php new file mode 100644 index 0000000..309b848 --- /dev/null +++ b/app/controllers/Controller.php @@ -0,0 +1,25 @@ +view = new View(); + } + + protected function render(string $view, array $data = [], string $layout = 'main'): void + { + foreach ($data as $key => $value) { + $this->view->assign($key, $value); + } + $this->view->render($view, $layout); + } +} diff --git a/app/controllers/DatenschutzController.php b/app/controllers/DatenschutzController.php new file mode 100644 index 0000000..9bb59b6 --- /dev/null +++ b/app/controllers/DatenschutzController.php @@ -0,0 +1,18 @@ +render('datenschutz/index', [ + 'pageTitle' => 'Datenschutzerklärung – Haus Schleusingen', + 'pageDescription' => 'Datenschutzerklärung der Website haus-schleusingen.de', + 'robots' => 'noindex', + 'canonical' => 'https://haus-schleusingen.de/datenschutz', + ]); + } +} diff --git a/app/controllers/HomeController.php b/app/controllers/HomeController.php new file mode 100644 index 0000000..0d7b51a --- /dev/null +++ b/app/controllers/HomeController.php @@ -0,0 +1,174 @@ + '', 'lname' => '', 'email' => '', 'phone' => '', 'interest' => 'Besichtigung anfragen', 'message' => '']; + } + + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $formData['fname'] = $normalizeContactValue((string) ($_POST['fname'] ?? '')); + $formData['lname'] = $normalizeContactValue((string) ($_POST['lname'] ?? '')); + $formData['email'] = $normalizeContactValue((string) ($_POST['email'] ?? '')); + $formData['phone'] = $normalizeContactValue((string) ($_POST['phone'] ?? '')); + $formData['interest'] = $normalizeContactValue((string) ($_POST['interest'] ?? '')); + $formData['message'] = $normalizeContactValue((string) ($_POST['message'] ?? '')); + + $honeypot = $normalizeContactValue((string) ($_POST['website'] ?? '')); + if ($honeypot !== '') { + header('Location: ' . $_SERVER['REQUEST_URI'] . '#form-result'); + $_SESSION['form_success'] = true; + exit; + } else { + if ($formData['fname'] === '') { + $formErrors[] = 'Bitte geben Sie Ihren Vornamen an.'; + } + if ($formData['lname'] === '') { + $formErrors[] = 'Bitte geben Sie Ihren Nachnamen an.'; + } + if ($formData['email'] === '' || !filter_var($formData['email'], FILTER_VALIDATE_EMAIL)) { + $formErrors[] = 'Bitte geben Sie eine gültige E-Mail-Adresse an.'; + } + if ($formData['message'] === '') { + $formErrors[] = 'Bitte geben Sie eine Nachricht ein.'; + } + + if ($containsHeaderInjection($formData['email']) || $containsHeaderInjection($formData['fname'] . ' ' . $formData['lname'])) { + $formErrors[] = 'Ungültige Zeichen in den Eingabefeldern.'; + } + + $formTime = isset($_POST['form_time']) ? (int) $_POST['form_time'] : 0; + if ($formTime > 0 && (time() - $formTime) < 3) { + $formErrors[] = 'Das Formular wurde zu schnell abgeschickt. Bitte versuchen Sie es erneut.'; + } + + $lastSubmit = $_SESSION['last_contact_submit'] ?? 0; + if ($lastSubmit && (time() - $lastSubmit) < 60) { + $formErrors[] = 'Bitte warten Sie einen Moment vor der nächsten Anfrage.'; + } + + if (empty($formErrors)) { + $to = 'mki@kies-media.de'; + $subject = 'Kontaktanfrage: ' . $formData['interest']; + $body = "Von: {$formData['fname']} {$formData['lname']}\n" + . "E-Mail: {$formData['email']}\n"; + if ($formData['phone'] !== '') { + $body .= "Telefon: {$formData['phone']}\n"; + } + $body .= "Anliegen: {$formData['interest']}\n\n" + . $formData['message']; + + $headers = "From: {$formData['email']}\r\n"; + $headers .= "Reply-To: {$formData['email']}\r\n"; + $headers .= "Content-Type: text/plain; charset=UTF-8\r\n"; + $headers .= "X-Mailer: PHP/" . phpversion(); + + $mailSent = mail($to, $subject, $body, $headers); + + if ($mailSent) { + $_SESSION['last_contact_submit'] = time(); + header('Location: ' . $_SERVER['REQUEST_URI'] . '#form-result'); + $_SESSION['form_success'] = true; + exit; + } else { + $formErrors[] = 'Leider konnte die E-Mail nicht gesendet werden. Bitte versuchen Sie es später erneut oder schreiben Sie uns direkt an mki@kies-media.de.'; + } + } + } + if (!empty($formErrors)) { + header('Location: ' . $_SERVER['REQUEST_URI'] . '#form-result'); + $_SESSION['form_errors'] = $formErrors; + $_SESSION['form_data'] = $formData; + exit; + } + } + + $this->render('home/index', [ + 'formSuccess' => $formSuccess, + 'formErrors' => $formErrors, + 'formData' => $formData, + 'escapeContactValue' => $escapeContactValue, + 'pageTitle' => 'Einfamilienhaus mieten Schleusingen | 227 m², 6 Zimmer | 1.300 € Kaltmiete', + 'pageDescription' => 'Einfamilienhaus zur Langzeitmiete in Schleusingen: 227 m² Wohnfläche, 6 Zimmer, 3 Etagen mit Dachterrasse. Kaltmiete 1.300 €. Bahnhofstraße 10, 98553 Schleusingen. Ab sofort verfügbar.', + 'canonical' => 'https://haus-schleusingen.de/', + 'openGraph' => [ + 'ogTitle' => 'Einfamilienhaus zur Miete in Schleusingen – 227 m², 6 Zimmer', + 'ogDescription' => 'Großzügiges Einfamilienhaus zur Langzeitmiete: 227 m², 6 Zimmer, 3 Etagen + Dachterrasse. Kaltmiete 1.300 €. Ab sofort verfügbar in Schleusingen.', + 'ogImage' => 'https://haus-schleusingen.de/bilder/Außenansicht-2.png', + 'ogUrl' => 'https://haus-schleusingen.de/', + ], + 'structuredData' => json_encode([ + '@context' => 'https://schema.org', + '@type' => 'RealEstateListing', + 'name' => 'Einfamilienhaus zur Miete in Schleusingen', + 'description' => 'Großzügiges Einfamilienhaus zur Langzeitmiete: 227 m² Wohnfläche, 6 Zimmer, 3 Etagen mit Dachterrasse. Kaltmiete 1.300 €.', + 'url' => 'https://haus-schleusingen.de/', + 'image' => 'https://haus-schleusingen.de/bilder/Außenansicht-2.png', + 'datePosted' => '2026-05-14', + 'address' => [ + '@type' => 'PostalAddress', + 'streetAddress' => 'Bahnhofstraße 10', + 'addressLocality' => 'Schleusingen', + 'postalCode' => '98553', + 'addressCountry' => 'DE', + ], + 'offers' => [ + '@type' => 'Offer', + 'price' => '1300', + 'priceCurrency' => 'EUR', + 'priceSpecification' => [ + '@type' => 'UnitPriceSpecification', + 'price' => '1300', + 'priceCurrency' => 'EUR', + 'unitCode' => 'MON', + 'description' => 'Kaltmiete pro Monat', + ], + ], + 'floorSize' => [ + '@type' => 'QuantitativeValue', + 'value' => '227', + 'unitCode' => 'MTK', + ], + 'numberOfRooms' => [ + '@type' => 'QuantitativeValue', + 'value' => '6', + ], + ]), + ]); + } +} diff --git a/app/controllers/ImpressumController.php b/app/controllers/ImpressumController.php new file mode 100644 index 0000000..a7bef04 --- /dev/null +++ b/app/controllers/ImpressumController.php @@ -0,0 +1,18 @@ +render('impressum/index', [ + 'pageTitle' => 'Impressum – Haus Schleusingen', + 'pageDescription' => 'Impressum der Website haus-schleusingen.de', + 'robots' => 'noindex', + 'canonical' => 'https://haus-schleusingen.de/impressum', + ]); + } +} diff --git a/app/core/Router.php b/app/core/Router.php new file mode 100644 index 0000000..2f17cb2 --- /dev/null +++ b/app/core/Router.php @@ -0,0 +1,60 @@ +routes[$path] = [ + 'controller' => $controller, + 'action' => $action, + ]; + } + + public function dispatch(string $uri): void + { + // Normalize: strip query string and trailing slash + $path = parse_url($uri, PHP_URL_PATH); + $path = rtrim($path, '/') ?: '/'; + + // Direct match + if (isset($this->routes[$path])) { + $this->execute($this->routes[$path]); + return; + } + + // Legacy .html redirect (301) + if (preg_match('#^/(impressum|datenschutz)\.html$#', $path, $m)) { + header('Location: /' . $m[1], true, 301); + exit; + } + + // 404 + http_response_code(404); + echo '

404 – Seite nicht gefunden

'; + echo '

Zurück zur Startseite

'; + } + + private function execute(array $route): void + { + $controllerClass = $route['controller']; + $action = $route['action']; + + if (!class_exists($controllerClass)) { + throw new \RuntimeException("Controller {$controllerClass} nicht gefunden."); + } + + $controller = new $controllerClass(); + + if (!method_exists($controller, $action)) { + throw new \RuntimeException("Action {$action} in {$controllerClass} nicht gefunden."); + } + + $controller->$action(); + } +} diff --git a/app/core/View.php b/app/core/View.php new file mode 100644 index 0000000..47210a5 --- /dev/null +++ b/app/core/View.php @@ -0,0 +1,46 @@ +viewsPath = $viewsPath ?? dirname(__DIR__) . '/views'; + } + + public function assign(string $key, mixed $value): void + { + $this->data[$key] = $value; + } + + public function render(string $view, string $layout = 'main'): void + { + $viewFile = $this->viewsPath . '/' . $view . '.php'; + $layoutFile = $this->viewsPath . '/layouts/' . $layout . '.php'; + + if (!file_exists($viewFile)) { + throw new \RuntimeException("View {$view} nicht gefunden: {$viewFile}"); + } + + if (!file_exists($layoutFile)) { + throw new \RuntimeException("Layout {$layout} nicht gefunden: {$layoutFile}"); + } + + // Extract data to variables for the view + extract($this->data, EXTR_SKIP); + + // Capture view content + ob_start(); + require $viewFile; + $content = ob_get_clean(); + + // Render layout with $content + require $layoutFile; + } +} diff --git a/datenschutz.html b/app/views/datenschutz/index.php similarity index 60% rename from datenschutz.html rename to app/views/datenschutz/index.php index 578b169..7bb1594 100644 --- a/datenschutz.html +++ b/app/views/datenschutz/index.php @@ -1,110 +1,12 @@ - - - - - - Datenschutzerklärung – Haus Schleusingen - - - - - - - -
@@ -209,15 +111,13 @@ Zur Ausübung Ihrer Rechte wenden Sie sich bitte an: mki@kies-media.de

- ← Zurück zum Objekt + ← Zurück zum Objekt
- - diff --git a/app/views/home/index.php b/app/views/home/index.php new file mode 100644 index 0000000..6358e9f --- /dev/null +++ b/app/views/home/index.php @@ -0,0 +1,504 @@ + + + + +
+
+
+
+
Zur Langzeitmiete · Ab sofort verfügbar
+

+ Großzügiges +
+ Einfamilienhaus +
+ in Schleusingen +

+
+ Schleusinger Bahnhofstraße 10 + 227 m² Wohnfläche + 6 Zimmer + 3 Etagen + Dachterrasse +
+
+
+ Entdecken +
+
+
+ +
+
+
+
227
+
m² Wohnfläche
+
+
+
6
+
Zimmer
+
+
+
3
+
Etagen
+
+
+
1.300
+
€ Kaltmiete
+
+
+ +
+
+
Das Objekt
+

Wohnen mit Charakter und viel Raum

+

+ Vermietet wird ein vollständiges Einfamilienhaus in ruhiger Lage von Schleusingen. Das + Haus verbindet historischen Charme mit modernem Wohnkomfort auf drei großzügigen Etagen. +

+

+ Garage für zwei Fahrzeuge, großzügige Dachterrasse mit 35,8 m², vollausgestattete Küche, + Vollbad sowie Abstell- und Nutzräume machen das Haus zu einem außergewöhnlichen + Mietobjekt. +

+
+
+
154,9 m²
+
Nutzfläche
+
+
+
35,8 m²
+
Dachterrasse
+
+
+
2 Stpl.
+
Garage
+
+
+
+
+ + + Wohnzimmer + +
Wohnzimmer · 42,6 m²
+
+
+ + + +
+
Raumaufteilung
+

Großzügig auf allen Etagen

+
+
+ +
+
+
Flur20,1 m²
+
WC0,8 m²
+
Garage / Partykeller42,6 m²
+
Abstellraum 19,9 m²
+
Abstellraum 27,8 m²
+
Heizungskeller18,3 m²
+
+
+ + + Grundriss Erdgeschoss + + + + Grundriss Erdgeschoss + +
+
+
+
+ +
+
+
Flur20,1 m²
+
Wohnzimmer42,6 m²
+
Gästezimmer11,5 m²
+
Badezimmer9,8 m²
+
Küche18,4 m²
+
Schlafzimmer18,0 m²
+
+
+ + + Grundriss 1. Obergeschoss + + + + Grundriss 1. Obergeschoss + +
+
+
+
+ +
+
+
Flur13,9 m²
+
Kinderzimmer 121,7 m²
+
Kinderzimmer 215,7 m²
+
Spielzimmer6,3 m²
+
Ankleidezimmer1,4 m²
+
Dachterrasse9,0 m² (25% von 35,8 m²)
+
+
+ + + Grundriss 2. Obergeschoss + + + + Grundriss 2. Obergeschoss + +
+
+
+
+ +
+
+
Dachboden unten (ungeheizt)52 m²
+
Dachboden Mitte (ungeheizt)31 m²
+
Dachboden oben (ungeheizt)11 m²
+
+
+ + + Grundriss Dachboden + + + + Grundriss Dachboden + +
+
+
+
+
+ +
+
+
Mietkonditionen
+

Transparente Preisgestaltung

+
+
+
Kaltmiete
+
1.300 €
+
pro Monat
+
+
+
Gesamtmiete warm
+
1.600 €
+
inkl. 300 € Nebenkosten
+
+
+
Kaution
+
2.600 €
+
2 Nettokaltmieten
+
+
+
+
+ Verfügbarkeit + Ab sofort · unbefristete Laufzeit +
+
+ Nebenkosten + Vorauszahlung 300 €/Monat, jährliche Abrechnung +
+
+ Energieausweis + Wird bei Mietbeginn übergeben · Erdgasheizung +
+
+ Haustiere + Auf Anfrage +
+
+
+
+ +
+
Standort
+

Zentral und ruhig zugleich

+
+
+
🛒
+
+
Einkaufen & Versorgung
+
Supermärkte, Ärzte, Apotheken und Schulen sind fußläufig erreichbar
+
+
+
+
🚌
+
+
Öffentlicher Nahverkehr
+
Zentrale Bushaltestelle ca. 200 m entfernt — direkte Verbindungen in die Region
+
+
+
+
🏛
+
+
Innenstadt Schleusingen
+
Wochenmarkt und Stadtmitte nur ca. 500 m entfernt
+
+
+
+
📍
+
+
Genaue Adresse
+
Schleusinger Bahnhofstraße 10
98533 Schleusingen, Thüringen
+
+
+
+
+ +
+
+ +
+
+
Kontakt
+

Interesse?
Schreiben Sie uns.

+

+ Wir freuen uns über Ihre Anfrage und melden uns innerhalb von 24 Stunden. + Besichtigungstermine sind nach Absprache möglich. Bitte geben Sie bei Ihrer Anfrage ein + paar Terminvorschläge an. +

+
+ +
+

Vielen Dank für Ihre Anfrage!

+
+ Wir haben Ihre Nachricht erhalten und melden uns innerhalb von 24 Stunden bei Ihnen. +
+ + +
+
    + +
  • + +
+
+ +
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ + + +
+ +
+
+

Oder schreiben Sie uns direkt: mki@kies-media.de

+
+
+
+ +
+ + + diff --git a/impressum.html b/app/views/impressum/index.php similarity index 53% rename from impressum.html rename to app/views/impressum/index.php index 8480798..e246e54 100644 --- a/impressum.html +++ b/app/views/impressum/index.php @@ -1,110 +1,12 @@ - - - - - - Impressum – Haus Schleusingen - - - - - - - -
@@ -171,15 +73,13 @@ Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.

- ← Zurück zum Objekt + ← Zurück zum Objekt
- - diff --git a/app/views/layouts/main.php b/app/views/layouts/main.php new file mode 100644 index 0000000..02ce463 --- /dev/null +++ b/app/views/layouts/main.php @@ -0,0 +1,51 @@ + + + + + + + <?= htmlspecialchars($pageTitle) ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docker-preview.png b/docker-preview.png old mode 100644 new mode 100755 diff --git a/eslint.config.js b/eslint.config.js old mode 100644 new mode 100755 index 37a76da..d8421f2 --- a/eslint.config.js +++ b/eslint.config.js @@ -13,7 +13,6 @@ module.exports = [ sourceType: "script", globals: { ...globals.browser, - ...globals.jquery, }, }, plugins: { diff --git a/index.php b/index.php deleted file mode 100644 index 93ef33f..0000000 --- a/index.php +++ /dev/null @@ -1,828 +0,0 @@ - '', 'lname' => '', 'email' => '', 'phone' => '', 'interest' => 'Besichtigung anfragen', 'message' => '']; -} - -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - // Collect and normalize input - $formData['fname'] = normalizeContactValue((string) ($_POST['fname'] ?? '')); - $formData['lname'] = normalizeContactValue((string) ($_POST['lname'] ?? '')); - $formData['email'] = normalizeContactValue((string) ($_POST['email'] ?? '')); - $formData['phone'] = normalizeContactValue((string) ($_POST['phone'] ?? '')); - $formData['interest'] = normalizeContactValue((string) ($_POST['interest'] ?? '')); - $formData['message'] = normalizeContactValue((string) ($_POST['message'] ?? '')); - - // Honeypot check – hidden field must be empty - $honeypot = normalizeContactValue((string) ($_POST['website'] ?? '')); - if ($honeypot !== '') { - // Bot detected – pretend success - header('Location: ' . $_SERVER['REQUEST_URI'] . '#form-result'); - $_SESSION['form_success'] = true; - exit; - } else { - // Server-side validation - if ($formData['fname'] === '') { - $formErrors[] = 'Bitte geben Sie Ihren Vornamen an.'; - } - if ($formData['lname'] === '') { - $formErrors[] = 'Bitte geben Sie Ihren Nachnamen an.'; - } - if ($formData['email'] === '' || !filter_var($formData['email'], FILTER_VALIDATE_EMAIL)) { - $formErrors[] = 'Bitte geben Sie eine gültige E-Mail-Adresse an.'; - } - if ($formData['message'] === '') { - $formErrors[] = 'Bitte geben Sie eine Nachricht ein.'; - } - - // Header injection check - if (containsHeaderInjection($formData['email']) || containsHeaderInjection($formData['fname'] . ' ' . $formData['lname'])) { - $formErrors[] = 'Ungültige Zeichen in den Eingabefeldern.'; - } - - // Minimum time check – form submitted too fast (< 3 seconds) - $formTime = isset($_POST['form_time']) ? (int) $_POST['form_time'] : 0; - if ($formTime > 0 && (time() - $formTime) < 3) { - $formErrors[] = 'Das Formular wurde zu schnell abgeschickt. Bitte versuchen Sie es erneut.'; - } - - // Session rate limit – max 1 submission per 60 seconds - $lastSubmit = $_SESSION['last_contact_submit'] ?? 0; - if ($lastSubmit && (time() - $lastSubmit) < 60) { - $formErrors[] = 'Bitte warten Sie einen Moment vor der nächsten Anfrage.'; - } - - // Send email if no errors - if (empty($formErrors)) { - $to = 'mki@kies-media.de'; - $subject = 'Kontaktanfrage: ' . $formData['interest']; - $body = "Von: {$formData['fname']} {$formData['lname']}\n" - . "E-Mail: {$formData['email']}\n"; - if ($formData['phone'] !== '') { - $body .= "Telefon: {$formData['phone']}\n"; - } - $body .= "Anliegen: {$formData['interest']}\n\n" - . $formData['message']; - - $headers = "From: {$formData['email']}\r\n"; - $headers .= "Reply-To: {$formData['email']}\r\n"; - $headers .= "Content-Type: text/plain; charset=UTF-8\r\n"; - $headers .= "X-Mailer: PHP/" . phpversion(); - - $mailSent = mail($to, $subject, $body, $headers); - - if ($mailSent) { - $_SESSION['last_contact_submit'] = time(); - header('Location: ' . $_SERVER['REQUEST_URI'] . '#form-result'); - $_SESSION['form_success'] = true; - exit; - } else { - $formErrors[] = 'Leider konnte die E-Mail nicht gesendet werden. Bitte versuchen Sie es später erneut oder schreiben Sie uns direkt an mki@kies-media.de.'; - } - } - } - if (!empty($formErrors)) { - header('Location: ' . $_SERVER['REQUEST_URI'] . '#form-result'); - $_SESSION['form_errors'] = $formErrors; - $_SESSION['form_data'] = $formData; - exit; - } -} -?> - - - - - - Einfamilienhaus mieten Schleusingen | 227 m², 6 Zimmer | 1.300 € Kaltmiete - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
Zur Langzeitmiete · Ab sofort verfügbar
-

- Großzügiges -
- Einfamilienhaus -
- in Schleusingen -

-
- Schleusinger Bahnhofstraße 10 - 227 m² Wohnfläche - 6 Zimmer - 3 Etagen + Dachterrasse -
-
-
- Entdecken -
-
-
- -
-
-
227
-
m² Wohnfläche
-
-
-
6
-
Zimmer
-
-
-
3
-
Etagen
-
-
-
1.300
-
€ Kaltmiete
-
-
- -
-
-
Das Objekt
-

Wohnen mit Charakter und viel Raum

-

- Vermietet wird ein vollständiges Einfamilienhaus in ruhiger Lage von Schleusingen. Das - Haus verbindet historischen Charme mit modernem Wohnkomfort auf drei großzügigen Etagen. -

-

- Garage für zwei Fahrzeuge, großzügige Dachterrasse mit 35,8 m², vollausgestattete Küche, - Vollbad sowie Abstell- und Nutzräume machen das Haus zu einem außergewöhnlichen - Mietobjekt. -

-
-
-
154,9 m²
-
Nutzfläche
-
-
-
35,8 m²
-
Dachterrasse
-
-
-
2 Stpl.
-
Garage
-
-
-
-
- - - Wohnzimmer - -
Wohnzimmer · 42,6 m²
-
-
- - - -
-
Raumaufteilung
-

Großzügig auf allen Etagen

-
-
-
- Erdgeschoss -
- 99,5 m² -
+
-
-
-
-
-
- Flur - 20,1 m² -
-
- WC - 0,8 m² -
-
- Garage / Partykeller - 42,6 m² -
-
- Abstellraum 1 - 9,9 m² -
-
- Abstellraum 2 - 7,8 m² -
-
- Heizungskeller - 18,3 m² -
-
-
- - - Grundriss Erdgeschoss - - - - Grundriss Erdgeschoss - -
-
-
-
-
- 1. Obergeschoss -
- 120,4 m² -
+
-
-
-
-
-
- Flur - 20,1 m² -
-
- Wohnzimmer - 42,6 m² -
-
- Gästezimmer - 11,5 m² -
-
- Badezimmer - 9,8 m² -
-
- Küche - 18,4 m² -
-
- Schlafzimmer - 18,0 m² -
-
-
- - - Grundriss 1. Obergeschoss - - - - Grundriss 1. Obergeschoss - -
-
-
-
-
- 2. Obergeschoss -
- 68 m² -
+
-
-
-
-
-
- Flur - 13,9 m² -
-
- Kinderzimmer 1 - 21,7 m² -
-
- Kinderzimmer 2 - 15,7 m² -
-
- Spielzimmer - 6,3 m² -
-
- Ankleidezimmer - 1,4 m² -
-
- Dachterrasse - 9,0 m² (25% von 35,8 m²) -
-
-
- - - Grundriss 2. Obergeschoss (1) - - - - Grundriss 2. Obergeschoss (1) - -
-
-
-
-
- Dachboden -
- 94 m² Nutzfläche -
+
-
-
-
-
-
- Dachboden unten (ungeheizt) - 52 m² -
-
- Dachboden Mitte (ungeheizt) - 31 m² -
-
- Dachboden oben (ungeheizt) - 11 m² -
-
-
- - - Grundriss Dachboden - - - - Grundriss Dachboden - -
-
-
-
-
- -
-
-
Mietkonditionen
-

Transparente Preisgestaltung

-
-
-
Kaltmiete
-
1.300 €
-
pro Monat
-
-
-
Gesamtmiete warm
-
1.600 €
-
inkl. 300 € Nebenkosten
-
-
-
Kaution
-
2.600 €
-
2 Nettokaltmieten
-
-
-
-
- Verfügbarkeit - Ab sofort · unbefristete Laufzeit -
-
- Nebenkosten - Vorauszahlung 300 €/Monat, jährliche Abrechnung -
-
- Energieausweis - Wird bei Mietbeginn übergeben · Erdgasheizung -
-
- Haustiere - Auf Anfrage -
-
-
-
- -
-
Standort
-

Zentral und ruhig zugleich

-
-
-
🛒
-
-
Einkaufen & Versorgung
-
- Supermärkte, Ärzte, Apotheken und Schulen sind fußläufig erreichbar -
-
-
-
-
🚌
-
-
Öffentlicher Nahverkehr
-
- Zentrale Bushaltestelle ca. 200 m entfernt — direkte Verbindungen in die Region -
-
-
-
-
🏛
-
-
Innenstadt Schleusingen
-
Wochenmarkt und Stadtmitte nur ca. 500 m entfernt
-
-
-
-
📍
-
-
Genaue Adresse
-
- Schleusinger Bahnhofstraße 10 -
- 98533 Schleusingen, Thüringen -
-
-
-
- -
- -
-
- -
-
-
Kontakt
-

- Interesse? -
- Schreiben Sie uns. -

-

- Wir freuen uns über Ihre Anfrage und melden uns innerhalb von 24 Stunden. - Besichtigungstermine sind nach Absprache möglich. Bitte geben Sie bei Ihrer Anfrage ein - paar Terminvorschläge an. -

-
- -
-

Vielen Dank für Ihre Anfrage!

-
- Wir haben Ihre Nachricht erhalten und melden uns innerhalb von 24 Stunden bei Ihnen. -
- - -
-
    - -
  • - -
-
- -
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
-
-
- - -
-
- - - - - -
- -
-
-

Oder schreiben Sie uns direkt: mki@kies-media.de

-
-
-
- - - - - - - - diff --git a/js/haus-schleusingen.js b/js/haus-schleusingen.js deleted file mode 100644 index 1d6bf06..0000000 --- a/js/haus-schleusingen.js +++ /dev/null @@ -1,131 +0,0 @@ -$(function () { - // Navbar scroll - $(window).on("scroll", function () { - if ($(this).scrollTop() > 60) $("#navbar").addClass("scrolled"); - else $("#navbar").removeClass("scrolled"); - }); - - // Hero animation on load - setTimeout(function () { - $("#heroContent").addClass("visible"); - $("#heroBg").addClass("loaded"); - }, 200); - - // Scroll animations - function checkVisible() { - $(".fact, [data-animate]").each(function () { - var el = $(this); - var top = el.offset().top; - var windowBottom = $(window).scrollTop() + $(window).height(); - if (windowBottom > top + 60) { - el.addClass("visible"); - el.css({ opacity: 1, transform: "translateY(0)" }); - } - }); - } - $("[data-animate]").css({ - opacity: 0, - transform: "translateY(30px)", - transition: "opacity 0.8s ease, transform 0.8s ease", - }); - $(window).on("scroll", checkVisible); - checkVisible(); - - // Floor accordion - $(".floor-header").on("click", function () { - var item = $(this).closest(".floor-item"); - var isOpen = item.hasClass("open"); - $(".floor-item").removeClass("open"); - $(".floor-body").slideUp(300); - if (!isOpen) { - item.addClass("open"); - item.find(".floor-body").slideDown(300); - } - }); - - // Lightbox – gallery grid items - $(document).on("click", ".grid-item", function () { - var src = $(this).data("img") || $(this).find("img").attr("src"); - $("#lightboxImg").off("error").on("error", function () { - // WebP fallback: try original format - if ($(this).attr('src').endsWith('.webp')) { - $(this).attr('src', src.replace(/\.webp$/, '.png')); - } - }); - $("#lightboxImg").attr("src", src); - $("#lightbox").addClass("open"); - $("body").css("overflow", "hidden"); - }); - - // Lightbox – floor plan images in Raumaufteilung - $(document).on("click", ".floor-plan img[data-img]", function () { - var src = $(this).data("img"); - $("#lightboxImg").off("error").on("error", function () { - if ($(this).attr('src').endsWith('.webp')) { - $(this).attr('src', src.replace(/\.webp$/, '.png')); - } - }); - $("#lightboxImg").attr("src", src); - $("#lightbox").addClass("open"); - $("body").css("overflow", "hidden"); - }); - $("#lightboxClose, #lightbox").on("click", function (e) { - if (e.target === this) { - $("#lightbox").removeClass("open"); - $("body").css("overflow", ""); - } - }); - $(document).on("keydown", function (e) { - if (e.key === "Escape") { - $("#lightbox").removeClass("open"); - $("body").css("overflow", ""); - } - }); - - // Form submit is handled server-side by PHP – no JS intervention needed. -}); - -// Mobile hamburger menu (vanilla JS) -(function () { - var hamburger = document.querySelector(".nav-hamburger"); - var nav = document.getElementById("navbar"); - var overlay = document.querySelector(".nav-mobile-overlay"); - var links = nav ? nav.querySelectorAll(".nav-links a") : []; - - function toggleMenu() { - var isOpen = hamburger.classList.toggle("active"); - nav.classList.toggle("mobile-open", isOpen); - if (overlay) overlay.classList.toggle("active", isOpen); - hamburger.setAttribute("aria-expanded", isOpen); - document.body.style.overflow = isOpen ? "hidden" : ""; - } - - function closeMenu() { - hamburger.classList.remove("active"); - nav.classList.remove("mobile-open"); - if (overlay) overlay.classList.remove("active"); - hamburger.setAttribute("aria-expanded", "false"); - document.body.style.overflow = ""; - } - - if (hamburger) { - hamburger.addEventListener("click", toggleMenu); - } - - if (overlay) { - overlay.addEventListener("click", closeMenu); - } - - links.forEach(function (link) { - link.addEventListener("click", closeMenu); - }); - - document.addEventListener("keydown", function (e) { - if (e.key === "Escape") closeMenu(); - }); - - // Close on resize to desktop - window.addEventListener("resize", function () { - if (window.innerWidth > 900) closeMenu(); - }); -})(); diff --git a/nginx.conf b/nginx.conf old mode 100644 new mode 100755 diff --git a/package.json b/package.json old mode 100644 new mode 100755 diff --git a/page-preview.png b/page-preview.png old mode 100644 new mode 100755 diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..9be60ac --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,15 @@ +# Enable rewrite engine +RewriteEngine On + +# Legacy redirects (301) – must be before the catch-all +RewriteRule ^impressum\.html$ /impressum [R=301,L] +RewriteRule ^datenschutz\.html$ /datenschutz [R=301,L] +RewriteRule ^haus-schleusingen\.html$ / [R=301,L] + +# Serve existing files/directories directly (css, js, images, fonts, etc.) +RewriteCond %{REQUEST_FILENAME} -f [OR] +RewriteCond %{REQUEST_FILENAME} -d +RewriteRule ^ - [L] + +# Route everything else through the front controller +RewriteRule ^(.*)$ index.php [QSA,L] diff --git a/bilder/Außenansicht-2-small.png b/public/bilder/Außenansicht-2-small.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/Außenansicht-2-small.png rename to public/bilder/Außenansicht-2-small.png diff --git a/bilder/Außenansicht-2-small.webp b/public/bilder/Außenansicht-2-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Außenansicht-2-small.webp rename to public/bilder/Außenansicht-2-small.webp diff --git a/bilder/Außenansicht-2.png b/public/bilder/Außenansicht-2.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/Außenansicht-2.png rename to public/bilder/Außenansicht-2.png diff --git a/bilder/Außenansicht-2.webp b/public/bilder/Außenansicht-2.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Außenansicht-2.webp rename to public/bilder/Außenansicht-2.webp diff --git a/bilder/Bad-2-small.jpg b/public/bilder/Bad-2-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-2-small.jpg rename to public/bilder/Bad-2-small.jpg diff --git a/bilder/Bad-2-small.webp b/public/bilder/Bad-2-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-2-small.webp rename to public/bilder/Bad-2-small.webp diff --git a/bilder/Bad-2.jpeg b/public/bilder/Bad-2.jpeg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-2.jpeg rename to public/bilder/Bad-2.jpeg diff --git a/bilder/Bad-2.webp b/public/bilder/Bad-2.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-2.webp rename to public/bilder/Bad-2.webp diff --git a/bilder/Bad-3-small.jpg b/public/bilder/Bad-3-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-3-small.jpg rename to public/bilder/Bad-3-small.jpg diff --git a/bilder/Bad-3-small.webp b/public/bilder/Bad-3-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-3-small.webp rename to public/bilder/Bad-3-small.webp diff --git a/bilder/Bad-3.jpeg b/public/bilder/Bad-3.jpeg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-3.jpeg rename to public/bilder/Bad-3.jpeg diff --git a/bilder/Bad-3.webp b/public/bilder/Bad-3.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-3.webp rename to public/bilder/Bad-3.webp diff --git a/bilder/Bad-4-small.jpg b/public/bilder/Bad-4-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-4-small.jpg rename to public/bilder/Bad-4-small.jpg diff --git a/bilder/Bad-4-small.webp b/public/bilder/Bad-4-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-4-small.webp rename to public/bilder/Bad-4-small.webp diff --git a/bilder/Bad-4.jpeg b/public/bilder/Bad-4.jpeg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-4.jpeg rename to public/bilder/Bad-4.jpeg diff --git a/bilder/Bad-4.webp b/public/bilder/Bad-4.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-4.webp rename to public/bilder/Bad-4.webp diff --git a/bilder/Bad-small.jpg b/public/bilder/Bad-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-small.jpg rename to public/bilder/Bad-small.jpg diff --git a/bilder/Bad-small.webp b/public/bilder/Bad-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad-small.webp rename to public/bilder/Bad-small.webp diff --git a/bilder/Bad.jpg b/public/bilder/Bad.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad.jpg rename to public/bilder/Bad.jpg diff --git a/bilder/Bad.webp b/public/bilder/Bad.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Bad.webp rename to public/bilder/Bad.webp diff --git a/bilder/Kinderzimmer 2-small.png b/public/bilder/Kinderzimmer 2-small.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer 2-small.png rename to public/bilder/Kinderzimmer 2-small.png diff --git a/bilder/Kinderzimmer 2-small.webp b/public/bilder/Kinderzimmer 2-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer 2-small.webp rename to public/bilder/Kinderzimmer 2-small.webp diff --git a/bilder/Kinderzimmer 2.jpg b/public/bilder/Kinderzimmer 2.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer 2.jpg rename to public/bilder/Kinderzimmer 2.jpg diff --git a/bilder/Kinderzimmer 2.webp b/public/bilder/Kinderzimmer 2.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer 2.webp rename to public/bilder/Kinderzimmer 2.webp diff --git a/bilder/Kinderzimmer 3-small.png b/public/bilder/Kinderzimmer 3-small.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer 3-small.png rename to public/bilder/Kinderzimmer 3-small.png diff --git a/bilder/Kinderzimmer 3-small.webp b/public/bilder/Kinderzimmer 3-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer 3-small.webp rename to public/bilder/Kinderzimmer 3-small.webp diff --git a/bilder/Kinderzimmer 3.jpg b/public/bilder/Kinderzimmer 3.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer 3.jpg rename to public/bilder/Kinderzimmer 3.jpg diff --git a/bilder/Kinderzimmer 3.webp b/public/bilder/Kinderzimmer 3.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer 3.webp rename to public/bilder/Kinderzimmer 3.webp diff --git a/bilder/Kinderzimmer-small.png b/public/bilder/Kinderzimmer-small.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer-small.png rename to public/bilder/Kinderzimmer-small.png diff --git a/bilder/Kinderzimmer-small.webp b/public/bilder/Kinderzimmer-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer-small.webp rename to public/bilder/Kinderzimmer-small.webp diff --git a/bilder/Kinderzimmer.png b/public/bilder/Kinderzimmer.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer.png rename to public/bilder/Kinderzimmer.png diff --git a/bilder/Kinderzimmer.webp b/public/bilder/Kinderzimmer.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Kinderzimmer.webp rename to public/bilder/Kinderzimmer.webp diff --git a/bilder/Küche 1-small.jpg b/public/bilder/Küche 1-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Küche 1-small.jpg rename to public/bilder/Küche 1-small.jpg diff --git a/bilder/Küche 1-small.webp b/public/bilder/Küche 1-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Küche 1-small.webp rename to public/bilder/Küche 1-small.webp diff --git a/bilder/Küche 1.jpg b/public/bilder/Küche 1.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/Küche 1.jpg rename to public/bilder/Küche 1.jpg diff --git a/bilder/Küche 1.webp b/public/bilder/Küche 1.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/Küche 1.webp rename to public/bilder/Küche 1.webp diff --git a/public/bilder/favicon/apple-touch-icon.png b/public/bilder/favicon/apple-touch-icon.png new file mode 100755 index 0000000000000000000000000000000000000000..b34ffd290886ac3435acba32604a07301aa78049 GIT binary patch literal 55489 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 literal 0 HcmV?d00001 diff --git a/public/bilder/favicon/favicon-32x32.png b/public/bilder/favicon/favicon-32x32.png new file mode 100755 index 0000000000000000000000000000000000000000..6352df8fbf39b7f19e564d11550e0eac3b1eb78d GIT binary patch literal 2440 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 literal 0 HcmV?d00001 diff --git a/public/bilder/favicon/favicon.ico b/public/bilder/favicon/favicon.ico new file mode 100755 index 0000000000000000000000000000000000000000..c49b767edd721aa82fb3244c18c1fb721f8875e6 GIT binary patch literal 3329 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 LNkvXXu0mjfuSP%4 literal 0 HcmV?d00001 diff --git a/public/bilder/favicon/site.webmanifest b/public/bilder/favicon/site.webmanifest new file mode 100755 index 0000000..f6f3493 --- /dev/null +++ b/public/bilder/favicon/site.webmanifest @@ -0,0 +1,10 @@ +{ + "name": "Haus Schleusingen", + "short_name": "HS", + "icons": [ + { "src": "/bilder/favicon/favicon-32x32.png", "sizes": "32x32", "type": "image/png" }, + { "src": "/bilder/favicon/favicon-16x16.png", "sizes": "16x16", "type": "image/png" } + ], + "theme_color": "#1c1917", + "background_color": "#fafaf9" +} diff --git a/bilder/grundrisse/Dachboden unten 2-small.jpg b/public/bilder/grundrisse/Dachboden unten 2-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/Dachboden unten 2-small.jpg rename to public/bilder/grundrisse/Dachboden unten 2-small.jpg diff --git a/bilder/grundrisse/Dachboden unten 2-small.webp b/public/bilder/grundrisse/Dachboden unten 2-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/Dachboden unten 2-small.webp rename to public/bilder/grundrisse/Dachboden unten 2-small.webp diff --git a/bilder/grundrisse/Dachboden unten 2.png b/public/bilder/grundrisse/Dachboden unten 2.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/Dachboden unten 2.png rename to public/bilder/grundrisse/Dachboden unten 2.png diff --git a/bilder/grundrisse/Dachboden unten 2.webp b/public/bilder/grundrisse/Dachboden unten 2.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/Dachboden unten 2.webp rename to public/bilder/grundrisse/Dachboden unten 2.webp diff --git a/bilder/grundrisse/Dachboden unten-small.jpg b/public/bilder/grundrisse/Dachboden unten-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/Dachboden unten-small.jpg rename to public/bilder/grundrisse/Dachboden unten-small.jpg diff --git a/bilder/grundrisse/Dachboden unten-small.webp b/public/bilder/grundrisse/Dachboden unten-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/Dachboden unten-small.webp rename to public/bilder/grundrisse/Dachboden unten-small.webp diff --git a/bilder/grundrisse/Dachboden unten.png b/public/bilder/grundrisse/Dachboden unten.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/Dachboden unten.png rename to public/bilder/grundrisse/Dachboden unten.png diff --git a/bilder/grundrisse/Dachboden unten.webp b/public/bilder/grundrisse/Dachboden unten.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/Dachboden unten.webp rename to public/bilder/grundrisse/Dachboden unten.webp diff --git a/bilder/grundrisse/EG 3D-small.jpg b/public/bilder/grundrisse/EG 3D-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/EG 3D-small.jpg rename to public/bilder/grundrisse/EG 3D-small.jpg diff --git a/bilder/grundrisse/EG 3D-small.webp b/public/bilder/grundrisse/EG 3D-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/EG 3D-small.webp rename to public/bilder/grundrisse/EG 3D-small.webp diff --git a/bilder/grundrisse/EG 3D.png b/public/bilder/grundrisse/EG 3D.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/EG 3D.png rename to public/bilder/grundrisse/EG 3D.png diff --git a/bilder/grundrisse/EG 3D.webp b/public/bilder/grundrisse/EG 3D.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/EG 3D.webp rename to public/bilder/grundrisse/EG 3D.webp diff --git a/bilder/grundrisse/EG-small.jpg b/public/bilder/grundrisse/EG-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/EG-small.jpg rename to public/bilder/grundrisse/EG-small.jpg diff --git a/bilder/grundrisse/EG-small.webp b/public/bilder/grundrisse/EG-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/EG-small.webp rename to public/bilder/grundrisse/EG-small.webp diff --git a/bilder/grundrisse/EG.png b/public/bilder/grundrisse/EG.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/EG.png rename to public/bilder/grundrisse/EG.png diff --git a/bilder/grundrisse/EG.webp b/public/bilder/grundrisse/EG.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/EG.webp rename to public/bilder/grundrisse/EG.webp diff --git a/bilder/grundrisse/OG 1 2-small.jpg b/public/bilder/grundrisse/OG 1 2-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 1 2-small.jpg rename to public/bilder/grundrisse/OG 1 2-small.jpg diff --git a/bilder/grundrisse/OG 1 2-small.webp b/public/bilder/grundrisse/OG 1 2-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 1 2-small.webp rename to public/bilder/grundrisse/OG 1 2-small.webp diff --git a/bilder/grundrisse/OG 1 2.png b/public/bilder/grundrisse/OG 1 2.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 1 2.png rename to public/bilder/grundrisse/OG 1 2.png diff --git a/bilder/grundrisse/OG 1 2.webp b/public/bilder/grundrisse/OG 1 2.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 1 2.webp rename to public/bilder/grundrisse/OG 1 2.webp diff --git a/bilder/grundrisse/OG 1 3D-small.jpg b/public/bilder/grundrisse/OG 1 3D-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 1 3D-small.jpg rename to public/bilder/grundrisse/OG 1 3D-small.jpg diff --git a/bilder/grundrisse/OG 1 3D-small.webp b/public/bilder/grundrisse/OG 1 3D-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 1 3D-small.webp rename to public/bilder/grundrisse/OG 1 3D-small.webp diff --git a/bilder/grundrisse/OG 1 3D.png b/public/bilder/grundrisse/OG 1 3D.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 1 3D.png rename to public/bilder/grundrisse/OG 1 3D.png diff --git a/bilder/grundrisse/OG 1 3D.webp b/public/bilder/grundrisse/OG 1 3D.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 1 3D.webp rename to public/bilder/grundrisse/OG 1 3D.webp diff --git a/bilder/grundrisse/OG 2 3D-small.jpg b/public/bilder/grundrisse/OG 2 3D-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 2 3D-small.jpg rename to public/bilder/grundrisse/OG 2 3D-small.jpg diff --git a/bilder/grundrisse/OG 2 3D-small.webp b/public/bilder/grundrisse/OG 2 3D-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 2 3D-small.webp rename to public/bilder/grundrisse/OG 2 3D-small.webp diff --git a/bilder/grundrisse/OG 2 3D.png b/public/bilder/grundrisse/OG 2 3D.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 2 3D.png rename to public/bilder/grundrisse/OG 2 3D.png diff --git a/bilder/grundrisse/OG 2 3D.webp b/public/bilder/grundrisse/OG 2 3D.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 2 3D.webp rename to public/bilder/grundrisse/OG 2 3D.webp diff --git a/bilder/grundrisse/OG 2 grundriss-small.jpg b/public/bilder/grundrisse/OG 2 grundriss-small.jpg old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 2 grundriss-small.jpg rename to public/bilder/grundrisse/OG 2 grundriss-small.jpg diff --git a/bilder/grundrisse/OG 2 grundriss-small.webp b/public/bilder/grundrisse/OG 2 grundriss-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 2 grundriss-small.webp rename to public/bilder/grundrisse/OG 2 grundriss-small.webp diff --git a/bilder/grundrisse/OG 2 grundriss.png b/public/bilder/grundrisse/OG 2 grundriss.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 2 grundriss.png rename to public/bilder/grundrisse/OG 2 grundriss.png diff --git a/bilder/grundrisse/OG 2 grundriss.webp b/public/bilder/grundrisse/OG 2 grundriss.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/grundrisse/OG 2 grundriss.webp rename to public/bilder/grundrisse/OG 2 grundriss.webp diff --git a/bilder/kinderzimmer 2 2-small.png b/public/bilder/kinderzimmer 2 2-small.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/kinderzimmer 2 2-small.png rename to public/bilder/kinderzimmer 2 2-small.png diff --git a/bilder/kinderzimmer 2 2-small.webp b/public/bilder/kinderzimmer 2 2-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/kinderzimmer 2 2-small.webp rename to public/bilder/kinderzimmer 2 2-small.webp diff --git a/bilder/kinderzimmer 2 2.jpeg b/public/bilder/kinderzimmer 2 2.jpeg old mode 100644 new mode 100755 similarity index 100% rename from bilder/kinderzimmer 2 2.jpeg rename to public/bilder/kinderzimmer 2 2.jpeg diff --git a/bilder/kinderzimmer 2 2.webp b/public/bilder/kinderzimmer 2 2.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/kinderzimmer 2 2.webp rename to public/bilder/kinderzimmer 2 2.webp diff --git a/bilder/schlafzimmer-small.png b/public/bilder/schlafzimmer-small.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/schlafzimmer-small.png rename to public/bilder/schlafzimmer-small.png diff --git a/bilder/schlafzimmer-small.webp b/public/bilder/schlafzimmer-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/schlafzimmer-small.webp rename to public/bilder/schlafzimmer-small.webp diff --git a/bilder/schlafzimmer.png b/public/bilder/schlafzimmer.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/schlafzimmer.png rename to public/bilder/schlafzimmer.png diff --git a/bilder/schlafzimmer.webp b/public/bilder/schlafzimmer.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/schlafzimmer.webp rename to public/bilder/schlafzimmer.webp diff --git a/bilder/wohnzimmer2-small.png b/public/bilder/wohnzimmer2-small.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/wohnzimmer2-small.png rename to public/bilder/wohnzimmer2-small.png diff --git a/bilder/wohnzimmer2-small.webp b/public/bilder/wohnzimmer2-small.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/wohnzimmer2-small.webp rename to public/bilder/wohnzimmer2-small.webp diff --git a/bilder/wohnzimmer2.png b/public/bilder/wohnzimmer2.png old mode 100644 new mode 100755 similarity index 100% rename from bilder/wohnzimmer2.png rename to public/bilder/wohnzimmer2.png diff --git a/bilder/wohnzimmer2.webp b/public/bilder/wohnzimmer2.webp old mode 100644 new mode 100755 similarity index 100% rename from bilder/wohnzimmer2.webp rename to public/bilder/wohnzimmer2.webp diff --git a/css/haus-schleusingen.css b/public/css/haus-schleusingen.css old mode 100644 new mode 100755 similarity index 95% rename from css/haus-schleusingen.css rename to public/css/haus-schleusingen.css index 68a09b1..a4bab37 --- a/css/haus-schleusingen.css +++ b/public/css/haus-schleusingen.css @@ -1,7 +1,55 @@ +/* SKIP LINK */ +.skip-link { + position: absolute; + left: -9999px; + top: 0; + background: var(--accent); + color: var(--white); + padding: 0.75rem 1.5rem; + font-size: 0.85rem; + font-weight: 500; + z-index: 200; + text-decoration: none; + transition: none; +} + +.skip-link:focus { + left: 0; + outline: 2px solid var(--white); + outline-offset: 2px; +} + +/* FOCUS VISIBLE */ +*:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.lightbox-close:focus-visible { + outline: 2px solid var(--white); + outline-offset: 2px; +} + +button:focus-visible, +a:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.grid-item:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.floor-header:focus-visible { + outline: 2px solid var(--accent); + outline-offset: -2px; +} + :root { --cream: #f5f0e8; --warm: #e8dfd0; - --stone: #9e9485; + --stone: #7a7062; --dark: #1c1a17; --charcoal: #2e2b26; --accent: #8b6914; @@ -1168,7 +1216,7 @@ footer { gap: 0; z-index: 95; border-bottom: 1px solid var(--warm); - animation: slideDown 0.3s ease; + animation: slide-down 0.3s ease; } nav.mobile-open .nav-links a { @@ -1191,11 +1239,12 @@ footer { background: transparent; } - @keyframes slideDown { + @keyframes slide-down { from { opacity: 0; transform: translateY(-10px); } + to { opacity: 1; transform: translateY(0); diff --git a/fonts/CormorantGaramond-Light.ttf b/public/fonts/CormorantGaramond-Light.ttf old mode 100644 new mode 100755 similarity index 100% rename from fonts/CormorantGaramond-Light.ttf rename to public/fonts/CormorantGaramond-Light.ttf diff --git a/fonts/CormorantGaramond-Regular.ttf b/public/fonts/CormorantGaramond-Regular.ttf old mode 100644 new mode 100755 similarity index 100% rename from fonts/CormorantGaramond-Regular.ttf rename to public/fonts/CormorantGaramond-Regular.ttf diff --git a/fonts/CormorantGaramond-SemiBold.ttf b/public/fonts/CormorantGaramond-SemiBold.ttf old mode 100644 new mode 100755 similarity index 100% rename from fonts/CormorantGaramond-SemiBold.ttf rename to public/fonts/CormorantGaramond-SemiBold.ttf diff --git a/fonts/DMSans-Light.ttf b/public/fonts/DMSans-Light.ttf old mode 100644 new mode 100755 similarity index 100% rename from fonts/DMSans-Light.ttf rename to public/fonts/DMSans-Light.ttf diff --git a/fonts/DMSans-Medium.ttf b/public/fonts/DMSans-Medium.ttf old mode 100644 new mode 100755 similarity index 100% rename from fonts/DMSans-Medium.ttf rename to public/fonts/DMSans-Medium.ttf diff --git a/fonts/DMSans-Regular.ttf b/public/fonts/DMSans-Regular.ttf old mode 100644 new mode 100755 similarity index 100% rename from fonts/DMSans-Regular.ttf rename to public/fonts/DMSans-Regular.ttf diff --git a/fonts/fonts.css b/public/fonts/fonts.css old mode 100644 new mode 100755 similarity index 100% rename from fonts/fonts.css rename to public/fonts/fonts.css diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..005abcc --- /dev/null +++ b/public/index.php @@ -0,0 +1,44 @@ +addRoute('/', \App\Controllers\HomeController::class, 'index'); +$router->addRoute('/impressum', \App\Controllers\ImpressumController::class, 'index'); +$router->addRoute('/datenschutz', \App\Controllers\DatenschutzController::class, 'index'); + +// Dispatch +$uri = $_SERVER['REQUEST_URI'] ?? '/'; +$router->dispatch($uri); diff --git a/public/js/haus-schleusingen.js b/public/js/haus-schleusingen.js new file mode 100755 index 0000000..205e143 --- /dev/null +++ b/public/js/haus-schleusingen.js @@ -0,0 +1,259 @@ +document.addEventListener("DOMContentLoaded", function () { + // Navbar scroll + var navbar = document.getElementById("navbar"); + window.addEventListener("scroll", function () { + if (window.scrollY > 60) navbar.classList.add("scrolled"); + else navbar.classList.remove("scrolled"); + }); + + // Hero animation on load + setTimeout(function () { + document.getElementById("heroContent").classList.add("visible"); + document.getElementById("heroBg").classList.add("loaded"); + }, 200); + + // Scroll animations via IntersectionObserver + var animElements = document.querySelectorAll(".fact, [data-animate]"); + animElements.forEach(function (el) { + el.style.opacity = "0"; + el.style.transform = "translateY(30px)"; + el.style.transition = "opacity 0.8s ease, transform 0.8s ease"; + }); + + if ("IntersectionObserver" in window) { + var observer = new IntersectionObserver( + function (entries) { + entries.forEach(function (entry) { + if (entry.isIntersecting) { + entry.target.classList.add("visible"); + entry.target.style.opacity = "1"; + entry.target.style.transform = "translateY(0)"; + observer.unobserve(entry.target); + } + }); + }, + { rootMargin: "0px 0px -60px 0px" } + ); + animElements.forEach(function (el) { + observer.observe(el); + }); + } else { + // Fallback: show all immediately + animElements.forEach(function (el) { + el.classList.add("visible"); + el.style.opacity = "1"; + el.style.transform = "translateY(0)"; + }); + } + + // Floor accordion + // Floor accordion (vanilla JS + a11y) + document.querySelectorAll(".floor-header").forEach(function (header) { + header.addEventListener("click", function () { + var item = this.closest(".floor-item"); + var isOpen = item.classList.contains("open"); + var allItems = document.querySelectorAll(".floor-item"); + + // Close all + allItems.forEach(function (fi) { + fi.classList.remove("open"); + var hdr = fi.querySelector(".floor-header"); + if (hdr) hdr.setAttribute("aria-expanded", "false"); + var body = fi.querySelector(".floor-body"); + if (body) body.style.display = "none"; + }); + + // Open clicked if it was closed + if (!isOpen) { + item.classList.add("open"); + this.setAttribute("aria-expanded", "true"); + var body = item.querySelector(".floor-body"); + if (body) body.style.display = "block"; + } + }); + }); + + // Accordion keyboard handler (Enter/Space) + document.querySelectorAll(".floor-header").forEach(function (header) { + header.addEventListener("keydown", function (e) { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + this.click(); + } + }); + }); + + // Lightbox – track last focused element for focus return + var lightboxTrigger = null; + + function openLightbox(src) { + lightboxTrigger = document.activeElement; + var img = document.getElementById("lightboxImg"); + // WebP fallback: if .webp fails, try original format + img.onerror = function () { + if (img.getAttribute('src').endsWith('.webp')) { + img.setAttribute('src', src.replace(/\.webp$/, '.png')); + } + }; + img.setAttribute("src", src); + img.setAttribute("alt", ""); + document.getElementById("lightbox").classList.add("open"); + document.body.style.overflow = "hidden"; + // Set focus to close button + setTimeout(function () { + document.getElementById("lightboxClose").focus(); + }, 50); + } + + function closeLightbox() { + document.getElementById("lightbox").classList.remove("open"); + document.body.style.overflow = ""; + // Return focus to trigger + if (lightboxTrigger) { + lightboxTrigger.focus(); + lightboxTrigger = null; + } + } + + // Lightbox – gallery grid items + document.querySelectorAll(".grid-item").forEach(function (item) { + item.addEventListener("click", function () { + var src = this.dataset.img || this.querySelector("img").getAttribute("src"); + openLightbox(src); + }); + }); + + // Gallery keyboard handler (Enter/Space) + document.querySelectorAll(".grid-item").forEach(function (item) { + item.setAttribute("tabindex", "0"); + item.addEventListener("keydown", function (e) { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + this.click(); + } + }); + }); + + // Lightbox – floor plan images in Raumaufteilung + document.querySelectorAll(".floor-plan img[data-img]").forEach(function (img) { + img.addEventListener("click", function () { + openLightbox(this.dataset.img); + }); + }); + + + + document.getElementById("lightboxClose").addEventListener("click", closeLightbox); + document.getElementById("lightbox").addEventListener("click", function (e) { + if (e.target === this) closeLightbox(); + }); + document.addEventListener("keydown", function (e) { + if (e.key === "Escape") closeLightbox(); + }); + + // Focus trap for lightbox + document.getElementById("lightbox").addEventListener("keydown", function (e) { + if (e.key !== "Tab") return; + + var focusable = this.querySelectorAll("button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])"); + focusable = Array.from(focusable).filter(function (el) { return el.offsetParent !== null; }); + if (focusable.length === 0) return; + + var first = focusable[0]; + var last = focusable[focusable.length - 1]; + + if (e.shiftKey) { + if (document.activeElement === first) { + e.preventDefault(); + last.focus(); + } + } else { + if (document.activeElement === last) { + e.preventDefault(); + first.focus(); + } + } + }); + + // Form submit is handled server-side by PHP – no JS intervention needed. + // Form submit – opens email client with pre-filled mailto: link + document.getElementById("contactForm").addEventListener("submit", function (e) { + e.preventDefault(); + + var fname = document.getElementById("fname").value.trim(); + var lname = document.getElementById("lname").value.trim(); + var email = document.getElementById("email").value.trim(); + var phone = document.getElementById("phone").value.trim(); + var interest = document.getElementById("interest").value; + var message = document.getElementById("message").value.trim(); + + var subject = "Kontaktanfrage: " + interest; + var body = "Von: " + fname + " " + lname + "\n"; + body += "E-Mail: " + email + "\n"; + if (phone) body += "Telefon: " + phone + "\n"; + body += "Anliegen: " + interest + "\n\n"; + body += message; + + var mailto = + "mailto:mki@kies-media.de" + + "?subject=" + encodeURIComponent(subject) + + "&body=" + encodeURIComponent(body); + + window.location.href = mailto; + + // Show success message + this.style.display = "none"; + var success = document.getElementById("formSuccess"); + success.style.display = "block"; + success.style.opacity = "0"; + success.style.transition = "opacity 0.4s ease"; + requestAnimationFrame(function () { + success.style.opacity = "1"; + }); + }); +}); + +// Mobile hamburger menu (vanilla JS) +(function () { + var hamburger = document.querySelector(".nav-hamburger"); + var nav = document.getElementById("navbar"); + var overlay = document.querySelector(".nav-mobile-overlay"); + var links = nav ? nav.querySelectorAll(".nav-links a") : []; + + function toggleMenu() { + var isOpen = hamburger.classList.toggle("active"); + nav.classList.toggle("mobile-open", isOpen); + if (overlay) overlay.classList.toggle("active", isOpen); + hamburger.setAttribute("aria-expanded", isOpen); + document.body.style.overflow = isOpen ? "hidden" : ""; + } + + function closeMenu() { + hamburger.classList.remove("active"); + nav.classList.remove("mobile-open"); + if (overlay) overlay.classList.remove("active"); + hamburger.setAttribute("aria-expanded", "false"); + document.body.style.overflow = ""; + } + + if (hamburger) { + hamburger.addEventListener("click", toggleMenu); + } + + if (overlay) { + overlay.addEventListener("click", closeMenu); + } + + links.forEach(function (link) { + link.addEventListener("click", closeMenu); + }); + + document.addEventListener("keydown", function (e) { + if (e.key === "Escape") closeMenu(); + }); + + // Close on resize to desktop + window.addEventListener("resize", function () { + if (window.innerWidth > 900) closeMenu(); + }); +})(); diff --git a/public/robots.txt b/public/robots.txt new file mode 100755 index 0000000..516c855 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: / +Sitemap: https://haus-schleusingen.de/haus-schleusingen.html diff --git a/robots.txt b/robots.txt old mode 100644 new mode 100755 diff --git a/screenshot-landingpage-thumb.png b/screenshot-landingpage-thumb.png old mode 100644 new mode 100755 diff --git a/screenshot-landingpage.png b/screenshot-landingpage.png old mode 100644 new mode 100755