From 822481f2e49f5d7fbf939266b56cd60d42ab588a Mon Sep 17 00:00:00 2001 From: root Date: Thu, 1 Oct 2026 14:20:18 +0000 Subject: [PATCH] Relaunch Phase 1: Gestaltungs-Grundlage, Kopfleiste, Footer, neue Startseiten-Struktur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Token für Hell und Dunkel, eine Schriftfamilie (Instrument Sans selbst gehostet, ?schrift=a für die Systemschrift), gemeinsames Layout für alle Seiten, Abschnitte Über uns und Kontakt, Platzhalter für Hero, Kundenportal, Leistungen und Preise. Co-Authored-By: Claude Opus 5.5 --- public/fonts/instrument-sans/LICENSE | 93 +++++ ...nstrument-sans-latin-ext-wght-normal.woff2 | Bin 0 -> 11144 bytes .../instrument-sans-latin-wght-normal.woff2 | Bin 0 -> 30092 bytes src/components/home/HeroKarte.tsx | 10 + src/components/home/KontaktBuehne.tsx | 32 ++ src/components/home/Kundenportal.tsx | 10 + src/components/home/Leistungen.tsx | 10 + src/components/home/Preise.tsx | 10 + src/components/home/UeberUns.tsx | 25 ++ src/components/home/home.css | 46 +++ src/components/site/SiteFooter.tsx | 78 ++++ src/components/site/SiteHeader.tsx | 155 ++++++++ src/components/site/site.css | 283 +++++++++++++++ src/data/projekte.ts | 14 + src/main.tsx | 13 + src/pages/Index.tsx | 42 +-- src/routes.tsx | 23 +- src/styles/relaunch.css | 335 ++++++++++++++++++ tailwind.config.ts | 22 +- 19 files changed, 1150 insertions(+), 51 deletions(-) create mode 100644 public/fonts/instrument-sans/LICENSE create mode 100644 public/fonts/instrument-sans/instrument-sans-latin-ext-wght-normal.woff2 create mode 100644 public/fonts/instrument-sans/instrument-sans-latin-wght-normal.woff2 create mode 100644 src/components/home/HeroKarte.tsx create mode 100644 src/components/home/KontaktBuehne.tsx create mode 100644 src/components/home/Kundenportal.tsx create mode 100644 src/components/home/Leistungen.tsx create mode 100644 src/components/home/Preise.tsx create mode 100644 src/components/home/UeberUns.tsx create mode 100644 src/components/home/home.css create mode 100644 src/components/site/SiteFooter.tsx create mode 100644 src/components/site/SiteHeader.tsx create mode 100644 src/components/site/site.css create mode 100644 src/data/projekte.ts create mode 100644 src/styles/relaunch.css 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 0000000000000000000000000000000000000000..0ea0da04cb2bdacb918460c16ca2863138a19f4d GIT binary patch literal 11144 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

