Files
einfach-produktiv/app/challenge/page.tsx
T
Marco 268f2e841d Nudge checkmark/login icon vertical alignment
- Checklist checkmarks (Challenge, todo-cards, newsletter): mt-0.5 -> mt-1,
  centering against the first line's glyphs instead of sitting flush at
  the very top edge.
- Navbar login icon: -translate-y-0.5 — its round head vs. wide shoulders
  read as optically bottom-heavy next to the cart icon despite both
  having a mathematically centered bounding box.
2026-07-24 20:02:44 +00:00

370 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Metadata } from "next";
import Link from "next/link";
import Image from "next/image";
import { draftMode } from "next/headers";
import { Footer } from "../components/Footer";
import { Reveal, RevealGroup, RevealItem } from "../components/Reveal";
import { StepArrow } from "../components/StepArrow";
import { TestimonialsGrid } from "../components/TestimonialsGrid";
import { LiveTestimonialsGrid } from "../components/LiveTestimonialsGrid";
import { getTestimonials } from "../lib/payload";
import { EmailCapture } from "./components/EmailCapture";
const title = "7-Tage-Challenge Mehr Klarheit in 7 Tagen";
const description =
"Die 7-Tage-Challenge für deinen klaren Kopf und mehr Struktur im Alltag: 7 kurze, praktische Impulse direkt ins Postfach für mehr Fokus, Ruhe und Klarheit.";
export const metadata: Metadata = {
title,
description,
alternates: {
canonical: "/challenge",
},
openGraph: {
title,
description,
url: "/challenge",
images: ["/blog-featured.jpg"],
},
twitter: {
title,
description,
images: ["/blog-featured.jpg"],
},
};
function IconEnvelope() {
return (
<svg width="52" height="44" viewBox="0 0 52 44" fill="none">
<rect x="2" y="2" width="48" height="40" rx="3" stroke="#f6a701" strokeWidth="2" />
<path d="M2 2l24 22L50 2" stroke="#f6a701" strokeWidth="2" />
</svg>
);
}
function IconMailLines() {
return (
<svg width="56" height="44" viewBox="0 0 56 44" fill="none">
<line x1="2" y1="12" x2="12" y2="12" stroke="#f6a701" strokeWidth="2" strokeLinecap="round" />
<line x1="2" y1="20" x2="9" y2="20" stroke="#f6a701" strokeWidth="2" strokeLinecap="round" />
<line x1="2" y1="28" x2="7" y2="28" stroke="#f6a701" strokeWidth="2" strokeLinecap="round" />
<rect x="13" y="2" width="41" height="40" rx="3" stroke="#f6a701" strokeWidth="2" />
<path d="M13 2l20.5 19L54 2" stroke="#f6a701" strokeWidth="2" />
</svg>
);
}
function IconNotepad() {
return (
<svg width="46" height="52" viewBox="0 0 46 52" fill="none">
<rect x="2" y="4" width="32" height="42" rx="2" stroke="#f6a701" strokeWidth="2" />
<line x1="9" y1="16" x2="27" y2="16" stroke="#f6a701" strokeWidth="2" strokeLinecap="round" />
<line x1="9" y1="23" x2="24" y2="23" stroke="#f6a701" strokeWidth="2" strokeLinecap="round" />
<line x1="9" y1="30" x2="20" y2="30" stroke="#f6a701" strokeWidth="2" strokeLinecap="round" />
<circle cx="37" cy="40" r="7" stroke="#f6a701" strokeWidth="2" />
<line x1="37" y1="27" x2="37" y2="33" stroke="#f6a701" strokeWidth="2" strokeLinecap="round" />
</svg>
);
}
function IconCheckCircle() {
return (
<svg width="48" height="48" viewBox="0 0 48 48" fill="none">
<circle cx="24" cy="24" r="21" stroke="#f6a701" strokeWidth="2" />
<path d="M14 24l7.5 7.5L34 16" stroke="#f6a701" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
}
function Check() {
return (
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" className="shrink-0 mt-1">
<path d="M3 9.5l4 4L15 4" stroke="#f6a701" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
}
const steps = [
{
icon: <IconEnvelope />,
title: "1. Anmelden",
desc: "Trage dich mit deiner E-Mail-Adresse ein und starte sofort.",
},
{
icon: <IconMailLines />,
title: "2. E-Mail erhalten",
desc: "Du bekommst 7 Tage lang jeweils einen Impuls direkt in dein Postfach.",
},
{
icon: <IconNotepad />,
title: "3. Umsetzen",
desc: "Setze die einfache Aufgabe in wenigen Minuten um für mehr Klarheit und Fokus.",
},
{
icon: <IconCheckCircle />,
title: "4. Dranbleiben",
desc: "Kleine Schritte führen zu großen Veränderungen Tag für Tag.",
},
];
const benefits = [
{ title: "Klarheit gewinnen", desc: "Sortiere deine Gedanken und erkenne, was wirklich zählt." },
{ title: "Fokus stärken", desc: "Richte deine Aufmerksamkeit auf das Wesentliche." },
{ title: "Struktur schaffen", desc: "Einfache Methoden für mehr Ordnung im Alltag." },
{ title: "Gewohnheiten aufbauen", desc: "Kleine Schritte, die langfristig Wirkung zeigen." },
{ title: "Gelassener leben", desc: "Weniger Stress, mehr Zeit für die Dinge, die dir wichtig sind." },
];
export default async function ChallengePage() {
const { isEnabled: isPreview } = await draftMode();
const testimonials = await getTestimonials("challenge", { draft: isPreview });
return (
<>
<main className="flex flex-col flex-1 bg-[#f5f0e8]">
{/* ── Hero ── */}
<section className="w-full flex items-stretch overflow-hidden" style={{ minHeight: "32rem" }}>
{/* Left: text + form. justify-center removed from here — the
outer section's items-stretch already makes this column full
height, but centering its whole content (breadcrumb included)
made the breadcrumb's Y position drift depending on this
page's content length vs. /todo-cards's and /newsletter's own
(different) content lengths. Same fix as both of those. */}
{/* pt-10 md:pt-12 (not the original py-10 lg:py-14's top value) —
matches /todo-cards's and /newsletter's breadcrumb top offset
exactly; pb-10 lg:pb-14 keeps this page's original bottom
spacing, which was never the inconsistent part. */}
<Reveal className="flex flex-col gap-6 px-8 lg:px-[5rem] pt-10 md:pt-12 pb-10 lg:pb-14 w-full lg:w-[52%] lg:shrink-0">
{/* Breadcrumb — 3 levels (Startseite Werkzeuge
7-Tage-Challenge), matching /todo-cards's and
/newsletter's pattern; was missing "Werkzeuge" in the
middle. Also switched from this page's hardcoded hex
colors to the shared text-body-sm/text-text-muted/
text-text-primary tokens the other two breadcrumbs use —
text-body-sm is 0.875rem, identical to the old literal
value, so this is a pure consistency fix, not a visual
change. Deliberately NOT part of the centered block below. */}
<p className="text-body-sm text-text-muted flex items-center gap-2">
<Link href="/" className="hover:text-brand transition-colors">Startseite</Link>
<span></span>
<Link href="/#werkzeuge" className="hover:text-brand transition-colors">Werkzeuge</Link>
<span></span>
<span className="text-text-primary">7-Tage-Challenge</span>
</p>
{/* Everything else — centered in the remaining vertical space,
same fix as /todo-cards's and /newsletter's Hero sections. */}
<div className="flex flex-col gap-6 flex-1 justify-center">
{/* Headline */}
<h1
className="font-semibold text-[#222221] leading-[1.15]"
style={{ fontFamily: "var(--font-lora)", fontSize: "clamp(2.25rem, 5vw, 3.75rem)" }}
>
7 Tage.<br />
Mehr Klarheit.<br />
Weniger Stress<span className="text-brand">.</span>
</h1>
{/* Subtitle */}
<p className="text-[1rem] text-[#444] leading-[1.6] max-w-[30rem]">
Die 7-Tage-Challenge für deinen klaren Kopf und mehr Struktur im Alltag.
</p>
{/* Checklist */}
<ul className="flex flex-col gap-2">
{[
"7 kurze Impulse direkt in dein Postfach",
"Praktisch, umsetzbar und alltagstauglich",
"Für mehr Fokus, Ruhe und Klarheit",
].map((item) => (
<li key={item} className="flex items-start gap-2 text-[#222221] text-[0.95rem]">
<Check />
{item}
</li>
))}
</ul>
{/* Email form */}
<EmailCapture />
</div>
</Reveal>
{/* Right: hero image with badge — group + scale-105 on hover,
same restrained "photo feels alive" treatment as the Home/
todo-cards hero images; delay={0.15} mirrors their text→image
stagger. */}
<Reveal className="hidden lg:block group flex-1 relative overflow-hidden" delay={0.15}>
<Image
alt="7-Tage-Challenge"
src="/blog-featured.jpg"
fill
sizes="48vw"
className="object-cover object-center pointer-events-none transition-transform duration-500 group-hover:scale-105"
/>
{/* Badge */}
<div className="absolute top-8 right-8 w-[7.5rem] h-[7.5rem] rounded-full bg-white shadow-md flex flex-col items-center justify-center text-center p-3 gap-1">
<p className="text-[0.65rem] font-semibold text-[#222221] leading-tight">
Jeden Tag ein neuer Impuls in deinem Postfach.
</p>
<svg width="20" height="16" viewBox="0 0 20 16" fill="none">
<rect x="1" y="1" width="18" height="14" rx="2" stroke="#f6a701" strokeWidth="1.5" />
<path d="M1 1l9 8 9-8" stroke="#f6a701" strokeWidth="1.5" />
</svg>
</div>
</Reveal>
</section>
{/* ── So funktioniert die Challenge ── */}
<section className="bg-white w-full py-14 lg:py-20">
<div className="px-8 lg:px-[5rem] max-w-[1280px] mx-auto flex flex-col items-center gap-12">
<Reveal className="flex flex-col items-center gap-2 text-center">
<h2
className="font-semibold text-[#222221]"
style={{ fontFamily: "var(--font-lora)", fontSize: "clamp(1.5rem, 3vw, 2rem)" }}
>
So funktioniert die Challenge
</h2>
<p className="text-[1rem] text-[#666]">Jeden Tag ein Impuls. In nur wenigen Minuten.</p>
</Reveal>
{/* items-center below lg: (was items-start) — the step blocks
are centered columns now (see RevealItem below), so the
connector arrows between them need to be centered too,
not flush against the left edge. */}
<RevealGroup className="flex flex-col lg:flex-row items-center lg:items-start gap-8 lg:gap-2 w-full">
{steps.flatMap((step, i) => [
// Icon-above-text, centered, at every breakpoint now
// (previously a left-aligned icon+text row below lg: —
// fixed 2026-07-24 to match the lg: layout instead of
// diverging from it).
<RevealItem key={step.title} className="group flex flex-col items-center gap-4 lg:gap-5 flex-1 min-w-0">
<div className="flex items-center justify-center w-16 h-14 shrink-0 transition-transform duration-300 group-hover:scale-110">
{step.icon}
</div>
<div className="flex flex-col gap-1 text-center">
<p className="font-semibold text-[#222221] text-[1rem]">{step.title}</p>
<p className="text-[0.875rem] text-[#666] leading-[1.5]">{step.desc}</p>
</div>
</RevealItem>,
i < steps.length - 1 ? (
// Shared StepArrow component (see its own file) — same
// rotate-on-stack pattern as todo-cards/newsletter's
// HowItWorks. Always visible (rotated 90° while stacked
// below lg, this page's own structural breakpoint) rather
// than hidden below lg like before. Bigger below lg:
// (w-8 h-8, was w-6 h-6) per explicit feedback.
<div key={`arrow-${i}`} className="flex items-center justify-center shrink-0 lg:mt-5">
<StepArrow className="w-8 h-8 rotate-90 lg:w-10 lg:h-4 lg:rotate-0" />
</div>
) : null,
])}
</RevealGroup>
</div>
</section>
{/* ── Das erwartet dich ── */}
<section className="w-full py-14 lg:py-20">
<div className="px-8 lg:px-[5rem] max-w-[1280px] mx-auto flex flex-col gap-10">
<Reveal className="flex flex-col items-center gap-2 text-center">
<h2
className="font-semibold text-[#222221]"
style={{ fontFamily: "var(--font-lora)", fontSize: "clamp(1.5rem, 3vw, 2rem)" }}
>
Das erwartet dich
</h2>
<p className="text-[1rem] text-[#666]">7 Tage. 7 Impulse. Für mehr Klarheit in deinem Alltag.</p>
</Reveal>
<div className="flex flex-col lg:flex-row gap-10 lg:gap-16 items-center">
{/* Image */}
<Reveal
className="group relative w-full lg:w-[44%] lg:shrink-0 rounded-xl overflow-hidden"
style={{ minHeight: "18rem" }}
>
<Image
alt="Notizbuch"
src="/challenge-content.jpg"
fill
sizes="(min-width: 1024px) 44vw, 100vw"
className="object-cover transition-transform duration-500 group-hover:scale-105"
/>
</Reveal>
{/* Checklist */}
<Reveal delay={0.1} className="flex-1 w-full">
<ul className="flex flex-col gap-5">
{benefits.map((b) => (
<li key={b.title} className="flex items-start gap-3">
<Check />
<div className="flex flex-col gap-0.5">
<p className="font-semibold text-[#222221] text-[1rem]">{b.title}</p>
<p className="text-[0.9rem] text-[#555] leading-[1.5]">{b.desc}</p>
</div>
</li>
))}
</ul>
</Reveal>
</div>
</div>
</section>
{/* ── Was andere sagen ── */}
{isPreview ? (
<LiveTestimonialsGrid testimonials={testimonials} />
) : (
<TestimonialsGrid testimonials={testimonials} />
)}
{/* ── Bottom CTA ── */}
<section className="w-full py-14 lg:py-16">
<div className="px-8 lg:px-[5rem] max-w-[1280px] mx-auto">
<Reveal className="bg-[#f8f3ec] rounded-xl flex flex-col lg:flex-row gap-8 lg:gap-[3.5rem] items-start lg:items-center px-6 lg:px-10 py-8">
{/* Left: icon + copy — icon above text, centered, below lg:
(matches the Home Newsletter card's icon-above-text
pattern), row layout again from lg: up alongside the
outer Reveal's own flex-col -> lg:flex-row switch. */}
<div className="flex flex-col items-center text-center gap-5 lg:flex-row lg:items-start lg:text-left flex-1 min-w-0">
<div className="shrink-0 -rotate-4">
<svg width="52" height="44" viewBox="0 0 52 44" fill="none">
<rect x="2" y="2" width="48" height="40" rx="3" stroke="#f6a701" strokeWidth="2" />
<path d="M2 2l24 22L50 2" stroke="#f6a701" strokeWidth="2" />
</svg>
</div>
<div className="flex flex-col gap-2">
<p
className="font-semibold text-[#222221] leading-normal"
style={{ fontFamily: "var(--font-lora)", fontSize: "clamp(1.125rem, 2vw, 1.375rem)" }}
>
Starte jetzt deine 7-Tage-Challenge
</p>
<p className="text-[0.9rem] text-[#555] leading-[1.5]">
Trage dich ein und erhalte ab sofort täglich einen Impuls für mehr Klarheit und Fokus.
</p>
</div>
</div>
{/* Right: form */}
<div className="w-full lg:w-[30rem] lg:shrink-0">
<EmailCapture />
</div>
</Reveal>
</div>
</section>
</main>
<Footer />
</>
);
}