Design System
12 Blöcke · ganze Seite
Akzent · global

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
1import { ArrowRight, BarChart3, BrainCircuit, Check, ChevronDown, Code, Layers3, Minus, Puzzle, Rocket, Server, ShieldCheck, Sparkles, Workflow, Zap } from "lucide-react";
2
3function 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
28function 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
56function 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
91function 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
115function 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
142function 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
173function 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
198function 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">&ldquo;{item.quote}&rdquo;</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
232function 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
289function 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
366function 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
396function 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
411export 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}