Compare commits
68 Commits
feature/is
...
2b5b0afd91
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b5b0afd91 | |||
| 3db7dc8971 | |||
| e30bc5704b | |||
| 25a48e9958 | |||
| a170afa7c0 | |||
| 148b4849fd | |||
|
|
4d2393f436 | ||
| 6b605bb961 | |||
|
|
9c2c8324b0 | ||
| 344b0d8271 | |||
| 9b92136048 | |||
| bd1407f8ab | |||
| d44fb337e2 | |||
| a919a392cc | |||
| 2d9f1838b6 | |||
| 36b5639801 | |||
| ffbf23a524 | |||
| 1aedcaf314 | |||
| 7e3b89bf63 | |||
|
|
afbf4ef80e | ||
|
|
a0615d10e2 | ||
|
|
a0d89a93a6 | ||
| 6612a0207a | |||
|
|
9c0a9a856a | ||
| 4ca48a7445 | |||
| 6b13b95102 | |||
| 9a8776412e | |||
| 127faaffaf | |||
| c6eda36750 | |||
| 336fbc12a6 | |||
|
|
8b73603293 | ||
| d609175b3c | |||
|
|
73635a5f03 | ||
|
|
b237cb6315 | ||
|
|
98cb53df09 | ||
|
|
8666bc1eec | ||
|
|
1fcdca95b7 | ||
| 88ef7aa6ac | |||
| bf53da13be | |||
| 2307c379dc | |||
| 2c6ed749d5 | |||
| c2f2709790 | |||
| 69ca8efa47 | |||
| 40001adbce | |||
| 158f07e374 | |||
| 76b1ec58c2 | |||
| 565c8b304d | |||
| 51d4f96b20 | |||
| 5167634ee6 | |||
| 0995684989 | |||
| 7706f11106 | |||
| 143962a0fa | |||
| 04d570cb91 | |||
|
|
8706cb2b70 | ||
|
|
3df40952c1 | ||
|
|
c467f8cc1e | ||
|
|
d4a59ee306 | ||
|
|
7be0a2e9d5 | ||
|
|
10bc7c1d77 | ||
|
|
e24db23888 | ||
| 48df09df6c | |||
|
|
3bbbe85599 | ||
| 88780c300a | |||
|
|
cc7b2d8d70 | ||
| ea85280cde | |||
| 958f52fd5d | |||
| 9c68365ab8 | |||
| 5b304730fa |
0
.continue/mcpServers/new-mcp-server.yaml
Normal file → Executable file
0
.dockerignore
Normal file → Executable file
67
.gitea/workflows/deploy-test.yml
Executable file
@@ -0,0 +1,67 @@
|
||||
name: Deploy Feature Branch to Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "feature/**"
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
volumes:
|
||||
- /var/www/test/html:/deploy
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Show branch info
|
||||
run: |
|
||||
echo "=== Deploying branch: ${{ gitea.ref_name }} ==="
|
||||
echo "=== Commit: ${{ gitea.sha }} ==="
|
||||
echo "=== By: ${{ gitea.actor }} ==="
|
||||
date
|
||||
|
||||
- name: Deploy to test environment
|
||||
run: |
|
||||
echo "Syncing files to test environment..."
|
||||
apt-get update -qq && apt-get install -y -qq rsync > /dev/null 2>&1 || true
|
||||
|
||||
rsync -av --delete \
|
||||
--exclude='.git' \
|
||||
--exclude='.gitea' \
|
||||
--exclude='.husky' \
|
||||
--exclude='.prettierrc' \
|
||||
--exclude='.prettierignore' \
|
||||
--exclude='.stylelintrc.json' \
|
||||
--exclude='.htmlhintrc' \
|
||||
--exclude='.gitignore' \
|
||||
--exclude='.dockerignore' \
|
||||
--exclude='Dockerfile' \
|
||||
--exclude='nginx.conf' \
|
||||
--exclude='eslint.config.js' \
|
||||
--exclude='package.json' \
|
||||
--exclude='docs/' \
|
||||
--exclude='AGENTS.md' \
|
||||
--exclude='README.md' \
|
||||
./ /deploy/
|
||||
|
||||
|
||||
echo "✅ Deployment complete!"
|
||||
|
||||
- name: Set permissions
|
||||
run: |
|
||||
chown -R 33:33 /deploy/ 2>/dev/null || true
|
||||
chmod -R 755 /deploy/ 2>/dev/null || true
|
||||
echo "✅ Permissions set"
|
||||
|
||||
- name: Deployment summary
|
||||
run: |
|
||||
echo "=========================================="
|
||||
echo " 🚀 Deployment Summary"
|
||||
echo "=========================================="
|
||||
echo " Branch: ${{ gitea.ref_name }}"
|
||||
echo " Commit: ${{ gitea.sha }}"
|
||||
echo " Target: http://178.104.150.0/"
|
||||
echo " Time: $(date)"
|
||||
echo "=========================================="
|
||||
64
.gitea/workflows/lint.yml
Normal file
@@ -0,0 +1,64 @@
|
||||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
lint-php:
|
||||
name: PHP Syntax Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install PHP
|
||||
run: |
|
||||
apt-get update -qq && apt-get install -y -qq php-cli > /dev/null 2>&1
|
||||
|
||||
- name: PHP Lint
|
||||
run: |
|
||||
errors=0
|
||||
while IFS= read -r file; do
|
||||
if ! php -l "$file" > /dev/null 2>&1; then
|
||||
echo "❌ Syntax error in $file"
|
||||
php -l "$file"
|
||||
errors=1
|
||||
fi
|
||||
done < <(find . -name "*.php" -not -path "./vendor/*")
|
||||
if [ "$errors" -eq 1 ]; then
|
||||
echo "::error::PHP lint check failed"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ All PHP files pass syntax check"
|
||||
|
||||
lint-css:
|
||||
name: CSS Lint (stylelint)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node.js & stylelint
|
||||
run: |
|
||||
apt-get update -qq && apt-get install -y -qq npm nodejs > /dev/null 2>&1
|
||||
npm install -g stylelint stylelint-config-standard stylelint-prettier > /dev/null 2>&1
|
||||
|
||||
- name: CSS Lint
|
||||
run: |
|
||||
npx stylelint "**/*.css" --config .stylelintrc.json --allow-empty-input
|
||||
echo "✅ All CSS files pass lint"
|
||||
|
||||
lint-html:
|
||||
name: HTML Lint (htmlhint)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node.js & htmlhint
|
||||
run: |
|
||||
apt-get update -qq && apt-get install -y -qq npm nodejs > /dev/null 2>&1
|
||||
npm install -g htmlhint > /dev/null 2>&1
|
||||
|
||||
- name: HTML Lint
|
||||
run: |
|
||||
npx htmlhint "**/*.html" --config .htmlhintrc
|
||||
echo "✅ All HTML files pass lint"
|
||||
0
.gitignore
vendored
Normal file → Executable file
8
.htaccess
Normal file
@@ -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]
|
||||
0
.htmlhintrc
Normal file → Executable file
0
.husky/pre-commit
Normal file → Executable file
0
.prettierignore
Normal file → Executable file
0
.prettierrc
Normal file → Executable file
0
.stylelintrc.json
Normal file → Executable file
2
AGENTS.md
Normal file → Executable file
@@ -17,7 +17,7 @@
|
||||
|
||||
| Pfad | Beschreibung |
|
||||
| --------------------------- | -------------------------------------------- |
|
||||
| `haus-schleusingen.html` | Einstiegsseite (einzige HTML-Datei) |
|
||||
| `public/index.php` | Einstiegsseite (PHP-Entry-Point) |
|
||||
| `css/haus-schleusingen.css` | Hauptstylesheet |
|
||||
| `js/haus-schleusingen.js` | Haupt-JavaScript |
|
||||
| `js/masonry.pkgd.min.js` | Masonry-Layout-Bibliothek (nicht bearbeiten) |
|
||||
|
||||
0
Dockerfile
Normal file → Executable file
20
README.md
Normal file → Executable file
@@ -4,8 +4,8 @@ Statische Landingpage für **Haus Schleusingen**.
|
||||
Das Projekt basiert auf reinem HTML, CSS und JavaScript und wird über einen Nginx-Container ausgeliefert.
|
||||
|
||||
<div align="right">
|
||||
<a href="screenshot-landingpage.png">
|
||||
<img src="screenshot-landingpage-thumb.png" alt="Screenshot der Landingpage – Haus Schleusingen" width="300" />
|
||||
<a href="docs/screenshot-landingpage.png">
|
||||
<img src="docs/screenshot-landingpage-thumb.png" alt="Screenshot der Landingpage – Haus Schleusingen" width="300" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,7 @@ Das Projekt basiert auf reinem HTML, CSS und JavaScript und wird über einen Ngi
|
||||
## Projektstruktur
|
||||
|
||||
```
|
||||
├── haus-schleusingen.html # Einstiegsseite (einzige HTML-Datei)
|
||||
├── public/index.php # Einstiegsseite (PHP-Entry-Point)
|
||||
├── css/
|
||||
│ └── haus-schleusingen.css # Hauptstylesheet
|
||||
├── js/
|
||||
@@ -172,6 +172,20 @@ npm run lint
|
||||
|
||||
## Git-Workflow
|
||||
|
||||
### Pre-Commit Hooks aktivieren
|
||||
|
||||
Die Pre-Commit Hooks (Husky + lint-staged) werden automatisch beim Installieren der Abhängigkeiten eingerichtet:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Der `prepare`-Script in `package.json` (`"prepare": "husky"`) sorgt dafür, dass Husky die Git Hooks im `.husky/`-Verzeichnis registriert. Nach `npm install` sind die Hooks aktiv – kein manueller Schritt nötig.
|
||||
|
||||
> **Falls Hooks nicht laufen:** Prüfe ob `.husky/pre-commit` ausführbar ist (`chmod +x .husky/pre-commit`) und ob `core.hooksPath` nicht überschrieben wurde (`git config core.hooksPath`).
|
||||
|
||||
### Was wird beim Commit geprüft?
|
||||
|
||||
Beim Committen führt **Husky** automatisch den Pre-Commit Hook (`.husky/pre-commit`) aus, der **lint-staged** startet.
|
||||
|
||||
### lint-staged prüft automatisch:
|
||||
|
||||
25
app/controllers/Controller.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Core\View;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
protected View $view;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
18
app/controllers/DatenschutzController.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
class DatenschutzController extends Controller
|
||||
{
|
||||
public function index(): void
|
||||
{
|
||||
$this->render('datenschutz/index', [
|
||||
'pageTitle' => 'Datenschutzerklärung – Haus Schleusingen',
|
||||
'pageDescription' => 'Datenschutzerklärung der Website haus-schleusingen.de',
|
||||
'robots' => 'noindex',
|
||||
'canonical' => 'https://haus-schleusingen.de/datenschutz',
|
||||
]);
|
||||
}
|
||||
}
|
||||
187
app/controllers/HomeController.php
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public function index(): void
|
||||
{
|
||||
session_start();
|
||||
|
||||
// --- Helper functions ---
|
||||
$normalizeContactValue = function (string $value): string {
|
||||
return trim($value);
|
||||
};
|
||||
|
||||
$escapeContactValue = function (string $value): string {
|
||||
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
|
||||
};
|
||||
|
||||
$containsHeaderInjection = function (string $value): bool {
|
||||
return (bool) preg_match('/[\r\n]/', $value);
|
||||
};
|
||||
|
||||
// --- Form processing ---
|
||||
$formErrors = [];
|
||||
$formSuccess = false;
|
||||
if (!empty($_SESSION['form_success'])) {
|
||||
$formSuccess = true;
|
||||
unset($_SESSION['form_success']);
|
||||
}
|
||||
if (!empty($_SESSION['form_errors'])) {
|
||||
$formErrors = $_SESSION['form_errors'];
|
||||
unset($_SESSION['form_errors']);
|
||||
}
|
||||
if (!empty($_SESSION['form_data'])) {
|
||||
$formData = $_SESSION['form_data'];
|
||||
unset($_SESSION['form_data']);
|
||||
} else {
|
||||
$formData = ['fname' => '', 'lname' => '', 'email' => '', 'phone' => '', 'interest' => 'Besichtigung anfragen', 'message' => ''];
|
||||
}
|
||||
|
||||
// CSRF-Token generieren (nach Session-Start)
|
||||
if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// CSRF-Token validieren
|
||||
$csrfToken = $_POST['csrf_token'] ?? '';
|
||||
if (!hash_equals($_SESSION['csrf_token'] ?? '', $csrfToken)) {
|
||||
header('Location: /#form-result');
|
||||
$_SESSION['form_errors'] = ['Sicherheitsüberprüfung fehlgeschlagen. Bitte versuchen Sie es erneut.'];
|
||||
exit;
|
||||
}
|
||||
|
||||
$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: /#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: /#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: /#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',
|
||||
],
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
18
app/controllers/ImpressumController.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
class ImpressumController extends Controller
|
||||
{
|
||||
public function index(): void
|
||||
{
|
||||
$this->render('impressum/index', [
|
||||
'pageTitle' => 'Impressum – Haus Schleusingen',
|
||||
'pageDescription' => 'Impressum der Website haus-schleusingen.de',
|
||||
'robots' => 'noindex',
|
||||
'canonical' => 'https://haus-schleusingen.de/impressum',
|
||||
]);
|
||||
}
|
||||
}
|
||||
60
app/core/Router.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Core;
|
||||
|
||||
class Router
|
||||
{
|
||||
private array $routes = [];
|
||||
|
||||
public function addRoute(string $path, string $controller, string $action = 'index'): void
|
||||
{
|
||||
$this->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 '<h1>404 – Seite nicht gefunden</h1>';
|
||||
echo '<p><a href="/">Zurück zur Startseite</a></p>';
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
46
app/core/View.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Core;
|
||||
|
||||
class View
|
||||
{
|
||||
private string $viewsPath;
|
||||
private array $data = [];
|
||||
|
||||
public function __construct(?string $viewsPath = null)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
123
app/views/datenschutz/index.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<nav id="navbar" class="scrolled">
|
||||
<div class="nav-logo">Bahnhofstraße 10</div>
|
||||
<ul class="nav-links">
|
||||
<li><a href="/#galerie">Galerie</a></li>
|
||||
<li><a href="/#grundriss">Grundriss</a></li>
|
||||
<li><a href="/#miete">Miete</a></li>
|
||||
<li><a href="/#lage">Lage</a></li>
|
||||
</ul>
|
||||
<a href="/#kontakt" class="nav-cta" style="text-decoration:none;">Jetzt anfragen</a>
|
||||
</nav>
|
||||
|
||||
<main class="legal-page">
|
||||
<div class="section-eyebrow">Datenschutz</div>
|
||||
<h1>Datenschutzerklärung</h1>
|
||||
|
||||
<h2>1. Verantwortliche Stelle</h2>
|
||||
<address>
|
||||
Martin Kiesewetter<br />
|
||||
Am Schaftalsgraben 4<br />
|
||||
98529 Suhl<br />
|
||||
Telefon: 0176 – 45853923<br />
|
||||
E-Mail: <a href="mailto:mki@kies-media.de">mki@kies-media.de</a>
|
||||
</address>
|
||||
<p>
|
||||
Diese Datenschutzerklärung informiert Sie über die Art, den Umfang und den Zweck der Erhebung und Verwendung personenbezogener Daten auf dieser Website.
|
||||
</p>
|
||||
|
||||
<hr class="legal-divider" />
|
||||
|
||||
<h2>2. Erhebung und Speicherung personenbezogener Daten</h2>
|
||||
|
||||
<h3>a) Beim Besuch der Website</h3>
|
||||
<p>
|
||||
Beim Aufrufen dieser Website werden durch den Hosting-Anbieter automatisch Informationen allgemeiner Natur erfasst. Diese Informationen (Server-Logfiles) beinhalten etwa die Art des Webbrowsers, das verwendete Betriebssystem, den Domainnamen Ihres Internet-Service-Providers, Ihre IP-Adresse und Ähnliches. Sie werden insbesondere zu einem sicheren und reibungslosen Betrieb der Website benötigt.
|
||||
</p>
|
||||
<ul>
|
||||
<li>IP-Adresse</li>
|
||||
<li>Datum und Uhrzeit der Anfrage</li>
|
||||
<li>Zeitzonenunterschied zur Greenwich Mean Time (GMT)</li>
|
||||
<li>Inhalt der Anforderung (konkrete Seite)</li>
|
||||
<li>Zugriffsstatus/HTTP-Statuscode</li>
|
||||
<li>Jeweils übertragene Datenmenge</li>
|
||||
<li>Website, von der die Anforderung kommt (Referrer-URL)</li>
|
||||
<li>Verwendeter Browser</li>
|
||||
<li>Verwendetes Betriebssystem</li>
|
||||
</ul>
|
||||
<p>
|
||||
Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO. Die Daten werden nicht mit anderen Datenquellen zusammengeführt und nach 30 Tagen automatisch gelöscht.
|
||||
</p>
|
||||
|
||||
<h3>b) Kontakt per E-Mail</h3>
|
||||
<p>
|
||||
Auf dieser Website wird die Kontaktaufnahme über einen E-Mail-Link (mailto:) angeboten. Wenn Sie uns per E-Mail kontaktieren, werden Ihre Angaben (E-Mail-Adresse, ggf. Name und Nachricht) zwecks Bearbeitung Ihrer Anfrage gespeichert. Die Daten werden ausschließlich zur Beantwortung Ihrer Anfrage verwendet und nach Abschluss der Kommunikation gelöscht.
|
||||
</p>
|
||||
<p>
|
||||
Rechtsgrundlage ist Art. 6 Abs. 1 lit. a DSGVO (Ihre Einwilligung) oder Art. 6 Abs. 1 lit. b DSGVO (zur Erfüllung eines Vertrags bzw. vorvertraglicher Maßnahmen).
|
||||
</p>
|
||||
|
||||
<hr class="legal-divider" />
|
||||
|
||||
<h2>3. Cookies</h2>
|
||||
<p>
|
||||
Diese Website verwendet <strong>keine Cookies</strong>. Es werden keine Tracking-Cookies, Werbe-Cookies oder sonstige Cookies gesetzt.
|
||||
</p>
|
||||
|
||||
<h2>4. Tracking & Analyse</h2>
|
||||
<p>
|
||||
Diese Website setzt <strong>keine Tracking- oder Analyse-Tools</strong> ein. Es werden keine Besucherstatistiken erstellt, kein Google Analytics, kein Facebook Pixel und keine ähnlichen Dienste verwendet.
|
||||
</p>
|
||||
|
||||
<h2>5. Social-Media-Plugins</h2>
|
||||
<p>
|
||||
Diese Website verwendet <strong>keine Social-Media-Plugins</strong> (Facebook, Twitter, Instagram etc.).
|
||||
</p>
|
||||
|
||||
<hr class="legal-divider" />
|
||||
|
||||
<h2>6. Google Maps</h2>
|
||||
<p>
|
||||
Auf dieser Website wird ein Google Maps-Embed (Kartenansicht) eingebunden. Beim Laden der Karte werden Daten an Google übertragen, darunter möglicherweise Ihre IP-Adresse. Google Maps wird ausschließlich genutzt, um Ihnen die Lage des Mietobjekts anzuzeigen.
|
||||
</p>
|
||||
<p>
|
||||
Weitere Informationen zum Datenschutz bei Google finden Sie unter: <a href="https://policies.google.com/privacy" target="_blank" rel="noopener">https://policies.google.com/privacy</a>
|
||||
</p>
|
||||
<p>
|
||||
Rechtsgrundlage: Art. 6 Abs. 1 lit. f DSGVO (berechtigte Interessen an der Darstellung des Objektstandorts).
|
||||
</p>
|
||||
|
||||
<hr class="legal-divider" />
|
||||
|
||||
<h2>7. SSL-Verschlüsselung</h2>
|
||||
<p>
|
||||
Diese Seite nutzt aus Sicherheitsgründen eine SSL-Verschlüsselung. Eine verschlüsselte Verbindung erkennen Sie daran, dass die Adresszeile des Browsers von „http://" auf „https://" wechselt und an dem Schloss-Symbol in Ihrer Browserzeile.
|
||||
</p>
|
||||
|
||||
<hr class="legal-divider" />
|
||||
|
||||
<h2>8. Ihre Rechte</h2>
|
||||
<p>Sie haben gegenüber uns folgende Rechte hinsichtlich der Sie betreffenden personenbezogenen Daten:</p>
|
||||
<ul>
|
||||
<li><strong>Recht auf Auskunft</strong> (Art. 15 DSGVO)</li>
|
||||
<li><strong>Recht auf Berichtigung</strong> (Art. 16 DSGVO)</li>
|
||||
<li><strong>Recht auf Löschung</strong> (Art. 17 DSGVO)</li>
|
||||
<li><strong>Recht auf Einschränkung der Verarbeitung</strong> (Art. 18 DSGVO)</li>
|
||||
<li><strong>Recht auf Datenübertragbarkeit</strong> (Art. 20 DSGVO)</li>
|
||||
<li><strong>Widerspruchsrecht</strong> (Art. 21 DSGVO)</li>
|
||||
<li><strong>Recht auf Widerruf der Einwilligung</strong> (Art. 7 Abs. 3 DSGVO)</li>
|
||||
<li><strong>Beschwerderecht bei einer Aufsichtsbehörde</strong> (Art. 77 DSGVO)</li>
|
||||
</ul>
|
||||
<p>
|
||||
Zur Ausübung Ihrer Rechte wenden Sie sich bitte an: <a href="mailto:mki@kies-media.de">mki@kies-media.de</a>
|
||||
</p>
|
||||
|
||||
<a href="/" class="legal-back">← Zurück zum Objekt</a>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="footer-logo">Bahnhofstraße 10 · Schleusingen</div>
|
||||
<div class="footer-links">
|
||||
<a href="/impressum">Impressum</a>
|
||||
<a href="/datenschutz">Datenschutz</a>
|
||||
</div>
|
||||
</footer>
|
||||
505
app/views/home/index.php
Normal file
@@ -0,0 +1,505 @@
|
||||
<a href="#main-content" class="skip-link">Zum Inhalt springen</a>
|
||||
<nav id="navbar" role="navigation" aria-label="Hauptnavigation">
|
||||
<div class="nav-logo">Bahnhofstraße 10</div>
|
||||
<button class="nav-hamburger" aria-label="Navigation öffnen" aria-expanded="false">
|
||||
<span></span>
|
||||
</button>
|
||||
<ul class="nav-links">
|
||||
<li><a href="#galerie">Galerie</a></li>
|
||||
<li><a href="#grundriss">Grundriss</a></li>
|
||||
<li><a href="#miete">Miete</a></li>
|
||||
<li><a href="#lage">Lage</a></li>
|
||||
</ul>
|
||||
<button
|
||||
class="nav-cta"
|
||||
onclick="$('html').animate({ scrollTop: $('#kontakt').offset().top }, 700)"
|
||||
>
|
||||
Jetzt anfragen
|
||||
</button>
|
||||
</nav>
|
||||
<div class="nav-mobile-overlay" aria-hidden="true"></div>
|
||||
|
||||
<section class="hero" id="hero">
|
||||
<div
|
||||
class="hero-bg"
|
||||
id="heroBg"
|
||||
style="background-image: url(/bilder/Außenansicht-2.webp)"
|
||||
></div>
|
||||
<div class="hero-overlay"></div>
|
||||
<div class="hero-content" id="heroContent">
|
||||
<div class="hero-tag">Zur Langzeitmiete · Ab sofort verfügbar</div>
|
||||
<h1>
|
||||
Großzügiges
|
||||
<br />
|
||||
<em>Einfamilienhaus</em>
|
||||
<br />
|
||||
in Schleusingen
|
||||
</h1>
|
||||
<div class="hero-meta">
|
||||
<span><strong>Schleusinger Bahnhofstraße 10</strong></span>
|
||||
<span>227 m² Wohnfläche</span>
|
||||
<span>6 Zimmer</span>
|
||||
<span>3 Etagen + Dachterrasse</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-scroll">
|
||||
<span>Entdecken</span>
|
||||
<div class="scroll-line"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<main id="main-content">
|
||||
<div class="facts-strip">
|
||||
<div class="fact">
|
||||
<div class="fact-val">227</div>
|
||||
<div class="fact-label">m² Wohnfläche</div>
|
||||
</div>
|
||||
<div class="fact">
|
||||
<div class="fact-val">6</div>
|
||||
<div class="fact-label">Zimmer</div>
|
||||
</div>
|
||||
<div class="fact">
|
||||
<div class="fact-val">3</div>
|
||||
<div class="fact-label">Etagen</div>
|
||||
</div>
|
||||
<div class="fact">
|
||||
<div class="fact-val">1.300</div>
|
||||
<div class="fact-label">€ Kaltmiete</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="intro" id="intro">
|
||||
<div class="intro-text" data-animate>
|
||||
<div class="section-eyebrow">Das Objekt</div>
|
||||
<h2>Wohnen mit Charakter und viel Raum</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<div class="intro-stats">
|
||||
<div>
|
||||
<div class="istat-val">154,9 m²</div>
|
||||
<div class="istat-label">Nutzfläche</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="istat-val">35,8 m²</div>
|
||||
<div class="istat-label">Dachterrasse</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="istat-val">2 Stpl.</div>
|
||||
<div class="istat-label">Garage</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="intro-img" data-animate>
|
||||
<picture>
|
||||
<source srcset="/bilder/wohnzimmer2.webp" type="image/webp">
|
||||
<img src="/bilder/wohnzimmer2.png" alt="Wohnzimmer" loading="lazy" />
|
||||
</picture>
|
||||
<div class="intro-img-badge">Wohnzimmer · 42,6 m²</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="galerie" class="gallery-section" aria-label="Fotogalerie">
|
||||
<div class="gallery-header">
|
||||
<div>
|
||||
<div class="section-eyebrow">Fotogalerie</div>
|
||||
<h2>Einblicke ins Haus</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="masonry-grid">
|
||||
<div class="grid-sizer"></div>
|
||||
|
||||
<div class="grid-item" data-img="/bilder/Außenansicht-2.webp" role="button" tabindex="0" aria-label="Außenansicht – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/Außenansicht-2-small.webp" type="image/webp">
|
||||
<img src="/bilder/Außenansicht-2-small.png" alt="Außenansicht des Einfamilienhauses" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Außenansicht</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/wohnzimmer2.webp" role="button" tabindex="0" aria-label="Wohnzimmer – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/wohnzimmer2-small.webp" type="image/webp">
|
||||
<img src="/bilder/wohnzimmer2-small.png" alt="Wohnzimmer mit 42,6 m² Wohnfläche" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Wohnzimmer · 42,6 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/Küche 1.webp" role="button" tabindex="0" aria-label="Küche – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/Küche 1-small.webp" type="image/webp">
|
||||
<img src="/bilder/Küche 1.jpg" alt="Küche mit 18,4 m²" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Küche · 18,4 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/schlafzimmer.webp" role="button" tabindex="0" aria-label="Schlafzimmer – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/schlafzimmer-small.webp" type="image/webp">
|
||||
<img src="/bilder/schlafzimmer-small.png" alt="Schlafzimmer mit 18 m²" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Schlafzimmer · 18 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/Bad.webp" role="button" tabindex="0" aria-label="Badezimmer – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/Bad-small.webp" type="image/webp">
|
||||
<img src="/bilder/Bad.jpg" alt="Badezimmer mit 9,8 m²" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Badezimmer · 9,8 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/Kinderzimmer.webp" role="button" tabindex="0" aria-label="Kinderzimmer 1 – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/Kinderzimmer-small.webp" type="image/webp">
|
||||
<img src="/bilder/Kinderzimmer-small.png" alt="Kinderzimmer 1 mit 21,7 m²" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Kinderzimmer 1 · 21,7 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/Kinderzimmer 2.webp" role="button" tabindex="0" aria-label="Kinderzimmer 2 – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/Kinderzimmer 2-small.webp" type="image/webp">
|
||||
<img src="/bilder/Kinderzimmer 2-small.png" alt="Kinderzimmer 2 mit 15,7 m²" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Kinderzimmer 2 · 15,7 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/kinderzimmer 2 2.webp" role="button" tabindex="0" aria-label="Kinderzimmer Detail – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/kinderzimmer 2 2-small.webp" type="image/webp">
|
||||
<img src="/bilder/kinderzimmer 2 2-small.png" alt="Detailansicht Kinderzimmer" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Kinderzimmer Detail</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/Kinderzimmer 3.webp" role="button" tabindex="0" aria-label="Gästezimmer – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/Kinderzimmer 3-small.webp" type="image/webp">
|
||||
<img src="/bilder/Kinderzimmer 3-small.png" alt="Gästezimmer mit 11,5 m²" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Gästezimmer · 11,5 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/Bad-2.webp" role="button" tabindex="0" aria-label="Zweites Bad – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/Bad-2-small.webp" type="image/webp">
|
||||
<img src="/bilder/Bad-2-small.jpg" alt="Zweites Badezimmer im Haus" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Wohnbereich</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/Bad-3.webp" role="button" tabindex="0" aria-label="Drittes Bad – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/Bad-3-small.webp" type="image/webp">
|
||||
<img src="/bilder/Bad-3-small.jpg" alt="Drittes Badezimmer im Haus" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Wohnbereich Detail</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="/bilder/Bad-4.webp" role="button" tabindex="0" aria-label="Wohnbereich Detail – Großansicht öffnen">
|
||||
<picture>
|
||||
<source srcset="/bilder/Bad-4-small.webp" type="image/webp">
|
||||
<img src="/bilder/Bad-4-small.jpg" alt="Wohnbereich Detail 3" loading="lazy" />
|
||||
</picture>
|
||||
<span class="grid-item-label">Hausansicht</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="floors-section" id="grundriss">
|
||||
<div class="section-eyebrow">Raumaufteilung</div>
|
||||
<h2>Großzügig auf allen Etagen</h2>
|
||||
<div class="floor-accordion">
|
||||
<div class="floor-item">
|
||||
<div class="floor-header" role="button" tabindex="0" aria-expanded="false" aria-controls="floor-body-0" id="floor-title-0">
|
||||
<span class="floor-title">Erdgeschoss</span>
|
||||
<div class="floor-size">
|
||||
<span>99,5 m²</span>
|
||||
<div class="floor-icon">+</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-body" id="floor-body-0" role="region" aria-labelledby="floor-title-0">
|
||||
<div class="floor-rooms-grid">
|
||||
<div class="room-chip">Flur<span class="room-chip-area">20,1 m²</span></div>
|
||||
<div class="room-chip">WC<span class="room-chip-area">0,8 m²</span></div>
|
||||
<div class="room-chip">Garage / Partykeller<span class="room-chip-area">42,6 m²</span></div>
|
||||
<div class="room-chip">Abstellraum 1<span class="room-chip-area">9,9 m²</span></div>
|
||||
<div class="room-chip">Abstellraum 2<span class="room-chip-area">7,8 m²</span></div>
|
||||
<div class="room-chip">Heizungskeller<span class="room-chip-area">18,3 m²</span></div>
|
||||
</div>
|
||||
<div class="floor-plan floor-plan-multi">
|
||||
<picture>
|
||||
<source srcset="/bilder/grundrisse/EG-small.webp" type="image/webp">
|
||||
<img src="/bilder/grundrisse/EG-small.jpg" alt="Grundriss Erdgeschoss" loading="lazy" data-img="/bilder/grundrisse/EG.webp" />
|
||||
</picture>
|
||||
<picture>
|
||||
<source srcset="/bilder/grundrisse/EG 3D-small.webp" type="image/webp">
|
||||
<img src="/bilder/grundrisse/EG 3D-small.jpg" alt="Grundriss Erdgeschoss" loading="lazy" data-img="/bilder/grundrisse/EG 3D.webp" />
|
||||
</picture>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-item">
|
||||
<div class="floor-header" role="button" tabindex="0" aria-expanded="false" aria-controls="floor-body-1" id="floor-title-1">
|
||||
<span class="floor-title">1. Obergeschoss</span>
|
||||
<div class="floor-size">
|
||||
<span>120,4 m²</span>
|
||||
<div class="floor-icon">+</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-body" id="floor-body-1" role="region" aria-labelledby="floor-title-1">
|
||||
<div class="floor-rooms-grid">
|
||||
<div class="room-chip">Flur<span class="room-chip-area">20,1 m²</span></div>
|
||||
<div class="room-chip">Wohnzimmer<span class="room-chip-area">42,6 m²</span></div>
|
||||
<div class="room-chip">Gästezimmer<span class="room-chip-area">11,5 m²</span></div>
|
||||
<div class="room-chip">Badezimmer<span class="room-chip-area">9,8 m²</span></div>
|
||||
<div class="room-chip">Küche<span class="room-chip-area">18,4 m²</span></div>
|
||||
<div class="room-chip">Schlafzimmer<span class="room-chip-area">18,0 m²</span></div>
|
||||
</div>
|
||||
<div class="floor-plan floor-plan-multi">
|
||||
<picture>
|
||||
<source srcset="/bilder/grundrisse/OG 1 2-small.webp" type="image/webp">
|
||||
<img src="/bilder/grundrisse/OG 1 2-small.jpg" alt="Grundriss 1. Obergeschoss" loading="lazy" data-img="/bilder/grundrisse/OG 1 2.webp" />
|
||||
</picture>
|
||||
<picture>
|
||||
<source srcset="/bilder/grundrisse/OG 1 3D-small.webp" type="image/webp">
|
||||
<img src="/bilder/grundrisse/OG 1 3D-small.jpg" alt="Grundriss 1. Obergeschoss" loading="lazy" data-img="/bilder/grundrisse/OG 1 3D.webp" />
|
||||
</picture>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-item">
|
||||
<div class="floor-header" role="button" tabindex="0" aria-expanded="false" aria-controls="floor-body-2" id="floor-title-2">
|
||||
<span class="floor-title">2. Obergeschoss</span>
|
||||
<div class="floor-size">
|
||||
<span>68 m²</span>
|
||||
<div class="floor-icon">+</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-body" id="floor-body-2" role="region" aria-labelledby="floor-title-2">
|
||||
<div class="floor-rooms-grid">
|
||||
<div class="room-chip">Flur<span class="room-chip-area">13,9 m²</span></div>
|
||||
<div class="room-chip">Kinderzimmer 1<span class="room-chip-area">21,7 m²</span></div>
|
||||
<div class="room-chip">Kinderzimmer 2<span class="room-chip-area">15,7 m²</span></div>
|
||||
<div class="room-chip">Spielzimmer<span class="room-chip-area">6,3 m²</span></div>
|
||||
<div class="room-chip">Ankleidezimmer<span class="room-chip-area">1,4 m²</span></div>
|
||||
<div class="room-chip">Dachterrasse<span class="room-chip-area">9,0 m²</span> <small>(25% von 35,8 m²)</small></div>
|
||||
</div>
|
||||
<div class="floor-plan floor-plan-multi">
|
||||
<picture>
|
||||
<source srcset="/bilder/grundrisse/OG 2 grundriss-small.webp" type="image/webp">
|
||||
<img src="/bilder/grundrisse/OG 2 grundriss-small.jpg" alt="Grundriss 2. Obergeschoss" loading="lazy" data-img="/bilder/grundrisse/OG 2 grundriss.webp" />
|
||||
</picture>
|
||||
<picture>
|
||||
<source srcset="/bilder/grundrisse/OG 2 3D-small.webp" type="image/webp">
|
||||
<img src="/bilder/grundrisse/OG 2 3D-small.jpg" alt="Grundriss 2. Obergeschoss" loading="lazy" data-img="/bilder/grundrisse/OG 2 3D.webp" />
|
||||
</picture>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-item">
|
||||
<div class="floor-header" role="button" tabindex="0" aria-expanded="false" aria-controls="floor-body-3" id="floor-title-3">
|
||||
<span class="floor-title">Dachboden</span>
|
||||
<div class="floor-size">
|
||||
<span>94 m² Nutzfläche</span>
|
||||
<div class="floor-icon">+</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-body" id="floor-body-3" role="region" aria-labelledby="floor-title-3">
|
||||
<div class="floor-rooms-grid">
|
||||
<div class="room-chip">Dachboden unten (ungeheizt)<span class="room-chip-area">52 m²</span></div>
|
||||
<div class="room-chip">Dachboden Mitte (ungeheizt)<span class="room-chip-area">31 m²</span></div>
|
||||
<div class="room-chip">Dachboden oben (ungeheizt)<span class="room-chip-area">11 m²</span></div>
|
||||
</div>
|
||||
<div class="floor-plan floor-plan-multi">
|
||||
<picture>
|
||||
<source srcset="/bilder/grundrisse/Dachboden unten 2-small.webp" type="image/webp">
|
||||
<img src="/bilder/grundrisse/Dachboden unten 2-small.jpg" alt="Grundriss Dachboden" loading="lazy" data-img="/bilder/grundrisse/Dachboden unten 2.webp" />
|
||||
</picture>
|
||||
<picture>
|
||||
<source srcset="/bilder/grundrisse/Dachboden unten-small.webp" type="image/webp">
|
||||
<img src="/bilder/grundrisse/Dachboden unten-small.jpg" alt="Grundriss Dachboden" loading="lazy" data-img="/bilder/grundrisse/Dachboden unten.webp" />
|
||||
</picture>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="pricing-section" id="miete" aria-label="Mietkonditionen">
|
||||
<div class="pricing-inner">
|
||||
<div class="section-eyebrow">Mietkonditionen</div>
|
||||
<h2>Transparente Preisgestaltung</h2>
|
||||
<div class="price-cards">
|
||||
<div class="price-card">
|
||||
<div class="pc-label">Kaltmiete</div>
|
||||
<div class="pc-val">1.300 €</div>
|
||||
<div class="pc-sub">pro Monat</div>
|
||||
</div>
|
||||
<div class="price-card highlight">
|
||||
<div class="pc-label">Gesamtmiete warm</div>
|
||||
<div class="pc-val">1.600 €</div>
|
||||
<div class="pc-sub">inkl. 300 € Nebenkosten</div>
|
||||
</div>
|
||||
<div class="price-card">
|
||||
<div class="pc-label">Kaution</div>
|
||||
<div class="pc-val">2.600 €</div>
|
||||
<div class="pc-sub">2 Nettokaltmieten</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="price-note">
|
||||
<div class="pn-item">
|
||||
<strong>Verfügbarkeit</strong>
|
||||
Ab sofort · unbefristete Laufzeit
|
||||
</div>
|
||||
<div class="pn-item">
|
||||
<strong>Nebenkosten</strong>
|
||||
Vorauszahlung 300 €/Monat, jährliche Abrechnung
|
||||
</div>
|
||||
<div class="pn-item">
|
||||
<strong>Energieausweis</strong>
|
||||
Wird bei Mietbeginn übergeben · Erdgasheizung
|
||||
</div>
|
||||
<div class="pn-item">
|
||||
<strong>Haustiere</strong>
|
||||
Auf Anfrage
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="lage-section" id="lage">
|
||||
<div class="section-eyebrow">Standort</div>
|
||||
<h2>Zentral und ruhig zugleich</h2>
|
||||
<div class="lage-grid">
|
||||
<div class="lage-item">
|
||||
<div class="lage-icon">🛒</div>
|
||||
<div>
|
||||
<div class="lage-title">Einkaufen & Versorgung</div>
|
||||
<div class="lage-desc">Supermärkte, Ärzte, Apotheken und Schulen sind fußläufig erreichbar</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lage-item">
|
||||
<div class="lage-icon">🚌</div>
|
||||
<div>
|
||||
<div class="lage-title">Öffentlicher Nahverkehr</div>
|
||||
<div class="lage-desc">Zentrale Bushaltestelle ca. 200 m entfernt — direkte Verbindungen in die Region</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lage-item">
|
||||
<div class="lage-icon">🏛</div>
|
||||
<div>
|
||||
<div class="lage-title">Innenstadt Schleusingen</div>
|
||||
<div class="lage-desc">Wochenmarkt und Stadtmitte nur ca. 500 m entfernt</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lage-item">
|
||||
<div class="lage-icon">📍</div>
|
||||
<div>
|
||||
<div class="lage-title">Genaue Adresse</div>
|
||||
<div class="lage-desc">Schleusinger Bahnhofstraße 10<br />98533 Schleusingen, Thüringen</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lage-map-wrapper">
|
||||
<iframe
|
||||
src="https://maps.google.com/maps?q=50.5090045,10.7473859&t=&z=16&ie=UTF8&iwloc=&output=embed"
|
||||
width="100%" height="450" style="border: 0" allowfullscreen="" loading="lazy"
|
||||
referrerpolicy="no-referrer-when-downgrade"
|
||||
title="Standort Bahnhofstraße 10, Schleusingen"
|
||||
></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="contact-section" id="kontakt" aria-label="Kontaktformular">
|
||||
<div class="contact-inner">
|
||||
<div class="section-eyebrow">Kontakt</div>
|
||||
<h2>Interesse?<br /><em>Schreiben Sie uns.</em></h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<div class="contact-form">
|
||||
<?php if ($formSuccess): ?>
|
||||
<div id="form-result" class="form-success" style="display: block">
|
||||
<p>Vielen Dank für Ihre Anfrage!</p>
|
||||
<br />
|
||||
<small>Wir haben Ihre Nachricht erhalten und melden uns innerhalb von 24 Stunden bei Ihnen.</small>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php if (!empty($formErrors)): ?>
|
||||
<div id="form-errors" class="form-errors">
|
||||
<ul>
|
||||
<?php foreach ($formErrors as $error): ?>
|
||||
<li><?= $escapeContactValue($error) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<form id="contactForm" method="post">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token'] ?? '') ?>" />
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label for="fname">Vorname</label>
|
||||
<input type="text" id="fname" name="fname" placeholder="Max" required value="<?= $escapeContactValue($formData['fname']) ?>" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="lname">Nachname</label>
|
||||
<input type="text" id="lname" name="lname" placeholder="Mustermann" required value="<?= $escapeContactValue($formData['lname']) ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label for="email">E-Mail</label>
|
||||
<input type="email" id="email" name="email" placeholder="max@beispiel.de" required value="<?= $escapeContactValue($formData['email']) ?>" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="phone">Telefon</label>
|
||||
<input type="tel" id="phone" name="phone" placeholder="+49 ..." value="<?= $escapeContactValue($formData['phone']) ?>" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field full">
|
||||
<label for="interest">Anliegen</label>
|
||||
<select id="interest" name="interest">
|
||||
<?php
|
||||
$interestOptions = ['Besichtigung anfragen', 'Allgemeine Informationen', 'Mietbewerbung einreichen'];
|
||||
foreach ($interestOptions as $opt):
|
||||
$selected = ($formData['interest'] === $opt) ? ' selected' : '';
|
||||
?>
|
||||
<option<?= $selected ?>><?= $escapeContactValue($opt) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field full">
|
||||
<label for="message">Nachricht</label>
|
||||
<textarea id="message" name="message" rows="4" placeholder="Ihre Nachricht ..." required><?= $escapeContactValue($formData['message']) ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hp-field" aria-hidden="true">
|
||||
<label for="website">Website</label>
|
||||
<input type="text" id="website" name="website" tabindex="-1" autocomplete="off" />
|
||||
</div>
|
||||
<input type="hidden" name="form_time" value="<?= time() ?>" />
|
||||
<button type="submit" class="btn-submit">Anfrage absenden</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="contact-details">
|
||||
<p>Oder schreiben Sie uns direkt: <a href="mailto:mki@kies-media.de">mki@kies-media.de</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
<footer role="contentinfo">
|
||||
<div class="footer-logo">Bahnhofstraße 10 · Schleusingen</div>
|
||||
<div class="footer-links">
|
||||
<a href="/impressum">Impressum</a>
|
||||
<a href="/datenschutz">Datenschutz</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<div class="lightbox" id="lightbox" role="dialog" aria-modal="true" aria-label="Bildansicht">
|
||||
<button class="lightbox-close" id="lightboxClose" aria-label="Bildansicht schließen">×</button>
|
||||
<img src="" id="lightboxImg" alt="" />
|
||||
</div>
|
||||
85
app/views/impressum/index.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<nav id="navbar" class="scrolled">
|
||||
<div class="nav-logo">Bahnhofstraße 10</div>
|
||||
<ul class="nav-links">
|
||||
<li><a href="/#galerie">Galerie</a></li>
|
||||
<li><a href="/#grundriss">Grundriss</a></li>
|
||||
<li><a href="/#miete">Miete</a></li>
|
||||
<li><a href="/#lage">Lage</a></li>
|
||||
</ul>
|
||||
<a href="/#kontakt" class="nav-cta" style="text-decoration:none;">Jetzt anfragen</a>
|
||||
</nav>
|
||||
|
||||
<main class="legal-page">
|
||||
<div class="section-eyebrow">Pflichtangaben</div>
|
||||
<h1>Impressum</h1>
|
||||
|
||||
<h2>Angaben gemäß § 5 TMG</h2>
|
||||
<address>
|
||||
Martin Kiesewetter<br />
|
||||
Am Schaftalsgraben 4<br />
|
||||
98529 Suhl<br />
|
||||
Deutschland
|
||||
</address>
|
||||
|
||||
<h3>Kontakt</h3>
|
||||
<ul>
|
||||
<li>Telefon: 0176 – 45853923</li>
|
||||
<li>E-Mail: <a href="mailto:mki@kies-media.de">mki@kies-media.de</a></li>
|
||||
</ul>
|
||||
|
||||
<hr class="legal-divider" />
|
||||
|
||||
<h2>Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV</h2>
|
||||
<p>
|
||||
Martin Kiesewetter<br />
|
||||
Am Schaftalsgraben 4<br />
|
||||
98529 Suhl
|
||||
</p>
|
||||
|
||||
<hr class="legal-divider" />
|
||||
|
||||
<h2>Streitschlichtung</h2>
|
||||
<p>
|
||||
Die Europäische Kommission stellt eine Plattform zur Online-Streitbeilegung (OS) bereit:
|
||||
<a href="https://ec.europa.eu/consumers/odr/" target="_blank" rel="noopener">https://ec.europa.eu/consumers/odr/</a>
|
||||
</p>
|
||||
<p>
|
||||
Wir sind nicht bereit oder verpflichtet, an Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen.
|
||||
</p>
|
||||
|
||||
<hr class="legal-divider" />
|
||||
|
||||
<h2>Haftung für Inhalte</h2>
|
||||
<p>
|
||||
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen.
|
||||
</p>
|
||||
<p>
|
||||
Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.
|
||||
</p>
|
||||
|
||||
<h2>Haftung für Links</h2>
|
||||
<p>
|
||||
Unser Angebot enthält Links zu externen Websites Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich.
|
||||
</p>
|
||||
<p>
|
||||
Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.
|
||||
</p>
|
||||
|
||||
<h2>Urheberrecht</h2>
|
||||
<p>
|
||||
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet.
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<a href="/" class="legal-back">← Zurück zum Objekt</a>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="footer-logo">Bahnhofstraße 10 · Schleusingen</div>
|
||||
<div class="footer-links">
|
||||
<a href="/impressum">Impressum</a>
|
||||
<a href="/datenschutz">Datenschutz</a>
|
||||
</div>
|
||||
</footer>
|
||||
51
app/views/layouts/main.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<?php if (!isset($pageTitle)) $pageTitle = 'Einfamilienhaus mieten Schleusingen | 227 m², 6 Zimmer | 1.300 € Kaltmiete'; ?>
|
||||
<title><?= htmlspecialchars($pageTitle) ?></title>
|
||||
<?php if (isset($pageDescription)): ?>
|
||||
<meta name="description" content="<?= htmlspecialchars($pageDescription) ?>" />
|
||||
<?php else: ?>
|
||||
<meta name="description" content="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." />
|
||||
<?php endif; ?>
|
||||
<?php if (isset($robots)): ?>
|
||||
<meta name="robots" content="<?= htmlspecialchars($robots) ?>" />
|
||||
<?php endif; ?>
|
||||
<?php if (isset($canonical)): ?>
|
||||
<link rel="canonical" href="<?= htmlspecialchars($canonical) ?>" />
|
||||
<?php endif; ?>
|
||||
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/bilder/favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/bilder/favicon/favicon-16x16.png">
|
||||
<link rel="icon" type="image/x-icon" href="/bilder/favicon/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/bilder/favicon/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/bilder/favicon/site.webmanifest">
|
||||
|
||||
<?php if (isset($openGraph)): extract($openGraph); ?>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="<?= htmlspecialchars($ogTitle ?? '') ?>" />
|
||||
<meta property="og:description" content="<?= htmlspecialchars($ogDescription ?? '') ?>" />
|
||||
<meta property="og:image" content="<?= htmlspecialchars($ogImage ?? '') ?>" />
|
||||
<meta property="og:url" content="<?= htmlspecialchars($ogUrl ?? '') ?>" />
|
||||
<meta property="og:locale" content="de_DE" />
|
||||
<meta property="og:site_name" content="Haus Schleusingen" />
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($structuredData)): ?>
|
||||
<script type="application/ld+json"><?= $structuredData ?></script>
|
||||
<?php endif; ?>
|
||||
|
||||
<link rel="stylesheet" href="/fonts/fonts.css" />
|
||||
<link rel="stylesheet" href="/css/haus-schleusingen.css" />
|
||||
<?php if (isset($extraCss)): ?>
|
||||
<style><?= $extraCss ?></style>
|
||||
<?php endif; ?>
|
||||
</head>
|
||||
<body>
|
||||
<?= $content ?>
|
||||
|
||||
<script src="/js/haus-schleusingen.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
0
docker-preview.png → docs/docker-preview.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.5 MiB |
0
page-preview.png → docs/page-preview.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.5 MiB |
0
screenshot-landingpage-thumb.png → docs/screenshot-landingpage-thumb.png
Normal file → Executable file
|
Before Width: | Height: | Size: 338 KiB After Width: | Height: | Size: 338 KiB |
0
screenshot-landingpage.png → docs/screenshot-landingpage.png
Normal file → Executable file
|
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 2.8 MiB |
1
eslint.config.js
Normal file → Executable file
@@ -13,7 +13,6 @@ module.exports = [
|
||||
sourceType: "script",
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.jquery,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
|
||||
@@ -1,551 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Einfamilienhaus zur Miete - Schleusingen</title>
|
||||
<link rel="stylesheet" href="fonts/fonts.css" />
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||
<link rel="stylesheet" href="css/haus-schleusingen.css" />
|
||||
</head>
|
||||
<body>
|
||||
<nav id="navbar">
|
||||
<div class="nav-logo">Bahnhofstraße 10</div>
|
||||
<ul class="nav-links">
|
||||
<li><a href="#galerie">Galerie</a></li>
|
||||
<li><a href="#grundriss">Grundriss</a></li>
|
||||
<li><a href="#miete">Miete</a></li>
|
||||
<li><a href="#lage">Lage</a></li>
|
||||
</ul>
|
||||
<button
|
||||
class="nav-cta"
|
||||
onclick="$('html').animate({ scrollTop: $('#kontakt').offset().top }, 700)"
|
||||
>
|
||||
Jetzt anfragen
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<section class="hero" id="hero">
|
||||
<div
|
||||
class="hero-bg"
|
||||
id="heroBg"
|
||||
style="background-image: url(bilder/Außenansicht-2.png)"
|
||||
></div>
|
||||
<div class="hero-overlay"></div>
|
||||
<div class="hero-content" id="heroContent">
|
||||
<div class="hero-tag">Zur Langzeitmiete · Ab sofort verfügbar</div>
|
||||
<h1>
|
||||
Großzügiges
|
||||
<br />
|
||||
<em>Einfamilienhaus</em>
|
||||
<br />
|
||||
in Schleusingen
|
||||
</h1>
|
||||
<div class="hero-meta">
|
||||
<span><strong>Schleusinger Bahnhofstraße 10</strong></span>
|
||||
<span>227 m² Wohnfläche</span>
|
||||
<span>6 Zimmer</span>
|
||||
<span>3 Etagen + Dachterrasse</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-scroll">
|
||||
<span>Entdecken</span>
|
||||
<div class="scroll-line"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="facts-strip">
|
||||
<div class="fact">
|
||||
<div class="fact-val">227</div>
|
||||
<div class="fact-label">m² Wohnfläche</div>
|
||||
</div>
|
||||
<div class="fact">
|
||||
<div class="fact-val">6</div>
|
||||
<div class="fact-label">Zimmer</div>
|
||||
</div>
|
||||
<div class="fact">
|
||||
<div class="fact-val">3</div>
|
||||
<div class="fact-label">Etagen</div>
|
||||
</div>
|
||||
<div class="fact">
|
||||
<div class="fact-val">1.300</div>
|
||||
<div class="fact-label">€ Kaltmiete</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="intro" id="intro">
|
||||
<div class="intro-text" data-animate>
|
||||
<div class="section-eyebrow">Das Objekt</div>
|
||||
<h2>Wohnen mit Charakter und viel Raum</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<div class="intro-stats">
|
||||
<div>
|
||||
<div class="istat-val">154,9 m²</div>
|
||||
<div class="istat-label">Nutzfläche</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="istat-val">35,8 m²</div>
|
||||
<div class="istat-label">Dachterrasse</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="istat-val">2 Stpl.</div>
|
||||
<div class="istat-label">Garage</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="intro-img" data-animate>
|
||||
<img src="bilder/wohnzimmer2.png" alt="Wohnzimmer" />
|
||||
<div class="intro-img-badge">Wohnzimmer · 42,6 m²</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="galerie" class="gallery-section">
|
||||
<div class="gallery-header">
|
||||
<div>
|
||||
<div class="section-eyebrow">Fotogalerie</div>
|
||||
<h2>Einblicke ins Haus</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="masonry-grid">
|
||||
<div class="grid-sizer"></div>
|
||||
|
||||
<div class="grid-item" data-img="bilder/Außenansicht-2.png">
|
||||
<img src="bilder/Außenansicht-2-small.png" alt="Außenansicht" />
|
||||
<span class="grid-item-label">Außenansicht</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/wohnzimmer2.png">
|
||||
<img src="bilder/wohnzimmer2-small.png" alt="Wohnzimmer" />
|
||||
<span class="grid-item-label">Wohnzimmer · 42,6 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/Küche 1.jpg">
|
||||
<img src="bilder/Küche 1.jpg" alt="Küche" />
|
||||
<span class="grid-item-label">Küche · 18,4 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/schlafzimmer.png">
|
||||
<img src="bilder/schlafzimmer-small.png" alt="Schlafzimmer" />
|
||||
<span class="grid-item-label">Schlafzimmer · 18 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/Bad.jpg">
|
||||
<img src="bilder/Bad.jpg" alt="Badezimmer" />
|
||||
<span class="grid-item-label">Badezimmer · 9,8 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/Kinderzimmer.png">
|
||||
<img src="bilder/Kinderzimmer-small.png" alt="Kinderzimmer 1" />
|
||||
<span class="grid-item-label">Kinderzimmer 1 · 21,7 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/Kinderzimmer 2.jpg">
|
||||
<img src="bilder/Kinderzimmer 2-small.png" alt="Kinderzimmer 2" />
|
||||
<span class="grid-item-label">Kinderzimmer 2 · 15,7 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/kinderzimmer 2 2.jpeg">
|
||||
<img src="bilder/kinderzimmer 2 2-small.png" alt="Kinderzimmer Detail" />
|
||||
<span class="grid-item-label">Kinderzimmer Detail</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/Kinderzimmer 3.jpg">
|
||||
<img src="bilder/Kinderzimmer 3-small.png" alt="Kinderzimmer 3" />
|
||||
<span class="grid-item-label">Gästezimmer · 11,5 m²</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/Bad-2.jpg">
|
||||
<img src="bilder/Bad-2-small.jpg" alt="Wohnbereich Detail 1" />
|
||||
<span class="grid-item-label">Wohnbereich</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/bad3.jpg">
|
||||
<img src="bilder/Bad-3-small.jpg" alt="Wohnbereich Detail 2" />
|
||||
<span class="grid-item-label">Wohnbereich Detail</span>
|
||||
</div>
|
||||
<div class="grid-item" data-img="bilder/WhatsApp Image 2026-03-30 at 07.50.42 (2).jpeg">
|
||||
<img
|
||||
src="bilder/WhatsApp Image 2026-03-30 at 07.50.42 (2).jpeg"
|
||||
alt="Wohnbereich Detail 3"
|
||||
/>
|
||||
<span class="grid-item-label">Hausansicht</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="floors-section" id="grundriss">
|
||||
<div class="section-eyebrow">Raumaufteilung</div>
|
||||
<h2>Großzügig auf allen Etagen</h2>
|
||||
<div class="floor-accordion">
|
||||
<div class="floor-item">
|
||||
<div class="floor-header">
|
||||
<span class="floor-title">Erdgeschoss</span>
|
||||
<div class="floor-size">
|
||||
<span>99,5 m²</span>
|
||||
<div class="floor-icon">+</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-body">
|
||||
<div class="floor-rooms-grid">
|
||||
<div class="room-chip">
|
||||
Flur
|
||||
<span class="room-chip-area">20,1 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
WC
|
||||
<span class="room-chip-area">0,8 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Garage / Partykeller
|
||||
<span class="room-chip-area">42,6 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Abstellraum 1
|
||||
<span class="room-chip-area">9,9 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Abstellraum 2
|
||||
<span class="room-chip-area">7,8 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Heizungskeller
|
||||
<span class="room-chip-area">18,3 m²</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-plan floor-plan-multi">
|
||||
<img
|
||||
src="bilder/grundrisse/EG-small.jpg"
|
||||
alt="Grundriss Erdgeschoss"
|
||||
data-img="bilder/grundrisse/EG.png"
|
||||
/>
|
||||
<img
|
||||
src="bilder/grundrisse/EG 3D-small.jpg"
|
||||
alt="Grundriss Erdgeschoss"
|
||||
data-img="bilder/grundrisse/EG 3D.png"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-item">
|
||||
<div class="floor-header">
|
||||
<span class="floor-title">1. Obergeschoss</span>
|
||||
<div class="floor-size">
|
||||
<span>120,4 m²</span>
|
||||
<div class="floor-icon">+</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-body">
|
||||
<div class="floor-rooms-grid">
|
||||
<div class="room-chip">
|
||||
Flur
|
||||
<span class="room-chip-area">20,1 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Wohnzimmer
|
||||
<span class="room-chip-area">42,6 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Gästezimmer
|
||||
<span class="room-chip-area">11,5 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Badezimmer
|
||||
<span class="room-chip-area">9,8 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Küche
|
||||
<span class="room-chip-area">18,4 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Schlafzimmer
|
||||
<span class="room-chip-area">18,0 m²</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-plan floor-plan-multi">
|
||||
<img
|
||||
src="bilder/grundrisse/OG 1 2-small.jpg"
|
||||
alt="Grundriss 1. Obergeschoss"
|
||||
data-img="bilder/grundrisse/OG 1 2.png"
|
||||
/>
|
||||
<img
|
||||
src="bilder/grundrisse/OG 1 3D-small.jpg"
|
||||
alt="Grundriss 1. Obergeschoss"
|
||||
data-img="bilder/grundrisse/OG 1 3D.png"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-item">
|
||||
<div class="floor-header">
|
||||
<span class="floor-title">2. Obergeschoss</span>
|
||||
<div class="floor-size">
|
||||
<span>68 m²</span>
|
||||
<div class="floor-icon">+</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-body">
|
||||
<div class="floor-rooms-grid">
|
||||
<div class="room-chip">
|
||||
Flur
|
||||
<span class="room-chip-area">13,9 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Kinderzimmer 1
|
||||
<span class="room-chip-area">21,7 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Kinderzimmer 2
|
||||
<span class="room-chip-area">15,7 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Spielzimmer
|
||||
<span class="room-chip-area">6,3 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Ankleidezimmer
|
||||
<span class="room-chip-area">1,4 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Dachterrasse
|
||||
<span class="room-chip-area">9,0 m²</span> <small>(25% von 35,8 m²)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-plan floor-plan-multi">
|
||||
<img
|
||||
src="bilder/grundrisse/OG 2 grundriss-small.jpg"
|
||||
alt="Grundriss 2. Obergeschoss (1)"
|
||||
data-img="bilder/grundrisse/OG 2 grundriss.png"
|
||||
/>
|
||||
<img
|
||||
src="bilder/grundrisse/OG 2 3D-small.jpg"
|
||||
alt="Grundriss 2. Obergeschoss (1)"
|
||||
data-img="bilder/grundrisse/OG 2 3D.png"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-item">
|
||||
<div class="floor-header">
|
||||
<span class="floor-title">Dachboden</span>
|
||||
<div class="floor-size">
|
||||
<span>94 m² Nutzfläche</span>
|
||||
<div class="floor-icon">+</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-body">
|
||||
<div class="floor-rooms-grid">
|
||||
<div class="room-chip">
|
||||
Dachboden unten (ungeheizt)
|
||||
<span class="room-chip-area">52 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Dachboden Mitte (ungeheizt)
|
||||
<span class="room-chip-area">31 m²</span>
|
||||
</div>
|
||||
<div class="room-chip">
|
||||
Dachboden oben (ungeheizt)
|
||||
<span class="room-chip-area">11 m²</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="floor-plan floor-plan-multi">
|
||||
<img
|
||||
src="bilder/grundrisse/Dachboden unten 2-small.jpg"
|
||||
alt="Grundriss Dachboden"
|
||||
data-img="bilder/grundrisse/Dachboden unten 2.png"
|
||||
/>
|
||||
<img
|
||||
src="bilder/grundrisse/Dachboden unten-small.jpg"
|
||||
alt="Grundriss Dachboden"
|
||||
data-img="bilder/grundrisse/Dachboden unten.png"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="pricing-section" id="miete">
|
||||
<div class="pricing-inner">
|
||||
<div class="section-eyebrow">Mietkonditionen</div>
|
||||
<h2>Transparente Preisgestaltung</h2>
|
||||
<div class="price-cards">
|
||||
<div class="price-card">
|
||||
<div class="pc-label">Kaltmiete</div>
|
||||
<div class="pc-val">1.300 €</div>
|
||||
<div class="pc-sub">pro Monat</div>
|
||||
</div>
|
||||
<div class="price-card highlight">
|
||||
<div class="pc-label">Gesamtmiete warm</div>
|
||||
<div class="pc-val">1.600 €</div>
|
||||
<div class="pc-sub">inkl. 300 € Nebenkosten</div>
|
||||
</div>
|
||||
<div class="price-card">
|
||||
<div class="pc-label">Kaution</div>
|
||||
<div class="pc-val">2.600 €</div>
|
||||
<div class="pc-sub">2 Nettokaltmieten</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="price-note">
|
||||
<div class="pn-item">
|
||||
<strong>Verfügbarkeit</strong>
|
||||
Ab sofort · unbefristete Laufzeit
|
||||
</div>
|
||||
<div class="pn-item">
|
||||
<strong>Nebenkosten</strong>
|
||||
Vorauszahlung 300 €/Monat, jährliche Abrechnung
|
||||
</div>
|
||||
<div class="pn-item">
|
||||
<strong>Energieausweis</strong>
|
||||
Wird bei Mietbeginn übergeben · Erdgasheizung
|
||||
</div>
|
||||
<div class="pn-item">
|
||||
<strong>Haustiere</strong>
|
||||
Auf Anfrage
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="lage-section" id="lage">
|
||||
<div class="section-eyebrow">Standort</div>
|
||||
<h2>Zentral und ruhig zugleich</h2>
|
||||
<div class="lage-grid">
|
||||
<div class="lage-item">
|
||||
<div class="lage-icon">🛒</div>
|
||||
<div>
|
||||
<div class="lage-title">Einkaufen & Versorgung</div>
|
||||
<div class="lage-desc">
|
||||
Supermärkte, Ärzte, Apotheken und Schulen sind fußläufig erreichbar
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lage-item">
|
||||
<div class="lage-icon">🚌</div>
|
||||
<div>
|
||||
<div class="lage-title">Öffentlicher Nahverkehr</div>
|
||||
<div class="lage-desc">
|
||||
Zentrale Bushaltestelle ca. 200 m entfernt — direkte Verbindungen in die Region
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lage-item">
|
||||
<div class="lage-icon">🏛</div>
|
||||
<div>
|
||||
<div class="lage-title">Innenstadt Schleusingen</div>
|
||||
<div class="lage-desc">Wochenmarkt und Stadtmitte nur ca. 500 m entfernt</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lage-item">
|
||||
<div class="lage-icon">📍</div>
|
||||
<div>
|
||||
<div class="lage-title">Genaue Adresse</div>
|
||||
<div class="lage-desc">
|
||||
Schleusinger Bahnhofstraße 10
|
||||
<br />
|
||||
98533 Schleusingen, Thüringen
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lage-map-wrapper">
|
||||
<iframe
|
||||
src="https://maps.google.com/maps?q=50.5090045,10.7473859&t=&z=16&ie=UTF8&iwloc=&output=embed"
|
||||
width="100%"
|
||||
height="450"
|
||||
style="border: 0"
|
||||
allowfullscreen=""
|
||||
loading="lazy"
|
||||
referrerpolicy="no-referrer-when-downgrade"
|
||||
title="Standort Bahnhofstraße 10, Schleusingen"
|
||||
></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="contact-section" id="kontakt">
|
||||
<div class="contact-inner">
|
||||
<div class="section-eyebrow">Kontakt</div>
|
||||
<h2>
|
||||
Interesse?
|
||||
<br />
|
||||
<em>Schreiben Sie uns.</em>
|
||||
</h2>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<div class="contact-form">
|
||||
<form id="contactForm">
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label for="fname">Vorname</label>
|
||||
<input type="text" id="fname" name="fname" placeholder="Max" required />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="lname">Nachname</label>
|
||||
<input type="text" id="lname" name="lname" placeholder="Mustermann" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label for="email">E-Mail</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
placeholder="max@beispiel.de"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="phone">Telefon</label>
|
||||
<input type="tel" id="phone" name="phone" placeholder="+49 ..." />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field full">
|
||||
<label for="interest">Anliegen</label>
|
||||
<select id="interest" name="interest">
|
||||
<option>Besichtigung anfragen</option>
|
||||
<option>Allgemeine Informationen</option>
|
||||
<option>Mietbewerbung einreichen</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field full">
|
||||
<label for="message">Nachricht</label>
|
||||
<textarea
|
||||
id="message"
|
||||
name="message"
|
||||
rows="4"
|
||||
placeholder="Ihre Nachricht ..."
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn-submit">Anfrage absenden</button>
|
||||
</form>
|
||||
<div class="form-success" id="formSuccess">
|
||||
<p>Vielen Dank für Ihre Anfrage!</p>
|
||||
<br />
|
||||
<small>Wir melden uns schnellstmöglich bei Ihnen.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<div class="footer-logo">Bahnhofstraße 10 · Schleusingen</div>
|
||||
<div class="footer-links">
|
||||
<a href="#">Impressum</a>
|
||||
<a href="#">Datenschutz</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<div class="lightbox" id="lightbox">
|
||||
<button class="lightbox-close" id="lightboxClose">×</button>
|
||||
<img src="" id="lightboxImg" alt="Vollbild" />
|
||||
</div>
|
||||
|
||||
<script src="js/haus-schleusingen.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,84 +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").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").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
|
||||
$("#contactForm").on("submit", function (e) {
|
||||
e.preventDefault();
|
||||
var btn = $(this).find(".btn-submit");
|
||||
btn.text("Wird gesendet...").prop("disabled", true);
|
||||
setTimeout(function () {
|
||||
$("#contactForm").hide();
|
||||
$("#formSuccess").fadeIn(400);
|
||||
}, 1200);
|
||||
});
|
||||
});
|
||||
9
js/masonry.pkgd.min.js
vendored
17
nginx.conf
Normal file → Executable file
@@ -3,9 +3,22 @@ server {
|
||||
server_name localhost;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index haus-schleusingen.html;
|
||||
index index.php;
|
||||
|
||||
# Gzip aktivieren
|
||||
gzip on;
|
||||
gzip_types text/css application/javascript image/svg+xml application/json text/xml;
|
||||
gzip_min_length 256;
|
||||
gzip_vary on;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /haus-schleusingen.html;
|
||||
try_files $uri $uri/ /index.php;
|
||||
}
|
||||
|
||||
# Lange Cache-Dauer für Bilder und statische Assets
|
||||
location ~* \.(jpg|jpeg|png|webp|gif|ico|svg|css|js|woff2?)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
0
package.json
Normal file → Executable file
23
public/.htaccess
Normal file
@@ -0,0 +1,23 @@
|
||||
# Enable rewrite engine
|
||||
RewriteEngine On
|
||||
|
||||
# Security Headers
|
||||
<IfModule mod_headers.c>
|
||||
Header set X-Content-Type-Options "nosniff"
|
||||
Header set X-Frame-Options "SAMEORIGIN"
|
||||
Header set Referrer-Policy "strict-origin-when-cross-origin"
|
||||
Header set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-src https://www.google.com/ https://www.google.de/; connect-src 'self'"
|
||||
</IfModule>
|
||||
|
||||
# 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]
|
||||
0
bilder/Außenansicht-2-small.png → public/bilder/Außenansicht-2-small.png
Normal file → Executable file
|
Before Width: | Height: | Size: 231 KiB After Width: | Height: | Size: 231 KiB |
BIN
public/bilder/Außenansicht-2-small.webp
Executable file
|
After Width: | Height: | Size: 20 KiB |
0
bilder/Außenansicht-2.png → public/bilder/Außenansicht-2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.5 MiB |
BIN
public/bilder/Außenansicht-2.webp
Executable file
|
After Width: | Height: | Size: 153 KiB |
0
bilder/Bad-2-small.jpg → public/bilder/Bad-2-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
BIN
public/bilder/Bad-2-small.webp
Executable file
|
After Width: | Height: | Size: 16 KiB |
0
bilder/Bad-2.jpeg → public/bilder/Bad-2.jpeg
Normal file → Executable file
|
Before Width: | Height: | Size: 259 KiB After Width: | Height: | Size: 259 KiB |
BIN
public/bilder/Bad-2.webp
Executable file
|
After Width: | Height: | Size: 202 KiB |
0
bilder/Bad-3-small.jpg → public/bilder/Bad-3-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
BIN
public/bilder/Bad-3-small.webp
Executable file
|
After Width: | Height: | Size: 12 KiB |
0
bilder/Bad-3.jpeg → public/bilder/Bad-3.jpeg
Normal file → Executable file
|
Before Width: | Height: | Size: 211 KiB After Width: | Height: | Size: 211 KiB |
BIN
public/bilder/Bad-3.webp
Executable file
|
After Width: | Height: | Size: 145 KiB |
0
bilder/Bad-4-small.jpg → public/bilder/Bad-4-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
BIN
public/bilder/Bad-4-small.webp
Executable file
|
After Width: | Height: | Size: 14 KiB |
0
bilder/Bad-4.jpeg → public/bilder/Bad-4.jpeg
Normal file → Executable file
|
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 220 KiB |
BIN
public/bilder/Bad-4.webp
Executable file
|
After Width: | Height: | Size: 159 KiB |
0
bilder/Bad-small.jpg → public/bilder/Bad-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
BIN
public/bilder/Bad-small.webp
Executable file
|
After Width: | Height: | Size: 16 KiB |
0
bilder/Bad.jpg → public/bilder/Bad.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 456 KiB After Width: | Height: | Size: 456 KiB |
BIN
public/bilder/Bad.webp
Executable file
|
After Width: | Height: | Size: 290 KiB |
0
bilder/Kinderzimmer 2-small.png → public/bilder/Kinderzimmer 2-small.png
Normal file → Executable file
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
BIN
public/bilder/Kinderzimmer 2-small.webp
Executable file
|
After Width: | Height: | Size: 9.3 KiB |
0
bilder/Kinderzimmer 2.jpg → public/bilder/Kinderzimmer 2.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.5 MiB |
BIN
public/bilder/Kinderzimmer 2.webp
Executable file
|
After Width: | Height: | Size: 132 KiB |
0
bilder/Kinderzimmer 3-small.png → public/bilder/Kinderzimmer 3-small.png
Normal file → Executable file
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
BIN
public/bilder/Kinderzimmer 3-small.webp
Executable file
|
After Width: | Height: | Size: 8.6 KiB |
0
bilder/Kinderzimmer 3.jpg → public/bilder/Kinderzimmer 3.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 2.7 MiB |
BIN
public/bilder/Kinderzimmer 3.webp
Executable file
|
After Width: | Height: | Size: 174 KiB |
0
bilder/Kinderzimmer-small.png → public/bilder/Kinderzimmer-small.png
Normal file → Executable file
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
BIN
public/bilder/Kinderzimmer-small.webp
Executable file
|
After Width: | Height: | Size: 11 KiB |
0
bilder/Kinderzimmer.png → public/bilder/Kinderzimmer.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
BIN
public/bilder/Kinderzimmer.webp
Executable file
|
After Width: | Height: | Size: 104 KiB |
0
bilder/Küche 1-small.jpg → public/bilder/Küche 1-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
BIN
public/bilder/Küche 1-small.webp
Executable file
|
After Width: | Height: | Size: 15 KiB |
0
bilder/Küche 1.jpg → public/bilder/Küche 1.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 501 KiB After Width: | Height: | Size: 501 KiB |
BIN
public/bilder/Küche 1.webp
Executable file
|
After Width: | Height: | Size: 371 KiB |
BIN
public/bilder/favicon/apple-touch-icon.png
Executable file
|
After Width: | Height: | Size: 54 KiB |
BIN
public/bilder/favicon/favicon-16x16.png
Executable file
|
After Width: | Height: | Size: 851 B |
BIN
public/bilder/favicon/favicon-32x32.png
Executable file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
public/bilder/favicon/favicon.ico
Executable file
|
After Width: | Height: | Size: 3.3 KiB |
10
public/bilder/favicon/site.webmanifest
Executable file
@@ -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"
|
||||
}
|
||||
0
bilder/grundrisse/Dachboden unten 2-small.jpg → public/bilder/grundrisse/Dachboden unten 2-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
BIN
public/bilder/grundrisse/Dachboden unten 2-small.webp
Executable file
|
After Width: | Height: | Size: 9.0 KiB |
0
bilder/grundrisse/Dachboden unten 2.png → public/bilder/grundrisse/Dachboden unten 2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 891 KiB After Width: | Height: | Size: 891 KiB |
BIN
public/bilder/grundrisse/Dachboden unten 2.webp
Executable file
|
After Width: | Height: | Size: 98 KiB |
0
bilder/grundrisse/Dachboden unten-small.jpg → public/bilder/grundrisse/Dachboden unten-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
BIN
public/bilder/grundrisse/Dachboden unten-small.webp
Executable file
|
After Width: | Height: | Size: 8.3 KiB |
0
bilder/grundrisse/Dachboden unten.png → public/bilder/grundrisse/Dachboden unten.png
Normal file → Executable file
|
Before Width: | Height: | Size: 664 KiB After Width: | Height: | Size: 664 KiB |
BIN
public/bilder/grundrisse/Dachboden unten.webp
Executable file
|
After Width: | Height: | Size: 54 KiB |
0
bilder/grundrisse/EG 3D-small.jpg → public/bilder/grundrisse/EG 3D-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
BIN
public/bilder/grundrisse/EG 3D-small.webp
Executable file
|
After Width: | Height: | Size: 7.8 KiB |
0
bilder/grundrisse/EG 3D.png → public/bilder/grundrisse/EG 3D.png
Normal file → Executable file
|
Before Width: | Height: | Size: 416 KiB After Width: | Height: | Size: 416 KiB |
BIN
public/bilder/grundrisse/EG 3D.webp
Executable file
|
After Width: | Height: | Size: 39 KiB |
0
bilder/grundrisse/EG-small.jpg → public/bilder/grundrisse/EG-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
BIN
public/bilder/grundrisse/EG-small.webp
Executable file
|
After Width: | Height: | Size: 13 KiB |
0
bilder/grundrisse/EG.png → public/bilder/grundrisse/EG.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
BIN
public/bilder/grundrisse/EG.webp
Executable file
|
After Width: | Height: | Size: 117 KiB |
0
bilder/grundrisse/OG 1 2-small.jpg → public/bilder/grundrisse/OG 1 2-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
BIN
public/bilder/grundrisse/OG 1 2-small.webp
Executable file
|
After Width: | Height: | Size: 17 KiB |
0
bilder/grundrisse/OG 1 2.png → public/bilder/grundrisse/OG 1 2.png
Normal file → Executable file
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
BIN
public/bilder/grundrisse/OG 1 2.webp
Executable file
|
After Width: | Height: | Size: 138 KiB |
0
bilder/grundrisse/OG 1 3D-small.jpg → public/bilder/grundrisse/OG 1 3D-small.jpg
Normal file → Executable file
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
BIN
public/bilder/grundrisse/OG 1 3D-small.webp
Executable file
|
After Width: | Height: | Size: 6.8 KiB |
0
bilder/grundrisse/OG 1 3D.png → public/bilder/grundrisse/OG 1 3D.png
Normal file → Executable file
|
Before Width: | Height: | Size: 390 KiB After Width: | Height: | Size: 390 KiB |
BIN
public/bilder/grundrisse/OG 1 3D.webp
Executable file
|
After Width: | Height: | Size: 40 KiB |