Professionalize landing page design
This commit is contained in:
@@ -7,32 +7,48 @@ interface About19Props {
|
||||
|
||||
const About19 = ({ className }: About19Props) => {
|
||||
return (
|
||||
<section className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<div className="grid grid-cols-1 gap-15 lg:grid-cols-7 lg:gap-1">
|
||||
<div className="col-span-4 h-120">
|
||||
<section className={cn("px-4 py-20 sm:px-6 lg:px-8 lg:py-28", className)}>
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<div className="grid gap-10 lg:grid-cols-[minmax(0,1fr)_minmax(0,0.88fr)] lg:items-start lg:gap-14">
|
||||
<div className="overflow-hidden rounded-lg border border-border bg-card">
|
||||
<img
|
||||
src="/about.jpg"
|
||||
alt=""
|
||||
className="h-full w-full object-cover rounded-xl shadow-md"
|
||||
alt="Matthias Meister bei der Webentwicklung"
|
||||
className="h-[20rem] w-full object-cover sm:h-[28rem] lg:h-[34rem]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-span-3 ml-auto max-w-4xl space-y-15 lg:pl-15">
|
||||
<h1 className="text-2xl font-medium tracking-tight">
|
||||
Hallo, ich bin Matthias.
|
||||
</h1>
|
||||
<p className="text-base text-foreground/40 lg:text-lg">
|
||||
Ich bin in der Region aufgewachsen, war durch die Bundeswehr viele Jahre weg — und bin jetzt zurück. Und ich plane zu bleiben.
|
||||
<div className="max-w-xl">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.16em] text-primary">
|
||||
Über die Zusammenarbeit
|
||||
</p>
|
||||
<p className="text-base text-foreground/40 lg:text-lg">
|
||||
Seit über 15 Jahren beschäftige ich mich mit Webentwicklung und Software. Einen Großteil davon intern für die Bundeswehr — Projekte die ich Ihnen leider nicht zeigen kann. Was ich Ihnen zeigen kann: Wie ich arbeite. Zuverlässig, präzise und ohne unnötigen Schnickschnack.
|
||||
</p>
|
||||
<p className="text-base text-foreground/40 lg:text-lg">
|
||||
Neben Websites für regionale Unternehmen entwickle ich eigene Software und Apps. Das bedeutet: Wenn Ihre Anforderungen irgendwann über eine einfache Website hinausgehen, bin ich noch immer der richtige Ansprechpartner.
|
||||
</p>
|
||||
<p className="text-base text-foreground/40 lg:text-lg">
|
||||
Mein Ziel ist es, Unternehmen aus der Region — Handwerker, Friseure, Ärzte — mit dem auszustatten, was Großstadtagenturen ihren Kunden für viel mehr Geld verkaufen. Eine Website die funktioniert, gefunden wird und Ihnen keine Kopfschmerzen macht.
|
||||
<h2 className="mt-4 text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
|
||||
Hallo, ich bin Matthias. Zurück in der Region und hier, um zu
|
||||
bleiben.
|
||||
</h2>
|
||||
<div className="mt-8 space-y-5 text-base leading-8 text-muted-foreground">
|
||||
<p>
|
||||
Ich bin in der Region aufgewachsen, war durch die Bundeswehr
|
||||
viele Jahre weg und bin jetzt zurück.
|
||||
</p>
|
||||
<p>
|
||||
Seit über 15 Jahren beschäftige ich mich mit Webentwicklung und
|
||||
Software. Einen Großteil davon intern für die Bundeswehr:
|
||||
Projekte, die ich Ihnen leider nicht zeigen kann. Was ich Ihnen
|
||||
zeigen kann: wie ich arbeite. Zuverlässig, präzise und ohne
|
||||
unnötigen Schnickschnack.
|
||||
</p>
|
||||
<p>
|
||||
Neben Websites für regionale Unternehmen entwickle ich eigene
|
||||
Software und Apps. Wenn Ihre Anforderungen irgendwann über eine
|
||||
einfache Website hinausgehen, bleibt der Ansprechpartner also
|
||||
derselbe.
|
||||
</p>
|
||||
</div>
|
||||
<p className="mt-8 rounded-lg border border-border bg-card p-5 text-base font-medium leading-7 text-foreground">
|
||||
Mein Ziel: Unternehmen aus der Region mit einer Website
|
||||
ausstatten, die funktioniert, gefunden wird und Ihnen keine
|
||||
Kopfschmerzen macht.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,7 @@ const contactFormSchema = z.object({
|
||||
email: z
|
||||
.string()
|
||||
.min(1, "Bitte geben Sie Ihre E-Mail ein")
|
||||
.email("Bitte geben Sie eine gueltige E-Mail ein"),
|
||||
.email("Bitte geben Sie eine gültige E-Mail ein"),
|
||||
message: z.string().min(1, "Bitte beschreiben Sie kurz Ihr Anliegen"),
|
||||
});
|
||||
|
||||
@@ -68,19 +68,29 @@ const Contact21 = ({ className, onSubmit }: Contact21Props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<section id="kontakt" className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<div className="mt-20 flex flex-col justify-between gap-15 md:gap-10 lg:flex-row">
|
||||
<section
|
||||
id="kontakt"
|
||||
className={cn("px-4 py-20 sm:px-6 lg:px-8 lg:py-28", className)}
|
||||
>
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<div className="grid gap-10 rounded-lg border border-border bg-card p-5 sm:p-8 lg:grid-cols-[minmax(0,0.82fr)_minmax(0,1.18fr)] lg:gap-14 lg:p-10">
|
||||
<div className="flex w-full max-w-lg flex-col justify-between gap-10">
|
||||
<p className="indent-[22%] text-3xl font-medium tracking-tight text-muted-foreground/50 lg:text-4xl">
|
||||
Erzählen Sie mir kurz von Ihrem Unternehmen — ich melde mich innerhalb von 24 Stunden mit einem unverbindlichen Angebot.
|
||||
</p>
|
||||
<div className="mt-5 flex items-center gap-4 lg:mt-20">
|
||||
<img
|
||||
src="https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/avatar3.png"
|
||||
className="size-12"
|
||||
alt="Matthias Meister"
|
||||
/>
|
||||
<div>
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.16em] text-primary">
|
||||
Kontakt
|
||||
</p>
|
||||
<h2 className="mt-4 text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
|
||||
Erzählen Sie kurz, worum es geht.
|
||||
</h2>
|
||||
<p className="mt-5 text-base leading-7 text-muted-foreground">
|
||||
Ich melde mich innerhalb von 24 Stunden mit einer ersten
|
||||
Einschätzung und dem passenden nächsten Schritt.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex size-12 items-center justify-center rounded-full bg-primary text-sm font-semibold text-primary-foreground">
|
||||
MM
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-medium tracking-tight">
|
||||
Matthias Meister
|
||||
@@ -91,26 +101,22 @@ const Contact21 = ({ className, onSubmit }: Contact21Props) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-4 flex w-full flex-col gap-2 lg:pl-10">
|
||||
<h2 className="mb-7 text-6xl font-semibold tracking-tight lg:text-5xl">
|
||||
Jetzt Website anfordern
|
||||
</h2>
|
||||
|
||||
{isSubmitted && (
|
||||
<div
|
||||
className={cn(
|
||||
"mb-4 rounded-lg border border-green-500/20 bg-green-500/10 p-4 text-center transition-opacity duration-500",
|
||||
showSuccess ? "opacity-100" : "opacity-0",
|
||||
)}
|
||||
>
|
||||
<p className="text-sm font-medium text-green-600 dark:text-green-400">
|
||||
Vielen Dank! Ich melde mich in Kürze bei Ihnen.
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
{isSubmitted && (
|
||||
<div
|
||||
className={cn(
|
||||
"mb-4 rounded-lg border border-primary/20 bg-primary/10 p-4 text-center transition-opacity duration-500",
|
||||
showSuccess ? "opacity-100" : "opacity-0",
|
||||
)}
|
||||
>
|
||||
<p className="text-sm font-medium text-primary">
|
||||
Vielen Dank! Ich melde mich in Kürze bei Ihnen.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form onSubmit={form.handleSubmit(handleFormSubmit)}>
|
||||
<FieldGroup className="gap-0">
|
||||
<form onSubmit={form.handleSubmit(handleFormSubmit)}>
|
||||
<FieldGroup className="gap-0">
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="name"
|
||||
@@ -124,7 +130,7 @@ const Contact21 = ({ className, onSubmit }: Contact21Props) => {
|
||||
id={field.name}
|
||||
aria-invalid={fieldState.invalid}
|
||||
placeholder="Ihr Name*"
|
||||
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"
|
||||
className="h-14 rounded-none border-0 border-b border-b-border bg-transparent! px-0 shadow-none placeholder:text-muted-foreground/65 focus-visible:border-b-primary focus-visible:ring-0 lg:text-base"
|
||||
/>
|
||||
{fieldState.invalid && (
|
||||
<FieldError errors={[fieldState.error]} />
|
||||
@@ -147,7 +153,7 @@ const Contact21 = ({ className, onSubmit }: Contact21Props) => {
|
||||
type="email"
|
||||
aria-invalid={fieldState.invalid}
|
||||
placeholder="Ihre E-Mail*"
|
||||
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"
|
||||
className="h-14 rounded-none border-0 border-b border-b-border bg-transparent! px-0 shadow-none placeholder:text-muted-foreground/65 focus-visible:border-b-primary focus-visible:ring-0 lg:text-base"
|
||||
/>
|
||||
{fieldState.invalid && (
|
||||
<FieldError errors={[fieldState.error]} />
|
||||
@@ -170,7 +176,7 @@ const Contact21 = ({ className, onSubmit }: Contact21Props) => {
|
||||
aria-invalid={fieldState.invalid}
|
||||
placeholder="Nachricht: Worum geht es bei Ihrem Projekt?"
|
||||
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"
|
||||
className="min-h-36 w-full rounded-none border-0 border-b border-b-border bg-transparent px-0 py-4 text-base text-foreground shadow-none outline-none placeholder:text-muted-foreground/65 focus-visible:border-b-primary focus-visible:ring-0 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive lg:text-base"
|
||||
/>
|
||||
{fieldState.invalid && (
|
||||
<FieldError errors={[fieldState.error]} />
|
||||
@@ -186,7 +192,7 @@ const Contact21 = ({ className, onSubmit }: Contact21Props) => {
|
||||
)}
|
||||
|
||||
<Button
|
||||
className="mt-15 flex items-center justify-start gap-2 rounded-none px-8! lg:h-12 lg:text-base"
|
||||
className="mt-8 flex h-11 w-full items-center justify-center gap-2 rounded-md px-6 lg:w-fit lg:text-base"
|
||||
disabled={form.formState.isSubmitting}
|
||||
>
|
||||
{form.formState.isSubmitting ? (
|
||||
|
||||
@@ -23,19 +23,18 @@ const trustAnchors = [
|
||||
|
||||
export default function CTASection() {
|
||||
return (
|
||||
<section className="px-4 pb-16 pt-4 sm:px-6 lg:px-8 lg:pb-24">
|
||||
<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="max-w-md space-y-4">
|
||||
<section className="px-4 pb-14 sm:px-6 lg:px-8 lg:pb-20">
|
||||
<div className="mx-auto max-w-6xl border-y border-border/80 py-9 lg:grid lg:grid-cols-[minmax(0,0.82fr)_minmax(0,1.55fr)] lg:gap-14 lg:py-11">
|
||||
<div className="max-w-md space-y-4 lg:pt-1">
|
||||
<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
|
||||
Vertrauensanker
|
||||
Vor dem Angebot
|
||||
</p>
|
||||
<h2 className="text-2xl font-semibold tracking-tight text-balance lg:text-3xl">
|
||||
Ein gemeinsamer Startpunkt statt leerer Versprechen.
|
||||
Erst verstehen, dann bauen.
|
||||
</h2>
|
||||
<p className="text-base leading-7 text-muted-foreground">
|
||||
Noch bevor es um Pakete oder Features geht, soll direkt klar sein,
|
||||
warum diese Zusammenarbeit für regionale Unternehmen greifbar und
|
||||
verlaesslich wirkt.
|
||||
Die Zusammenarbeit ist bewusst direkt gehalten: ein Gespräch, eine
|
||||
klare Empfehlung und ein Vorschlag, der zu Ihrem Betrieb passt.
|
||||
</p>
|
||||
</div>
|
||||
<dl className="mt-8 grid gap-6 sm:grid-cols-3 lg:mt-0 lg:gap-0">
|
||||
@@ -46,14 +45,14 @@ export default function CTASection() {
|
||||
"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",
|
||||
: "border-t border-border/70 pt-5 sm:border-t-0 sm:border-l sm:pl-6 sm:pt-0 lg:pl-8",
|
||||
)}
|
||||
>
|
||||
<dt className="text-sm font-medium text-foreground">
|
||||
<dt className="text-sm font-semibold text-foreground">
|
||||
{item.title}
|
||||
</dt>
|
||||
<dd className="space-y-2">
|
||||
<p className="text-lg font-semibold leading-7 text-balance text-foreground">
|
||||
<p className="text-base font-medium leading-7 text-balance text-foreground lg:text-lg">
|
||||
{item.description}
|
||||
</p>
|
||||
<p className="text-sm leading-6 text-muted-foreground">
|
||||
|
||||
@@ -41,35 +41,39 @@ interface Faq7Props {
|
||||
|
||||
const Faq7 = ({ className }: Faq7Props) => {
|
||||
return (
|
||||
<section className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<div className="mx-auto grid max-w-7xl gap-10 md:grid-cols-2">
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className="text-4xl font-semibold">
|
||||
Fragen vor dem Start?
|
||||
<br />
|
||||
<span className="text-muted-foreground/70">
|
||||
Hier finden Sie schnelle Antworten.
|
||||
</span>
|
||||
<section className={cn("px-4 py-20 sm:px-6 lg:px-8 lg:py-28", className)}>
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<div className="grid gap-10 border-t border-border/80 pt-10 md:grid-cols-[minmax(0,0.85fr)_minmax(0,1.15fr)] lg:gap-16">
|
||||
<div className="flex max-w-md flex-col gap-6">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.16em] text-primary">
|
||||
Häufige Fragen
|
||||
</p>
|
||||
<h2 className="text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
|
||||
Vor dem Start soll nichts schwammig bleiben.
|
||||
</h2>
|
||||
<p className="text-lg text-muted-foreground md:text-xl">
|
||||
Falls noch etwas offen ist, schreiben Sie mir gern ueber das
|
||||
<a href="#" className="mx-1 whitespace-nowrap underline">
|
||||
<p className="text-base leading-7 text-muted-foreground">
|
||||
Falls noch etwas offen ist, schreiben Sie mir gern über das
|
||||
<a
|
||||
href="#kontakt"
|
||||
className="mx-1 whitespace-nowrap underline underline-offset-4 transition-colors hover:text-foreground"
|
||||
>
|
||||
Kontaktformular
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
<Button size="lg" variant="outline" className="w-fit">
|
||||
Alle Fragen ansehen
|
||||
<Button asChild size="lg" variant="outline" className="w-fit rounded-md">
|
||||
<a href="#kontakt">Frage stellen</a>
|
||||
</Button>
|
||||
</div>
|
||||
<Accordion type="multiple">
|
||||
<Accordion type="multiple" className="rounded-lg border border-border bg-card px-4">
|
||||
{faqs.map((faq, index) => (
|
||||
<AccordionItem key={index} value={`item-${index}`}>
|
||||
<AccordionTrigger className="text-left">
|
||||
<AccordionTrigger className="text-left text-base font-semibold">
|
||||
{faq.question}
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>{faq.answer}</AccordionContent>
|
||||
<AccordionContent className="text-muted-foreground">
|
||||
{faq.answer}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
|
||||
@@ -1,44 +1,43 @@
|
||||
import { HelpCircleIcon } from "lucide-react";
|
||||
import React from "react";
|
||||
import {
|
||||
Gauge,
|
||||
Handshake,
|
||||
MapPinned,
|
||||
Search,
|
||||
Smartphone,
|
||||
} from "lucide-react";
|
||||
|
||||
import { GlowingEffect } from "@/components/ui/glowing-effect";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const featureData = [
|
||||
{
|
||||
desc: "Ihre Website erklaert in wenigen Sekunden, fuer wen Sie arbeiten und was Sie konkret anbieten.",
|
||||
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img1.jpeg",
|
||||
desc: "Die Startseite sagt schnell, für wen Sie arbeiten, was Sie anbieten und wie Interessenten Kontakt aufnehmen.",
|
||||
title: "Klare Positionierung",
|
||||
badgeTitle: "Vorteil 01",
|
||||
gridClass: "md:col-span-1",
|
||||
badgeTitle: "01",
|
||||
icon: MapPinned,
|
||||
},
|
||||
{
|
||||
desc: "Ein zeitgemaesses Design sorgt fuer einen starken ersten Eindruck und passt zu Ihrem Unternehmen.",
|
||||
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img7.jpeg",
|
||||
title: "Modernes Erscheinungsbild",
|
||||
badgeTitle: "Vorteil 02",
|
||||
gridClass: "lg:col-span-2",
|
||||
desc: "Gestaltung, Texte und Struktur wirken seriös, ohne den Charakter eines regionalen Betriebs glattzubügeln.",
|
||||
title: "Glaubwürdiger Auftritt",
|
||||
badgeTitle: "02",
|
||||
icon: Handshake,
|
||||
},
|
||||
{
|
||||
desc: "Ihre Inhalte funktionieren sauber auf Smartphone, Tablet und Desktop - ohne Umwege fuer Besucher.",
|
||||
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img11.jpeg",
|
||||
title: "Mobil optimiert",
|
||||
badgeTitle: "Vorteil 03",
|
||||
gridClass: "md:col-span-1 lg:row-span-2 ",
|
||||
desc: "Telefonnummer, Formular und zentrale Informationen bleiben auf Smartphone und Desktop leicht erreichbar.",
|
||||
title: "Mobil sauber geführt",
|
||||
badgeTitle: "03",
|
||||
icon: Smartphone,
|
||||
},
|
||||
{
|
||||
desc: "Klare Kontaktwege mit gut sichtbaren Handlungsaufforderungen machen den naechsten Schritt leicht.",
|
||||
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img2.jpeg",
|
||||
title: "Anfragen ohne Huerden",
|
||||
badgeTitle: "Vorteil 04",
|
||||
gridClass: "lg:col-span-2",
|
||||
desc: "Technik, Bilder und Inhalte werden so umgesetzt, dass die Seite schnell lädt und stabil bleibt.",
|
||||
title: "Schnell und robust",
|
||||
badgeTitle: "04",
|
||||
icon: Gauge,
|
||||
},
|
||||
{
|
||||
desc: "Die Seite bleibt wartbar aufgebaut, damit Inhalte spaeter schnell angepasst oder erweitert werden koennen.",
|
||||
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img4.jpeg",
|
||||
title: "Pflegeleicht aufgebaut",
|
||||
badgeTitle: "Vorteil 05",
|
||||
gridClass: "md:col-span-1",
|
||||
desc: "Google findet die richtigen Inhalte: Leistungen, Region, Kontakt und die wichtigsten Suchbegriffe.",
|
||||
title: "Für Suche vorbereitet",
|
||||
badgeTitle: "05",
|
||||
icon: Search,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -48,45 +47,43 @@ interface Feature284Props {
|
||||
|
||||
const Feature284 = ({ className }: Feature284Props) => {
|
||||
return (
|
||||
<section className={cn("h-full overflow-hidden py-32", className)}>
|
||||
<div className="container flex h-full w-full items-center justify-center">
|
||||
<div className="grid w-full max-w-6xl grid-cols-1 grid-rows-2 gap-4 md:grid-cols-2 lg:h-[800px] lg:grid-cols-4">
|
||||
<section className={cn("px-4 py-20 sm:px-6 lg:px-8 lg:py-28", className)}>
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<div className="grid gap-8 border-t border-border/80 pt-10 lg:grid-cols-[minmax(0,0.8fr)_minmax(0,1.4fr)] lg:gap-16">
|
||||
<div className="max-w-md">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.16em] text-primary">
|
||||
Was die Seite leisten muss
|
||||
</p>
|
||||
<h2 className="mt-4 text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
|
||||
Professionell heißt hier: verständlich, erreichbar, belastbar.
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
{featureData.map((feature, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={cn(
|
||||
"relative flex flex-col gap-2 rounded-3xl border p-4",
|
||||
feature.gridClass,
|
||||
)}
|
||||
className="group flex min-h-52 flex-col justify-between rounded-lg border border-border bg-card p-5 transition-colors hover:border-primary/40"
|
||||
>
|
||||
<GlowingEffect
|
||||
spread={40}
|
||||
glow={true}
|
||||
disabled={false}
|
||||
proximity={64}
|
||||
inactiveZone={0.01}
|
||||
/>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<p className="text-muted-foreground">{feature.badgeTitle}</p>
|
||||
<HelpCircleIcon className="size-4 text-muted-foreground" />
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"w-full flex-1 overflow-hidden rounded-3xl bg-muted",
|
||||
)}
|
||||
>
|
||||
<img
|
||||
src={feature.img}
|
||||
alt={feature.title}
|
||||
className="pointer-events-none h-full w-full object-cover"
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.16em] text-muted-foreground">
|
||||
{feature.badgeTitle}
|
||||
</p>
|
||||
<feature.icon
|
||||
className="size-5 text-primary transition-transform group-hover:-translate-y-0.5"
|
||||
aria-hidden
|
||||
/>
|
||||
</div>
|
||||
<h3 className="mt-4 text-2xl font-semibold tracking-tight">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p className="text-muted-foreground">{feature.desc}</p>
|
||||
<div className="mt-10 space-y-3">
|
||||
<h3 className="text-xl font-semibold tracking-tight">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p className="text-sm leading-6 text-muted-foreground">
|
||||
{feature.desc}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { ArrowUpRight } from "lucide-react";
|
||||
import { ArrowRight, Mail, Phone } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface Footer27Props {
|
||||
@@ -12,137 +8,65 @@ interface Footer27Props {
|
||||
}
|
||||
|
||||
const Footer27 = ({ className }: Footer27Props) => {
|
||||
const socialLinks = [
|
||||
{ name: "E-Mail", href: "#" },
|
||||
{ name: "LinkedIn", href: "#" },
|
||||
];
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
duration: 0.6,
|
||||
staggerChildren: 0.1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: { duration: 0.5 },
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<footer>
|
||||
<footer className={cn("px-4 pb-10 sm:px-6 lg:px-8", className)}>
|
||||
<div className="mx-auto max-w-6xl border-t border-border/80 pt-8">
|
||||
<div className="grid gap-8 lg:grid-cols-[minmax(0,1fr)_auto] lg:items-start">
|
||||
<div>
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true }}
|
||||
className="flex flex-col justify-between md:flex-row md:items-center"
|
||||
>
|
||||
<div className="space-y-8">
|
||||
<motion.div variants={itemVariants} className="space-y-6">
|
||||
<h2 className="text-4xl leading-tight font-bold text-foreground lg:text-5xl">
|
||||
Bereit für eine Website, die Kunden bringt?
|
||||
</h2>
|
||||
<p className="max-w-md text-lg leading-relaxed text-muted-foreground">
|
||||
Erzählen Sie mir kurz von Ihrem Unternehmen — ich melde mich innerhalb von 24 Stunden mit einem unverbindlichen Angebot.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<motion.div variants={itemVariants}>
|
||||
<Button size="lg">Kostenloses Angebot anfordern</Button>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<div className="mt-5 space-y-8 md:mt-0">
|
||||
<motion.div variants={itemVariants}>
|
||||
<div className="space-y-6">
|
||||
{socialLinks.map((link) => (
|
||||
<motion.div
|
||||
key={link.name}
|
||||
variants={itemVariants}
|
||||
whileHover={{ x: 4 }}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 300,
|
||||
damping: 20,
|
||||
}}
|
||||
>
|
||||
<a
|
||||
href={link.href}
|
||||
className="group flex items-center gap-2 py-2 text-foreground transition-colors hover:text-foreground/80"
|
||||
>
|
||||
<span className="text-xl font-medium">
|
||||
{link.name}
|
||||
</span>
|
||||
<ArrowUpRight className="h-6 w-6 transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5" />
|
||||
</a>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true }}
|
||||
className="mt-16"
|
||||
>
|
||||
<motion.div variants={itemVariants}>
|
||||
<Separator className="mb-8" />
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
variants={itemVariants}
|
||||
className="flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center"
|
||||
>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
© 2025 Matthias Meister Webdesign — Crimmitschau
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-6 text-sm">
|
||||
<span className="text-muted-foreground">
|
||||
Kontakt:{" "}
|
||||
<a href="mailto:info@matthias-meister-webdesign.de" className="underline underline-offset-4 transition-colors hover:text-foreground">
|
||||
info@matthias-meister-webdesign.de
|
||||
</a>
|
||||
</span>
|
||||
<span className="text-muted-foreground">
|
||||
Tel:{" "}
|
||||
<a href="tel:037627984400" className="underline underline-offset-4 transition-colors hover:text-foreground">
|
||||
03762 798 4400
|
||||
</a>
|
||||
</span>
|
||||
<span className="text-muted-foreground">
|
||||
<a href="/impressum" className="underline underline-offset-4 transition-colors hover:text-foreground">
|
||||
Impressum
|
||||
</a>
|
||||
</span>
|
||||
<span className="text-muted-foreground">
|
||||
<a href="/datenschutz" className="underline underline-offset-4 transition-colors hover:text-foreground">
|
||||
Datenschutz
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
<h2 className="max-w-2xl text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
|
||||
Bereit für eine Website, die Ihr Unternehmen klarer erklärt?
|
||||
</h2>
|
||||
<p className="mt-4 max-w-xl text-base leading-7 text-muted-foreground">
|
||||
Eine kurze Nachricht reicht. Ich prüfe, welcher Weg sinnvoll ist,
|
||||
und melde mich mit einer ehrlichen Einschätzung.
|
||||
</p>
|
||||
<Button asChild size="lg" className="mt-6 h-11 rounded-md px-5">
|
||||
<a href="#kontakt">
|
||||
Kostenloses Angebot anfordern
|
||||
<ArrowRight className="shrink-0" aria-hidden />
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<address className="not-italic">
|
||||
<div className="space-y-3 text-sm text-muted-foreground">
|
||||
<a
|
||||
href="mailto:info@matthias-meister-webdesign.de"
|
||||
className="flex items-center gap-2 transition-colors hover:text-foreground"
|
||||
>
|
||||
<Mail className="size-4" aria-hidden />
|
||||
info@matthias-meister-webdesign.de
|
||||
</a>
|
||||
<a
|
||||
href="tel:037627984400"
|
||||
className="flex items-center gap-2 transition-colors hover:text-foreground"
|
||||
>
|
||||
<Phone className="size-4" aria-hidden />
|
||||
03762 798 4400
|
||||
</a>
|
||||
</div>
|
||||
</address>
|
||||
</div>
|
||||
|
||||
<div className="mt-10 flex flex-col gap-4 border-t border-border/80 pt-6 text-sm text-muted-foreground sm:flex-row sm:items-center sm:justify-between">
|
||||
<p>© 2026 Matthias Meister Webdesign — Crimmitschau</p>
|
||||
<div className="flex flex-wrap items-center gap-x-5 gap-y-2">
|
||||
<a
|
||||
href="/impressum"
|
||||
className="underline underline-offset-4 transition-colors hover:text-foreground"
|
||||
>
|
||||
Impressum
|
||||
</a>
|
||||
<a
|
||||
href="/datenschutz"
|
||||
className="underline underline-offset-4 transition-colors hover:text-foreground"
|
||||
>
|
||||
Datenschutz
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ArrowRight } from "lucide-react";
|
||||
import { ArrowRight, Mail, MapPin, Phone } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
@@ -9,38 +9,103 @@ interface Hero235Props {
|
||||
|
||||
const Hero235 = ({ className }: Hero235Props) => {
|
||||
return (
|
||||
<section className={cn("px-4 sm:px-6 lg:px-8", className)}>
|
||||
<div className="mx-auto max-w-5xl py-20 sm:py-24 lg:py-28">
|
||||
<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">
|
||||
<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
|
||||
Matthias Meister | Webdesign für KMU aus der Region
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Rückmeldung innerhalb von 24 Stunden
|
||||
</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 für Unternehmen aus der Region - klar, schnell und
|
||||
glaubwürdig.
|
||||
</h1>
|
||||
<p className="max-w-[65ch] text-base leading-7 text-muted-foreground sm:text-lg">
|
||||
Ich arbeite direkt für Handwerk, Praxen und kleine Betriebe aus
|
||||
der Region. Ohne Baukasten-Look, Agenturshow oder technischen
|
||||
Umweg - sondern mit einer Website, die Ihr Angebot klar zeigt und
|
||||
Anfragen leichter macht.
|
||||
</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">
|
||||
Projekt anfragen
|
||||
<ArrowRight className="shrink-0" aria-hidden />
|
||||
</a>
|
||||
</Button>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Kurze Nachricht reicht - Sie erhalten direkt eine erste
|
||||
Einschätzung und den passenden nächsten Schritt.
|
||||
<section className={cn("px-4 pt-5 sm:px-6 lg:px-8", className)}>
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<header className="flex flex-col gap-4 border-b border-border/80 pb-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<a
|
||||
href="/"
|
||||
className="text-sm font-semibold tracking-tight text-foreground"
|
||||
>
|
||||
Matthias Meister Webdesign
|
||||
</a>
|
||||
<nav
|
||||
aria-label="Direkte Kontaktwege"
|
||||
className="flex flex-wrap items-center gap-x-5 gap-y-2 text-sm text-muted-foreground"
|
||||
>
|
||||
<a
|
||||
href="tel:037627984400"
|
||||
className="inline-flex items-center gap-1.5 transition-colors hover:text-foreground"
|
||||
>
|
||||
<Phone className="size-3.5" aria-hidden />
|
||||
03762 798 4400
|
||||
</a>
|
||||
<a
|
||||
href="mailto:info@matthias-meister-webdesign.de"
|
||||
className="inline-flex items-center gap-1.5 transition-colors hover:text-foreground"
|
||||
>
|
||||
<Mail className="size-3.5" aria-hidden />
|
||||
E-Mail
|
||||
</a>
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<MapPin className="size-3.5" aria-hidden />
|
||||
Crimmitschau
|
||||
</span>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div className="grid gap-10 py-16 sm:py-20 lg:grid-cols-[minmax(0,1.05fr)_minmax(320px,0.95fr)] lg:items-end lg:py-24">
|
||||
<div className="flex max-w-3xl flex-col gap-7">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.16em] text-primary">
|
||||
Webdesign für regionale KMU
|
||||
</p>
|
||||
<h1 className="max-w-[12ch] text-5xl font-semibold leading-[0.95] tracking-tight text-balance text-foreground sm:text-6xl lg:text-7xl">
|
||||
Websites, die vor Ort Vertrauen schaffen.
|
||||
</h1>
|
||||
<p className="max-w-[62ch] text-lg leading-8 text-muted-foreground">
|
||||
Für Handwerk, Praxen und kleine Betriebe: klar erklärt, schnell
|
||||
gebaut und so strukturiert, dass Besucher ohne Umwege verstehen,
|
||||
warum sie gerade Sie anfragen sollten.
|
||||
</p>
|
||||
<div className="flex flex-col gap-3 pt-1 sm:flex-row sm:items-center">
|
||||
<Button asChild size="lg" className="h-11 rounded-md px-5">
|
||||
<a href="#kontakt">
|
||||
Projekt anfragen
|
||||
<ArrowRight className="shrink-0" aria-hidden />
|
||||
</a>
|
||||
</Button>
|
||||
<Button
|
||||
asChild
|
||||
size="lg"
|
||||
variant="outline"
|
||||
className="h-11 rounded-md px-5"
|
||||
>
|
||||
<a href="#preise">Pakete ansehen</a>
|
||||
</Button>
|
||||
</div>
|
||||
<dl className="grid gap-4 border-t border-border/80 pt-6 sm:grid-cols-3">
|
||||
{[
|
||||
["24h", "Rückmeldung"],
|
||||
["2 Wochen", "typischer Go-Live"],
|
||||
["Sachsen", "Hosting & Betrieb"],
|
||||
].map(([value, label]) => (
|
||||
<div key={label}>
|
||||
<dt className="text-2xl font-semibold tracking-tight text-foreground">
|
||||
{value}
|
||||
</dt>
|
||||
<dd className="mt-1 text-sm text-muted-foreground">
|
||||
{label}
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div className="relative">
|
||||
<figure className="overflow-hidden rounded-lg border border-border bg-card">
|
||||
<img
|
||||
src="/about.jpg"
|
||||
alt="Arbeitsplatz von Matthias Meister beim Entwickeln einer Website"
|
||||
className="h-[19rem] w-full object-cover sm:h-[24rem] lg:h-[31rem]"
|
||||
/>
|
||||
<figcaption className="grid gap-2 border-t border-border bg-card/95 p-5 sm:grid-cols-[1fr_auto] sm:items-center">
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
Direkt mit dem Entwickler statt mit wechselnden Agenturrollen.
|
||||
</span>
|
||||
<span className="text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground">
|
||||
Persönlich geplant
|
||||
</span>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,217 +5,211 @@ import { useState } from "react";
|
||||
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface PricingPlan {
|
||||
name: string;
|
||||
badge: string;
|
||||
price: string;
|
||||
description?: string;
|
||||
period: string;
|
||||
description: string;
|
||||
features: string[];
|
||||
buttonText: string;
|
||||
isPopular?: boolean;
|
||||
}
|
||||
|
||||
interface Pricing4Props {
|
||||
title?: string;
|
||||
description?: string;
|
||||
plans?: PricingPlan[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const developmentPlans: PricingPlan[] = [
|
||||
{
|
||||
name: "Basis",
|
||||
price: "799 €",
|
||||
period: "Einmalpreis",
|
||||
description: "Für einen klaren Webauftritt mit den wichtigsten Inhalten.",
|
||||
features: [
|
||||
"Eine Seite mit fünf Sektionen",
|
||||
"Kontaktformular",
|
||||
"Impressum und Datenschutz",
|
||||
"Mobilfreundlich und für Google vorbereitet",
|
||||
"Cookiefreie Analytics ohne Banner",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Profi",
|
||||
price: "1.499 €",
|
||||
period: "Einmalpreis",
|
||||
description: "Für Betriebe, die mehrere Leistungen sauber erklären wollen.",
|
||||
features: [
|
||||
"Bis zu fünf Unterseiten",
|
||||
"Google Maps Integration",
|
||||
"SEO-Basis für lokale Auffindbarkeit",
|
||||
"Optionaler Blog",
|
||||
"Alles aus Basis inklusive",
|
||||
],
|
||||
isPopular: true,
|
||||
},
|
||||
{
|
||||
name: "Maßarbeit",
|
||||
price: "2.499 €",
|
||||
period: "Einmalpreis",
|
||||
description: "Für individuelle Anforderungen, CMS und spätere Erweiterungen.",
|
||||
features: [
|
||||
"Individuelles Design nach Ihren Anforderungen",
|
||||
"CMS zur eigenen Inhaltspflege",
|
||||
"Erweiterbare Struktur",
|
||||
"Alles aus Profi inklusive",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const servicePlans: PricingPlan[] = [
|
||||
{
|
||||
name: "Hosting",
|
||||
price: "19 €",
|
||||
period: "pro Monat",
|
||||
description: "Solide technische Basis für kleine Unternehmensseiten.",
|
||||
features: [
|
||||
"Hosting auf deutschen Servern in Sachsen",
|
||||
"SSL, Domain und tägliche Backups",
|
||||
"Monatlicher Einblick in Besucherzahlen",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Wartung",
|
||||
price: "39 €",
|
||||
period: "pro Monat",
|
||||
description: "Für Unternehmen, die Betrieb und Sicherheit abgeben möchten.",
|
||||
features: [
|
||||
"Alles aus Hosting inklusive",
|
||||
"Regelmäßige Updates und Sicherheitschecks",
|
||||
"1 Stunde Support pro Monat",
|
||||
"Monitoring bei technischen Problemen",
|
||||
],
|
||||
isPopular: true,
|
||||
},
|
||||
{
|
||||
name: "Full Service",
|
||||
price: "69 €",
|
||||
period: "pro Monat",
|
||||
description: "Für laufende Änderungen ohne jedes Mal ein neues Projekt.",
|
||||
features: [
|
||||
"Alles aus Wartung inklusive",
|
||||
"Kleinere Inhaltsänderungen bis 2 Stunden pro Monat",
|
||||
"Häufigerer Einblick in Besucherzahlen",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const Pricing4 = ({
|
||||
title = "Entwicklungspakete",
|
||||
title = "Pakete mit klarer Kante.",
|
||||
description =
|
||||
"Alle Websites laufen auf deutschen Servern, sind DSGVO-konform und kommen ohne Cookie-Banner aus. Auf Wunsch erhalten Sie monatlich einen Einblick, wie viele Menschen Ihre Website besuchen haben — und woher sie kommen.",
|
||||
plans = [
|
||||
{
|
||||
name: "BASIS",
|
||||
badge: "799 €",
|
||||
price: "799 €",
|
||||
features: [
|
||||
"Eine Seite, fünf Sektionen",
|
||||
"Kontaktformular",
|
||||
"Impressum & Datenschutz",
|
||||
"Mobilfreundlich & für Google optimiert",
|
||||
"DSGVO-konformes Kontaktformular",
|
||||
"Cookiefreies Analytics — ohne Abmahnrisiko",
|
||||
],
|
||||
buttonText: "Kostenloses Angebot anfordern",
|
||||
},
|
||||
{
|
||||
name: "PROFI",
|
||||
badge: "1.499 € ⭐ Empfehlung",
|
||||
price: "1.499 €",
|
||||
features: [
|
||||
"Bis zu 5 Unterseiten",
|
||||
"Google Maps Integration",
|
||||
"SEO-Basis (bessere Auffindbarkeit bei Google)",
|
||||
"Optionaler Blog",
|
||||
"DSGVO-konformes Kontaktformular",
|
||||
"Cookiefreies Analytics — ohne Abmahnrisiko",
|
||||
"Alles aus Basis inklusive",
|
||||
],
|
||||
buttonText: "Kostenloses Angebot anfordern",
|
||||
isPopular: true,
|
||||
},
|
||||
{
|
||||
name: "MASSARBEIT",
|
||||
badge: "2.499 €",
|
||||
price: "2.499 €",
|
||||
features: [
|
||||
"Individuelles Design nach Ihren Wünschen",
|
||||
"CMS — Sie pflegen Inhalte selbst",
|
||||
"DSGVO-konformes Kontaktformular",
|
||||
"Cookiefreies Analytics — ohne Abmahnrisiko",
|
||||
"Alles aus Profi inklusive",
|
||||
],
|
||||
buttonText: "Kostenloses Angebot anfordern",
|
||||
},
|
||||
],
|
||||
"Die Preise sind bewusst nachvollziehbar gehalten. Im Gespräch klären wir, welches Paket passt und wo ein schlankerer Weg sinnvoller ist.",
|
||||
className,
|
||||
}: Pricing4Props) => {
|
||||
const [isMonthly, setIsMonthly] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState<"development" | "service">(
|
||||
"development",
|
||||
);
|
||||
const plans = activeTab === "development" ? developmentPlans : servicePlans;
|
||||
|
||||
return (
|
||||
<section className={cn("py-32", className)}>
|
||||
<div className="container mx-auto">
|
||||
<div className="flex flex-col gap-6">
|
||||
<h2 className="text-4xl font-semibold text-pretty lg:text-6xl">
|
||||
{title}
|
||||
</h2>
|
||||
<div className="flex flex-col justify-between gap-10 md:flex-row">
|
||||
<p className="max-w-3xl text-muted-foreground lg:text-xl">
|
||||
<section
|
||||
id="preise"
|
||||
className={cn("px-4 py-20 sm:px-6 lg:px-8 lg:py-28", className)}
|
||||
>
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<div className="grid gap-8 lg:grid-cols-[minmax(0,0.8fr)_minmax(0,1.4fr)] lg:items-end lg:gap-16">
|
||||
<div className="max-w-xl">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.16em] text-primary">
|
||||
Preise
|
||||
</p>
|
||||
<h2 className="mt-4 text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
|
||||
{title}
|
||||
</h2>
|
||||
<p className="mt-5 text-base leading-7 text-muted-foreground">
|
||||
{description}
|
||||
</p>
|
||||
<Tabs
|
||||
value={isMonthly ? "monthly" : "yearly"}
|
||||
onValueChange={(value: string) =>
|
||||
setIsMonthly(value === "monthly")
|
||||
}
|
||||
className="w-fit shrink-0"
|
||||
aria-label="Leistungsvariante"
|
||||
</div>
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onValueChange={(value: string) =>
|
||||
setActiveTab(value as "development" | "service")
|
||||
}
|
||||
className="w-fit lg:justify-self-end"
|
||||
aria-label="Paketart auswählen"
|
||||
>
|
||||
<TabsList className="grid h-11 w-full grid-cols-2 rounded-md border border-border bg-card p-1 sm:w-max">
|
||||
<TabsTrigger
|
||||
value="development"
|
||||
className="h-full min-h-0 px-5 py-0 text-sm font-semibold data-active:bg-primary data-active:text-primary-foreground"
|
||||
>
|
||||
Entwicklung
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="service"
|
||||
className="h-full min-h-0 px-5 py-0 text-sm font-semibold data-active:bg-primary data-active:text-primary-foreground"
|
||||
>
|
||||
Hosting & Wartung
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
<div className="mt-10 grid gap-4 lg:grid-cols-3">
|
||||
{plans.map((plan) => (
|
||||
<article
|
||||
key={plan.name}
|
||||
className={cn(
|
||||
"flex min-h-[32rem] flex-col rounded-lg border bg-card p-6",
|
||||
plan.isPopular
|
||||
? "border-primary shadow-[0_18px_60px_oklch(0.285_0.045_148/0.12)]"
|
||||
: "border-border",
|
||||
)}
|
||||
>
|
||||
<TabsList className="grid h-11 w-max grid-cols-2 gap-0 rounded-md p-1 text-lg">
|
||||
<TabsTrigger
|
||||
value="monthly"
|
||||
className="h-full min-h-0 px-7 py-0 font-semibold text-muted-foreground data-active:text-foreground"
|
||||
>
|
||||
Entwicklung
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="yearly"
|
||||
className="h-full min-h-0 px-7 py-0 font-semibold text-muted-foreground data-active:text-foreground"
|
||||
>
|
||||
Hosting & Wartung
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</div>
|
||||
<div className="flex w-full flex-col items-stretch gap-6 md:flex-row">
|
||||
{isMonthly ? (
|
||||
plans.map((plan) => (
|
||||
<div
|
||||
key={plan.name}
|
||||
className={`flex w-full flex-col rounded-xl border shadow-sm p-6 text-left ${
|
||||
plan.isPopular ? "bg-muted" : ""
|
||||
}`}
|
||||
>
|
||||
<Badge className="mb-8 block w-fit uppercase">
|
||||
{plan.badge}
|
||||
</Badge>
|
||||
<h3 className="font-mono text-4xl lg:text-5xl">
|
||||
{plan.price}
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold tracking-tight">
|
||||
{plan.name}
|
||||
</h3>
|
||||
<p className="text-muted-foreground">Einmalpreis</p>
|
||||
<Separator className="my-6" />
|
||||
<div className="flex h-full flex-col justify-between gap-20">
|
||||
<ul className="space-y-4 text-muted-foreground md:leading-snug">
|
||||
{plan.features.map((feature, featureIndex) => (
|
||||
<li
|
||||
key={featureIndex}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Check className="size-4 shrink-0" aria-hidden="true" />
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button className="w-full">{plan.buttonText}</Button>
|
||||
</div>
|
||||
<p className="mt-2 text-sm leading-6 text-muted-foreground">
|
||||
{plan.description}
|
||||
</p>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
[
|
||||
{
|
||||
name: "BASIC HOSTING",
|
||||
badge: "19 €/Monat",
|
||||
price: "19 €",
|
||||
features: [
|
||||
"Hosting auf deutschen Servern in Sachsen",
|
||||
"Grünes Schloss im Browser (SSL) — sicher & von Google bevorzugt",
|
||||
"Tägliche Backups — Ihre Daten sind immer geschützt",
|
||||
"Domain inklusive",
|
||||
"Monatlicher Einblick in Ihre Besucherzahlen",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "WARTUNG",
|
||||
badge: "39 €/Monat ⭐ Empfehlung",
|
||||
price: "39 €",
|
||||
features: [
|
||||
"Alles aus Basic Hosting inklusive",
|
||||
"Regelmäßige Updates & Sicherheitschecks",
|
||||
"1 Stunde Support pro Monat",
|
||||
"Monitoring — ich merke bevor Sie es tun, wenn etwas nicht stimmt",
|
||||
"Wöchentlicher Einblick in Ihre Besucherzahlen",
|
||||
],
|
||||
isPopular: true,
|
||||
},
|
||||
{
|
||||
name: "FULL SERVICE",
|
||||
badge: "69 €/Monat",
|
||||
price: "69 €",
|
||||
features: [
|
||||
"Alles aus Wartung inklusive",
|
||||
"Kleinere Inhaltsänderungen (bis 2 Stunden/Monat)",
|
||||
"Täglicher Einblick in Ihre Besucherzahlen",
|
||||
],
|
||||
},
|
||||
].map((plan) => (
|
||||
<div
|
||||
key={plan.name}
|
||||
className={`flex w-full flex-col rounded-xl border shadow-sm p-6 text-left ${
|
||||
plan.isPopular ? "bg-muted" : ""
|
||||
}`}
|
||||
>
|
||||
<Badge className="mb-8 block w-fit uppercase">
|
||||
{plan.badge}
|
||||
{plan.isPopular && (
|
||||
<Badge variant="outline" className="rounded-md">
|
||||
Empfohlen
|
||||
</Badge>
|
||||
<h3 className="font-mono text-4xl lg:text-5xl">
|
||||
{plan.price}
|
||||
</h3>
|
||||
<p className="text-muted-foreground">Monatlicher Preis</p>
|
||||
<Separator className="my-6" />
|
||||
<div className="flex h-full flex-col justify-between gap-20">
|
||||
<ul className="space-y-4 text-muted-foreground md:leading-snug">
|
||||
{plan.features.map((feature, featureIndex) => (
|
||||
<li
|
||||
key={featureIndex}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Check className="size-4 shrink-0" aria-hidden="true" />
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button className="w-full">Kostenloses Angebot anfordern</Button>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mt-8">
|
||||
<p className="text-4xl font-semibold tracking-tight">
|
||||
{plan.price}
|
||||
</p>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
{plan.period}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ul className="mt-8 flex-1 space-y-4 text-sm leading-6 text-muted-foreground">
|
||||
{plan.features.map((feature) => (
|
||||
<li key={feature} className="flex gap-3">
|
||||
<Check
|
||||
className="mt-0.5 size-4 shrink-0 text-primary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<Button asChild className="mt-8 w-full rounded-md">
|
||||
<a href="#kontakt">Kostenloses Angebot anfordern</a>
|
||||
</Button>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -5,59 +5,39 @@ interface Stats11Props {
|
||||
}
|
||||
|
||||
const Stats11 = ({ className }: Stats11Props) => {
|
||||
return (
|
||||
<section className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<div className="relative isolate overflow-hidden bg-linear-to-b from-primary/10 to-transparent md:border-x md:border-border">
|
||||
<div className="absolute right-0 -left-px -z-20 h-full w-full bg-[linear-gradient(90deg,var(--muted-foreground)_1px,transparent_1px)] mask-[linear-gradient(transparent_25%,black_25%,black_75%,transparent_75%)] bg-size-[calc(100%/16)_100%] mask-size-[100%_16px] opacity-20 [-webkit-mask-image:linear-gradient(transparent_25%,black_25%,black_75%,transparent_75%)] [-webkit-mask-size:100%_16px]" />
|
||||
const stats = [
|
||||
["SEO-ready", "Leistungsseiten, Region und Kontakt sauber strukturiert."],
|
||||
["< 1 Sek.", "Auf schnelle Ladezeiten und klare Technik ausgelegt."],
|
||||
["ab 799 €", "Transparente Einstiegspreise ohne Paketnebel."],
|
||||
["2 Wochen", "Typischer Zeitraum vom Startgespräch bis zur Vorschau."],
|
||||
];
|
||||
|
||||
return (
|
||||
<section className={cn("px-4 py-20 sm:px-6 lg:px-8 lg:py-28", className)}>
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<div className="rounded-lg border border-border bg-primary p-6 text-primary-foreground sm:p-8 lg:grid lg:grid-cols-[minmax(0,0.85fr)_minmax(0,1.45fr)] lg:gap-12 lg:p-10">
|
||||
<div>
|
||||
<h2 className="mb-16 max-w-3xl text-3xl leading-10 font-semibold sm:mb-24 md:mx-10">
|
||||
Für Google optimiert, schnell geladen und klar kalkulierbar.
|
||||
<span className="font-medium text-primary/50">
|
||||
{" "}
|
||||
Genau die Zahlen, die bei einer Website wirklich zählen.
|
||||
</span>
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.16em] text-primary-foreground/65">
|
||||
Messbare Grundlagen
|
||||
</p>
|
||||
<h2 className="mt-4 max-w-xl text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
|
||||
Gute Websites fühlen sich ruhig an, weil die Basis stimmt.
|
||||
</h2>
|
||||
<div className="relative grid max-w-2xl gap-4 border-x border-border pb-32 sm:grid-cols-2 sm:gap-10 sm:pb-44 md:ml-10 md:border-0">
|
||||
<div className="absolute inset-0 top-[-1100px] -left-[calc(1000px-22vw)] -z-10 size-[1500px] rounded-full border border-primary bg-background sm:top-[-480%] sm:left-[-185%] sm:size-[2000px] md:top-[-906%] md:left-[-294%] md:size-[3500px] lg:top-[-1186%] lg:left-[-380%] lg:size-[4500px] xl:top-[-1200%] xl:left-[-350%] 2xl:top-[-1196%] 2xl:left-[-345%]"></div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="flex gap-5 text-3xl font-semibold">
|
||||
<span className="relative -left-px w-px bg-primary/50"></span>
|
||||
SEO-ready
|
||||
</span>
|
||||
<p className="pl-5 font-medium text-muted-foreground/80">
|
||||
Für Google optimiert
|
||||
</div>
|
||||
<div className="mt-10 grid gap-4 sm:grid-cols-2 lg:mt-0">
|
||||
{stats.map(([value, label]) => (
|
||||
<div
|
||||
key={value}
|
||||
className="rounded-md border border-primary-foreground/15 bg-primary-foreground/[0.06] p-5"
|
||||
>
|
||||
<p className="text-3xl font-semibold tracking-tight">
|
||||
{value}
|
||||
</p>
|
||||
<p className="mt-3 text-sm leading-6 text-primary-foreground/72">
|
||||
{label}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="flex gap-5 text-3xl font-semibold">
|
||||
<span className="relative -left-px w-px bg-primary/50"></span>
|
||||
{"< 1 Sek."}
|
||||
</span>
|
||||
<p className="pl-5 font-medium text-muted-foreground/80">
|
||||
Ladezeit
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="flex gap-5 text-3xl font-semibold">
|
||||
<span className="relative -left-px w-px bg-primary/50"></span>
|
||||
ab 799 €
|
||||
</span>
|
||||
<p className="pl-5 font-medium text-muted-foreground/80">
|
||||
Transparenter Einmalpreis
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="flex gap-5 text-3xl font-semibold">
|
||||
<span className="relative -left-px w-px bg-primary/50"></span>
|
||||
2 Wochen
|
||||
</span>
|
||||
<p className="pl-5 font-medium text-muted-foreground/80">
|
||||
Bis zum Go-Live
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -25,8 +25,8 @@ import "@/styles/global.css";
|
||||
defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="mx-auto w-full max-w-7xl">
|
||||
<Hero235 client:load />
|
||||
<main class="w-full overflow-x-hidden">
|
||||
<Hero235 client:load />
|
||||
<CTASection client:load />
|
||||
<Feature284 client:load />
|
||||
<Stats11 client:load />
|
||||
@@ -35,6 +35,6 @@ import "@/styles/global.css";
|
||||
<About19 client:load />
|
||||
<Contact21 client:load />
|
||||
<Footer27 client:load />
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -49,38 +49,38 @@
|
||||
}
|
||||
|
||||
:root {
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.87 0 0);
|
||||
--chart-2: oklch(0.556 0 0);
|
||||
--chart-3: oklch(0.439 0 0);
|
||||
--chart-4: oklch(0.371 0 0);
|
||||
--chart-5: oklch(0.269 0 0);
|
||||
--radius: 0.625rem;
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
--background: oklch(0.982 0.012 82);
|
||||
--foreground: oklch(0.235 0.024 72);
|
||||
--card: oklch(0.996 0.006 82);
|
||||
--card-foreground: oklch(0.235 0.024 72);
|
||||
--popover: oklch(0.996 0.006 82);
|
||||
--popover-foreground: oklch(0.235 0.024 72);
|
||||
--primary: oklch(0.285 0.045 148);
|
||||
--primary-foreground: oklch(0.985 0.011 82);
|
||||
--secondary: oklch(0.915 0.028 82);
|
||||
--secondary-foreground: oklch(0.275 0.031 72);
|
||||
--muted: oklch(0.94 0.018 82);
|
||||
--muted-foreground: oklch(0.485 0.024 72);
|
||||
--accent: oklch(0.705 0.079 141);
|
||||
--accent-foreground: oklch(0.17 0.026 148);
|
||||
--destructive: oklch(0.56 0.19 27);
|
||||
--border: oklch(0.86 0.018 80);
|
||||
--input: oklch(0.84 0.018 80);
|
||||
--ring: oklch(0.53 0.071 142);
|
||||
--chart-1: oklch(0.66 0.08 142);
|
||||
--chart-2: oklch(0.55 0.055 72);
|
||||
--chart-3: oklch(0.47 0.04 215);
|
||||
--chart-4: oklch(0.72 0.055 93);
|
||||
--chart-5: oklch(0.38 0.046 148);
|
||||
--radius: 0.5rem;
|
||||
--sidebar: oklch(0.965 0.012 82);
|
||||
--sidebar-foreground: oklch(0.235 0.024 72);
|
||||
--sidebar-primary: oklch(0.285 0.045 148);
|
||||
--sidebar-primary-foreground: oklch(0.985 0.011 82);
|
||||
--sidebar-accent: oklch(0.93 0.02 82);
|
||||
--sidebar-accent-foreground: oklch(0.275 0.031 72);
|
||||
--sidebar-border: oklch(0.86 0.018 80);
|
||||
--sidebar-ring: oklch(0.53 0.071 142);
|
||||
}
|
||||
|
||||
.dark {
|
||||
@@ -122,9 +122,20 @@
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
@apply bg-background text-foreground antialiased;
|
||||
}
|
||||
html {
|
||||
@apply font-sans;
|
||||
@apply scroll-smooth font-sans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background-image:
|
||||
linear-gradient(to bottom, oklch(0.988 0.01 82), var(--background) 46rem),
|
||||
linear-gradient(90deg, oklch(0.86 0.018 80 / 0.28) 1px, transparent 1px);
|
||||
background-size: auto, 6rem 6rem;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: oklch(0.78 0.075 141 / 0.35);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user