12 Blöcke · ganze Seite
Fertige React-Seite zum Kopieren — eigenständiges .tsx mit Tailwind & lucide-react, ohne Abhängigkeit von diesem Repo. Einzelne Sektionen findest du unter Blöcke.
page.tsx
| 1 | import { ArrowRight, BarChart3, BrainCircuit, Check, ChevronDown, Code, Layers3, Minus, Puzzle, Rocket, Server, ShieldCheck, Sparkles, Workflow, Zap } from "lucide-react"; |
| 2 | |
| 3 | function Hero() { |
| 4 | return ( |
| 5 | <section className="bg-background text-foreground py-24 md:py-32"> |
| 6 | <div className="mx-auto grid max-w-7xl items-center gap-12 px-6 md:grid-cols-2"> |
| 7 | <div className="flex flex-col"> |
| 8 | <span className="inline-flex w-fit items-center rounded-full border px-3 py-1 text-xs font-medium text-muted-foreground">paulmill Design System</span> |
| 9 | <h1 className="mt-5 text-4xl font-semibold tracking-tight sm:text-5xl md:text-6xl">Landing Pages, die konvertieren — block für block.</h1> |
| 10 | <p className="mt-6 max-w-xl text-lg text-muted-foreground">Baue professionelle Seiten aus typsicheren, wiederverwendbaren Sektionen. Ohne Datenbank, voll im Repo, sofort in der Galerie visualisiert.</p> |
| 11 | <div className="mt-8 flex flex-wrap gap-3"> |
| 12 | <a href="/blocks" className="inline-flex items-center justify-center gap-2 rounded-md px-5 py-2.5 text-sm font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90">Galerie öffnen <ArrowRight className="size-4" /></a> |
| 13 | <a href="/tokens" className="inline-flex items-center justify-center gap-2 rounded-md px-5 py-2.5 text-sm font-medium transition-colors border hover:bg-muted">Tokens ansehen</a> |
| 14 | </div> |
| 15 | </div> |
| 16 | <img |
| 17 | src="/img/home-hero.jpg" |
| 18 | alt="Modulare UI-Blöcke, die sich zu einer Landing Page zusammensetzen" |
| 19 | width={1280} |
| 20 | height={720} |
| 21 | className="w-full rounded-xl border bg-card shadow-2xl" |
| 22 | /> |
| 23 | </div> |
| 24 | </section> |
| 25 | ); |
| 26 | } |
| 27 | |
| 28 | function Logos() { |
| 29 | const logos = [ |
| 30 | { name: "Northwind", Icon: Layers3 }, |
| 31 | { name: "Aether", Icon: Sparkles }, |
| 32 | { name: "Quanta", Icon: BarChart3 }, |
| 33 | { name: "Helios", Icon: Zap }, |
| 34 | { name: "Vertex", Icon: Workflow }, |
| 35 | { name: "Lumen", Icon: BrainCircuit }, |
| 36 | { name: "Cobalt", Icon: ShieldCheck }, |
| 37 | { name: "Monolith", Icon: Server }, |
| 38 | ]; |
| 39 | return ( |
| 40 | <section className="bg-muted/40 text-foreground py-16 md:py-20"> |
| 41 | <div className="mx-auto max-w-7xl px-6"> |
| 42 | <p className="text-center text-xs font-medium uppercase tracking-widest text-muted-foreground">Im Einsatz bei Teams, die liefern</p> |
| 43 | <div className="mt-10 flex flex-wrap items-center justify-center gap-x-12 gap-y-8"> |
| 44 | {logos.map((logo) => ( |
| 45 | <div key={logo.name} className="flex items-center gap-2.5 text-foreground/60"> |
| 46 | {logo.Icon && <logo.Icon className="size-5" />} |
| 47 | <span className="text-lg font-semibold tracking-tight">{logo.name}</span> |
| 48 | </div> |
| 49 | ))} |
| 50 | </div> |
| 51 | </div> |
| 52 | </section> |
| 53 | ); |
| 54 | } |
| 55 | |
| 56 | function Platform() { |
| 57 | const items = [ |
| 58 | { Icon: BrainCircuit, title: "Schneller von Idee zu Launch", description: "Komponiere komplette Seiten aus typsicheren Blöcken statt jede Sektion neu zu bauen. Vorschau, Code-Export und Theming inklusive.", metric: "10×", span: "sm:col-span-2 lg:col-span-2 lg:row-span-2" }, |
| 59 | { Icon: ShieldCheck, title: "Typsicher by Design", description: "Discriminated Unions fangen falsch verdrahtete Blöcke schon im Build ab.", metric: "", span: "sm:col-span-1" }, |
| 60 | { Icon: Sparkles, title: "Token-getrieben", description: "Ein Theme-Wechsel zieht sich automatisch durch alle Sektionen.", metric: "", span: "sm:col-span-1" }, |
| 61 | { Icon: Workflow, title: "Frei komponierbar", description: "Seiten sind nur ein Array aus Blöcken — neu sortieren, austauschen, fertig.", metric: "", span: "sm:col-span-2 lg:col-span-2" }, |
| 62 | { Icon: Zap, title: "Statisch ausgeliefert", description: "Server Components by default, Client-JS nur wo nötig.", metric: "< 1s", span: "sm:col-span-1" }, |
| 63 | ]; |
| 64 | return ( |
| 65 | <section className="bg-background text-foreground py-20 md:py-28"> |
| 66 | <div className="mx-auto max-w-7xl px-6"> |
| 67 | <div className="mx-auto max-w-2xl text-center"> |
| 68 | <p className="text-sm font-semibold uppercase tracking-wider text-primary">Plattform</p> |
| 69 | <h2 className="text-3xl font-semibold tracking-tight sm:text-4xl">Eine Grundlage, die mitwächst</h2> |
| 70 | <p className="mt-4 text-lg text-muted-foreground">Modulare Bausteine, die sich zu jeder Seite kombinieren lassen — ohne dass die Konsistenz leidet.</p> |
| 71 | </div> |
| 72 | <div className="mt-14 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 lg:auto-rows-[13rem]"> |
| 73 | {items.map((item) => ( |
| 74 | <div key={item.title} className={"relative flex flex-col justify-between overflow-hidden rounded-3xl border bg-card p-7 " + item.span}> |
| 75 | <div className="flex size-12 items-center justify-center rounded-2xl bg-primary/10 text-primary"> |
| 76 | <item.Icon className="size-5" /> |
| 77 | </div> |
| 78 | <div className="mt-6"> |
| 79 | {item.metric && <div className="text-4xl font-semibold tracking-tight">{item.metric}</div>} |
| 80 | <h3 className="mt-2 text-lg font-semibold tracking-tight">{item.title}</h3> |
| 81 | <p className="mt-2 text-sm leading-relaxed text-muted-foreground">{item.description}</p> |
| 82 | </div> |
| 83 | </div> |
| 84 | ))} |
| 85 | </div> |
| 86 | </div> |
| 87 | </section> |
| 88 | ); |
| 89 | } |
| 90 | |
| 91 | function Architektur() { |
| 92 | return ( |
| 93 | <section className="bg-background text-foreground py-20 md:py-28"> |
| 94 | <div className="mx-auto grid max-w-7xl items-center gap-12 px-6 md:grid-cols-2"> |
| 95 | <div className=""> |
| 96 | <p className="text-sm font-semibold uppercase tracking-wider text-primary">Workflow</p> |
| 97 | <h2 className="mt-3 text-3xl font-semibold tracking-tight sm:text-4xl">Inhalt und Darstellung sauber getrennt</h2> |
| 98 | <p className="mt-4 text-lg leading-relaxed text-muted-foreground">Der Content-Layer kennt kein JSX, die Sektionen kennen keine Daten. Das hält beides unabhängig wartbar und macht Redesigns risikoarm — genau das, was du hier gerade siehst.</p> |
| 99 | <div className="mt-8 flex flex-wrap gap-3"> |
| 100 | <a href="/blocks" className="inline-flex items-center justify-center gap-2 rounded-md px-5 py-2.5 text-sm font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90">Architektur ansehen <ArrowRight className="size-4" /></a> |
| 101 | </div> |
| 102 | </div> |
| 103 | <img |
| 104 | src="/img/ds-architecture.jpg" |
| 105 | alt="Modulare Architektur aus sauber getrennten Glas-Layern" |
| 106 | width={1280} |
| 107 | height={960} |
| 108 | className="w-full rounded-xl border bg-card shadow-2xl" |
| 109 | /> |
| 110 | </div> |
| 111 | </section> |
| 112 | ); |
| 113 | } |
| 114 | |
| 115 | function Zahlen() { |
| 116 | const stats = [ |
| 117 | { value: "13", label: "Sektions-Typen" }, |
| 118 | { value: "100%", label: "Typsicher" }, |
| 119 | { value: "0", label: "Datenbanken" }, |
| 120 | { value: "< 1s", label: "Statisch generiert" }, |
| 121 | ]; |
| 122 | return ( |
| 123 | <section className="bg-primary text-primary-foreground py-20 md:py-28"> |
| 124 | <div className="mx-auto max-w-7xl px-6"> |
| 125 | <div className="mx-auto max-w-2xl text-center"> |
| 126 | <p className="text-sm font-semibold uppercase tracking-wider text-primary">In Zahlen</p> |
| 127 | <h2 className="text-3xl font-semibold tracking-tight sm:text-4xl">Zahlen, die überzeugen</h2> |
| 128 | </div> |
| 129 | <dl className="mt-14 grid grid-cols-2 gap-x-8 gap-y-12 lg:grid-cols-4"> |
| 130 | {stats.map((stat) => ( |
| 131 | <div key={stat.label} className="text-center"> |
| 132 | <dd className="text-4xl font-semibold tracking-tight tabular-nums sm:text-5xl">{stat.value}</dd> |
| 133 | <dt className="mt-2 text-sm text-primary-foreground/75">{stat.label}</dt> |
| 134 | </div> |
| 135 | ))} |
| 136 | </dl> |
| 137 | </div> |
| 138 | </section> |
| 139 | ); |
| 140 | } |
| 141 | |
| 142 | function Ablauf() { |
| 143 | const steps = [ |
| 144 | { n: "01", Icon: Puzzle, title: "Blöcke wählen", description: "Stelle deine Seite aus der kuratierten Bibliothek zusammen — Block für Block." }, |
| 145 | { n: "02", Icon: Code, title: "Inhalt füllen", description: "Pflege Texte und Medien als typisierte Daten. Kein JSX, keine Datenbank." }, |
| 146 | { n: "03", Icon: Sparkles, title: "Live prüfen", description: "Jede Sektion ist sofort in der Galerie sichtbar — in Light und Dark." }, |
| 147 | { n: "04", Icon: Rocket, title: "Ausliefern", description: "Statisch generiert und versioniert im Repo. Ein Commit, ein Deploy." }, |
| 148 | ]; |
| 149 | return ( |
| 150 | <section className="bg-muted/40 text-foreground py-20 md:py-28"> |
| 151 | <div className="mx-auto max-w-7xl px-6"> |
| 152 | <div className="mx-auto max-w-2xl text-center"> |
| 153 | <p className="text-sm font-semibold uppercase tracking-wider text-primary">Workflow</p> |
| 154 | <h2 className="text-3xl font-semibold tracking-tight sm:text-4xl">In vier Schritten zur fertigen Seite</h2> |
| 155 | <p className="mt-4 text-lg text-muted-foreground">Von der leeren Datei bis zur ausgelieferten Landing Page.</p> |
| 156 | </div> |
| 157 | <ol className="mt-16 grid grid-cols-1 gap-x-8 gap-y-12 sm:grid-cols-2 lg:grid-cols-4"> |
| 158 | {steps.map((step) => ( |
| 159 | <li key={step.title} className="flex flex-col items-start"> |
| 160 | <div className="flex size-14 items-center justify-center rounded-2xl bg-primary/10 text-lg font-semibold text-primary"> |
| 161 | {step.Icon ? <step.Icon className="size-6" /> : step.n} |
| 162 | </div> |
| 163 | <h3 className="mt-6 text-lg font-semibold tracking-tight">{step.title}</h3> |
| 164 | <p className="mt-2 text-sm leading-relaxed text-muted-foreground">{step.description}</p> |
| 165 | </li> |
| 166 | ))} |
| 167 | </ol> |
| 168 | </div> |
| 169 | </section> |
| 170 | ); |
| 171 | } |
| 172 | |
| 173 | function Tokens() { |
| 174 | return ( |
| 175 | <section className="bg-background text-foreground py-20 md:py-28"> |
| 176 | <div className="mx-auto grid max-w-7xl items-center gap-12 px-6 md:grid-cols-2"> |
| 177 | <div className="md:order-2"> |
| 178 | <p className="text-sm font-semibold uppercase tracking-wider text-primary">Tokens</p> |
| 179 | <h2 className="mt-3 text-3xl font-semibold tracking-tight sm:text-4xl">Dark Mode ohne Zusatzaufwand</h2> |
| 180 | <p className="mt-4 text-lg leading-relaxed text-muted-foreground">Alle Sektionen nutzen ausschließlich semantische OKLCH-Tokens. Ein Theme- oder Akzent-Wechsel funktioniert dadurch automatisch — kein einziges dark:-Suffix nötig, über jede Seite hinweg.</p> |
| 181 | <div className="mt-8 flex flex-wrap gap-3"> |
| 182 | <a href="/tokens" className="inline-flex items-center justify-center gap-2 rounded-md px-5 py-2.5 text-sm font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90">Token-Editor öffnen <ArrowRight className="size-4" /></a> |
| 183 | <a href="/blocks" className="inline-flex items-center justify-center gap-2 rounded-md px-5 py-2.5 text-sm font-medium transition-colors border hover:bg-muted">Mehr erfahren</a> |
| 184 | </div> |
| 185 | </div> |
| 186 | <img |
| 187 | src="/img/home-canvas.jpg" |
| 188 | alt="Design-Tokens als schwebende Farb-Chips und Typo-Specimen" |
| 189 | width={1280} |
| 190 | height={960} |
| 191 | className="md:order-1 w-full rounded-xl border bg-card shadow-2xl" |
| 192 | /> |
| 193 | </div> |
| 194 | </section> |
| 195 | ); |
| 196 | } |
| 197 | |
| 198 | function Stimmen() { |
| 199 | const testimonials = [ |
| 200 | { quote: "Wir launchen neue Landing Pages jetzt in Stunden statt Tagen.", author: "Mara Köhler", role: "Head of Marketing" }, |
| 201 | { quote: "Endlich ein System, in dem Design und Inhalt nicht kollidieren.", author: "Jonas Reuter", role: "Frontend Lead" }, |
| 202 | { quote: "Die Galerie macht Reviews mit dem Team unglaublich einfach.", author: "Aylin Demir", role: "Product Designer" }, |
| 203 | ]; |
| 204 | return ( |
| 205 | <section className="bg-background text-foreground py-20 md:py-28"> |
| 206 | <div className="mx-auto max-w-7xl px-6"> |
| 207 | <div className="mx-auto max-w-2xl text-center"> |
| 208 | <p className="text-sm font-semibold uppercase tracking-wider text-primary">Stimmen</p> |
| 209 | <h2 className="text-3xl font-semibold tracking-tight sm:text-4xl">Das sagen Teams</h2> |
| 210 | </div> |
| 211 | <div className="mt-14 grid grid-cols-1 gap-6 md:grid-cols-3"> |
| 212 | {testimonials.map((item) => ( |
| 213 | <figure key={item.author} className="flex flex-col rounded-2xl border bg-card p-6"> |
| 214 | <blockquote className="flex-1 text-[0.95rem] leading-relaxed">“{item.quote}”</blockquote> |
| 215 | <figcaption className="mt-6 flex items-center gap-3 border-t pt-4"> |
| 216 | <div className="flex size-9 items-center justify-center rounded-full bg-primary/10 text-sm font-medium text-primary"> |
| 217 | {item.author.charAt(0)} |
| 218 | </div> |
| 219 | <div> |
| 220 | <div className="text-sm font-medium">{item.author}</div> |
| 221 | {item.role && <div className="text-sm text-muted-foreground">{item.role}</div>} |
| 222 | </div> |
| 223 | </figcaption> |
| 224 | </figure> |
| 225 | ))} |
| 226 | </div> |
| 227 | </div> |
| 228 | </section> |
| 229 | ); |
| 230 | } |
| 231 | |
| 232 | function Vergleich() { |
| 233 | const columns = [ |
| 234 | { name: "Block-System", highlight: true }, |
| 235 | { name: "Copy-Paste", highlight: false }, |
| 236 | { name: "Page-Builder", highlight: false }, |
| 237 | ]; |
| 238 | const rows = [ |
| 239 | { feature: "Typsicherheit beim Build", values: [true, false, false] }, |
| 240 | { feature: "Konsistentes Theming", values: [true, false, true] }, |
| 241 | { feature: "Versioniert im Repo", values: [true, true, false] }, |
| 242 | { feature: "Code-Export", values: [true, true, false] }, |
| 243 | { feature: "Wartungsaufwand", values: ["Gering", "Hoch", "Mittel"] }, |
| 244 | { feature: "Lock-in", values: ["Keiner", "Keiner", "Hoch"] }, |
| 245 | ]; |
| 246 | return ( |
| 247 | <section className="bg-muted/40 text-foreground py-20 md:py-28"> |
| 248 | <div className="mx-auto max-w-4xl px-6"> |
| 249 | <div className="mx-auto max-w-2xl text-center"> |
| 250 | <p className="text-sm font-semibold uppercase tracking-wider text-primary">Vergleich</p> |
| 251 | <h2 className="text-3xl font-semibold tracking-tight sm:text-4xl">Warum ein Block-System statt Copy-Paste</h2> |
| 252 | <p className="mt-4 text-lg text-muted-foreground">Der Unterschied zwischen wartbaren Seiten und wachsendem Wildwuchs.</p> |
| 253 | </div> |
| 254 | <div className="mt-14 overflow-x-auto"> |
| 255 | <table className="w-full min-w-[34rem] border-separate border-spacing-0"> |
| 256 | <thead> |
| 257 | <tr> |
| 258 | <th className="px-5 pb-5 text-left text-xs font-medium uppercase tracking-wider text-muted-foreground">Funktion</th> |
| 259 | {columns.map((col) => ( |
| 260 | <th key={col.name} className={"px-3 pb-5 text-center text-base font-semibold " + (col.highlight ? "text-primary" : "")}> |
| 261 | {col.name} |
| 262 | </th> |
| 263 | ))} |
| 264 | </tr> |
| 265 | </thead> |
| 266 | <tbody> |
| 267 | {rows.map((row) => ( |
| 268 | <tr key={row.feature}> |
| 269 | <td className="border-t px-5 py-4 text-sm font-medium">{row.feature}</td> |
| 270 | {row.values.map((value, i) => ( |
| 271 | <td key={i} className={"border-t px-3 py-4 text-center " + (columns[i].highlight ? "bg-primary/5" : "")}> |
| 272 | {typeof value === "boolean" ? ( |
| 273 | value ? <Check className="mx-auto size-5 text-primary" /> : <Minus className="mx-auto size-4 text-muted-foreground/40" /> |
| 274 | ) : ( |
| 275 | <span className="text-sm font-medium">{value}</span> |
| 276 | )} |
| 277 | </td> |
| 278 | ))} |
| 279 | </tr> |
| 280 | ))} |
| 281 | </tbody> |
| 282 | </table> |
| 283 | </div> |
| 284 | </div> |
| 285 | </section> |
| 286 | ); |
| 287 | } |
| 288 | |
| 289 | function Pricing() { |
| 290 | const tiers = [ |
| 291 | { |
| 292 | name: "Start", |
| 293 | price: "0 €", |
| 294 | period: "/ Monat", |
| 295 | description: "Für erste Experimente.", |
| 296 | features: ["Alle Basis-Blöcke", "Light & Dark Mode", "Community-Support"], |
| 297 | cta: { label: "Kostenlos starten", href: "/blocks" }, |
| 298 | featured: false, |
| 299 | }, |
| 300 | { |
| 301 | name: "Pro", |
| 302 | price: "29 €", |
| 303 | period: "/ Monat", |
| 304 | description: "Für produktive Teams.", |
| 305 | features: ["Alle Blöcke & Varianten", "Kategorie-Routing", "Priorisierter Support"], |
| 306 | cta: { label: "Pro wählen", href: "#" }, |
| 307 | featured: true, |
| 308 | }, |
| 309 | { |
| 310 | name: "Enterprise", |
| 311 | price: "Individuell", |
| 312 | period: "", |
| 313 | description: "Für große Organisationen.", |
| 314 | features: ["Eigene Blöcke", "Design-Token-Audit", "SLA & Onboarding"], |
| 315 | cta: { label: "Kontakt", href: "#" }, |
| 316 | featured: false, |
| 317 | }, |
| 318 | ]; |
| 319 | return ( |
| 320 | <section className="bg-background text-foreground py-20 md:py-28"> |
| 321 | <div className="mx-auto max-w-7xl px-6"> |
| 322 | <div className="mx-auto max-w-2xl text-center"> |
| 323 | <p className="text-sm font-semibold uppercase tracking-wider text-primary">Preise</p> |
| 324 | <h2 className="text-3xl font-semibold tracking-tight sm:text-4xl">Transparente Preise</h2> |
| 325 | <p className="mt-4 text-lg text-muted-foreground">Wähle den Umfang, der zu deinem Projekt passt.</p> |
| 326 | </div> |
| 327 | <div className="mx-auto mt-14 grid max-w-5xl grid-cols-1 gap-6 md:grid-cols-3"> |
| 328 | {tiers.map((tier) => ( |
| 329 | <div |
| 330 | key={tier.name} |
| 331 | className={"flex flex-col rounded-2xl border bg-card p-6 " + (tier.featured ? "ring-2 ring-primary shadow-lg" : "")} |
| 332 | > |
| 333 | {tier.featured && ( |
| 334 | <span className="mb-4 inline-flex w-fit rounded-full bg-primary px-3 py-1 text-xs font-medium text-primary-foreground"> |
| 335 | Beliebt |
| 336 | </span> |
| 337 | )} |
| 338 | <h3 className="text-lg font-semibold">{tier.name}</h3> |
| 339 | {tier.description && <p className="mt-1 text-sm text-muted-foreground">{tier.description}</p>} |
| 340 | <div className="mt-4 flex items-baseline gap-1"> |
| 341 | <span className="text-4xl font-semibold tracking-tight">{tier.price}</span> |
| 342 | {tier.period && <span className="text-sm text-muted-foreground">{tier.period}</span>} |
| 343 | </div> |
| 344 | <ul className="mt-6 flex flex-1 flex-col gap-3 text-sm"> |
| 345 | {tier.features.map((feature) => ( |
| 346 | <li key={feature} className="flex items-start gap-2.5"> |
| 347 | <Check className="mt-0.5 size-4 shrink-0 text-primary" /> |
| 348 | <span>{feature}</span> |
| 349 | </li> |
| 350 | ))} |
| 351 | </ul> |
| 352 | <a |
| 353 | href={tier.cta.href} |
| 354 | className={"mt-6 inline-flex items-center justify-center rounded-md px-5 py-2.5 text-sm font-medium transition-colors " + (tier.featured ? "bg-primary text-primary-foreground hover:bg-primary/90" : "border hover:bg-muted")} |
| 355 | > |
| 356 | {tier.cta.label} |
| 357 | </a> |
| 358 | </div> |
| 359 | ))} |
| 360 | </div> |
| 361 | </div> |
| 362 | </section> |
| 363 | ); |
| 364 | } |
| 365 | |
| 366 | function Faq() { |
| 367 | const faqs = [ |
| 368 | { question: "Brauche ich eine Datenbank?", answer: "Nein. Der gesamte Content lebt als typisierte TypeScript-Dateien im Repo und wird statisch generiert." }, |
| 369 | { question: "Wie füge ich einen neuen Block hinzu?", answer: "Block-Typ ins Schema, Komponente bauen, in der Registry registrieren. Der satisfies-Lock erzwingt Vollständigkeit." }, |
| 370 | { question: "Funktioniert Dark Mode automatisch?", answer: "Ja. Sektionen nutzen nur semantische Tokens, daher folgt jede Sektion dem Theme ohne Zusatzcode." }, |
| 371 | { question: "Kann ich den Code exportieren?", answer: "Ja. Jede Variante liefert eigenständigen, portablen TSX-Code, den du direkt in dein Next.js-Projekt übernimmst." }, |
| 372 | ]; |
| 373 | return ( |
| 374 | <section className="bg-background text-foreground py-20 md:py-28"> |
| 375 | <div className="mx-auto max-w-3xl px-6"> |
| 376 | <div className="mx-auto max-w-2xl text-center"> |
| 377 | <p className="text-sm font-semibold uppercase tracking-wider text-primary">FAQ</p> |
| 378 | <h2 className="text-3xl font-semibold tracking-tight sm:text-4xl">Häufige Fragen</h2> |
| 379 | </div> |
| 380 | <div className="mt-12 divide-y rounded-2xl border bg-card"> |
| 381 | {faqs.map((faq) => ( |
| 382 | <details key={faq.question} className="group p-5 [&_summary]:list-none"> |
| 383 | <summary className="flex cursor-pointer items-center justify-between gap-4 font-medium"> |
| 384 | {faq.question} |
| 385 | <ChevronDown className="size-4 shrink-0 text-muted-foreground transition-transform duration-200 group-open:rotate-180" /> |
| 386 | </summary> |
| 387 | <p className="mt-3 text-sm leading-relaxed text-muted-foreground">{faq.answer}</p> |
| 388 | </details> |
| 389 | ))} |
| 390 | </div> |
| 391 | </div> |
| 392 | </section> |
| 393 | ); |
| 394 | } |
| 395 | |
| 396 | function Cta() { |
| 397 | return ( |
| 398 | <section className="bg-primary text-primary-foreground py-24 md:py-28"> |
| 399 | <div className="mx-auto flex max-w-3xl flex-col items-center px-6 text-center"> |
| 400 | <h2 className="text-3xl font-semibold tracking-tight sm:text-4xl md:text-5xl">Bereit, deine nächste Landing Page zu bauen?</h2> |
| 401 | <p className="mt-4 max-w-xl text-lg text-primary-foreground/75">Starte mit der Block-Bibliothek und sieh das Ergebnis sofort in der Galerie.</p> |
| 402 | <div className="mt-8 flex flex-wrap justify-center gap-3"> |
| 403 | <a href="/blocks" className="inline-flex items-center justify-center gap-2 rounded-md px-5 py-2.5 text-sm font-medium transition-colors bg-background text-foreground hover:bg-background/90">Jetzt loslegen <ArrowRight className="size-4" /></a> |
| 404 | <a href="/tokens" className="inline-flex items-center justify-center gap-2 rounded-md px-5 py-2.5 text-sm font-medium transition-colors border border-white/25 text-current hover:bg-white/10">Tokens ansehen</a> |
| 405 | </div> |
| 406 | </div> |
| 407 | </section> |
| 408 | ); |
| 409 | } |
| 410 | |
| 411 | export default function Page() { |
| 412 | return ( |
| 413 | <main> |
| 414 | <Hero /> |
| 415 | <Logos /> |
| 416 | <Platform /> |
| 417 | <Architektur /> |
| 418 | <Zahlen /> |
| 419 | <Ablauf /> |
| 420 | <Tokens /> |
| 421 | <Stimmen /> |
| 422 | <Vergleich /> |
| 423 | <Pricing /> |
| 424 | <Faq /> |
| 425 | <Cta /> |
| 426 | </main> |
| 427 | ); |
| 428 | } |