# MapCN auf Kontaktseite integrieren (statt Google-Maps-Link) ## Ziel Die Platzhalter-Box auf der Kontaktseite (`/kontakt`) soll durch eine echte, interaktive Karte mit `mapcn` ersetzt werden. Die Karte zeigt den Praxisstandort inklusive Marker und optionalem Popup. ## Ist-Zustand - `src/pages/kontakt.astro` enthält aktuell nur einen statischen Map-Placeholder mit Link zu Google Maps. - React ist im Projekt bereits aktiviert (`@astrojs/react` in `astro.config.mjs`). - Shadcn-Struktur ist vorhanden (`components.json`, `src/components/ui/button.tsx`). - Es gibt noch keine Kartenkomponenten im Projekt. ## Empfohlener Ansatz `mapcn` per shadcn-Registry hinzufügen und eine kleine, dedizierte React-Komponente für die Kontaktkarte bauen. Diese wird als Astro-Client-Island (`client:visible`) in `kontakt.astro` eingebunden. Warum dieser Ansatz: - Sauber gekapselte Kartenlogik (statt JSX direkt in `.astro`). - Gute Performance (Hydration erst bei Sichtbarkeit). - Einfache Wiederverwendung für Footer/Standortseiten später. ## Umsetzungsplan ### 1) MapCN-Komponente ins Projekt holen **Änderungen:** Abhängig von shadcn-Generator-Ausgabe - Command (im Implementierungsschritt): - `bunx shadcn@latest add @mapcn/map` (alternativ `npx shadcn@latest add @mapcn/map`) - Erwartete Ergebnisse: - Neue Datei `src/components/ui/map.tsx` (oder äquivalent) - Neue Dependency `maplibre-gl` in `package.json` - Falls vom Generator benötigt: ergänzende CSS-Regeln/Imports (z. B. MapLibre-CSS) **Prüfpunkte:** - Map-Komponente ist importierbar aus `@/components/ui/map` - Keine TypeScript- oder Build-Fehler nach dem Add ### 2) Reusable Praxis-Map als React-Komponente erstellen **Neue Datei:** `src/components/maps/PracticeMap.tsx` Inhalt: - Import aus `@/components/ui/map`: - `Map` - `MapControls` (optional, aber sinnvoll) - `MapMarker`, `MarkerContent`, `MarkerLabel` (für Standortpin) - Container mit fester Höhe und Rounded Corners passend zur bestehenden Kontaktseite - Initiales Viewport-Center auf Praxisadresse - Empfohlene Koordinaten (OSM/Nominatim): `lon 12.3849586`, `lat 50.8203324` - Zoom ca. `14–15` - Markerlabel z. B. „Zahnarztpraxis Dr. Tittel“ - Optional: kleines Popup mit Adresse Hinweis: - Falls die generierte `Map`-Komponente `children` voll unterstützt, Marker/Controls direkt als Children. - Falls nicht, Minimalvariante nur mit `Map center/zoom` und Controls weglassen. ### 3) Kontaktseite umbauen **Datei:** `src/pages/kontakt.astro` Geplante Änderungen: - Import der neuen Komponente `PracticeMap`. - Bestehenden Placeholder-Block (Zeilenbereich um „Map placeholder“) entfernen/ersetzen. - Neue Einbindung: - `` - Karte visuell im selben Card-Stil belassen: - `rounded-2xl border border-border overflow-hidden` Optionaler UX-Zusatz unter der Karte: - Externer OpenStreetMap-/Google-Maps-Link als Fallback/Navigation beibehalten. ### 4) (Optional, aber empfohlen) Standortdaten zentralisieren **Datei:** `src/data/site.ts` - `siteConfig` um `location` erweitern, z. B.: - `latitude` - `longitude` - `PracticeMap` nutzt diese Werte statt hardcodierter Koordinaten. Vorteil: - Keine doppelten Daten, spätere Änderungen an einer Stelle. ### 5) Validierung Nach der Implementierung ausführen: - `bun run typecheck` - `bun run build` Manuelle Sichtprüfung: - `/kontakt` lädt ohne Console-Errors - Karte rendert korrekt auf Desktop und Mobile - Marker steht an plausibler Position (Bodelschwinghstraße 1, 08451 Crimmitschau) - Seite bleibt performant (Hydration nur beim Scrollen in Sichtbereich) ## Risiken / Stolpersteine - `maplibre-gl` benötigt ggf. CSS-Import; ohne den wirkt die Karte/Controls fehlerhaft. - In Astro muss React-Komponente mit `client:*` eingebunden werden, sonst keine Interaktivität. - Falls CSP/Cookie-Hinweise im Projekt strikt sind, muss Text „Karte wird nach Cookie-Einwilligung geladen“ angepasst/entfernt werden, da diese Map nicht dem bisherigen Google-Maps-Flow entspricht. ## Definition of Done - Kontaktseite zeigt eine funktionierende `mapcn`-Karte statt Placeholder. - Marker auf Praxisstandort vorhanden. - Projekt baut und typcheckt fehlerfrei. - Styling integriert sich in bestehendes Design ohne Layout-Bruch.