Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
492bb96fff | ||
|
|
9e3862093e | ||
|
|
c90c03084b | ||
|
|
76e179b077 | ||
|
|
b60e599dda | ||
|
|
791c265f42 | ||
|
|
78083fac6a | ||
|
|
b9740e6c1b |
No files matched your search
@@ -229,6 +229,26 @@
|
|||||||
],
|
],
|
||||||
"port": 8107
|
"port": 8107
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "becker",
|
||||||
|
"runtimeExecutable": "powershell",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"-NoProfile",
|
||||||
|
"-Command",
|
||||||
|
"$env:APP_ENV='dev'; $env:DATABASE_URL='sqlite:///C:/Django Project/KantSites/var/becker.db'; $env:MEDIA_DIRECTORY='C:/Django Project/KantSites/var/becker-media'; $env:SITE_ORIGIN='http://127.0.0.1:8116'; & C:/php84/php.exe -d upload_max_filesize=8M -d post_max_size=10M -d memory_limit=256M -S 127.0.0.1:8116 -t public bin/dev-router.php"
|
||||||
|
],
|
||||||
|
"port": 8116
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "becker-prod",
|
||||||
|
"runtimeExecutable": "powershell",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"-NoProfile",
|
||||||
|
"-Command",
|
||||||
|
"$env:APP_ENV='prod'; $env:APP_DEBUG='0'; $env:DATABASE_URL='sqlite:///C:/Django Project/KantSites/var/becker.db'; $env:MEDIA_DIRECTORY='C:/Django Project/KantSites/var/becker-media'; $env:SITE_ORIGIN='http://127.0.0.1:8117'; & C:/php84/php.exe -d upload_max_filesize=8M -d post_max_size=10M -d memory_limit=256M -S 127.0.0.1:8117 -t public bin/dev-router.php"
|
||||||
|
],
|
||||||
|
"port": 8117
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "luximmo",
|
"name": "luximmo",
|
||||||
"runtimeExecutable": "powershell",
|
"runtimeExecutable": "powershell",
|
||||||
|
|||||||
+23
-1
@@ -1,13 +1,35 @@
|
|||||||
# Projektstatus
|
# Projektstatus
|
||||||
|
|
||||||
|
## Neue Installation „Becker – Just In Time e. Kfm.“, Wiernsheim (10.11.2026)
|
||||||
|
|
||||||
|
**Anlass:** Umut lieferte `Becker-Just-In-Time-Version-5.zip` (ChatGPT-Sites-Entwurf), `Logo_Becker_original.pdf` und sieben Werbemotive mit Logos: „nachbauen, an die CI halten, eigenen Senf dazugeben, Bilder entlogolisieren und von ChatGPT ohne Logos nachbauen lassen“.
|
||||||
|
|
||||||
|
**Umgesetzt:** Die Fotos hat ChatGPT in Umuts Konto neu erzeugt (11 Motive, `var/becker-quelle/ki`, Originale in `var/becker-quelle/original`); die Asbestmotive zeigen dabei Schutzanzug und Atemschutz. `scripts/build-becker-assets.php` stellt das Logo aus dem PDF-Rasterbild frei (Kopf quer, Fuß gestapelt, drei Leistungssymbole, Favicon). `sh scripts/reset-becker.sh [var/becker-quelle]` baut alles neu: Navy #172234 + Logo-Gold #F4B43A, Montserrat/Manrope, Startseite mit Hero, Leistungskarten, Vorher/Nachher-Regler (Plugin „vergleich“), Ablauf, Einblicke-Galerie, Team, Seiten `/gartenbau`, `/zaunbau`, `/asbestsanierung`, `/kontakt` (Formular `anfrage` in zwei Schritten), Impressum, Datenschutz, 404, Paket `var/becker-paket.zip`. Port 8116 (dev) / 8117 (prod), Passwort in `var/becker-zugang.txt`.
|
||||||
|
|
||||||
|
**Geprüft:** Lighthouse im Produktionsmodus für `/`, `/gartenbau`, `/asbestsanierung`, `/kontakt`: Leistung mobil 97–98, Desktop 99–100; Barrierefreiheit, Best Practices, SEO, Agentic Browsing je 100. Ganzseitige Aufnahmen 1440 und 390 px angesehen. Gold-Streifen als Inline-SVG (vorher CSS-Verlauf, sah treppig aus). Nicht geprüft: `test:browser`, Formularversand, Bedienung des Reglers per Tastatur von Hand.
|
||||||
|
|
||||||
|
**Kern:** neues Symbol `house` (geschlossene Hausform, Tür ausgespart) in `public/assets/icons.js`, per `node scripts/build-icons.mjs` in Twig und Validator; Becker nutzt es als Startseiten-Punkt im Menü. `tests/icons.test.mjs` und PHPUnit-Filter „Icon“ (26) grün. Das Becker-Paket braucht deshalb einen Kern mit diesem Symbol (nächstes Release).
|
||||||
|
|
||||||
|
**Offen:** Impressum – „e. Kfm.“ verlangt Registergericht und HRA-Nummer (fehlen); die im Entwurf als USt-IdNr. genannte „48116/36926“ ist eine Steuernummer und steht deshalb nicht drin. E-Mail: Entwurf `info@becker-justintime.de`, Logo-PDF `Becker-Justintime@web.de` – verwendet ist die aus dem Entwurf. Fotos sind KI-Symbolbilder (so im Bildnachweis). Domain/Hosting unbekannt.
|
||||||
|
|
||||||
|
## Fassung 1.39.1: SVG statt Schriftzeichen auf der Website, Luximmo-Immobilien (09.11.2026)
|
||||||
|
|
||||||
|
**Anlass:** Umut: „nur eigene SVGs nutzen“. Bildbetrachter, PDF-Betrachter, Nach-oben-Knopf, Video-Knopf, Menüpfeile, Brotkrumen, Weiterlesen, Blättern und Zitatsterne sind SVG (Masken in `site.css`, sonst eingebettet).
|
||||||
|
|
||||||
|
**Geprüft:** PHPUnit 692 grün (PHP 8.4), `npm test` 41, `test:editor`, `test:browser`, Twig-Lint; Symbole im Browser nachgemessen. Tag `v1.39.1`, Download stimmt mit der Prüfsumme überein.
|
||||||
|
|
||||||
|
**Offen:** Die Verwaltung enthält weiter Schriftzeichen (Editor-Symbole samt Plugin-Bausteinen, Pfeile auf Knöpfen). `var/luximmo-paket.zip` trägt Fassung 1.39.0 und hat die Immobilien-Seite. Im Menü von Luximmo bricht der fünfte Punkt zwischen etwa 1025 und 1130 px um. Immoscout-Plugin aktuell 1.5.2: Paket-Import ersetzt die Mediathek, der Abgleich holt die Bilder danach neu.
|
||||||
|
|
||||||
## Kern: Plugins mit PHP-Code; Plugin „ImmoScout-Abgleich“ für DEEG (09.11.2026)
|
## Kern: Plugins mit PHP-Code; Plugin „ImmoScout-Abgleich“ für DEEG (09.11.2026)
|
||||||
|
|
||||||
**Anlass:** Umut: ImmoScout-Objekte im Takt abgleichen, kostenlos per URL, „100 % ein Plugin“, „wie WordPress“.
|
**Anlass:** Umut: ImmoScout-Objekte im Takt abgleichen, kostenlos per URL, „100 % ein Plugin“, „wie WordPress“.
|
||||||
|
|
||||||
**Kern (ADR 127):** `plugin.php` mit `PluginApi`/`PluginRuntime`: Hooks, Aufgaben, Seiten, eigene Tabellen, Verwaltungsbildschirme, Fehler je Plugin eingegrenzt. `VERSION` steht im Arbeitsstand auf 1.39.0, nicht committet, kein Release.
|
**Kern (ADR 127):** `plugin.php` mit `PluginApi`/`PluginRuntime`: Hooks, Aufgaben, Seiten, eigene Tabellen, Verwaltungsbildschirme, Fehler je Plugin eingegrenzt. **Release:** Tag `v1.39.0` auf `main`, Releaseeintrag mit Zip (3694 Dateien, 5,8 MB), `.sha256` und `install.php`, gebaut aus sauberem Stand ohne das ImmoScout-Plugin; anonymer Download stimmt mit der Prüfsumme überein.
|
||||||
|
|
||||||
**Geprüft:** PHPUnit 692 grün (PHP 8.4, neu `PluginServerTest`), `npm test` 41, `test:editor`, Twig-Lint, php-cs-fixer. Auf einer Kopie der DEEG-Installation in der Verwaltung: einschalten, einstellen, echter Abgleich (5 Objekte, Bilder, Exposés), Liste, Objektseite 1440 und 390 px ohne waagrechtes Scrollen, Sitemap, Anfrage mit Objektangabe gespeichert, verschwundenes Objekt beim zweiten Lauf inaktiv mit 410. Nicht geprüft: Hosting, MySQL, Mailversand, Lighthouse der Objektseiten; die Abweichung Angebotszahl/gelesene Objekte wurde nicht einzeln simuliert.
|
**Geprüft:** PHPUnit 692 grün (PHP 8.4, neu `PluginServerTest`), `npm test` 41, `test:editor`, Twig-Lint, php-cs-fixer. Auf einer Kopie der DEEG-Installation in der Verwaltung: einschalten, einstellen, echter Abgleich (5 Objekte, Bilder, Exposés), Liste, Objektseite 1440 und 390 px ohne waagrechtes Scrollen, Sitemap, Anfrage mit Objektangabe gespeichert, verschwundenes Objekt beim zweiten Lauf inaktiv mit 410. Nicht geprüft: Hosting, MySQL, Mailversand, Lighthouse der Objektseiten; die Abweichung Angebotszahl/gelesene Objekte wurde nicht einzeln simuliert.
|
||||||
|
|
||||||
|
**Nächster Schritt:** DEEG auf 1.39.0 aktualisieren, `var/immoscout-plugin-1.4.0.zip` nach `plugins/` entpacken, einschalten, Portal-Adresse eintragen, abgleichen, Baustein auf `/angebote` setzen. Vorher Zustimmung von DEEG einholen.
|
||||||
|
|
||||||
**Plugin:** liegt in `plugins/immoscout` (lokal von Git ausgeschlossen, Auslieferung als ZIP), nicht Teil des Kerns. ImmoScouts `robots.txt` verbietet automatisches Abrufen; das hat Umut entschieden, der Kunde sollte zustimmen. Eine Sperre wird nicht umgangen.
|
**Plugin:** liegt in `plugins/immoscout` (lokal von Git ausgeschlossen, Auslieferung als ZIP), nicht Teil des Kerns. ImmoScouts `robots.txt` verbietet automatisches Abrufen; das hat Umut entschieden, der Kunde sollte zustimmen. Eine Sperre wird nicht umgangen.
|
||||||
|
|
||||||
## Kern: Unternehmensart, Standort und Logo in den strukturierten Daten (09.11.2026)
|
## Kern: Unternehmensart, Standort und Logo in den strukturierten Daten (09.11.2026)
|
||||||
|
|||||||
@@ -39,10 +39,6 @@
|
|||||||
/* latin */
|
/* latin */
|
||||||
@font-face{font-family:'DM Sans';font-style:normal;font-weight:400 700;font-display:swap;src:url(/assets/fonts/dm-sans-400-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
|
@font-face{font-family:'DM Sans';font-style:normal;font-weight:400 700;font-display:swap;src:url(/assets/fonts/dm-sans-400-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
|
||||||
/* latin-ext */
|
/* latin-ext */
|
||||||
@font-face{font-family:'Manrope';font-style:normal;font-weight:400 700;font-display:swap;src:url(/assets/fonts/manrope-400-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
|
|
||||||
/* latin */
|
|
||||||
@font-face{font-family:'Manrope';font-style:normal;font-weight:400 700;font-display:swap;src:url(/assets/fonts/manrope-400-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
|
|
||||||
/* latin-ext */
|
|
||||||
@font-face{font-family:'Lora';font-style:normal;font-weight:500 600;font-display:swap;src:url(/assets/fonts/lora-500-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
|
@font-face{font-family:'Lora';font-style:normal;font-weight:500 600;font-display:swap;src:url(/assets/fonts/lora-500-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
|
||||||
/* latin */
|
/* latin */
|
||||||
@font-face{font-family:'Lora';font-style:normal;font-weight:500 600;font-display:swap;src:url(/assets/fonts/lora-500-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
|
@font-face{font-family:'Lora';font-style:normal;font-weight:500 600;font-display:swap;src:url(/assets/fonts/lora-500-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
|
||||||
@@ -50,3 +46,11 @@
|
|||||||
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:400 600;font-display:swap;src:url(/assets/fonts/instrument-sans-400-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
|
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:400 600;font-display:swap;src:url(/assets/fonts/instrument-sans-400-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
|
||||||
/* latin */
|
/* latin */
|
||||||
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:400 600;font-display:swap;src:url(/assets/fonts/instrument-sans-400-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
|
@font-face{font-family:'Instrument Sans';font-style:normal;font-weight:400 600;font-display:swap;src:url(/assets/fonts/instrument-sans-400-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face{font-family:'Manrope';font-style:normal;font-weight:400 800;font-display:swap;src:url(/assets/fonts/manrope-400-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
|
||||||
|
/* latin */
|
||||||
|
@font-face{font-family:'Manrope';font-style:normal;font-weight:400 800;font-display:swap;src:url(/assets/fonts/manrope-400-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face{font-family:'Montserrat';font-style:normal;font-weight:700 800;font-display:swap;src:url(/assets/fonts/montserrat-700-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
|
||||||
|
/* latin */
|
||||||
|
@font-face{font-family:'Montserrat';font-style:normal;font-weight:700 800;font-display:swap;src:url(/assets/fonts/montserrat-700-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -74,6 +74,7 @@ export const ICON_PATHS = {
|
|||||||
star: 'm12 3 2.7 5.9 6.3.7-4.7 4.3 1.3 6.1L12 17l-5.6 3 1.3-6.1L3 9.6l6.3-.7Z',
|
star: 'm12 3 2.7 5.9 6.3.7-4.7 4.3 1.3 6.1L12 17l-5.6 3 1.3-6.1L3 9.6l6.3-.7Z',
|
||||||
// Haus, Garten und Handwerk
|
// Haus, Garten und Handwerk
|
||||||
home: 'm3 11.5 9-7.5 9 7.5M5.5 10v10h13V10M10 20v-6.5h4V20',
|
home: 'm3 11.5 9-7.5 9 7.5M5.5 10v10h13V10M10 20v-6.5h4V20',
|
||||||
|
house: 'M4 10.5 12 4l8 6.5V19a1 1 0 0 1-1 1h-4.5v-5.5h-5V20H5a1 1 0 0 1-1-1Z',
|
||||||
building: 'M5 21V4h10v17m0-12h4v12M3 21h18M8.5 7.5h3m-3 3.5h3m-3 3.5h3',
|
building: 'M5 21V4h10v17m0-12h4v12M3 21h18M8.5 7.5h3m-3 3.5h3m-3 3.5h3',
|
||||||
wrench: 'M14.5 3.5a5 5 0 0 0-4.6 6.9L3.5 16.8a1.9 1.9 0 0 0 2.7 2.7l6.4-6.4a5 5 0 0 0 6.9-4.6l-3 3-3-1-1-3Z',
|
wrench: 'M14.5 3.5a5 5 0 0 0-4.6 6.9L3.5 16.8a1.9 1.9 0 0 0 2.7 2.7l6.4-6.4a5 5 0 0 0 6.9-4.6l-3 3-3-1-1-3Z',
|
||||||
hammer: 'M14 8.5 4.5 18a1.5 1.5 0 0 0 2.1 2.1L16 10.5M11 6l3-3 3.5 1L21 7.5 18.5 10l-2-2-2.5 2.5Z',
|
hammer: 'M14 8.5 4.5 18a1.5 1.5 0 0 0 2.1 2.1L16 10.5M11 6l3-3 3.5 1L21 7.5 18.5 10l-2-2-2.5 2.5Z',
|
||||||
@@ -128,7 +129,7 @@ export const ICON_LABELS = {
|
|||||||
mic: 'Mikrofon', book: 'Buch',
|
mic: 'Mikrofon', book: 'Buch',
|
||||||
user: 'Person', people: 'Personen', login: 'Anmelden', lock: 'Schloss', key: 'Schlüssel', shield: 'Schutz',
|
user: 'Person', people: 'Personen', login: 'Anmelden', lock: 'Schloss', key: 'Schlüssel', shield: 'Schutz',
|
||||||
eye: 'Ansehen', 'thumbs-up': 'Daumen hoch', award: 'Auszeichnung', graduation: 'Ausbildung', heart: 'Herz', star: 'Stern',
|
eye: 'Ansehen', 'thumbs-up': 'Daumen hoch', award: 'Auszeichnung', graduation: 'Ausbildung', heart: 'Herz', star: 'Stern',
|
||||||
home: 'Haus', building: 'Gebäude', wrench: 'Werkzeug', hammer: 'Hammer', brush: 'Malerrolle', ruler: 'Lineal',
|
home: 'Haus', house: 'Haus (Fläche)', building: 'Gebäude', wrench: 'Werkzeug', hammer: 'Hammer', brush: 'Malerrolle', ruler: 'Lineal',
|
||||||
leaf: 'Blatt', tree: 'Baum', sun: 'Sonne', droplet: 'Wasser', flame: 'Flamme', bolt: 'Strom', solar: 'Solar',
|
leaf: 'Blatt', tree: 'Baum', sun: 'Sonne', droplet: 'Wasser', flame: 'Flamme', bolt: 'Strom', solar: 'Solar',
|
||||||
thermometer: 'Temperatur', snowflake: 'Kälte', car: 'Auto',
|
thermometer: 'Temperatur', snowflake: 'Kälte', car: 'Auto',
|
||||||
check: 'Häkchen', 'check-circle': 'Häkchen im Kreis', info: 'Info', help: 'Frage', alert: 'Warnung',
|
check: 'Häkchen', 'check-circle': 'Häkchen im Kreis', info: 'Info', help: 'Frage', alert: 'Warnung',
|
||||||
@@ -144,7 +145,7 @@ export const ICON_GROUPS = [
|
|||||||
['Handel & Geld', ['shop', 'cart', 'tag', 'euro', 'credit-card', 'gift', 'percent', 'truck', 'package', 'briefcase']],
|
['Handel & Geld', ['shop', 'cart', 'tag', 'euro', 'credit-card', 'gift', 'percent', 'truck', 'package', 'briefcase']],
|
||||||
['Dateien & Medien', ['document', 'download', 'upload', 'print', 'link', 'share', 'image', 'camera', 'video', 'play', 'pause', 'music', 'mic', 'book']],
|
['Dateien & Medien', ['document', 'download', 'upload', 'print', 'link', 'share', 'image', 'camera', 'video', 'play', 'pause', 'music', 'mic', 'book']],
|
||||||
['Personen & Sicherheit', ['user', 'people', 'login', 'lock', 'key', 'shield', 'eye', 'thumbs-up', 'award', 'graduation', 'heart', 'star']],
|
['Personen & Sicherheit', ['user', 'people', 'login', 'lock', 'key', 'shield', 'eye', 'thumbs-up', 'award', 'graduation', 'heart', 'star']],
|
||||||
['Haus & Handwerk', ['home', 'building', 'wrench', 'hammer', 'brush', 'ruler', 'leaf', 'tree', 'sun', 'droplet', 'flame', 'bolt', 'solar', 'thermometer', 'snowflake', 'car']],
|
['Haus & Handwerk', ['home', 'house', 'building', 'wrench', 'hammer', 'brush', 'ruler', 'leaf', 'tree', 'sun', 'droplet', 'flame', 'bolt', 'solar', 'thermometer', 'snowflake', 'car']],
|
||||||
['Allgemein', ['check', 'check-circle', 'info', 'help', 'alert', 'search', 'settings', 'filter', 'grid', 'list', 'sparkle', 'coffee', 'utensils', 'laptop', 'hardware', 'network', 'design']],
|
['Allgemein', ['check', 'check-circle', 'info', 'help', 'alert', 'search', 'settings', 'filter', 'grid', 'list', 'sparkle', 'coffee', 'utensils', 'laptop', 'hardware', 'network', 'design']],
|
||||||
['Soziale Netzwerke', ['facebook', 'instagram', 'whatsapp']],
|
['Soziale Netzwerke', ['facebook', 'instagram', 'whatsapp']],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
/* Symbole als SVG: Schriftzeichen macht ein Telefon zu Emoji. */
|
||||||
|
const symbol = (p) => `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="${p}"/></svg>`;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Der Bildbetrachter.
|
* Der Bildbetrachter.
|
||||||
*
|
*
|
||||||
@@ -23,9 +26,9 @@
|
|||||||
<img class="zoom-image" alt="">
|
<img class="zoom-image" alt="">
|
||||||
<figcaption class="zoom-caption"></figcaption>
|
<figcaption class="zoom-caption"></figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
<button class="zoom-close" type="button" aria-label="Schließen">×</button>
|
<button class="zoom-close" type="button" aria-label="Schließen">${symbol('M6 6l12 12M18 6 6 18')}</button>
|
||||||
<button class="zoom-prev" type="button" aria-label="Vorheriges Bild">‹</button>
|
<button class="zoom-prev" type="button" aria-label="Vorheriges Bild">${symbol('M15 5.5 8.5 12l6.5 6.5')}</button>
|
||||||
<button class="zoom-next" type="button" aria-label="Nächstes Bild">›</button>
|
<button class="zoom-next" type="button" aria-label="Nächstes Bild">${symbol('m9 5.5 6.5 6.5L9 18.5')}</button>
|
||||||
<p class="zoom-counter" aria-live="polite"></p>
|
<p class="zoom-counter" aria-live="polite"></p>
|
||||||
`;
|
`;
|
||||||
document.body.append(dialog);
|
document.body.append(dialog);
|
||||||
@@ -138,7 +141,7 @@
|
|||||||
<p class="pdf-title" id="pdf-dialog-title"></p>
|
<p class="pdf-title" id="pdf-dialog-title"></p>
|
||||||
<a class="pdf-action pdf-download" download>Herunterladen</a>
|
<a class="pdf-action pdf-download" download>Herunterladen</a>
|
||||||
<a class="pdf-action pdf-open" target="_blank" rel="noopener">Im neuen Tab</a>
|
<a class="pdf-action pdf-open" target="_blank" rel="noopener">Im neuen Tab</a>
|
||||||
<button class="pdf-close" type="button" aria-label="Schließen">×</button>
|
<button class="pdf-close" type="button" aria-label="Schließen">${symbol('M6 6l12 12M18 6 6 18')}</button>
|
||||||
</div>
|
</div>
|
||||||
<iframe class="pdf-frame" title="PDF-Dokument"></iframe>
|
<iframe class="pdf-frame" title="PDF-Dokument"></iframe>
|
||||||
`;
|
`;
|
||||||
|
|||||||
+17
-7
@@ -1,3 +1,5 @@
|
|||||||
|
/* Symbole als eingebettete SVG-Masken: Schriftzeichen macht ein Telefon zu Emoji. */
|
||||||
|
:root{--kant-svg-unten:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");--kant-svg-oben:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 15 6-6 6 6'/%3E%3C/svg%3E");--kant-svg-rechts:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 5.5 6.5 6.5L9 18.5'/%3E%3C/svg%3E");--kant-svg-pfeil:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h15.5m-6.5-6.5 6.5 6.5-6.5 6.5'/%3E%3C/svg%3E");--kant-svg-pfeil-links:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 12H4.5M11 5.5 4.5 12 11 18.5'/%3E%3C/svg%3E");--kant-svg-pause:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 5v14m8-14v14'/%3E%3C/svg%3E");--kant-svg-play:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E")}
|
||||||
@charset "UTF-8";
|
@charset "UTF-8";
|
||||||
/* Lange Wörter dürfen umbrechen, damit nichts aus der Spalte läuft. Getrennt wird nur im
|
/* Lange Wörter dürfen umbrechen, damit nichts aus der Spalte läuft. Getrennt wird nur im
|
||||||
Fließtext: eine Überschrift mit Trennstrich („di-gitale") sieht nach Fehler aus. */
|
Fließtext: eine Überschrift mit Trennstrich („di-gitale") sieht nach Fehler aus. */
|
||||||
@@ -19,14 +21,14 @@ p{hyphens:auto}
|
|||||||
.menu-list a:hover,.menu-list summary:hover{text-decoration:underline}
|
.menu-list a:hover,.menu-list summary:hover{text-decoration:underline}
|
||||||
.menu-list [aria-current=page]{font-weight:700;text-decoration:none}
|
.menu-list [aria-current=page]{font-weight:700;text-decoration:none}
|
||||||
.menu-branch>summary{cursor:pointer;padding:6px 2px;list-style:none}
|
.menu-branch>summary{cursor:pointer;padding:6px 2px;list-style:none}
|
||||||
.menu-branch>summary::after{content:' ▾'}
|
.menu-branch>summary::after{content:'';display:inline-block;width:.75em;height:.75em;background:currentColor;-webkit-mask:var(--kant-svg-unten) center/contain no-repeat;mask:var(--kant-svg-unten) center/contain no-repeat;margin-left:.3em;vertical-align:-.05em}
|
||||||
.menu-branch[open]>summary::after{content:' ▴'}
|
.menu-branch[open]>summary::after{-webkit-mask-image:var(--kant-svg-oben);mask-image:var(--kant-svg-oben)}
|
||||||
.menu-branch-body{display:grid;gap:2px;padding:6px 0 6px 14px}
|
.menu-branch-body{display:grid;gap:2px;padding:6px 0 6px 14px}
|
||||||
.menu-level-2{flex-direction:column;align-items:flex-start;gap:2px}
|
.menu-level-2{flex-direction:column;align-items:flex-start;gap:2px}
|
||||||
|
|
||||||
/* Posts */
|
/* Posts */
|
||||||
.post-list{list-style:none;margin:0;padding:0;display:grid;gap:26px}.post-list-karten{grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}.post-list-liste{gap:18px}.post-list-liste .post-card{flex-direction:row;align-items:stretch}.post-list-liste .post-image{flex:0 0 34%;max-width:300px}.post-list-liste .post-image img{height:100%;aspect-ratio:auto;min-height:170px}.post-list-liste .post-body{flex:1 1 auto;align-content:center;padding:22px 26px}.post-list-wechsel{gap:0;counter-reset:beitrag}.post-list-wechsel .post-card{position:relative;counter-increment:beitrag;display:grid;grid-template-columns:1fr 1fr;align-items:center;gap:0 56px;padding:38px 0;background:transparent;border:0;border-radius:0;overflow:visible}.post-list-wechsel .post-card + .post-card{border-top:1px solid var(--line)}.post-list-wechsel .post-image{border-radius:20px;overflow:hidden;box-shadow:0 18px 46px -22px color-mix(in srgb,var(--ink) 55%,transparent)}.post-list-wechsel .post-image img{aspect-ratio:16/10;border-radius:20px}.post-list-wechsel .post-body{padding:0;display:grid;gap:12px;align-content:center}.post-list-wechsel .post-body::before{content:counter(beitrag,decimal-leading-zero);font-size:13px;font-weight:800;letter-spacing:2px;color:var(--accent)}.post-list-wechsel .post-card h3{font-size:28px;line-height:1.18;letter-spacing:-.5px}.post-list-wechsel .post-excerpt{margin:0;max-width:46ch}.post-list-wechsel .post-meta,.post-list-wechsel .post-terms{margin:0}.post-list-wechsel .post-more{display:inline-flex;align-items:center;gap:8px;margin-top:4px;font-size:15px;font-weight:700;color:var(--accent);text-decoration:none;width:fit-content}
|
.post-list{list-style:none;margin:0;padding:0;display:grid;gap:26px}.post-list-karten{grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}.post-list-liste{gap:18px}.post-list-liste .post-card{flex-direction:row;align-items:stretch}.post-list-liste .post-image{flex:0 0 34%;max-width:300px}.post-list-liste .post-image img{height:100%;aspect-ratio:auto;min-height:170px}.post-list-liste .post-body{flex:1 1 auto;align-content:center;padding:22px 26px}.post-list-wechsel{gap:0;counter-reset:beitrag}.post-list-wechsel .post-card{position:relative;counter-increment:beitrag;display:grid;grid-template-columns:1fr 1fr;align-items:center;gap:0 56px;padding:38px 0;background:transparent;border:0;border-radius:0;overflow:visible}.post-list-wechsel .post-card + .post-card{border-top:1px solid var(--line)}.post-list-wechsel .post-image{border-radius:20px;overflow:hidden;box-shadow:0 18px 46px -22px color-mix(in srgb,var(--ink) 55%,transparent)}.post-list-wechsel .post-image img{aspect-ratio:16/10;border-radius:20px}.post-list-wechsel .post-body{padding:0;display:grid;gap:12px;align-content:center}.post-list-wechsel .post-body::before{content:counter(beitrag,decimal-leading-zero);font-size:13px;font-weight:800;letter-spacing:2px;color:var(--accent)}.post-list-wechsel .post-card h3{font-size:28px;line-height:1.18;letter-spacing:-.5px}.post-list-wechsel .post-excerpt{margin:0;max-width:46ch}.post-list-wechsel .post-meta,.post-list-wechsel .post-terms{margin:0}.post-list-wechsel .post-more{display:inline-flex;align-items:center;gap:8px;margin-top:4px;font-size:15px;font-weight:700;color:var(--accent);text-decoration:none;width:fit-content}
|
||||||
.post-more::after{content:'→';transition:transform .2s}
|
.post-more::after{content:'';display:inline-block;width:1em;height:1em;background:currentColor;-webkit-mask:var(--kant-svg-pfeil) center/contain no-repeat;mask:var(--kant-svg-pfeil) center/contain no-repeat;vertical-align:-.12em;transition:transform .2s}
|
||||||
.post-more:hover::after{transform:translateX(4px)}.post-list-wechsel .post-more::after{content:'\2192'}.post-list-wechsel .post-card:nth-child(even) .post-image{order:2}.post-list-wechsel .post-card:nth-child(even) .post-body{order:1}@media(max-width:767px){.post-list-wechsel .post-card{grid-template-columns:1fr;gap:18px;padding:26px 0}.post-list-wechsel .post-card:nth-child(even) .post-image{order:0}.post-list-wechsel .post-card:nth-child(even) .post-body{order:0}.post-list-wechsel .post-card h3{font-size:22px}}.post-list-kompakt{gap:0}.post-list-kompakt .post-card{flex-direction:row;align-items:baseline;justify-content:space-between;gap:18px;background:transparent;border:0;border-bottom:1px solid var(--line);border-radius:0;overflow:visible}.post-list-kompakt .post-body{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 18px;padding:16px 2px}.post-list-kompakt .post-meta,.post-list-kompakt .post-terms{margin:0}.post-list-kompakt .post-excerpt{flex:1 1 100%;margin:0}
|
.post-more:hover::after{transform:translateX(4px)}.post-list-wechsel .post-more::after{content:'\2192'}.post-list-wechsel .post-card:nth-child(even) .post-image{order:2}.post-list-wechsel .post-card:nth-child(even) .post-body{order:1}@media(max-width:767px){.post-list-wechsel .post-card{grid-template-columns:1fr;gap:18px;padding:26px 0}.post-list-wechsel .post-card:nth-child(even) .post-image{order:0}.post-list-wechsel .post-card:nth-child(even) .post-body{order:0}.post-list-wechsel .post-card h3{font-size:22px}}.post-list-kompakt{gap:0}.post-list-kompakt .post-card{flex-direction:row;align-items:baseline;justify-content:space-between;gap:18px;background:transparent;border:0;border-bottom:1px solid var(--line);border-radius:0;overflow:visible}.post-list-kompakt .post-body{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 18px;padding:16px 2px}.post-list-kompakt .post-meta,.post-list-kompakt .post-terms{margin:0}.post-list-kompakt .post-excerpt{flex:1 1 100%;margin:0}
|
||||||
.post-card{display:flex;flex-direction:column;background:var(--paper);border:1px solid var(--line);border-radius:18px;overflow:hidden}.post-card>.post-body{display:grid;gap:10px;padding:20px 22px 22px}
|
.post-card{display:flex;flex-direction:column;background:var(--paper);border:1px solid var(--line);border-radius:18px;overflow:hidden}.post-card>.post-body{display:grid;gap:10px;padding:20px 22px 22px}
|
||||||
.post-image{display:block;position:relative;overflow:hidden;text-decoration:none}.post-view{position:absolute;inset:0;display:grid;place-items:center;background:color-mix(in srgb,var(--ink) 55%,transparent);color:#fff;font-weight:700;font-size:15px;letter-spacing:.4px;opacity:0}.post-card:hover .post-view,.post-card:focus-within .post-view{opacity:1}.post-image img{width:100%;height:auto;aspect-ratio:16/10;object-fit:cover;border-radius:0;display:block;background:var(--ink)}
|
.post-image{display:block;position:relative;overflow:hidden;text-decoration:none}.post-view{position:absolute;inset:0;display:grid;place-items:center;background:color-mix(in srgb,var(--ink) 55%,transparent);color:#fff;font-weight:700;font-size:15px;letter-spacing:.4px;opacity:0}.post-card:hover .post-view,.post-card:focus-within .post-view{opacity:1}.post-image img{width:100%;height:auto;aspect-ratio:16/10;object-fit:cover;border-radius:0;display:block;background:var(--ink)}
|
||||||
@@ -66,7 +68,9 @@ p{hyphens:auto}
|
|||||||
.block-quote blockquote p{margin:0;font-size:inherit;line-height:1.65}
|
.block-quote blockquote p{margin:0;font-size:inherit;line-height:1.65}
|
||||||
.block-quote figcaption{font-size:14px;font-weight:600}
|
.block-quote figcaption{font-size:14px;font-weight:600}
|
||||||
.block-quote figcaption span{font-weight:400;opacity:.85}
|
.block-quote figcaption span{font-weight:400;opacity:.85}
|
||||||
.quote-rating{margin:0;letter-spacing:3px}
|
.quote-rating{margin:0}
|
||||||
|
.quote-rating svg{display:inline-block;width:1.1em;height:1.1em;margin-right:2px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linejoin:round}
|
||||||
|
.quote-rating .quote-star-voll{fill:currentColor}
|
||||||
.block-logos{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));align-items:center;gap:24px}
|
.block-logos{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));align-items:center;gap:24px}
|
||||||
.block-logos img{max-height:52px;width:auto;margin-inline:auto;display:block}
|
.block-logos img{max-height:52px;width:auto;margin-inline:auto;display:block}
|
||||||
.kant .block-cta .button{background:var(--accent);color:var(--paper);border-color:var(--accent)}.kant .block-cta .button:hover{background:color-mix(in srgb,var(--accent) 86%,var(--ink))}.block-cta{display:flex;flex-wrap:wrap;gap:20px 34px;align-items:center;justify-content:space-between;padding:32px;border:1px solid currentColor;border-radius:14px}
|
.kant .block-cta .button{background:var(--accent);color:var(--paper);border-color:var(--accent)}.kant .block-cta .button:hover{background:color-mix(in srgb,var(--accent) 86%,var(--ink))}.block-cta{display:flex;flex-wrap:wrap;gap:20px 34px;align-items:center;justify-content:space-between;padding:32px;border:1px solid currentColor;border-radius:14px}
|
||||||
@@ -170,7 +174,7 @@ p{hyphens:auto}
|
|||||||
@media(max-width:767px){.form-summary-list{grid-template-columns:1fr;gap:2px 0}.form-summary-list dd{margin-bottom:8px}}
|
@media(max-width:767px){.form-summary-list{grid-template-columns:1fr;gap:2px 0}.form-summary-list dd{margin-bottom:8px}}
|
||||||
|
|
||||||
.block-breadcrumb ol{list-style:none;display:flex;flex-wrap:wrap;gap:6px 10px;margin:0;padding:0;font-size:13px}
|
.block-breadcrumb ol{list-style:none;display:flex;flex-wrap:wrap;gap:6px 10px;margin:0;padding:0;font-size:13px}
|
||||||
.block-breadcrumb li+li::before{content:'›';margin-right:10px;opacity:.6}
|
.block-breadcrumb li+li::before{content:'';display:inline-block;width:.85em;height:.85em;background:currentColor;-webkit-mask:var(--kant-svg-rechts) center/contain no-repeat;mask:var(--kant-svg-rechts) center/contain no-repeat;margin-right:10px;opacity:.6;vertical-align:-.08em}
|
||||||
.block-breadcrumb a{text-decoration:none}
|
.block-breadcrumb a{text-decoration:none}
|
||||||
.block-breadcrumb a:hover{text-decoration:underline}
|
.block-breadcrumb a:hover{text-decoration:underline}
|
||||||
|
|
||||||
@@ -247,8 +251,8 @@ body.consent-open{padding-bottom:320px}
|
|||||||
.section-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;pointer-events:none}
|
.section-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;pointer-events:none}
|
||||||
.has-video>.section-inner{position:relative;z-index:1}
|
.has-video>.section-inner{position:relative;z-index:1}
|
||||||
.video-toggle{position:absolute;right:16px;bottom:16px;z-index:2;width:44px;height:44px;padding:0;border:0;border-radius:50%;background:rgba(10,20,35,.72);color:#fff;font:14px/1 system-ui,sans-serif;cursor:pointer}
|
.video-toggle{position:absolute;right:16px;bottom:16px;z-index:2;width:44px;height:44px;padding:0;border:0;border-radius:50%;background:rgba(10,20,35,.72);color:#fff;font:14px/1 system-ui,sans-serif;cursor:pointer}
|
||||||
.video-toggle::before{content:"❚❚"}
|
.video-toggle::before{content:'';display:inline-block;width:20px;height:20px;background:currentColor;-webkit-mask:var(--kant-svg-pause) center/contain no-repeat;mask:var(--kant-svg-pause) center/contain no-repeat;display:block;margin:auto}
|
||||||
.video-toggle.is-paused::before{content:"▶"}
|
.video-toggle.is-paused::before{-webkit-mask-image:var(--kant-svg-play);mask-image:var(--kant-svg-play)}
|
||||||
.video-toggle:focus-visible{outline:3px solid #fff;outline-offset:2px}
|
.video-toggle:focus-visible{outline:3px solid #fff;outline-offset:2px}
|
||||||
.video-toggle[hidden]{display:none}
|
.video-toggle[hidden]{display:none}
|
||||||
.block-html{max-width:100%}
|
.block-html{max-width:100%}
|
||||||
@@ -603,6 +607,10 @@ html.kant-top-armed.kant-top-shown .scroll-top{opacity:1;visibility:visible;tran
|
|||||||
.zoom-close,.zoom-prev,.zoom-next{position:fixed;display:grid;place-items:center;width:52px;height:52px;border-radius:999px;border:0;background:rgba(255,255,255,.14);color:#fff;font-size:26px;line-height:1;cursor:pointer}
|
.zoom-close,.zoom-prev,.zoom-next{position:fixed;display:grid;place-items:center;width:52px;height:52px;border-radius:999px;border:0;background:rgba(255,255,255,.14);color:#fff;font-size:26px;line-height:1;cursor:pointer}
|
||||||
.zoom-close:hover,.zoom-prev:hover,.zoom-next:hover{background:rgba(255,255,255,.26)}
|
.zoom-close:hover,.zoom-prev:hover,.zoom-next:hover{background:rgba(255,255,255,.26)}
|
||||||
.zoom-close:focus-visible,.zoom-prev:focus-visible,.zoom-next:focus-visible{outline:3px solid #fff;outline-offset:3px}
|
.zoom-close:focus-visible,.zoom-prev:focus-visible,.zoom-next:focus-visible{outline:3px solid #fff;outline-offset:3px}
|
||||||
|
.zoom-close svg,.zoom-prev svg,.zoom-next svg,.pdf-close svg,.scroll-top svg{display:block;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
|
||||||
|
.zoom-close svg,.zoom-prev svg,.zoom-next svg{width:26px;height:26px}
|
||||||
|
.pdf-close svg{width:20px;height:20px}
|
||||||
|
.scroll-top svg{width:46%;height:46%}
|
||||||
.zoom-close{top:18px;right:18px}
|
.zoom-close{top:18px;right:18px}
|
||||||
.zoom-prev{left:18px;top:50%;transform:translateY(-50%)}
|
.zoom-prev{left:18px;top:50%;transform:translateY(-50%)}
|
||||||
.zoom-next{right:18px;top:50%;transform:translateY(-50%)}
|
.zoom-next{right:18px;top:50%;transform:translateY(-50%)}
|
||||||
@@ -644,3 +652,5 @@ html.kant-top-armed.kant-top-shown .scroll-top{opacity:1;visibility:visible;tran
|
|||||||
.tone-ink,.tone-mint{background:transparent;color:#000}
|
.tone-ink,.tone-mint{background:transparent;color:#000}
|
||||||
[data-step][hidden],.block-form [hidden]{display:block!important}
|
[data-step][hidden],.block-form [hidden]{display:block!important}
|
||||||
}
|
}
|
||||||
|
.post-pager a[rel="prev"]::before{content:'';display:inline-block;width:1em;height:1em;background:currentColor;-webkit-mask:var(--kant-svg-pfeil-links) center/contain no-repeat;mask:var(--kant-svg-pfeil-links) center/contain no-repeat;margin-right:.35em;vertical-align:-.12em}
|
||||||
|
.post-pager a[rel="next"]::after{content:'';display:inline-block;width:1em;height:1em;background:currentColor;-webkit-mask:var(--kant-svg-pfeil) center/contain no-repeat;mask:var(--kant-svg-pfeil) center/contain no-repeat;margin-left:.35em;vertical-align:-.12em}
|
||||||
@@ -56,14 +56,14 @@ export function initSliders(doc = document) {
|
|||||||
go(direction > 0 ? (last ? visible[0] : visible[Math.min(visible.length - 1, position + 1)]) : (first ? visible.at(-1) : visible[Math.max(0, position - 1)]));
|
go(direction > 0 ? (last ? visible[0] : visible[Math.min(visible.length - 1, position + 1)]) : (first ? visible.at(-1) : visible[Math.max(0, position - 1)]));
|
||||||
};
|
};
|
||||||
const manual = action => { playing = false; clearTimeout(timer); update(); action(); };
|
const manual = action => { playing = false; clearTimeout(timer); update(); action(); };
|
||||||
const previous = button('←', 'Vorherige Folie', () => manual(() => step(-1))); previous.className = 'slider-prev';
|
const previous = button('', 'Vorherige Folie', () => manual(() => step(-1))); previous.className = 'slider-prev';
|
||||||
const count = doc.createElement('span'); count.className = 'slider-position'; controls.append(count);
|
const count = doc.createElement('span'); count.className = 'slider-position'; controls.append(count);
|
||||||
const next = button('→', 'Nächste Folie', () => manual(() => step(1))); next.className = 'slider-next';
|
const next = button('', 'Nächste Folie', () => manual(() => step(1))); next.className = 'slider-next';
|
||||||
const dots = [];
|
const dots = [];
|
||||||
if (slider.classList.contains('slider-dots')) {
|
if (slider.classList.contains('slider-dots')) {
|
||||||
const group = doc.createElement('div'); group.className = 'slider-control-dots'; controls.append(group);
|
const group = doc.createElement('div'); group.className = 'slider-control-dots'; controls.append(group);
|
||||||
slides.forEach((slide, i) => {
|
slides.forEach((slide, i) => {
|
||||||
const dot = button('●', `Folie ${i + 1} anzeigen`, () => manual(() => go(i))); group.append(dot); dots.push(dot);
|
const dot = button('', `Folie ${i + 1} anzeigen`, () => manual(() => go(i))); group.append(dot); dots.push(dot);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const play = seconds >= 3 ? button('', 'Automatische Wiedergabe pausieren', () => { playing = !playing; update(); schedule(); }) : null;
|
const play = seconds >= 3 ? button('', 'Automatische Wiedergabe pausieren', () => { playing = !playing; update(); schedule(); }) : null;
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bereitet Logo und Fotos von „Becker – Just In Time e. Kfm.“ für die Mediathek des Nachbaus vor.
|
||||||
|
*
|
||||||
|
* Quellordner (var/becker-quelle):
|
||||||
|
* - logo-original.png: das Rasterbild aus Logo_Becker_original.pdf (1536 × 1024, Navy-Grund #172234),
|
||||||
|
* - ki/*.png: die von ChatGPT ohne Logos neu erzeugten Fotos (10.11.2026, nach Umuts Vorlagen).
|
||||||
|
*
|
||||||
|
* Daraus entstehen im Zielordner:
|
||||||
|
* - logo.png: Bagger-Signet links, „BECKER / JUST IN TIME e. Kfm.“ rechts – für den Kopf,
|
||||||
|
* - logo-gross.png: das Logo gestapelt mit den drei Leistungssymbolen – für den Fuß,
|
||||||
|
* - favicon.png: das Bagger-Signet auf Navy, 192 × 192,
|
||||||
|
* - je Foto eine WebP-Datei (Startbild 1920 px, sonst 1600 px breit).
|
||||||
|
*
|
||||||
|
* Der Navy-Grund des Logos wird weich freigestellt: Deckkraft aus dem Farbabstand zum Grund,
|
||||||
|
* die Kantenfarbe zurückgerechnet. So passt das Logo auf jede dunkle Fläche.
|
||||||
|
*
|
||||||
|
* Aufruf: php scripts/build-becker-assets.php <Quellordner> <Zielordner>
|
||||||
|
*/
|
||||||
|
$quelle = rtrim($argv[1] ?? '', '/\\');
|
||||||
|
$ziel = rtrim($argv[2] ?? '', '/\\');
|
||||||
|
if ('' === $quelle || '' === $ziel || !is_file($quelle.'/logo-original.png')) {
|
||||||
|
fwrite(STDERR, "Aufruf: php scripts/build-becker-assets.php <Ordner mit logo-original.png und ki/> <Zielordner>\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!is_dir($ziel) && !mkdir($ziel, 0775, true)) {
|
||||||
|
fwrite(STDERR, "Zielordner lässt sich nicht anlegen: $ziel\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$logo = imagecreatefrompng($quelle.'/logo-original.png');
|
||||||
|
$grund = [23, 34, 52];
|
||||||
|
|
||||||
|
/** Ein Ausschnitt des Logos mit freigestelltem Navy-Grund. */
|
||||||
|
$freistellen = static function (int $x, int $y, int $b, int $h) use ($logo, $grund): GdImage {
|
||||||
|
$bild = imagecreatetruecolor($b, $h);
|
||||||
|
imagealphablending($bild, false);
|
||||||
|
imagesavealpha($bild, true);
|
||||||
|
for ($j = 0; $j < $h; ++$j) {
|
||||||
|
for ($i = 0; $i < $b; ++$i) {
|
||||||
|
$c = imagecolorat($logo, $x + $i, $y + $j);
|
||||||
|
$p = [$c >> 16 & 0xFF, $c >> 8 & 0xFF, $c & 0xFF];
|
||||||
|
$abstand = max(abs($p[0] - $grund[0]), abs($p[1] - $grund[1]), abs($p[2] - $grund[2]));
|
||||||
|
$a = min(1.0, max(0.0, ($abstand - 6) / 90));
|
||||||
|
if ($a <= 0.0) {
|
||||||
|
imagesetpixel($bild, $i, $j, imagecolorallocatealpha($bild, 0, 0, 0, 127));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$f = array_map(static fn (int $k): int => (int) max(0, min(255, round($grund[$k] + ($p[$k] - $grund[$k]) / $a))), [0, 1, 2]);
|
||||||
|
imagesetpixel($bild, $i, $j, imagecolorallocatealpha($bild, $f[0], $f[1], $f[2], (int) round(127 * (1 - $a))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bild;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Verkleinert mit Durchsichtigkeit. */
|
||||||
|
$verkleinern = static function (GdImage $bild, int $breite): GdImage {
|
||||||
|
$hoehe = (int) round(imagesy($bild) * $breite / imagesx($bild));
|
||||||
|
$neu = imagecreatetruecolor($breite, $hoehe);
|
||||||
|
imagealphablending($neu, false);
|
||||||
|
imagesavealpha($neu, true);
|
||||||
|
imagefill($neu, 0, 0, imagecolorallocatealpha($neu, 0, 0, 0, 127));
|
||||||
|
imagecopyresampled($neu, $bild, 0, 0, 0, 0, $breite, $hoehe, imagesx($bild), imagesy($bild));
|
||||||
|
|
||||||
|
return $neu;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bänder im Original (gemessen): Signet y 15–455 / x 360–1196, „BECKER“ y 466–636,
|
||||||
|
// „JUST IN TIME e. Kfm.“ mit Linien y 647–701 / x 162–1382, Leistungssymbole y 722–897.
|
||||||
|
$signet = $freistellen(352, 8, 852, 456);
|
||||||
|
$schrift = $freistellen(154, 458, 1236, 252);
|
||||||
|
|
||||||
|
// Querformat für den Kopf: Signet links (so hoch wie die Schrift plus etwas), Schrift rechts.
|
||||||
|
$sh = 330;
|
||||||
|
$sb = (int) round(852 * $sh / 456);
|
||||||
|
$quer = imagecreatetruecolor($sb + 36 + 1236, $sh);
|
||||||
|
imagealphablending($quer, false);
|
||||||
|
imagesavealpha($quer, true);
|
||||||
|
imagefill($quer, 0, 0, imagecolorallocatealpha($quer, 0, 0, 0, 127));
|
||||||
|
imagealphablending($quer, true);
|
||||||
|
imagecopyresampled($quer, $signet, 0, 0, 0, 0, $sb, $sh, 852, 456);
|
||||||
|
imagecopy($quer, $schrift, $sb + 36, (int) round(($sh - 252) / 2) + 10, 0, 0, 1236, 252);
|
||||||
|
imagealphablending($quer, false);
|
||||||
|
imagepng($verkleinern($quer, 760), $ziel.'/logo.png', 9);
|
||||||
|
echo 'logo.png: 760 × '.(int) round($sh * 760 / imagesx($quer))."\n";
|
||||||
|
|
||||||
|
$gross = $freistellen(100, 8, 1336, 898);
|
||||||
|
imagepng($verkleinern($gross, 560), $ziel.'/logo-gross.png', 9);
|
||||||
|
echo "logo-gross.png: 560 px breit\n";
|
||||||
|
|
||||||
|
// Die drei Leistungssymbole des Logos (Blätter, Zaun, Dach) einzeln, quadratisch, 128 px.
|
||||||
|
foreach (['symbol-garten' => [250, 716, 186, 120], 'symbol-zaun' => [679, 716, 176, 124], 'symbol-asbest' => [1071, 716, 226, 120]] as $name => [$x, $y, $b, $h]) {
|
||||||
|
$teil = $freistellen($x, $y, $b, $h);
|
||||||
|
$q = max($b, $h);
|
||||||
|
$quadrat = imagecreatetruecolor(128, 128);
|
||||||
|
imagealphablending($quadrat, false);
|
||||||
|
imagesavealpha($quadrat, true);
|
||||||
|
imagefill($quadrat, 0, 0, imagecolorallocatealpha($quadrat, 0, 0, 0, 127));
|
||||||
|
$f = 128 / $q;
|
||||||
|
imagecopyresampled($quadrat, $teil, (int) round((128 - $b * $f) / 2), (int) round((128 - $h * $f) / 2), 0, 0, (int) round($b * $f), (int) round($h * $f), $b, $h);
|
||||||
|
imagepng($quadrat, $ziel.'/'.$name.'.png', 9);
|
||||||
|
echo "$name.png: 128 × 128\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seitensymbol: Signet mittig auf Navy.
|
||||||
|
$fav = imagecreatetruecolor(192, 192);
|
||||||
|
imagefill($fav, 0, 0, imagecolorallocate($fav, ...$grund));
|
||||||
|
imagecopyresampled($fav, $logo, 14, 22 + (int) round((148 - 164 * 440 / 836) / 2), 360, 15, 164, (int) round(164 * 440 / 836), 836, 440);
|
||||||
|
imagepng($fav, $ziel.'/favicon.png', 9);
|
||||||
|
echo "favicon.png: 192 × 192\n";
|
||||||
|
|
||||||
|
// Fotos: ChatGPT liefert PNG; als WebP auf Zielbreite.
|
||||||
|
foreach (['haus' => 1920, 'team' => 1600, 'zaun' => 1600, 'zauntor' => 1600, 'asbest' => 1600, 'dach' => 1600,
|
||||||
|
'bagger' => 1600, 'terrasse' => 1600, 'zisterne' => 1600, 'vorher' => 1600, 'nachher' => 1600] as $name => $breite) {
|
||||||
|
$pfad = $quelle.'/ki/'.$name.'.png';
|
||||||
|
if (!is_file($pfad)) {
|
||||||
|
fwrite(STDERR, "Foto fehlt: $pfad\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
$bild = imagecreatefrompng($pfad);
|
||||||
|
$breite = min($breite, imagesx($bild));
|
||||||
|
$hoehe = (int) round(imagesy($bild) * $breite / imagesx($bild));
|
||||||
|
$neu = imagecreatetruecolor($breite, $hoehe);
|
||||||
|
imagecopyresampled($neu, $bild, 0, 0, 0, 0, $breite, $hoehe, imagesx($bild), imagesy($bild));
|
||||||
|
imagewebp($neu, $ziel.'/'.$name.'.webp', 80);
|
||||||
|
echo "$name.webp: $breite × $hoehe\n";
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Wirft die Becker-Installation (Becker – Just In Time e. Kfm., Wiernsheim) weg und baut sie neu auf.
|
||||||
|
# Nur fuer den Aufbau gedacht.
|
||||||
|
# Erstes Argument (optional): Quellordner mit logo-original.png (Rasterbild aus Logo_Becker_original.pdf)
|
||||||
|
# und ki/*.png (die ohne Logos neu erzeugten Fotos). Dann entstehen Logo, Symbole und WebP-Fotos neu.
|
||||||
|
set -e
|
||||||
|
root="C:/Django Project/KantSites"
|
||||||
|
php="${PHP_BINARY:-C:/php84/php.exe}"
|
||||||
|
export DATABASE_URL="sqlite:///$root/var/becker.db"
|
||||||
|
export MEDIA_DIRECTORY="$root/var/becker-media"
|
||||||
|
assets="$root/var/becker-assets"
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
"$php" scripts/build-becker-assets.php "$1" "$assets"
|
||||||
|
fi
|
||||||
|
if [ ! -f "$assets/haus.webp" ] || [ ! -f "$assets/logo.png" ]; then
|
||||||
|
echo "Bilder fehlen: erst mit dem Quellordner (z. B. var/becker-quelle) als Argument aufrufen." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
rm -f "$root/var/becker.db"
|
||||||
|
rm -rf "$root/var/becker-media"
|
||||||
|
"$php" vendor/bin/doctrine-migrations migrate --no-interaction -q
|
||||||
|
"$php" -d memory_limit=512M scripts/seed-becker.php "$assets"
|
||||||
|
# Manrope und Montserrat vom eigenen Server; der Abruf ergaenzt fonts.css nur.
|
||||||
|
if [ -f "$root/var/cacert.pem" ]; then
|
||||||
|
"$php" -d curl.cainfo="$root/var/cacert.pem" -d openssl.cafile="$root/var/cacert.pem" bin/console cms:fonts:fetch
|
||||||
|
else
|
||||||
|
"$php" bin/console cms:fonts:fetch
|
||||||
|
fi
|
||||||
|
# Das Inhaltspaket fuer eine Live-Seite (ADR 118): dort unter System -> Inhalte uebertragen importieren.
|
||||||
|
rm -f "$root/var/becker-paket.zip"
|
||||||
|
"$php" bin/console cms:paket:export --ziel="$root/var/becker-paket.zip"
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -452,8 +452,8 @@ $kopf = [
|
|||||||
]],
|
]],
|
||||||
// Goldene Linie, die beim Überfahren wächst; das Klappmenü liegt als Fläche
|
// Goldene Linie, die beim Überfahren wächst; das Klappmenü liegt als Fläche
|
||||||
// unter dem ganzen Kopf.
|
// unter dem ganzen Kopf.
|
||||||
'css' => "& .menu-list{gap:4px 28px;align-items:center}\n"
|
'css' => "& .menu-list{gap:4px clamp(10px,calc(4.2vw - 32px),28px);align-items:center}\n"
|
||||||
."& .menu-list a{position:relative;padding:12px 0;text-decoration:none}\n"
|
."& .menu-list a{position:relative;padding:12px 0;text-decoration:none;font-size:clamp(13px,1.05vw,15px)}\n"
|
||||||
."& .menu-list a::after{content:'';position:absolute;left:0;right:100%;bottom:6px;height:1.5px;background:#BDA076;transition:right .25s ease}\n"
|
."& .menu-list a::after{content:'';position:absolute;left:0;right:100%;bottom:6px;height:1.5px;background:#BDA076;transition:right .25s ease}\n"
|
||||||
."& .menu-list a:hover::after{right:0}\n"
|
."& .menu-list a:hover::after{right:0}\n"
|
||||||
."& .menu-burger summary{width:46px;height:46px;display:flex;align-items:center;justify-content:center;padding:0}\n"
|
."& .menu-burger summary{width:46px;height:46px;display:flex;align-items:center;justify-content:center;padding:0}\n"
|
||||||
@@ -501,7 +501,7 @@ $fuss = [
|
|||||||
]),
|
]),
|
||||||
$column('fuss-seiten', [
|
$column('fuss-seiten', [
|
||||||
$kleinzeile('fuss-seiten-titel', 'Leistungen', '@gold-dunkel', '8px'),
|
$kleinzeile('fuss-seiten-titel', 'Leistungen', '@gold-dunkel', '8px'),
|
||||||
$fussText('fuss-seiten-text', '<a href="/#leistungen">Immobilienverkauf</a><br><a href="/#leistungen">WEG-Verwaltung</a><br><a href="/#leistungen">Mietverwaltung</a><br><a href="/#leistungen">Sondereigentum</a><br><a href="/verwaltungsanfrage">Verwaltungsanfrage</a><br><a href="/immobilienbewertung">Immobilienbewertung</a>'),
|
$fussText('fuss-seiten-text', '<a href="/#leistungen">Immobilienverkauf</a><br><a href="/#leistungen">WEG-Verwaltung</a><br><a href="/#leistungen">Mietverwaltung</a><br><a href="/#leistungen">Sondereigentum</a><br><a href="/verwaltungsanfrage">Verwaltungsanfrage</a><br><a href="/immobilienbewertung">Immobilienbewertung</a><br><a href="/immobilien">Immobilien</a>'),
|
||||||
]),
|
]),
|
||||||
], [
|
], [
|
||||||
'desktop' => ['display' => 'grid', 'gridColumns' => 3, 'gap' => '40px', 'padding' => ['top' => '56px', 'bottom' => '40px']],
|
'desktop' => ['display' => 'grid', 'gridColumns' => 3, 'gap' => '40px', 'padding' => ['top' => '56px', 'bottom' => '40px']],
|
||||||
@@ -649,7 +649,10 @@ $startseite = [
|
|||||||
$section('leistungen-bereich', [
|
$section('leistungen-bereich', [
|
||||||
$zeile('leistungen-kopf', [
|
$zeile('leistungen-kopf', [
|
||||||
$heading('leistungen-titel', 'Leistungen', 2, $h2Stil),
|
$heading('leistungen-titel', 'Leistungen', 2, $h2Stil),
|
||||||
$text('leistungen-link', '<a href="/verwaltungsanfrage">Unverbindlich anfragen →</a>', ['desktop' => ['fontSize' => '15px', 'fontWeight' => '500', 'margin' => ['bottom' => '0px']]], $linkCss),
|
$zeile('leistungen-link-zeile', [
|
||||||
|
$text('leistungen-link', '<a href="/verwaltungsanfrage">Unverbindlich anfragen</a>', ['desktop' => ['fontSize' => '15px', 'fontWeight' => '500', 'margin' => ['bottom' => '0px']]], $linkCss),
|
||||||
|
$symbol('leistungen-link-pfeil', 'arrow-right', 16, ['desktop' => ['color' => '@tinte']]),
|
||||||
|
], '6px'),
|
||||||
], '16px', ['justifyContent' => 'space-between', 'alignItems' => 'baseline', 'flexWrap' => 'wrap', 'margin' => ['bottom' => '56px']], ['margin' => ['bottom' => '36px']]),
|
], '16px', ['justifyContent' => 'space-between', 'alignItems' => 'baseline', 'flexWrap' => 'wrap', 'margin' => ['bottom' => '56px']], ['margin' => ['bottom' => '36px']]),
|
||||||
$column('leistungen-raster', [
|
$column('leistungen-raster', [
|
||||||
$leistung('leistung-verkauf', $medien['poster'], 'Offener Wohn- und Essbereich mit Treppe, Holzlamellen und großer Glasfront', 'Immobilienverkauf', 'Professionelle Vermarktung, marktgerechte Bewertung und persönliche Begleitung bis zum erfolgreichen Verkauf.', [
|
$leistung('leistung-verkauf', $medien['poster'], 'Offener Wohn- und Essbereich mit Treppe, Holzlamellen und großer Glasfront', 'Immobilienverkauf', 'Professionelle Vermarktung, marktgerechte Bewertung und persönliche Begleitung bis zum erfolgreichen Verkauf.', [
|
||||||
@@ -816,7 +819,11 @@ $startseite = [
|
|||||||
]),
|
]),
|
||||||
$column('kontakt-mehr', [
|
$column('kontakt-mehr', [
|
||||||
$kleinzeile('kontakt-mehr-titel', 'Direkt', '@gold-dunkel', '8px'),
|
$kleinzeile('kontakt-mehr-titel', 'Direkt', '@gold-dunkel', '8px'),
|
||||||
$text('kontakt-mehr-text', '<a href="'.$tel.'">'.$telefon.'</a><br><a href="mailto:'.$mail.'">'.$mail.'</a><br>Für ein Angebot:<br><a href="/verwaltungsanfrage">Verwaltungsanfrage →</a>', ['desktop' => ['fontSize' => '17px', 'lineHeight' => 1.6, 'margin' => ['bottom' => '0px']]], $linkCss),
|
$text('kontakt-mehr-text', '<a href="'.$tel.'">'.$telefon.'</a><br><a href="mailto:'.$mail.'">'.$mail.'</a><br>Für ein Angebot:', ['desktop' => ['fontSize' => '17px', 'lineHeight' => 1.6, 'margin' => ['bottom' => '0px']]], $linkCss),
|
||||||
|
$zeile('kontakt-mehr-zeile', [
|
||||||
|
$text('kontakt-mehr-link', '<a href="/verwaltungsanfrage">Verwaltungsanfrage</a>', ['desktop' => ['fontSize' => '17px', 'lineHeight' => 1.6, 'margin' => ['bottom' => '0px']]], $linkCss),
|
||||||
|
$symbol('kontakt-mehr-pfeil', 'arrow-right', 16, ['desktop' => ['color' => '@tinte']]),
|
||||||
|
], '6px'),
|
||||||
]),
|
]),
|
||||||
], '56px', ['alignItems' => 'flex-start', 'flexWrap' => 'wrap', 'rowGap' => '32px']),
|
], '56px', ['alignItems' => 'flex-start', 'flexWrap' => 'wrap', 'rowGap' => '32px']),
|
||||||
]),
|
]),
|
||||||
@@ -959,6 +966,21 @@ $hinweis = static fn (string $id, string $titel, array $punkte) => $column($id,
|
|||||||
// Die Bildkarten einer Auswahl: Bild oben, gerundet, dunkler Rand bei Wahl.
|
// Die Bildkarten einer Auswahl: Bild oben, gerundet, dunkler Rand bei Wahl.
|
||||||
$kartenCss = "\n& .form-choice-grid{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px}\n& .form-choice-card label{border:1.5px solid #E6DED2;border-radius:20px;background:#fff;padding:10px 10px 14px;font-weight:500;font-size:15px;color:#141414}\n& .form-choice-card label:hover{border-color:#BDA076}\n& .form-choice-card input:checked+label{border-color:#141414;box-shadow:0 0 0 1.5px #141414}\n& .form-choice-card input{accent-color:#141414;top:20px;left:20px;width:20px;height:20px;min-height:0;padding:0;margin:0}\n& .form-choice-card input:focus{outline:none}\n& .form-choice-picture{border-radius:12px}";
|
$kartenCss = "\n& .form-choice-grid{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px}\n& .form-choice-card label{border:1.5px solid #E6DED2;border-radius:20px;background:#fff;padding:10px 10px 14px;font-weight:500;font-size:15px;color:#141414}\n& .form-choice-card label:hover{border-color:#BDA076}\n& .form-choice-card input:checked+label{border-color:#141414;box-shadow:0 0 0 1.5px #141414}\n& .form-choice-card input{accent-color:#141414;top:20px;left:20px;width:20px;height:20px;min-height:0;padding:0;margin:0}\n& .form-choice-card input:focus{outline:none}\n& .form-choice-picture{border-radius:12px}";
|
||||||
|
|
||||||
|
// Die Objekte kommen aus dem Plugin „ImmoScout-Abgleich“; der Baustein trägt das Luximmo-Aussehen.
|
||||||
|
// Ohne eingeschaltetes Plugin bleibt die Seite erreichbar, nur die Liste fehlt.
|
||||||
|
$anlegen('immobilien', $einblenden([
|
||||||
|
'schemaVersion' => $SCHEMA, 'title' => 'Immobilien',
|
||||||
|
'description' => 'Aktuelle Immobilienangebote von Luximmo in Gaggenau und Umgebung, Baden-Baden und im Schwarzwald.',
|
||||||
|
'blocks' => [
|
||||||
|
$seitenkopf('immobilien', 'Aktuelle Angebote', 'Unsere Immobilien.', 'Wohnungen und Häuser, die wir aktuell in Gaggenau und Umgebung, Baden-Baden und im Schwarzwald anbieten.'),
|
||||||
|
$section('immobilien', [
|
||||||
|
['id' => 'immobilien-liste', 'type' => 'immoscout.liste',
|
||||||
|
'props' => ['art' => 'alle', 'darstellung' => 'kacheln', 'spalten' => '3', 'spaltenTablet' => '2', 'spaltenMobil' => '1', 'reihen' => 0, 'anzahl' => 0, 'bild' => 'breit', 'abstand' => 'normal', 'ausrichtung' => 'links', 'zeigeArt' => true, 'zeigeOrt' => true, 'zeigeFakten' => true],
|
||||||
|
'css' => "& .immoscout-karte{border:0;border-radius:24px;overflow:hidden;background:#F7F4EF}\n& .immoscout-karte-text{padding:24px 26px 28px}\n& .immoscout-karte h2{font-size:22px;font-weight:500;letter-spacing:-0.015em}\n& .immoscout-art{font-size:13px;font-weight:500;letter-spacing:0.04em;color:#6E5830}\n& .immoscout-ort{color:#5A554D;opacity:1}\n& .immoscout-karte dt{color:#5A554D;opacity:1}\n& .immoscout-karte dd{font-weight:500}\n& .immoscout-leer{border:0;border-radius:24px;background:#F7F4EF}\n& .immoscout-leer h2{font-weight:500;letter-spacing:-0.02em}\n& .immoscout-leer p{color:#5A554D}"],
|
||||||
|
], $abschnitt('0px', '160px'), null, '', 'wide'),
|
||||||
|
],
|
||||||
|
], ['immobilien-liste' => ['rise']]), 'Immobilien in Gaggenau, Baden-Baden und im Schwarzwald | LUXIMMO', $medien['miet']['id']);
|
||||||
|
|
||||||
$anlegen('immobilienbewertung', $einblenden([
|
$anlegen('immobilienbewertung', $einblenden([
|
||||||
'schemaVersion' => $SCHEMA, 'title' => 'Immobilienbewertung',
|
'schemaVersion' => $SCHEMA, 'title' => 'Immobilienbewertung',
|
||||||
'description' => 'Was ist Ihre Immobilie wert? Luximmo schätzt Wohnungen, Häuser, Mehrfamilienhäuser und Grundstücke in Gaggenau und Umgebung – kostenlos und unverbindlich.',
|
'description' => 'Was ist Ihre Immobilie wert? Luximmo schätzt Wohnungen, Häuser, Mehrfamilienhäuser und Grundstücke in Gaggenau und Umgebung – kostenlos und unverbindlich.',
|
||||||
@@ -1093,6 +1115,7 @@ $anker = static fn (string $label, string $anker): array => ['label' => $label,
|
|||||||
$menus->save('header', 'Hauptnavigation', [
|
$menus->save('header', 'Hauptnavigation', [
|
||||||
$anker('Leistungen', 'leistungen'),
|
$anker('Leistungen', 'leistungen'),
|
||||||
$anker('Über uns', 'ueber-uns'),
|
$anker('Über uns', 'ueber-uns'),
|
||||||
|
['label' => 'Immobilien', 'type' => 'page', 'pageId' => $seiteId('immobilien'), 'children' => []],
|
||||||
['label' => 'Bewertung', 'type' => 'page', 'pageId' => $seiteId('immobilienbewertung'), 'children' => []],
|
['label' => 'Bewertung', 'type' => 'page', 'pageId' => $seiteId('immobilienbewertung'), 'children' => []],
|
||||||
['label' => 'Anfrage', 'type' => 'page', 'pageId' => $seiteId('verwaltungsanfrage'), 'children' => []],
|
['label' => 'Anfrage', 'type' => 'page', 'pageId' => $seiteId('verwaltungsanfrage'), 'children' => []],
|
||||||
], 0);
|
], 0);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ final class DocumentValidator
|
|||||||
/** Blocks introduced with schema v6 for the sections a marketing page actually needs. */
|
/** Blocks introduced with schema v6 for the sections a marketing page actually needs. */
|
||||||
public const V6_TYPES = ['iconcard', 'stat', 'quote', 'logos', 'cta', 'contact', 'divider', 'spacer', 'accordion', 'accordionitem'];
|
public const V6_TYPES = ['iconcard', 'stat', 'quote', 'logos', 'cta', 'contact', 'divider', 'spacer', 'accordion', 'accordionitem'];
|
||||||
/** Icons ship as inline SVG from this fixed list; no icon font and no external request. */
|
/** Icons ship as inline SVG from this fixed list; no icon font and no external request. */
|
||||||
public const ICONS = ['arrow-up-right', 'arrow-right', 'arrow-left', 'arrow-up', 'arrow-down', 'chevron-right', 'chevron-left', 'chevron-up', 'chevron-down', 'arrow-circle', 'external', 'refresh', 'menu', 'close', 'plus', 'minus', 'phone', 'app', 'mail', 'chat', 'send', 'calendar', 'clock', 'pin', 'map', 'navigation', 'web', 'wifi', 'support', 'shop', 'cart', 'tag', 'euro', 'credit-card', 'gift', 'percent', 'truck', 'package', 'briefcase', 'document', 'download', 'upload', 'print', 'link', 'share', 'image', 'camera', 'video', 'play', 'pause', 'music', 'mic', 'book', 'user', 'people', 'login', 'lock', 'key', 'shield', 'eye', 'thumbs-up', 'award', 'graduation', 'heart', 'star', 'home', 'building', 'wrench', 'hammer', 'brush', 'ruler', 'leaf', 'tree', 'sun', 'droplet', 'flame', 'bolt', 'solar', 'thermometer', 'snowflake', 'car', 'check', 'check-circle', 'info', 'help', 'alert', 'search', 'settings', 'filter', 'grid', 'list', 'sparkle', 'coffee', 'utensils', 'laptop', 'hardware', 'network', 'design', 'facebook', 'instagram', 'whatsapp'];
|
public const ICONS = ['arrow-up-right', 'arrow-right', 'arrow-left', 'arrow-up', 'arrow-down', 'chevron-right', 'chevron-left', 'chevron-up', 'chevron-down', 'arrow-circle', 'external', 'refresh', 'menu', 'close', 'plus', 'minus', 'phone', 'app', 'mail', 'chat', 'send', 'calendar', 'clock', 'pin', 'map', 'navigation', 'web', 'wifi', 'support', 'shop', 'cart', 'tag', 'euro', 'credit-card', 'gift', 'percent', 'truck', 'package', 'briefcase', 'document', 'download', 'upload', 'print', 'link', 'share', 'image', 'camera', 'video', 'play', 'pause', 'music', 'mic', 'book', 'user', 'people', 'login', 'lock', 'key', 'shield', 'eye', 'thumbs-up', 'award', 'graduation', 'heart', 'star', 'home', 'house', 'building', 'wrench', 'hammer', 'brush', 'ruler', 'leaf', 'tree', 'sun', 'droplet', 'flame', 'bolt', 'solar', 'thermometer', 'snowflake', 'car', 'check', 'check-circle', 'info', 'help', 'alert', 'search', 'settings', 'filter', 'grid', 'list', 'sparkle', 'coffee', 'utensils', 'laptop', 'hardware', 'network', 'design', 'facebook', 'instagram', 'whatsapp'];
|
||||||
/** Das Symbol eines Buttons, wenn keins gewählt ist: der Pfeil, den jeder Button vor v25 hatte. */
|
/** Das Symbol eines Buttons, wenn keins gewählt ist: der Pfeil, den jeder Button vor v25 hatte. */
|
||||||
public const BUTTON_DEFAULT_ICON = 'arrow-up-right';
|
public const BUTTON_DEFAULT_ICON = 'arrow-up-right';
|
||||||
public const SPACER_SIZES = ['small', 'medium', 'large', 'huge'];
|
public const SPACER_SIZES = ['small', 'medium', 'large', 'huge'];
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ final class LanguageExtension extends AbstractExtension
|
|||||||
'Beiträge in der Kategorie „%s“.' => 'Posts in the category “%s”.',
|
'Beiträge in der Kategorie „%s“.' => 'Posts in the category “%s”.',
|
||||||
'Beiträge zum Schlagwort „%s“.' => 'Posts tagged “%s”.',
|
'Beiträge zum Schlagwort „%s“.' => 'Posts tagged “%s”.',
|
||||||
'von' => 'by',
|
'von' => 'by',
|
||||||
'← Neuere' => '← Newer',
|
'Neuere' => 'Newer',
|
||||||
'Ältere →' => 'Older →',
|
'Ältere' => 'Older',
|
||||||
'Seite %d von %d' => 'Page %d of %d',
|
'Seite %d von %d' => 'Page %d of %d',
|
||||||
'Externe Inhalte und Einwilligung' => 'External content and consent',
|
'Externe Inhalte und Einwilligung' => 'External content and consent',
|
||||||
'Diese Website lädt bestimmte Inhalte erst, wenn du zustimmst. Ohne Zustimmung wird die Seite vollständig angezeigt, nur eingebettete Inhalte anderer Anbieter bleiben leer.' => 'This website only loads certain content once you agree. Without consent the page is shown in full; only embedded content from other providers stays empty.',
|
'Diese Website lädt bestimmte Inhalte erst, wenn du zustimmst. Ohne Zustimmung wird die Seite vollständig angezeigt, nur eingebettete Inhalte anderer Anbieter bleiben leer.' => 'This website only loads certain content once you agree. Without consent the page is shown in full; only embedded content from other providers stays empty.',
|
||||||
@@ -173,8 +173,8 @@ final class LanguageExtension extends AbstractExtension
|
|||||||
'Beiträge in der Kategorie „%s“.' => '„%s“ kategorisindeki yazılar.',
|
'Beiträge in der Kategorie „%s“.' => '„%s“ kategorisindeki yazılar.',
|
||||||
'Beiträge zum Schlagwort „%s“.' => '„%s“ etiketli yazılar.',
|
'Beiträge zum Schlagwort „%s“.' => '„%s“ etiketli yazılar.',
|
||||||
'von' => 'yazan:',
|
'von' => 'yazan:',
|
||||||
'← Neuere' => '← Daha yeni',
|
'Neuere' => 'Daha yeni',
|
||||||
'Ältere →' => 'Daha eski →',
|
'Ältere' => 'Daha eski',
|
||||||
'Seite %d von %d' => 'Sayfa %d / %d',
|
'Seite %d von %d' => 'Sayfa %d / %d',
|
||||||
'Externe Inhalte und Einwilligung' => 'Harici içerikler ve onay',
|
'Externe Inhalte und Einwilligung' => 'Harici içerikler ve onay',
|
||||||
'Diese Website lädt bestimmte Inhalte erst, wenn du zustimmst. Ohne Zustimmung wird die Seite vollständig angezeigt, nur eingebettete Inhalte anderer Anbieter bleiben leer.' => 'Bu web sitesi bazı içerikleri ancak onayınızdan sonra yükler. Onay vermeseniz de sayfa eksiksiz görüntülenir; yalnızca diğer sağlayıcıların yerleştirilmiş içerikleri boş kalır.',
|
'Diese Website lädt bestimmte Inhalte erst, wenn du zustimmst. Ohne Zustimmung wird die Seite vollständig angezeigt, nur eingebettete Inhalte anderer Anbieter bleiben leer.' => 'Bu web sitesi bazı içerikleri ancak onayınızdan sonra yükler. Onay vermeseniz de sayfa eksiksiz görüntülenir; yalnızca diğer sağlayıcıların yerleştirilmiş içerikleri boş kalır.',
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
{% elseif type == 'quote' %}
|
{% elseif type == 'quote' %}
|
||||||
<figure id="{{ block.id }}" class="block-quote{{ designClasses }}">
|
<figure id="{{ block.id }}" class="block-quote{{ designClasses }}">
|
||||||
{% if props.rating|default(0) > 0 %}
|
{% if props.rating|default(0) > 0 %}
|
||||||
<p class="quote-rating"><span class="visually-hidden">Bewertung: {{ props.rating }} von 5</span><span aria-hidden="true">{% for i in 1..5 %}{{ i <= props.rating ? '★' : '☆' }}{% endfor %}</span></p>
|
<p class="quote-rating"><span class="visually-hidden">Bewertung: {{ props.rating }} von 5</span><span aria-hidden="true">{% for i in 1..5 %}<svg class="{{ i <= props.rating ? 'quote-star-voll' : 'quote-star' }}" viewBox="0 0 24 24" focusable="false"><path d="m12 3 2.7 5.9 6.3.7-4.7 4.3 1.3 6.1L12 17l-5.6 3 1.3-6.1L3 9.6l6.3-.7Z"/></svg>{% endfor %}</span></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<blockquote><p>{{ props.text }}</p></blockquote>
|
<blockquote><p>{{ props.text }}</p></blockquote>
|
||||||
<figcaption>{{ props.author }}{% if props.role|default('') %} <span>{{ props.role }}</span>{% endif %}</figcaption>
|
<figcaption>{{ props.author }}{% if props.role|default('') %} <span>{{ props.role }}</span>{% endif %}</figcaption>
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
heart: 'M12 20s-7.5-4.6-7.5-10A4.3 4.3 0 0 1 12 7.4 4.3 4.3 0 0 1 19.5 10c0 5.4-7.5 10-7.5 10Z',
|
heart: 'M12 20s-7.5-4.6-7.5-10A4.3 4.3 0 0 1 12 7.4 4.3 4.3 0 0 1 19.5 10c0 5.4-7.5 10-7.5 10Z',
|
||||||
star: 'm12 3 2.7 5.9 6.3.7-4.7 4.3 1.3 6.1L12 17l-5.6 3 1.3-6.1L3 9.6l6.3-.7Z',
|
star: 'm12 3 2.7 5.9 6.3.7-4.7 4.3 1.3 6.1L12 17l-5.6 3 1.3-6.1L3 9.6l6.3-.7Z',
|
||||||
home: 'm3 11.5 9-7.5 9 7.5M5.5 10v10h13V10M10 20v-6.5h4V20',
|
home: 'm3 11.5 9-7.5 9 7.5M5.5 10v10h13V10M10 20v-6.5h4V20',
|
||||||
|
house: 'M4 10.5 12 4l8 6.5V19a1 1 0 0 1-1 1h-4.5v-5.5h-5V20H5a1 1 0 0 1-1-1Z',
|
||||||
building: 'M5 21V4h10v17m0-12h4v12M3 21h18M8.5 7.5h3m-3 3.5h3m-3 3.5h3',
|
building: 'M5 21V4h10v17m0-12h4v12M3 21h18M8.5 7.5h3m-3 3.5h3m-3 3.5h3',
|
||||||
wrench: 'M14.5 3.5a5 5 0 0 0-4.6 6.9L3.5 16.8a1.9 1.9 0 0 0 2.7 2.7l6.4-6.4a5 5 0 0 0 6.9-4.6l-3 3-3-1-1-3Z',
|
wrench: 'M14.5 3.5a5 5 0 0 0-4.6 6.9L3.5 16.8a1.9 1.9 0 0 0 2.7 2.7l6.4-6.4a5 5 0 0 0 6.9-4.6l-3 3-3-1-1-3Z',
|
||||||
hammer: 'M14 8.5 4.5 18a1.5 1.5 0 0 0 2.1 2.1L16 10.5M11 6l3-3 3.5 1L21 7.5 18.5 10l-2-2-2.5 2.5Z',
|
hammer: 'M14 8.5 4.5 18a1.5 1.5 0 0 0 2.1 2.1L16 10.5M11 6l3-3 3.5 1L21 7.5 18.5 10l-2-2-2.5 2.5Z',
|
||||||
|
|||||||
@@ -41,8 +41,8 @@
|
|||||||
{% if pages|default(1) > 1 %}
|
{% if pages|default(1) > 1 %}
|
||||||
{# Dieselbe Blätterleiste wie im Archiv: eine Liste, die mehr hat als sie zeigt, sagt es. #}
|
{# Dieselbe Blätterleiste wie im Archiv: eine Liste, die mehr hat als sie zeigt, sagt es. #}
|
||||||
<nav class="post-pager" aria-label="{{ 'Weitere Beiträge'|kant_t }}">
|
<nav class="post-pager" aria-label="{{ 'Weitere Beiträge'|kant_t }}">
|
||||||
{% if page > 1 %}<a rel="prev" href="?seite={{ page - 1 }}">{{ '← Neuere'|kant_t }}</a>{% endif %}
|
{% if page > 1 %}<a rel="prev" href="?seite={{ page - 1 }}">{{ 'Neuere'|kant_t }}</a>{% endif %}
|
||||||
<span>{{ 'Seite %d von %d'|kant_t|format(page, pages) }}{% if total %} · {{ total }} {{ 'Beiträge'|kant_t }}{% endif %}</span>
|
<span>{{ 'Seite %d von %d'|kant_t|format(page, pages) }}{% if total %} · {{ total }} {{ 'Beiträge'|kant_t }}{% endif %}</span>
|
||||||
{% if page < pages %}<a rel="next" href="?seite={{ page + 1 }}">{{ 'Ältere →'|kant_t }}</a>{% endif %}
|
{% if page < pages %}<a rel="next" href="?seite={{ page + 1 }}">{{ 'Ältere'|kant_t }}</a>{% endif %}
|
||||||
</nav>
|
</nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
{# Ein Anker, kein Skript. Er springt an den Anfang - das kann ein Browser allein. Der nav-Rahmen
|
{# Ein Anker, kein Skript. Er springt an den Anfang - das kann ein Browser allein. Der nav-Rahmen
|
||||||
gibt ihm eine Landmarke: ein Verweis außerhalb jeder Landmarke ist für Vorlesesoftware
|
gibt ihm eine Landmarke: ein Verweis außerhalb jeder Landmarke ist für Vorlesesoftware
|
||||||
Inhalt ohne Ort, und axe meldet ihn als Verstoß gegen „region“. #}
|
Inhalt ohne Ort, und axe meldet ihn als Verstoß gegen „region“. #}
|
||||||
<nav aria-label="{{ oben.scrollTopLabel|default('Nach oben')|kant_t }}"><a class="scroll-top{{ oben.scrollTopPosition|default('rechts') == 'links' ? ' scroll-top-links' : '' }}" href="#seitenanfang" aria-label="{{ oben.scrollTopLabel|default('Nach oben')|kant_t }}"><span aria-hidden="true">↑</span></a></nav>
|
<nav aria-label="{{ oben.scrollTopLabel|default('Nach oben')|kant_t }}"><a class="scroll-top{{ oben.scrollTopPosition|default('rechts') == 'links' ? ' scroll-top-links' : '' }}" href="#seitenanfang" aria-label="{{ oben.scrollTopLabel|default('Nach oben')|kant_t }}"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 20V4.5m-6.5 6.5L12 4.5l6.5 6.5"/></svg></a></nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in new issue
Block a user