Enhance Contact21, CTA, and Hero235 components with improved structure and localized content; update styles and accessibility features for better user experience.

This commit is contained in:
2026-04-22 10:52:12 +02:00
parent ec22c238fa
commit b4acc4a308
5 changed files with 117 additions and 63 deletions
+17
View File
@@ -0,0 +1,17 @@
## Design Context
### Users
Owner-led regional small and medium-sized businesses in Germany, especially trades, salons, practices, and service companies. They need a credible website that helps local prospects understand the business quickly and take contact without friction.
### Brand Personality
Bodenstaendig, regional, glaubwuerdig. The interface should feel direct, calm, precise, and human rather than polished like a startup template or loud like an agency pitch.
### Aesthetic Direction
Use a light theme with restrained contrast, warm neutrals, and clear left-aligned structure. Favor quiet hierarchy, asymmetry, and editorial spacing over centered fullscreen hero patterns, decorative card grids, or theatrical gradients. Trust should appear early through concrete signals: direct contact, regional proximity, experience, response speed, and transparent delivery.
### Design Principles
- Trust before spectacle: lead with concrete proof, not abstract claims.
- Regional and human: show the person and working style behind the service early.
- Calm hierarchy: use spacing, alignment, and clear grouping instead of oversized centered compositions.
- Practical clarity: every section should answer what is offered, why it is credible, and what the next step is.
- Keep it grounded: avoid startup tropes, generic hero metrics, and decorative noise without informational value.
+7 -6
View File
@@ -68,7 +68,7 @@ const Contact21 = ({ className, onSubmit }: Contact21Props) => {
}; };
return ( return (
<section className={cn("py-32", className)}> <section id="kontakt" className={cn("py-32", className)}>
<div className="container"> <div className="container">
<div className="mt-20 flex flex-col justify-between gap-15 md:gap-10 lg:flex-row"> <div className="mt-20 flex flex-col justify-between gap-15 md:gap-10 lg:flex-row">
<div className="flex w-full max-w-lg flex-col justify-between gap-10"> <div className="flex w-full max-w-lg flex-col justify-between gap-10">
@@ -79,7 +79,7 @@ const Contact21 = ({ className, onSubmit }: Contact21Props) => {
<img <img
src="https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/avatar3.png" src="https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/avatar3.png"
className="size-12" className="size-12"
alt="avatar" alt="Matthias Meister"
/> />
<div> <div>
<h3 className="text-lg font-medium tracking-tight"> <h3 className="text-lg font-medium tracking-tight">
@@ -92,9 +92,9 @@ const Contact21 = ({ className, onSubmit }: Contact21Props) => {
</div> </div>
</div> </div>
<div className="col-span-4 flex w-full flex-col gap-2 lg:pl-10"> <div className="col-span-4 flex w-full flex-col gap-2 lg:pl-10">
<h1 className="mb-7 text-6xl font-semibold tracking-tight lg:text-5xl"> <h2 className="mb-7 text-6xl font-semibold tracking-tight lg:text-5xl">
Jetzt Website anfordern Jetzt Website anfordern
</h1> </h2>
{isSubmitted && ( {isSubmitted && (
<div <div
@@ -164,12 +164,13 @@ const Contact21 = ({ className, onSubmit }: Contact21Props) => {
<FieldLabel htmlFor={field.name} className="sr-only"> <FieldLabel htmlFor={field.name} className="sr-only">
Nachricht Nachricht
</FieldLabel> </FieldLabel>
<Input <textarea
{...field} {...field}
id={field.name} id={field.name}
aria-invalid={fieldState.invalid} aria-invalid={fieldState.invalid}
placeholder="Nachricht: Worum geht es bei Ihrem Projekt?" placeholder="Nachricht: Worum geht es bei Ihrem Projekt?"
className="h-15 rounded-none border-0 border-b border-b-foreground/25 bg-transparent! shadow-none placeholder:text-foreground/20 focus-visible:ring-0 lg:text-base" rows={4}
className="min-h-32 w-full rounded-none border-0 border-b border-b-foreground/25 bg-transparent px-0 py-3 text-base text-foreground shadow-none outline-none placeholder:text-foreground/20 focus-visible:border-ring focus-visible:ring-0 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive lg:text-base"
/> />
{fieldState.invalid && ( {fieldState.invalid && (
<FieldError errors={[fieldState.error]} /> <FieldError errors={[fieldState.error]} />
+58 -14
View File
@@ -1,24 +1,68 @@
import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils";
const trustAnchors = [
{
title: "Direkter Kontakt",
description:
"Sie sprechen mit dem Menschen, der die Website auch plant und baut.",
note: "Keine Vertriebsrunde, keine unklaren Uebergaben.",
},
{
title: "15+ Jahre Erfahrung",
description:
"Webentwicklung und Software mit Fokus auf robuste, wartbare Loesungen.",
note: "Praxis statt Buzzwords und Technik nur dort, wo sie wirklich hilft.",
},
{
title: "Hosting in Sachsen",
description:
"Deutsche Server, DSGVO-konform und passend fuer regionale Unternehmen.",
note: "Greifbar, nachvollziehbar und ohne unnoetiges Zusatztheater.",
},
];
export default function CTASection() { export default function CTASection() {
return ( return (
<section className="py-10 lg:py-16"> <section className="px-4 pb-16 pt-4 sm:px-6 lg:px-8 lg:pb-24">
<div className="mx-auto max-w-5xl px-4"> <div className="mx-auto max-w-6xl border-y border-border/80 py-8 lg:grid lg:grid-cols-[minmax(0,0.95fr)_minmax(0,1.45fr)] lg:gap-12 lg:py-10">
<div className="rounded-2xl bg-linear-to-r bg-[url('https://images.unsplash.com/photo-1739785890803-7a2191a37ef5?q=80&w=2940&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D')] bg-cover bg-bottom px-8 py-10 md:px-16 md:py-20"> <div className="max-w-md space-y-4">
<header className="mb-8 max-w-2xl space-y-4"> <p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
<h2 className="font-heading text-4xl leading-10 text-black lg:text-4xl"> Vertrauensanker
Jetzt Website anfordern </p>
<h2 className="text-2xl font-semibold tracking-tight text-balance lg:text-3xl">
Ein ruhiger Startpunkt statt voller Versprechen.
</h2> </h2>
<p className="text-lg text-black/60"> <p className="text-base leading-7 text-muted-foreground">
Erzählen Sie mir kurz von Ihrem Unternehmen — ich melde mich innerhalb von 24 Stunden mit einem unverbindlichen Angebot. Noch bevor es um Pakete oder Features geht, soll direkt klar sein,
warum diese Zusammenarbeit fuer regionale Unternehmen greifbar und
verlaesslich wirkt.
</p> </p>
</header>
{/* CTA Buttons */}
<div className="flex flex-wrap gap-4">
<Button size="lg">Anfrage senden</Button>
</div> </div>
<dl className="mt-8 grid gap-6 sm:grid-cols-3 lg:mt-0 lg:gap-0">
{trustAnchors.map((item, index) => (
<div
key={item.title}
className={cn(
"space-y-3",
index === 0
? ""
: "border-t border-border/70 pt-4 sm:border-t-0 sm:border-l sm:pl-6 sm:pt-0 lg:pl-8",
)}
>
<dt className="text-sm font-medium text-foreground">
{item.title}
</dt>
<dd className="space-y-2">
<p className="text-lg font-semibold leading-7 text-balance text-foreground">
{item.description}
</p>
<p className="text-sm leading-6 text-muted-foreground">
{item.note}
</p>
</dd>
</div> </div>
))}
</dl>
</div> </div>
</section> </section>
); );
+30 -38
View File
@@ -1,4 +1,4 @@
import { ArrowDown } from "lucide-react"; import { ArrowRight } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@@ -9,45 +9,37 @@ interface Hero235Props {
const Hero235 = ({ className }: Hero235Props) => { const Hero235 = ({ className }: Hero235Props) => {
return ( return (
<section <section className={cn("px-4 sm:px-6 lg:px-8", className)}>
className={cn( <div className="mx-auto max-w-5xl py-20 sm:py-24 lg:py-28">
"relative flex h-dvh items-center justify-center overflow-hidden bg-background py-32", <div className="mb-8 flex flex-col gap-3 border-b border-border/70 pb-5 sm:mb-10 sm:flex-row sm:items-center sm:justify-between">
className, <p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
)} Matthias Meister | Webdesign fuer KMU aus der Region
>
<div aria-hidden={true}>
<div
className="absolute inset-0 z-0 bg-[linear-gradient(to_right,var(--muted)_1px,transparent_1px),linear-gradient(to_bottom,var(--muted)_1px,transparent_1px)] bg-size-[40px_40px]"
style={{
WebkitMaskImage:
"radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 70%)",
maskImage:
"radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 70%)",
}}
/>
<div
className="pointer-events-none absolute inset-0 z-0 opacity-40"
style={{
backgroundImage:
"url(https://deifkwefumgah.cloudfront.net/shadcnblocks/block/noise.png)",
backgroundRepeat: "repeat",
}}
/>
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-40 bg-linear-to-b from-transparent via-background/10 to-background/90" />
</div>
<div className="relative container flex h-full flex-col justify-between">
<div className="flex flex-1 items-center justify-center">
<div className="mx-auto flex max-w-4xl flex-col items-center text-center">
<h1 className="text-4xl font-semibold tracking-tight text-balance text-foreground md:text-5xl lg:text-8xl">
Hallo, ich bin Matthias - ich baue Websites, die Kunden bringen.
</h1>
<p className="mt-8 max-w-xl text-pretty text-muted-foreground md:text-lg">
Moderne, blitzschnelle Auftritte für Handwerker, Friseure und Unternehmen aus der Region. Kein Agentur-Preisschild. Kein Overkill. Einfach eine Website, die funktioniert.
</p> </p>
<Button size="lg" className="mt-10"> <p className="text-sm text-muted-foreground">
Kostenloses Angebot Rueckmeldung innerhalb von 24 Stunden
<ArrowDown className="shrink-0" aria-hidden /> </p>
</div>
<div className="flex max-w-4xl flex-col gap-7">
<h1 className="max-w-[13ch] text-4xl font-semibold tracking-tight text-balance text-foreground sm:text-5xl lg:text-6xl">
Websites fuer Unternehmen aus der Region - klar, schnell und
glaubwuerdig.
</h1>
<p className="max-w-[65ch] text-base leading-7 text-muted-foreground sm:text-lg">
Ich arbeite direkt mit Handwerk, Praxen und kleinen Betrieben. Kein
Baukasten-Look, keine Agenturshow, kein technischer Umweg - sondern
ein Auftritt, der sofort zeigt, was Sie anbieten und wie man Sie
erreicht.
</p>
<div className="flex flex-wrap items-center gap-4 pt-1">
<Button asChild size="lg" className="h-11 rounded-full px-5">
<a href="#kontakt">
Kostenloses Angebot anfordern
<ArrowRight className="shrink-0" aria-hidden />
</a>
</Button> </Button>
<p className="text-sm text-muted-foreground">
Fuer Handwerk, Praxen und kleine Betriebe.
</p>
</div> </div>
</div> </div>
</div> </div>