import type { Metadata } from "next"; import Link from "next/link"; import Image from "next/image"; import { Reveal, RevealGroup, RevealItem } from "../components/Reveal"; import { Newsletter } from "../components/Newsletter"; import { Footer } from "../components/Footer"; import { getBlogPosts } from "../lib/payload"; import { formatDate } from "../lib/format"; export const metadata: Metadata = { title: "Blog", description: "Gedanken, Methoden und Impulse für einen leichteren und klareren Alltag.", alternates: { canonical: "/blog" }, openGraph: { title: "Blog | einfach produktiv.", description: "Gedanken, Methoden und Impulse für einen leichteren und klareren Alltag.", url: "/blog", type: "website", images: ["/blog-featured.jpg"], }, }; // Every distinct category name in DOM order — Payload's `categories` field // stores related docs, no separate slug on this side, but since this page // already fetches every published post (limit 100, no pagination), a // plain client-agnostic array filter is enough; no separate Payload query // per category needed. function distinctCategories(posts: { categories: string[] }[]): string[] { const seen = new Set(); for (const post of posts) for (const c of post.categories) seen.add(c); return Array.from(seen); } function buildCategoryHref(active: string[], category: string): string { const next = active.includes(category) ? active.filter((c) => c !== category) : [...active, category]; return next.length > 0 ? `/blog?categories=${next.map(encodeURIComponent).join(",")}` : "/blog"; } export default async function BlogOverviewPage({ searchParams, }: { searchParams: Promise<{ categories?: string }>; }) { const allPosts = await getBlogPosts(100); const { categories: categoriesParam } = await searchParams; const activeCategories = categoriesParam ? categoriesParam.split(",").filter(Boolean) : []; const allCategories = distinctCategories(allPosts); const posts = activeCategories.length === 0 ? allPosts : allPosts.filter((post) => post.categories.some((c) => activeCategories.includes(c))); const [featured, ...rest] = posts; return ( <>
{/* Header — copy left, photo bleeds to the viewport edge on the right with a left-edge fade into bg-base, matching Figma's hero-fade-left/hero-fade-bottom overlays (node 4577:330). */}

Blog

Gedanken, Methoden und Impulse für einen leichteren und klareren Alltag.

{allCategories.length > 1 && ( {allCategories.map((category) => { const active = activeCategories.includes(category); return ( {category} ); })} {activeCategories.length > 0 && ( Zurücksetzen )} )} {posts.length === 0 && (

Keine Beiträge in dieser Kategorie gefunden.

)} {featured && ( // -mt-8, not pt-10 — pulls the card up to slightly overlap the // hero section's bottom edge instead of sitting flush below it. // relative z-10 keeps it stacked above the hero's own photo.
{featured.thumbnail && ( )}
{featured.categories.join(", ")} {featured.readTime} Min {formatDate(featured.publishedAt)}

{featured.title}

{featured.excerpt}

Zum Beitrag
)} {rest.length > 0 && ( {rest.map((post) => (
{post.thumbnail && ( )}
{post.categories.join(", ")} {post.readTime} Min {formatDate(post.publishedAt)}

{post.title}

{post.excerpt}

Zum Beitrag
))}
)}