;7&cRT>@vBgT`qml^v#W*W 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 literal 0 HcmV?d00001 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 = () => ( +
+); + +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 = () => ( +
    +
    +
    +
    + + + WEBklar + +

    + WEBklar GbR +
    + Am Schwimmbad 10 +
    + 67722 Winnweiler +

    +
    + + +
    +

    © {new Date().getFullYear()} WEBklar GbR

    +
    +
    +); + +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 = () => ( <> - -
    + + Zum Inhalt springen + + +
    + +
    + ); /** Alle Seiten der Website; App.tsx rendert sie im BrowserRouter, die Tests im MemoryRouter. */ export const AppRoutes = () => ( - {/* Die Startseite bringt ihren Footer selbst mit; /datenschutz leitet nur weiter. */} - } /> + {/* /datenschutz leitet nur weiter */} } /> - }> + }> + } /> } /> } /> } /> diff --git a/src/styles/relaunch.css b/src/styles/relaunch.css new file mode 100644 index 0000000..7d04561 --- /dev/null +++ b/src/styles/relaunch.css @@ -0,0 +1,335 @@ +/* + * Relaunch 2026: Gestaltungs-Grundlage (Spezifikation Abschnitt 8). + * Eine Schriftfamilie, zwei Gewichte, neutrale Flächen und eine Akzentfarbe (Rot wie der Kartenpunkt). + * Wird nach index.css geladen und überschreibt dort die alten Token, damit auch die + * Rechtsseiten (shadcn-Klassen wie bg-background, text-muted-foreground) den neuen Look bekommen. + */ + +/* Schrift B: Instrument Sans, selbst gehostet (SIL Open Font License, public/fonts/instrument-sans/LICENSE) */ +@font-face { + font-family: "Instrument Sans"; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(/fonts/instrument-sans/instrument-sans-latin-ext-wght-normal.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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: "Instrument Sans"; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url(/fonts/instrument-sans/instrument-sans-latin-wght-normal.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; +} + +:root { + /* Schrift: B (Instrument Sans) ist Standard im Entwurf, ?schrift=a schaltet auf die Systemschrift */ + --font-system: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + --font-ui: "Instrument Sans", var(--font-system); + + --fs-hero: clamp(2.5rem, 1.569rem + 3.81vw, 5rem); + --fs-h2: clamp(2rem, 1.444rem + 2.29vw, 3.5rem); + --fs-h3: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem); + --fs-lead: clamp(1.1875rem, 1.05rem + 0.6vw, 1.625rem); + --fs-body: 1.0625rem; + --fs-small: 0.875rem; + --measure-text: 46rem; + --container: 1100px; + --gutter: clamp(16px, 4vw, 32px); + --section-space: clamp(72px, 9vw, 160px); + --header-h: 60px; + + --ease: cubic-bezier(0.2, 0.8, 0.2, 1); + --dur-state: 200ms; + --dur-enter: 600ms; + + /* Farben hell */ + --bg: #ffffff; + --bg-alt: #f5f5f7; + --fg: #1d1d1f; + --fg-muted: #6e6e73; + --line: #d2d2d7; + --line-strong: #86868b; + --accent: #e5251c; + --accent-text: #c81e16; + --focus: #c81e16; + + /* shadcn-Token auf die neuen Farben gelegt (HSL ohne hsl()) */ + --background: 0 0% 100%; + --foreground: 240 3% 12%; + --card: 240 11% 96%; + --card-foreground: 240 3% 12%; + --popover: 0 0% 100%; + --popover-foreground: 240 3% 12%; + --primary: 240 3% 12%; + --primary-foreground: 0 0% 100%; + --secondary: 240 11% 96%; + --secondary-foreground: 240 3% 12%; + --muted: 240 11% 96%; + --muted-foreground: 240 2% 44%; + --accent-hsl: 3 80% 43%; + --border: 240 6% 84%; + --input: 240 6% 84%; + --ring: 3 80% 43%; + --radius: 0.75rem; + --font-sans: var(--font-ui); + --font-display: var(--font-ui); +} + +.dark { + --bg: #0b0b0c; + --bg-alt: #161618; + --fg: #f5f5f7; + --fg-muted: #a1a1a6; + --line: #2c2c2e; + --line-strong: #636366; + --accent: #e5251c; + --accent-text: #ff5a4f; + --focus: #ff5a4f; + + --background: 240 4% 4%; + --foreground: 240 11% 96%; + --card: 240 4% 9%; + --card-foreground: 240 11% 96%; + --popover: 240 4% 9%; + --popover-foreground: 240 11% 96%; + --primary: 240 11% 96%; + --primary-foreground: 240 3% 12%; + --secondary: 240 4% 9%; + --secondary-foreground: 240 11% 96%; + --muted: 240 4% 9%; + --muted-foreground: 240 2% 64%; + --accent-hsl: 4 100% 65%; + --border: 240 2% 18%; + --input: 240 2% 18%; + --ring: 4 100% 65%; +} + +html[data-schrift="a"] { + --font-ui: var(--font-system); +} + +html { + scroll-behavior: smooth; + -webkit-text-size-adjust: 100%; +} +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } +} + +body { + background: var(--bg); + color: var(--fg); + font-family: var(--font-ui); + font-size: var(--fs-body); + line-height: 1.47; + letter-spacing: normal; + font-feature-settings: "kern", "calt"; + -webkit-font-smoothing: antialiased; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: var(--font-ui); + font-weight: 600; + letter-spacing: -0.015em; + text-transform: none; + text-wrap: balance; +} + +p { + text-wrap: pretty; +} + +:focus-visible { + outline: 2px solid var(--focus); + outline-offset: 3px; + border-radius: 6px; +} + +section[id] { + scroll-margin-top: calc(var(--header-h) + 24px); +} + +/* ── Bausteine ─────────────────────────────────────────────────────────── */ + +.wk-container { + width: 100%; + max-width: calc(var(--container) + 2 * var(--gutter)); + margin-inline: auto; + padding-inline: var(--gutter); +} + +.wk-section { + padding-block: var(--section-space); + background: var(--bg); +} +.wk-section--alt { + background: var(--bg-alt); +} + +.wk-eyebrow { + display: block; + font-size: var(--fs-small); + font-weight: 600; + color: var(--fg-muted); + letter-spacing: 0.005em; + margin-bottom: 1rem; +} + +.wk-h1 { + font-size: var(--fs-hero); + line-height: 1.05; + font-weight: 600; + letter-spacing: -0.02em; +} + +.wk-h2 { + font-size: var(--fs-h2); + line-height: 1.07; + font-weight: 600; + letter-spacing: -0.015em; + max-width: 20ch; +} + +.wk-h3 { + font-size: var(--fs-h3); + line-height: 1.2; + font-weight: 600; + letter-spacing: -0.01em; +} + +.wk-lead { + font-size: var(--fs-lead); + line-height: 1.38; + color: var(--fg-muted); + max-width: var(--measure-text); + text-wrap: pretty; +} +.wk-h2 + .wk-lead, +.wk-h1 + .wk-lead { + margin-top: 1.2em; +} + +.wk-muted { + color: var(--fg-muted); +} +.wk-small { + font-size: var(--fs-small); + line-height: 1.43; +} +.wk-num { + font-variant-numeric: tabular-nums; +} + +.wk-btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + min-height: 48px; + padding: 0 1.5rem; + border-radius: 999px; + font-size: 1.0625rem; + font-weight: 600; + line-height: 1; + white-space: nowrap; + transition: + background-color var(--dur-state) var(--ease), + color var(--dur-state) var(--ease), + box-shadow var(--dur-state) var(--ease), + opacity var(--dur-state) var(--ease); + -webkit-tap-highlight-color: transparent; +} +.wk-btn--primary { + background: var(--fg); + color: var(--bg); +} +.wk-btn--secondary { + background: transparent; + color: var(--fg); + box-shadow: inset 0 0 0 1px var(--line-strong); +} +.wk-btn--small { + min-height: 36px; + padding: 0 1rem; + font-size: 0.9375rem; +} +@media (hover: hover) and (pointer: fine) { + .wk-btn--primary:hover { + opacity: 0.86; + } + .wk-btn--secondary:hover { + box-shadow: inset 0 0 0 1px var(--fg); + } +} + +.wk-link { + color: var(--fg); + font-weight: 600; + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 4px; + text-decoration-color: var(--line-strong); + transition: text-decoration-color var(--dur-state) var(--ease); +} +@media (hover: hover) and (pointer: fine) { + .wk-link:hover { + text-decoration-color: var(--fg); + } +} + +.wk-visually-hidden { + position: absolute !important; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0 0 0 0); + white-space: nowrap; + border: 0; +} + +/* Sanftes Erscheinen beim Scrollen: Grundzustand sichtbar, nur mit Unterstützung und ohne reduzierte Bewegung */ +@media (prefers-reduced-motion: no-preference) { + @supports (animation-timeline: view()) { + .wk-reveal { + animation: wk-reveal linear both; + animation-timeline: view(); + animation-range: entry 0% cover 22%; + } + } +} +@keyframes wk-reveal { + from { + opacity: 0; + transform: translateY(28px); + } + to { + opacity: 1; + transform: none; + } +} + +.wk-skiplink { + position: absolute; + left: 1rem; + top: -100px; + z-index: 100; + padding: 0.75rem 1rem; + border-radius: 10px; + background: var(--fg); + color: var(--bg); + font-weight: 600; +} +.wk-skiplink:focus { + top: 0.75rem; +} diff --git a/tailwind.config.ts b/tailwind.config.ts index 8855aa7..50e03ef 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -14,25 +14,9 @@ export default { }, extend: { fontFamily: { - sans: [ - 'Inter', - 'ui-sans-serif', - 'system-ui', - '-apple-system', - 'BlinkMacSystemFont', - 'Segoe UI', - 'Roboto', - 'Helvetica Neue', - 'Arial', - 'Noto Sans', - 'sans-serif' - ], - display: [ - 'Space Grotesk', - 'Inter', - 'system-ui', - 'sans-serif' - ], + // Relaunch: eine Schriftfamilie für alles (src/styles/relaunch.css, --font-ui) + sans: ['var(--font-ui)'], + display: ['var(--font-ui)'], serif: [ 'Lora', 'ui-serif',
    + +