Add ToDo-Karten product page, fluid design tokens, and Navbar/Hero fixes
New /todo-cards page (Hero, How-it-works, Focus, Testimonials, Pricing) built with the fluid clamp() token system (app/lib/fluid.ts) and scroll-reveal animations (app/components/Reveal.tsx), matching styling consistency with /challenge's testimonial section. Navbar: page-aware active state and anchor-link navigation from any route (not just "/"), fixed logo click to actually navigate instead of silently rewriting the URL, fluid nav text size, custom hash-scroll handling for cross-page anchor links. Hero: responsive breakpoint fix for the text/image split at Tablet widths, entrance animation for the brand's orange dot, removed a red dot artifact from hero.png. Also includes prior uncommitted work on About/Blog/Newsletter/Footer and the cart lib (app/lib/cart.ts). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+77
-41
@@ -1,5 +1,30 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { Footer } from "../components/Footer";
|
||||
import { Reveal, RevealGroup, RevealItem } from "../components/Reveal";
|
||||
|
||||
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 (
|
||||
@@ -132,7 +157,7 @@ function EmailCapture({ buttonLabel = "Challenge starten" }: { buttonLabel?: str
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="shrink-0 bg-[#f6a701] rounded-lg px-5 py-3 font-bold text-[1rem] text-[#222221] whitespace-nowrap hover:brightness-95 transition-all"
|
||||
className="shrink-0 bg-[#f6a701] rounded-lg px-5 py-3 font-bold text-[1rem] text-[#222221] whitespace-nowrap hover:brightness-95 active:scale-[0.97] transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#f6a701] focus-visible:ring-offset-2"
|
||||
>
|
||||
{buttonLabel}
|
||||
</button>
|
||||
@@ -154,7 +179,7 @@ export default function ChallengePage() {
|
||||
<section className="w-full flex items-stretch overflow-hidden" style={{ minHeight: "32rem" }}>
|
||||
|
||||
{/* Left: text + form */}
|
||||
<div className="flex flex-col justify-center gap-6 px-8 lg:px-[5rem] py-10 lg:py-14 w-full lg:w-[52%] lg:shrink-0">
|
||||
<Reveal className="flex flex-col justify-center gap-6 px-8 lg:px-[5rem] py-10 lg:py-14 w-full lg:w-[52%] lg:shrink-0">
|
||||
|
||||
{/* Breadcrumb */}
|
||||
<p className="text-[0.875rem] text-[#888] flex items-center gap-1.5">
|
||||
@@ -194,14 +219,17 @@ export default function ChallengePage() {
|
||||
|
||||
{/* Email form */}
|
||||
<EmailCapture />
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
{/* Right: hero image with badge */}
|
||||
<div className="hidden lg:block flex-1 relative overflow-hidden">
|
||||
{/* 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}>
|
||||
<img
|
||||
alt="7-Tage-Challenge"
|
||||
src="/blog-featured.jpg"
|
||||
className="absolute inset-0 w-full h-full object-cover object-center pointer-events-none"
|
||||
className="absolute inset-0 w-full h-full 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">
|
||||
@@ -213,7 +241,7 @@ export default function ChallengePage() {
|
||||
<path d="M1 1l9 8 9-8" stroke="#f6a701" strokeWidth="1.5" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -221,7 +249,7 @@ export default function ChallengePage() {
|
||||
<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">
|
||||
|
||||
<div className="flex flex-col items-center gap-2 text-center">
|
||||
<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)" }}
|
||||
@@ -229,26 +257,26 @@ export default function ChallengePage() {
|
||||
So funktioniert die Challenge
|
||||
</h2>
|
||||
<p className="text-[1rem] text-[#666]">Jeden Tag ein Impuls. In nur wenigen Minuten.</p>
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
<div className="flex flex-col lg:flex-row items-start lg:items-start gap-8 lg:gap-2 w-full">
|
||||
<RevealGroup className="flex flex-col lg:flex-row items-start lg:items-start gap-8 lg:gap-2 w-full">
|
||||
{steps.flatMap((step, i) => [
|
||||
<div key={step.title} className="flex lg:flex-col items-start lg: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">
|
||||
<RevealItem key={step.title} className="group flex lg:flex-col items-start lg: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 lg: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>
|
||||
</div>,
|
||||
</RevealItem>,
|
||||
i < steps.length - 1 ? (
|
||||
<div key={`arrow-${i}`} className="hidden lg:flex items-center shrink-0 mt-5">
|
||||
<ArrowRight />
|
||||
</div>
|
||||
) : null,
|
||||
])}
|
||||
</div>
|
||||
</RevealGroup>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
@@ -257,7 +285,7 @@ export default function ChallengePage() {
|
||||
<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">
|
||||
|
||||
<div className="flex flex-col items-center gap-2 text-center">
|
||||
<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)" }}
|
||||
@@ -265,32 +293,37 @@ export default function ChallengePage() {
|
||||
Das erwartet dich
|
||||
</h2>
|
||||
<p className="text-[1rem] text-[#666]">7 Tage. 7 Impulse. Für mehr Klarheit in deinem Alltag.</p>
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
<div className="flex flex-col lg:flex-row gap-10 lg:gap-16 items-center">
|
||||
|
||||
{/* Image */}
|
||||
<div className="w-full lg:w-[44%] lg:shrink-0 rounded-xl overflow-hidden" style={{ minHeight: "18rem" }}>
|
||||
<Reveal
|
||||
className="group w-full lg:w-[44%] lg:shrink-0 rounded-xl overflow-hidden"
|
||||
style={{ minHeight: "18rem" }}
|
||||
>
|
||||
<img
|
||||
alt="Notizbuch"
|
||||
src="/challenge-content.jpg"
|
||||
className="w-full h-full object-cover"
|
||||
className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
|
||||
style={{ minHeight: "18rem" }}
|
||||
/>
|
||||
</div>
|
||||
</Reveal>
|
||||
|
||||
{/* Checklist */}
|
||||
<ul className="flex flex-col gap-5 flex-1">
|
||||
{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 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>
|
||||
@@ -300,34 +333,37 @@ export default function ChallengePage() {
|
||||
<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 gap-10">
|
||||
|
||||
<h2
|
||||
<Reveal
|
||||
className="font-semibold text-[#222221] text-center"
|
||||
style={{ fontFamily: "var(--font-lora)", fontSize: "clamp(1.5rem, 3vw, 2rem)" }}
|
||||
>
|
||||
Was andere sagen
|
||||
</h2>
|
||||
</Reveal>
|
||||
|
||||
<div className="flex flex-col lg:flex-row gap-6">
|
||||
{/* Same micro-interactions as /todo-cards's identically-styled
|
||||
testimonial cards (kept in sync deliberately): hover-lift on
|
||||
the card, avatar scale on the same hover via `group`. */}
|
||||
<RevealGroup className="flex flex-col lg:flex-row gap-6">
|
||||
{testimonials.map((t) => (
|
||||
<div
|
||||
<RevealItem
|
||||
key={t.name}
|
||||
className="flex-1 bg-[#f5f0e8] rounded-xl p-6 flex flex-col gap-4"
|
||||
className="group flex-1 bg-[#f5f0e8] rounded-xl p-6 flex flex-col gap-4 transition-transform duration-300 hover:-translate-y-1"
|
||||
>
|
||||
<p className="text-[#222221] text-[0.95rem] leading-[1.6] flex-1">{t.quote}</p>
|
||||
<div className="flex items-center gap-3">
|
||||
<img
|
||||
alt={t.name}
|
||||
src={t.avatar}
|
||||
className="w-10 h-10 rounded-full object-cover shrink-0"
|
||||
className="w-10 h-10 rounded-full object-cover shrink-0 transition-transform duration-300 group-hover:scale-110"
|
||||
/>
|
||||
<div>
|
||||
<p className="font-semibold text-[#222221] text-[0.9rem]">{t.name}</p>
|
||||
<p className="text-[#777] text-[0.8rem]">{t.role}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RevealItem>
|
||||
))}
|
||||
</div>
|
||||
</RevealGroup>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
@@ -335,7 +371,7 @@ export default function ChallengePage() {
|
||||
{/* ── Bottom CTA ── */}
|
||||
<section className="w-full py-14 lg:py-16">
|
||||
<div className="px-8 lg:px-[5rem] max-w-[1280px] mx-auto">
|
||||
<div 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">
|
||||
<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 */}
|
||||
<div className="flex gap-5 items-start flex-1 min-w-0">
|
||||
@@ -359,11 +395,11 @@ export default function ChallengePage() {
|
||||
</div>
|
||||
|
||||
{/* Right: form */}
|
||||
<div className="w-full lg:w-[24rem] lg:shrink-0">
|
||||
<div className="w-full lg:w-[30rem] lg:shrink-0">
|
||||
<EmailCapture />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user