diff --git a/public/fonts/instrument-sans/LICENSE b/public/fonts/instrument-sans/LICENSE new file mode 100644 index 0000000..9a39a8e --- /dev/null +++ b/public/fonts/instrument-sans/LICENSE @@ -0,0 +1,93 @@ +Copyright 2022 The Instrument Sans Project Authors (https://github.com/Instrument/instrument-sans) InstrumentSans-Italic[wdth,wght].ttf: Copyright 2022 The Instrument Sans Project Authors (https://github.com/Instrument/instrument-sans) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/public/fonts/instrument-sans/instrument-sans-latin-ext-wght-normal.woff2 b/public/fonts/instrument-sans/instrument-sans-latin-ext-wght-normal.woff2 new file mode 100644 index 0000000..0ea0da0 Binary files /dev/null and b/public/fonts/instrument-sans/instrument-sans-latin-ext-wght-normal.woff2 differ diff --git a/public/fonts/instrument-sans/instrument-sans-latin-wght-normal.woff2 b/public/fonts/instrument-sans/instrument-sans-latin-wght-normal.woff2 new file mode 100644 index 0000000..8611e41 Binary files /dev/null and b/public/fonts/instrument-sans/instrument-sans-latin-wght-normal.woff2 differ diff --git a/src/components/home/HeroKarte.tsx b/src/components/home/HeroKarte.tsx new file mode 100644 index 0000000..67c980f --- /dev/null +++ b/src/components/home/HeroKarte.tsx @@ -0,0 +1,10 @@ +/** Platzhalter: wird im Relaunch-Workflow gebaut (Spezifikation Abschnitt 7). */ +const HeroKarte = () => ( +
+
+

HeroKarte

+
+
+); + +export default HeroKarte; diff --git a/src/components/home/KontaktBuehne.tsx b/src/components/home/KontaktBuehne.tsx new file mode 100644 index 0000000..756c462 --- /dev/null +++ b/src/components/home/KontaktBuehne.tsx @@ -0,0 +1,32 @@ +import { Link } from "react-router-dom"; + +/** Spezifikation 7.7: ein Satz, ein Button, E-Mail und Telefon. */ +const KontaktBuehne = () => ( +
+
+

+ Erzählen Sie uns, was Sie vorhaben. +

+

+ Zwei Sätze genügen. Wir melden uns spätestens am nächsten Werktag. Im ersten Gespräch klären wir in + 15 Minuten, ob und wie wir helfen können – kostenlos und unverbindlich. +

+
+ + Projekt besprechen + +
+

+ + support@webklar.com + + · + + 0176 23726355 + +

+
+
+); + +export default KontaktBuehne; diff --git a/src/components/home/Kundenportal.tsx b/src/components/home/Kundenportal.tsx new file mode 100644 index 0000000..44d1c46 --- /dev/null +++ b/src/components/home/Kundenportal.tsx @@ -0,0 +1,10 @@ +/** Platzhalter: wird im Relaunch-Workflow gebaut (Spezifikation Abschnitt 7). */ +const Kundenportal = () => ( +
+
+

Kundenportal

+
+
+); + +export default Kundenportal; diff --git a/src/components/home/Leistungen.tsx b/src/components/home/Leistungen.tsx new file mode 100644 index 0000000..4bc99aa --- /dev/null +++ b/src/components/home/Leistungen.tsx @@ -0,0 +1,10 @@ +/** Platzhalter: wird im Relaunch-Workflow gebaut (Spezifikation Abschnitt 7). */ +const Leistungen = () => ( +
+
+

Leistungen

+
+
+); + +export default Leistungen; diff --git a/src/components/home/Preise.tsx b/src/components/home/Preise.tsx new file mode 100644 index 0000000..07c3615 --- /dev/null +++ b/src/components/home/Preise.tsx @@ -0,0 +1,10 @@ +/** Platzhalter: wird im Relaunch-Workflow gebaut (Spezifikation Abschnitt 7). */ +const Preise = () => ( +
+
+

Preise

+
+
+); + +export default Preise; diff --git a/src/components/home/UeberUns.tsx b/src/components/home/UeberUns.tsx new file mode 100644 index 0000000..51ff471 --- /dev/null +++ b/src/components/home/UeberUns.tsx @@ -0,0 +1,25 @@ +import { Link } from "react-router-dom"; + +/** Spezifikation 7.6: wer dahinter steckt. Keine Fotos, bis echte Teamfotos vorliegen. */ +const UeberUns = () => ( +
+
+

+ Wer hinter WEBklar steckt. +

+
+

+ Wir sind ein kleines Team aus Winnweiler in der Pfalz. Sie sprechen bei uns direkt mit den Leuten, die Ihre + Website bauen. +

+

+ + Mehr über uns + +

+
+
+
+); + +export default UeberUns; diff --git a/src/components/home/home.css b/src/components/home/home.css new file mode 100644 index 0000000..007878d --- /dev/null +++ b/src/components/home/home.css @@ -0,0 +1,46 @@ +/* Kleine Abschnitte der Startseite: Über uns und Kontakt */ + +.wk-ueber-uns { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); + gap: 2rem 4rem; + align-items: start; +} +.wk-ueber-uns__link { + margin-top: 1.5rem; +} +@media (max-width: 899.98px) { + .wk-ueber-uns { + grid-template-columns: 1fr; + } +} + +.wk-kontakt__inhalt { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} +.wk-kontakt .wk-h2 { + max-width: 16ch; +} +.wk-kontakt .wk-lead { + max-width: 38rem; +} +.wk-kontakt__aktion { + margin-top: 2.25rem; +} +.wk-kontakt__wege { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + gap: 0.25rem 0.9rem; + margin-top: 1.75rem; + color: var(--fg-muted); +} +.wk-kontakt__wege a { + display: inline-flex; + align-items: center; + min-height: 44px; +} diff --git a/src/components/site/SiteFooter.tsx b/src/components/site/SiteFooter.tsx new file mode 100644 index 0000000..c7597c4 --- /dev/null +++ b/src/components/site/SiteFooter.tsx @@ -0,0 +1,78 @@ +import { Link } from "react-router-dom"; +import Logo from "@/components/Logo"; +import "./site.css"; + +type FooterLink = { label: string; to?: string; href?: string; pflicht?: boolean }; + +/** Spezifikation 7.8: Seiten und Rechtliches; Kündigen und Widerrufen bleiben hervorgehoben. */ +const SEITEN: FooterLink[] = [ + { label: "Startseite", to: "/" }, + { label: "Kundenportal", to: "/#kundenportal" }, + { label: "Was wir bauen", to: "/#leistungen" }, + { label: "Preise", to: "/#preise" }, + { label: "Über uns", to: "/ueber-uns" }, + { label: "Kontakt", to: "/kontakt" }, + { label: "Wartungs-Abo", to: "/wartungs-abo" }, + { label: "Hosting-Abo", to: "/hosting-abo" }, +]; + +const RECHTLICHES: FooterLink[] = [ + { label: "AGB", to: "/agb" }, + { label: "Impressum", to: "/impressum" }, + { label: "Datenschutz", href: "https://project.webklar.com/datenschutz.html" }, + { label: "Verträge hier kündigen", href: "https://project.webklar.com/kuendigen.html", pflicht: true }, + { label: "Vertrag widerrufen", href: "https://project.webklar.com/widerrufen.html", pflicht: true }, +]; + +const Eintrag = ({ link }: { link: FooterLink }) => ( +
  • + {link.to ? ( + {link.label} + ) : ( + + {link.label} + + )} +
  • +); + +const SiteFooter = () => ( + +); + +export default SiteFooter; diff --git a/src/components/site/SiteHeader.tsx b/src/components/site/SiteHeader.tsx new file mode 100644 index 0000000..bca6c60 --- /dev/null +++ b/src/components/site/SiteHeader.tsx @@ -0,0 +1,155 @@ +import { useEffect, useId, useRef, useState } from "react"; +import { Link, useLocation } from "react-router-dom"; +import { useTheme } from "next-themes"; +import { Moon, Sun } from "lucide-react"; +import Logo from "@/components/Logo"; +import { projekte } from "@/data/projekte"; +import "./site.css"; + +/** Navigation der Kopfleiste (Spezifikation 6.1). „Projekte“ erscheint erst mit freigegebenen Referenzen. */ +export const NAVIGATION = [ + { label: "Kundenportal", to: "/#kundenportal" }, + { label: "Was wir bauen", to: "/#leistungen" }, + ...(projekte.length > 0 ? [{ label: "Projekte", to: "/#projekte" }] : []), + { label: "Preise", to: "/#preise" }, + { label: "Über uns", to: "/#ueber-uns" }, +]; + +/** Hell/Dunkel umschalten. Vor dem ersten Rendern ist das Thema unbekannt, daher kein Symbolwechsel beim Laden. */ +const ThemaSchalter = ({ mitText = false }: { mitText?: boolean }) => { + const { resolvedTheme, setTheme } = useTheme(); + const [bereit, setBereit] = useState(false); + useEffect(() => setBereit(true), []); + const dunkel = bereit && resolvedTheme === "dark"; + + return ( + + ); +}; + +/** Ein zweiter Klick auf denselben Anker ändert die URL nicht; dann selbst hinscrollen. */ +const zumAnker = (to: string) => { + const [pfad, id] = to.split("#"); + if (!id || window.location.pathname !== (pfad || "/") || window.location.hash !== `#${id}`) return; + document.getElementById(id)?.scrollIntoView(); +}; + +const SiteHeader = () => { + const [offen, setOffen] = useState(false); + const [gescrollt, setGescrollt] = useState(false); + const { pathname, hash } = useLocation(); + const panelId = useId(); + const knopfRef = useRef(null); + + // Trennlinie erst nach dem ersten Scrollen + useEffect(() => { + const pruefe = () => setGescrollt(window.scrollY > 4); + pruefe(); + window.addEventListener("scroll", pruefe, { passive: true }); + return () => window.removeEventListener("scroll", pruefe); + }, []); + + // Menü schließt bei jedem Seiten- oder Ankerwechsel + useEffect(() => setOffen(false), [pathname, hash]); + + // Offenes Menü: Seite sperren, Escape schließt und gibt den Fokus an den Knopf zurück + useEffect(() => { + if (!offen) return; + const vorher = document.body.style.overflow; + document.body.style.overflow = "hidden"; + const taste = (e: KeyboardEvent) => { + if (e.key === "Escape") { + setOffen(false); + knopfRef.current?.focus(); + } + }; + window.addEventListener("keydown", taste); + return () => { + document.body.style.overflow = vorher; + window.removeEventListener("keydown", taste); + }; + }, [offen]); + + return ( +
    +
    + + + WEBklar + + + + +
    + + + Projekt besprechen + +
    + + +
    + + {/* Handy-Menü: Abdunkelung schließt per Tipp daneben */} +
    setOffen(false)} aria-hidden /> + +
    + ); +}; + +export default SiteHeader; diff --git a/src/components/site/site.css b/src/components/site/site.css new file mode 100644 index 0000000..2cc736e --- /dev/null +++ b/src/components/site/site.css @@ -0,0 +1,283 @@ +/* Kopfleiste, Handy-Menü und Footer (Spezifikation 6.1 und 7.8) */ + +.wk-header { + position: sticky; + top: 0; + z-index: 50; + background: color-mix(in srgb, var(--bg) 94%, transparent); + border-bottom: 1px solid transparent; + transition: border-color var(--dur-state) var(--ease); +} +.wk-header--linie { + border-bottom-color: var(--line); +} + +.wk-header__zeile { + display: flex; + align-items: center; + gap: 2rem; + height: var(--header-h); +} + +.wk-header__marke { + display: inline-flex; + align-items: center; + gap: 0.55rem; + font-weight: 600; + font-size: 1.0625rem; + letter-spacing: 0; + color: var(--fg); + min-height: 44px; +} +.wk-header__marke svg { + border-radius: 7px; + box-shadow: inset 0 0 0 1px var(--line); +} + +.wk-header__nav { + flex: 1; +} +.wk-header__nav ul { + display: flex; + justify-content: center; + gap: 0.25rem; +} +.wk-header__nav a { + display: inline-flex; + align-items: center; + min-height: 44px; + padding: 0 0.85rem; + font-size: 0.9375rem; + color: var(--fg-muted); + transition: color var(--dur-state) var(--ease); +} +@media (hover: hover) and (pointer: fine) { + .wk-header__nav a:hover { + color: var(--fg); + } +} + +.wk-header__aktionen { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.wk-icon-btn { + display: inline-grid; + place-items: center; + width: 44px; + height: 44px; + border-radius: 999px; + color: var(--fg-muted); + transition: color var(--dur-state) var(--ease), background-color var(--dur-state) var(--ease); +} +@media (hover: hover) and (pointer: fine) { + .wk-icon-btn:hover { + color: var(--fg); + background: var(--bg-alt); + } +} + +.wk-header__menuknopf { + display: none; + width: 44px; + height: 44px; + margin-left: auto; + margin-right: -10px; + place-items: center; + color: var(--fg); +} + +.wk-burger { + position: relative; + display: block; + width: 20px; + height: 12px; +} +.wk-burger span { + position: absolute; + left: 0; + width: 100%; + height: 1.5px; + border-radius: 2px; + background: currentColor; + transition: transform var(--dur-state) var(--ease), top var(--dur-state) var(--ease); +} +.wk-burger span:first-child { + top: 2px; +} +.wk-burger span:last-child { + top: 9px; +} +.wk-burger[data-offen="true"] span:first-child { + top: 5.5px; + transform: rotate(45deg); +} +.wk-burger[data-offen="true"] span:last-child { + top: 5.5px; + transform: rotate(-45deg); +} + +.wk-menu, +.wk-menu-hintergrund { + display: none; +} + +@media (max-width: 899.98px) { + .wk-header__nav, + .wk-header__aktionen { + display: none; + } + .wk-header__menuknopf { + display: grid; + } + + .wk-menu-hintergrund { + display: block; + position: fixed; + inset: var(--header-h) 0 0 0; + background: rgb(0 0 0 / 0.32); + opacity: 0; + pointer-events: none; + transition: opacity var(--dur-state) var(--ease); + } + .wk-menu-hintergrund[data-offen="true"] { + opacity: 1; + pointer-events: auto; + } + + .wk-menu { + display: block; + position: fixed; + top: var(--header-h); + left: 0; + right: 0; + max-height: calc(100dvh - var(--header-h)); + overflow-y: auto; + background: var(--bg); + border-bottom: 1px solid var(--line); + padding: 0.5rem var(--gutter) calc(1.5rem + env(safe-area-inset-bottom)); + } + .wk-menu[hidden] { + display: none; + } + .wk-menu nav a { + display: flex; + align-items: center; + min-height: 56px; + font-size: 1.5rem; + font-weight: 600; + letter-spacing: -0.01em; + color: var(--fg); + border-bottom: 1px solid var(--line); + } + .wk-menu__fuss { + display: flex; + flex-direction: column; + gap: 0.75rem; + margin-top: 1.5rem; + } + .wk-menu__fuss .wk-btn { + width: 100%; + } + .wk-menu-theme { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + min-height: 48px; + border-radius: 999px; + color: var(--fg); + box-shadow: inset 0 0 0 1px var(--line); + font-weight: 600; + } + + @media (prefers-reduced-motion: no-preference) { + .wk-menu[data-offen="true"] { + animation: wk-menu-auf var(--dur-state) var(--ease); + } + } +} + +@keyframes wk-menu-auf { + from { + opacity: 0; + transform: translateY(-8px); + } + to { + opacity: 1; + transform: none; + } +} + +/* ── Footer ─────────────────────────────────────────────────────────────── */ + +.wk-footer { + background: var(--bg-alt); + border-top: 1px solid var(--line); + color: var(--fg-muted); + font-size: var(--fs-small); + line-height: 1.5; + padding-block: 56px calc(40px + env(safe-area-inset-bottom)); +} +.wk-footer__raster { + display: grid; + grid-template-columns: 1.4fr 1fr 1fr; + gap: 2.5rem; +} +.wk-footer__marke { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: var(--fg); + font-weight: 600; + font-size: 1rem; + margin-bottom: 0.75rem; +} +.wk-footer__marke svg { + border-radius: 6px; + box-shadow: inset 0 0 0 1px var(--line); +} +.wk-footer h2 { + font-size: var(--fs-small); + font-weight: 600; + letter-spacing: 0; + color: var(--fg); + margin-bottom: 0.75rem; +} +.wk-footer li a { + display: inline-flex; + align-items: center; + min-height: 32px; + color: var(--fg-muted); + transition: color var(--dur-state) var(--ease); +} +.wk-footer li a.wk-footer__pflicht { + color: var(--fg); + font-weight: 600; + text-decoration: underline; + text-underline-offset: 3px; +} +@media (hover: hover) and (pointer: fine) { + .wk-footer li a:hover { + color: var(--fg); + } +} +.wk-footer__unten { + margin-top: 3rem; + padding-top: 1.25rem; + border-top: 1px solid var(--line); +} + +@media (max-width: 719.98px) { + .wk-footer__raster { + grid-template-columns: 1fr 1fr; + } + .wk-footer__info { + grid-column: 1 / -1; + } + .wk-footer li a { + min-height: 44px; + } +} diff --git a/src/data/projekte.ts b/src/data/projekte.ts new file mode 100644 index 0000000..0038d59 --- /dev/null +++ b/src/data/projekte.ts @@ -0,0 +1,14 @@ +/** + * Referenzen für den Abschnitt „Projekte“ (Spezifikation 7.4). + * Nur Projekte, die online sind und deren Kunden zugestimmt haben (AGB § 13). + * Solange die Liste leer ist, gibt es weder Abschnitt noch Menüpunkt. + */ +export type Projekt = { + name: string; + beschreibung: string; + url: string; + /** eigener Screenshot unter public/, kein Stockfoto */ + bild: string; +}; + +export const projekte: Projekt[] = []; diff --git a/src/main.tsx b/src/main.tsx index 36c22c5..b7abd54 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -2,5 +2,18 @@ import { createRoot } from "react-dom/client"; import App from "./App.tsx"; import "./fonts.css"; import "./index.css"; +import "./styles/relaunch.css"; + +// Entwurf: Schriftvariante vergleichen, ?schrift=a (Systemschrift) oder ?schrift=b (Instrument Sans, Standard). +// Die Wahl gilt für den ganzen Besuch. Phase 2 entfernt den Umschalter. +try { + const wahl = new URLSearchParams(window.location.search).get("schrift") ?? sessionStorage.getItem("schrift"); + if (wahl === "a" || wahl === "b") { + sessionStorage.setItem("schrift", wahl); + document.documentElement.dataset.schrift = wahl; + } +} catch { + // ohne sessionStorage bleibt die Standardschrift +} createRoot(document.getElementById("root")!).render(); diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index b08e83f..ae3f0d3 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -1,34 +1,28 @@ -import Header from "@/components/Header"; -import Hero from "@/components/Hero"; -import Partners from "@/components/Partners"; -import ProblemSection from "@/components/ProblemSection"; -import SolutionSection from "@/components/SolutionSection"; -import Values from "@/components/Values"; -import Services from "@/components/Services"; -import Process from "@/components/Process"; -import Contact from "@/components/Contact"; -import Footer from "@/components/Footer"; +import HeroKarte from "@/components/home/HeroKarte"; +import Kundenportal from "@/components/home/Kundenportal"; +import Leistungen from "@/components/home/Leistungen"; +import Preise from "@/components/home/Preise"; +import UeberUns from "@/components/home/UeberUns"; +import KontaktBuehne from "@/components/home/KontaktBuehne"; +import "@/components/home/home.css"; import { usePageMeta } from "@/hooks/use-page-meta"; +/** Startseite des Relaunchs (Spezifikation 6.2). Kopfleiste und Footer kommen aus dem gemeinsamen Layout. */ const Index = () => { usePageMeta( - "WEBklar – Webagentur für KMU", - "WEBklar digitalisiert KMU: Website, Prozesse und Systeme aus einer Hand. Kostenlose Potenzialanalyse – Antwort spätestens am nächsten Werktag." + "WEBklar – Websites, Shops und Apps für kleine Betriebe", + "WEBklar baut Websites, Online-Shops und Web-Apps. Im Kundenportal sehen Sie jeden Schritt, mit Live-Vorschau Ihrer Website.", ); return ( -
    -
    - - - - - - - - -
    -
    + <> + + + + + + + ); }; diff --git a/src/routes.tsx b/src/routes.tsx index ba1c8bd..23a9193 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -1,5 +1,6 @@ import { Routes, Route, Outlet } from "react-router-dom"; -import Footer from "@/components/Footer"; +import SiteHeader from "@/components/site/SiteHeader"; +import SiteFooter from "@/components/site/SiteFooter"; import Index from "./pages/Index"; import ContactPage from "./pages/Contact"; import AGBPage from "./pages/AGB"; @@ -10,21 +11,27 @@ import HostingAboPage from "./pages/HostingAbo"; import DatenschutzPage from "./pages/Datenschutz"; import NotFound from "./pages/NotFound"; -/** Gemeinsamer Rahmen aller Unterseiten: Seiteninhalt, darunter der Footer mit Impressum, Datenschutz und Kündigen. */ -const SubpageLayout = () => ( +/** Gemeinsamer Rahmen aller Seiten: Kopfleiste, Inhalt, Footer mit Impressum, Datenschutz und Kündigen. */ +const SiteLayout = () => ( <> - -