design
This commit is contained in:
184
app/page.tsx
184
app/page.tsx
@@ -1,5 +1,39 @@
|
||||
import { ArrowRight, Check, Database, Layout, Shield, Workflow, X, Zap } from 'lucide-react';
|
||||
import { CirclePattern, ComparisonRow, ConnectorBranch, ConnectorEnd, ConnectorSplit, ConnectorStart, FlowLines, GridLines, HeroLines, ServicesFlow } from '../src/components/Landing';
|
||||
import { ArrowRight } from 'lucide-react';
|
||||
import {
|
||||
CirclePattern,
|
||||
ComparisonRow,
|
||||
ConnectorBranch,
|
||||
ConnectorEnd,
|
||||
ConnectorSplit,
|
||||
ConnectorStart,
|
||||
FlowLines,
|
||||
GridLines,
|
||||
HeroLines,
|
||||
ServicesFlow,
|
||||
DirectCommunication,
|
||||
FastPrototyping,
|
||||
CleanCode,
|
||||
FixedPrice,
|
||||
MinimalistArchitect,
|
||||
WebsitesIllustration,
|
||||
SystemsIllustration,
|
||||
AutomationIllustration,
|
||||
DifferenceIllustration,
|
||||
TargetGroupIllustration,
|
||||
ContactIllustration,
|
||||
PromiseSectionIllustration,
|
||||
ServicesSectionIllustration,
|
||||
ConceptCommunication,
|
||||
ConceptPrototyping,
|
||||
ConceptCode,
|
||||
ConceptPrice,
|
||||
ConceptWebsite,
|
||||
ConceptSystem,
|
||||
ConceptAutomation,
|
||||
ConceptTarget,
|
||||
FloatingParticles,
|
||||
ConceptMessy
|
||||
} from '../src/components/Landing';
|
||||
import { Reveal } from '../src/components/Reveal';
|
||||
import { Section } from '../src/components/Section';
|
||||
|
||||
@@ -15,10 +49,16 @@ export default function LandingPage() {
|
||||
|
||||
{/* Hero Section - Split Layout */}
|
||||
<section className="relative min-h-[80vh] flex items-center pt-12 md:pt-0 pb-24 md:pb-0">
|
||||
<div className="absolute inset-0 pointer-events-none">
|
||||
<FloatingParticles className="w-full h-full" />
|
||||
</div>
|
||||
<div className="narrow-container w-full relative">
|
||||
{/* Connector Start for Hero */}
|
||||
<div className="absolute left-[2.5rem] top-32 bottom-0 w-24 hidden md:block -z-10 pointer-events-none">
|
||||
<ConnectorStart className="h-full" />
|
||||
<div className="absolute top-64 left-0 w-32 h-32 opacity-20">
|
||||
<MinimalistArchitect />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-12 gap-12 md:gap-16 items-center">
|
||||
@@ -60,6 +100,12 @@ export default function LandingPage() {
|
||||
<div className="absolute -top-6 -left-6 w-12 h-12 bg-slate-900 text-white flex items-center justify-center rounded-full font-bold text-xl">
|
||||
01
|
||||
</div>
|
||||
|
||||
{/* Minimalist Architect Illustration in Background */}
|
||||
<div className="absolute right-4 bottom-4 w-24 h-24 opacity-10 -z-10">
|
||||
<MinimalistArchitect />
|
||||
</div>
|
||||
|
||||
<p className="text-xl md:text-2xl font-serif italic text-slate-600 leading-relaxed">
|
||||
"Ich baue digitale Systeme für Unternehmen, die Ergebnisse wollen – ohne Agentur-Zirkus, ohne Overhead, ohne Tech-Blabla."
|
||||
</p>
|
||||
@@ -79,8 +125,17 @@ export default function LandingPage() {
|
||||
</section>
|
||||
|
||||
{/* Section 02: The Promise */}
|
||||
<Section number="02" title="Das Versprechen" borderTop connector={<ConnectorBranch className="h-full" />}>
|
||||
<Section
|
||||
number="02"
|
||||
title="Das Versprechen"
|
||||
borderTop
|
||||
connector={<ConnectorBranch className="h-full" />}
|
||||
illustration={<PromiseSectionIllustration className="w-32 h-32" />}
|
||||
>
|
||||
<div className="space-y-16 relative">
|
||||
<div className="absolute inset-0 pointer-events-none">
|
||||
<FloatingParticles className="w-full h-full" delay={2} />
|
||||
</div>
|
||||
<div className="absolute right-0 top-0 w-64 h-64 -z-10 opacity-30 pointer-events-none">
|
||||
<GridLines />
|
||||
</div>
|
||||
@@ -96,19 +151,23 @@ export default function LandingPage() {
|
||||
<Reveal delay={0.1}>
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-center gap-4 text-slate-900 font-bold text-lg">
|
||||
<div className="w-8 h-8 rounded-full bg-slate-100 flex items-center justify-center"><Check className="w-4 h-4" /></div>
|
||||
<div className="w-12 h-12 rounded-xl bg-slate-50 flex items-center justify-center border border-slate-100">
|
||||
<ConceptCode className="w-8 h-8" />
|
||||
</div>
|
||||
Was ich biete
|
||||
</div>
|
||||
<ul className="space-y-4">
|
||||
<ul className="space-y-8">
|
||||
{[
|
||||
'Direkte Kommunikation ohne Account Manager',
|
||||
'Schnelle Prototypen statt langer Konzepte',
|
||||
'Sauberer Code, der auch morgen noch läuft',
|
||||
'Fixpreise für klare Budgetsicherheit'
|
||||
{ text: 'Direkte Kommunikation ohne Account Manager', icon: <ConceptCommunication className="w-16 h-16" /> },
|
||||
{ text: 'Schnelle Prototypen statt langer Konzepte', icon: <ConceptPrototyping className="w-16 h-16" /> },
|
||||
{ text: 'Sauberer Code, der auch morgen noch läuft', icon: <ConceptCode className="w-16 h-16" /> },
|
||||
{ text: 'Fixpreise für klare Budgetsicherheit', icon: <ConceptPrice className="w-16 h-16" /> }
|
||||
].map((item, i) => (
|
||||
<li key={i} className="flex items-start gap-3 text-slate-600 font-serif italic text-lg">
|
||||
<span className="w-1.5 h-1.5 bg-slate-900 rounded-full mt-2.5 shrink-0"></span>
|
||||
{item}
|
||||
<li key={i} className="flex items-center gap-6 text-slate-600 font-serif italic text-lg group">
|
||||
<div className="shrink-0 opacity-80 group-hover:opacity-100 transition-all duration-500 group-hover:scale-110">
|
||||
{item.icon}
|
||||
</div>
|
||||
{item.text}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
@@ -118,7 +177,9 @@ export default function LandingPage() {
|
||||
<Reveal delay={0.2}>
|
||||
<div className="space-y-8 opacity-50 hover:opacity-100 transition-opacity duration-500">
|
||||
<div className="flex items-center gap-4 text-slate-400 font-bold text-lg">
|
||||
<div className="w-8 h-8 rounded-full bg-slate-50 flex items-center justify-center"><X className="w-4 h-4" /></div>
|
||||
<div className="w-12 h-12 rounded-xl bg-slate-50 flex items-center justify-center border border-slate-100 grayscale">
|
||||
<ConceptMessy className="w-8 h-8" />
|
||||
</div>
|
||||
Was ich nicht mache
|
||||
</div>
|
||||
<ul className="space-y-4">
|
||||
@@ -141,13 +202,25 @@ export default function LandingPage() {
|
||||
</Section>
|
||||
|
||||
{/* Section 03: The Difference */}
|
||||
<Section number="03" title="Der Unterschied" variant="white" borderTop connector={<ConnectorStart className="h-full" />}>
|
||||
<Section
|
||||
number="03"
|
||||
title="Der Unterschied"
|
||||
variant="white"
|
||||
borderTop
|
||||
connector={<ConnectorStart className="h-full" />}
|
||||
illustration={<DifferenceIllustration className="w-32 h-32" />}
|
||||
>
|
||||
<div className="space-y-12 relative">
|
||||
<Reveal>
|
||||
<p className="text-xl md:text-2xl font-serif italic text-slate-600 max-w-2xl relative z-10">
|
||||
Der klassische Agentur-Weg ist oft langsam und teuer. Mein Ansatz ist radikal anders: Ich baue zuerst, dann reden wir über Details.
|
||||
</p>
|
||||
</Reveal>
|
||||
<div className="flex flex-col md:flex-row gap-12 items-center">
|
||||
<Reveal className="flex-1">
|
||||
<p className="text-xl md:text-2xl font-serif italic text-slate-600 max-w-2xl relative z-10">
|
||||
Der klassische Agentur-Weg ist oft langsam und teuer. Mein Ansatz ist radikal anders: Ich baue zuerst, dann reden wir über Details.
|
||||
</p>
|
||||
</Reveal>
|
||||
<Reveal delay={0.2} className="w-full md:w-80 shrink-0">
|
||||
<DifferenceIllustration className="w-full h-auto" />
|
||||
</Reveal>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-6 relative z-20">
|
||||
<ComparisonRow
|
||||
@@ -177,7 +250,13 @@ export default function LandingPage() {
|
||||
</Section>
|
||||
|
||||
{/* Section 04: Target Group */}
|
||||
<Section number="04" title="Zielgruppe" borderTop connector={<ConnectorSplit className="h-full" />}>
|
||||
<Section
|
||||
number="04"
|
||||
title="Zielgruppe"
|
||||
borderTop
|
||||
connector={<ConnectorSplit className="h-full" />}
|
||||
illustration={<TargetGroupIllustration className="w-32 h-32" />}
|
||||
>
|
||||
<div className="relative">
|
||||
<div className="absolute left-0 top-0 w-full h-full -z-10 opacity-30 pointer-events-none">
|
||||
<CirclePattern />
|
||||
@@ -185,9 +264,12 @@ export default function LandingPage() {
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 relative z-10">
|
||||
<Reveal>
|
||||
<div className="p-10 bg-slate-900 text-white rounded-3xl h-full flex flex-col justify-between group hover:scale-[1.02] transition-transform duration-500 shadow-2xl shadow-slate-900/20">
|
||||
<div className="space-y-6">
|
||||
<div className="w-12 h-12 bg-white/10 rounded-xl flex items-center justify-center">
|
||||
<Zap className="w-6 h-6 text-white" />
|
||||
<div className="space-y-6 relative overflow-hidden">
|
||||
<div className="absolute -right-4 -top-4 w-32 h-32 opacity-20 pointer-events-none">
|
||||
<ConceptTarget className="w-full h-full" />
|
||||
</div>
|
||||
<div className="w-16 h-16 bg-white/10 rounded-2xl flex items-center justify-center">
|
||||
<ConceptPrice className="w-10 h-10" />
|
||||
</div>
|
||||
<h3 className="text-3xl font-bold tracking-tight text-white">Unternehmer & <br/>Geschäftsführer</h3>
|
||||
<p className="text-slate-300 font-serif italic text-lg leading-relaxed">
|
||||
@@ -201,9 +283,12 @@ export default function LandingPage() {
|
||||
</Reveal>
|
||||
<Reveal delay={0.2}>
|
||||
<div className="p-10 bg-white border border-slate-100 rounded-3xl h-full flex flex-col justify-between group hover:border-slate-300 transition-colors duration-500 shadow-xl shadow-slate-100/50">
|
||||
<div className="space-y-6">
|
||||
<div className="w-12 h-12 bg-slate-50 border border-slate-200 rounded-xl flex items-center justify-center">
|
||||
<Shield className="w-6 h-6 text-slate-900" />
|
||||
<div className="space-y-6 relative overflow-hidden">
|
||||
<div className="absolute -right-4 -top-4 w-32 h-32 opacity-10 pointer-events-none">
|
||||
<ConceptTarget className="w-full h-full" />
|
||||
</div>
|
||||
<div className="w-16 h-16 bg-slate-50 border border-slate-200 rounded-2xl flex items-center justify-center">
|
||||
<ConceptWebsite className="w-10 h-10" />
|
||||
</div>
|
||||
<h3 className="text-3xl font-bold tracking-tight text-slate-900">Marketing & <br/>Vertrieb</h3>
|
||||
<p className="text-slate-600 font-serif italic text-lg leading-relaxed">
|
||||
@@ -220,7 +305,14 @@ export default function LandingPage() {
|
||||
</Section>
|
||||
|
||||
{/* Section 05: Services - Visual Flow */}
|
||||
<Section number="05" title="Leistungen" variant="gray" borderTop connector={<ConnectorBranch className="h-full" />}>
|
||||
<Section
|
||||
number="05"
|
||||
title="Leistungen"
|
||||
variant="gray"
|
||||
borderTop
|
||||
connector={<ConnectorBranch className="h-full" />}
|
||||
illustration={<ServicesSectionIllustration className="w-32 h-32" />}
|
||||
>
|
||||
<div className="relative py-12">
|
||||
{/* Connecting Line Illustration */}
|
||||
<div className="absolute top-1/2 left-0 w-full -translate-y-1/2 hidden md:block">
|
||||
@@ -229,9 +321,12 @@ export default function LandingPage() {
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 relative z-20">
|
||||
<Reveal delay={0.1}>
|
||||
<div className="bg-white p-8 rounded-2xl border border-slate-100 shadow-lg hover:shadow-xl transition-all duration-300 group h-full">
|
||||
<div className="w-16 h-16 bg-slate-50 rounded-2xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-500">
|
||||
<Layout className="w-8 h-8 text-slate-900" />
|
||||
<div className="bg-white p-8 rounded-2xl border border-slate-100 shadow-lg hover:shadow-xl transition-all duration-300 group h-full relative overflow-hidden">
|
||||
<div className="absolute -right-4 -top-4 w-32 h-32 opacity-[0.1] group-hover:opacity-[0.2] transition-opacity duration-500 pointer-events-none">
|
||||
<ConceptWebsite />
|
||||
</div>
|
||||
<div className="w-20 h-20 bg-slate-50 rounded-2xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-500">
|
||||
<ConceptWebsite className="w-12 h-12" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-slate-900 mb-4">Websites</h3>
|
||||
<p className="text-slate-500 font-serif italic mb-6">
|
||||
@@ -244,9 +339,12 @@ export default function LandingPage() {
|
||||
</Reveal>
|
||||
|
||||
<Reveal delay={0.3}>
|
||||
<div className="bg-white p-8 rounded-2xl border border-slate-100 shadow-lg hover:shadow-xl transition-all duration-300 group h-full mt-8 md:mt-0">
|
||||
<div className="w-16 h-16 bg-slate-50 rounded-2xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-500">
|
||||
<Database className="w-8 h-8 text-slate-900" />
|
||||
<div className="bg-white p-8 rounded-2xl border border-slate-100 shadow-lg hover:shadow-xl transition-all duration-300 group h-full mt-8 md:mt-0 relative overflow-hidden">
|
||||
<div className="absolute -right-4 -top-4 w-32 h-32 opacity-[0.1] group-hover:opacity-[0.2] transition-opacity duration-500 pointer-events-none">
|
||||
<ConceptSystem />
|
||||
</div>
|
||||
<div className="w-20 h-20 bg-slate-50 rounded-2xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-500">
|
||||
<ConceptSystem className="w-12 h-12" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-slate-900 mb-4">Systeme</h3>
|
||||
<p className="text-slate-500 font-serif italic">
|
||||
@@ -256,9 +354,12 @@ export default function LandingPage() {
|
||||
</Reveal>
|
||||
|
||||
<Reveal delay={0.5}>
|
||||
<div className="bg-white p-8 rounded-2xl border border-slate-100 shadow-lg hover:shadow-xl transition-all duration-300 group h-full">
|
||||
<div className="w-16 h-16 bg-slate-50 rounded-2xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-500">
|
||||
<Workflow className="w-8 h-8 text-slate-900" />
|
||||
<div className="bg-white p-8 rounded-2xl border border-slate-100 shadow-lg hover:shadow-xl transition-all duration-300 group h-full relative overflow-hidden">
|
||||
<div className="absolute -right-4 -top-4 w-32 h-32 opacity-[0.1] group-hover:opacity-[0.2] transition-opacity duration-500 pointer-events-none">
|
||||
<ConceptAutomation />
|
||||
</div>
|
||||
<div className="w-20 h-20 bg-slate-50 rounded-2xl flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-500">
|
||||
<ConceptAutomation className="w-12 h-12" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-slate-900 mb-4">Automatisierung</h3>
|
||||
<p className="text-slate-500 font-serif italic">
|
||||
@@ -271,11 +372,20 @@ export default function LandingPage() {
|
||||
</Section>
|
||||
|
||||
{/* Section 06: Contact */}
|
||||
<Section number="06" title="Kontakt" borderTop connector={<ConnectorEnd className="h-full" />}>
|
||||
<Section
|
||||
number="06"
|
||||
title="Kontakt"
|
||||
borderTop
|
||||
connector={<ConnectorEnd className="h-full" />}
|
||||
illustration={<ContactIllustration className="w-32 h-32" />}
|
||||
>
|
||||
<div className="relative py-12" id="contact">
|
||||
<div className="absolute right-0 top-1/2 -translate-y-1/2 w-[400px] h-[200px] -z-10 opacity-40 pointer-events-none">
|
||||
<FlowLines />
|
||||
</div>
|
||||
<div className="absolute left-1/2 top-0 -translate-x-1/2 w-32 h-32 opacity-10 -z-10">
|
||||
<ContactIllustration />
|
||||
</div>
|
||||
<Reveal>
|
||||
<div className="space-y-12">
|
||||
<h2 className="text-5xl md:text-7xl font-bold text-slate-900 tracking-tighter leading-[0.9]">
|
||||
|
||||
245
src/components/Landing/ConceptIllustrations.tsx
Normal file
245
src/components/Landing/ConceptIllustrations.tsx
Normal file
@@ -0,0 +1,245 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface IllustrationProps {
|
||||
className?: string;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
export const ConceptCommunication: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="20" cy="60" r="6" className="fill-slate-100 stroke-slate-200" strokeWidth="1" />
|
||||
<circle cx="100" cy="60" r="6" className="fill-slate-900" />
|
||||
<path d="M 26 60 H 94" stroke="currentColor" strokeWidth="1" className="text-slate-100" strokeDasharray="4 4" />
|
||||
<motion.path
|
||||
d="M 26 60 H 94"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
className="text-slate-400"
|
||||
initial={{ pathLength: 0 }}
|
||||
animate={{ pathLength: [0, 1, 1, 0], opacity: [0, 1, 1, 0] }}
|
||||
transition={{ duration: 3, repeat: Infinity, ease: "easeInOut", delay }}
|
||||
/>
|
||||
<motion.circle r="3" className="fill-slate-900">
|
||||
<animateMotion
|
||||
dur="3s"
|
||||
repeatCount="indefinite"
|
||||
path="M 26 60 H 94"
|
||||
/>
|
||||
</motion.circle>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ConceptPrototyping: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="15" y="25" width="90" height="70" rx="4" stroke="currentColor" strokeWidth="1" className="text-slate-200" />
|
||||
<path d="M 15 40 H 105" stroke="currentColor" strokeWidth="1" className="text-slate-100" />
|
||||
<motion.rect
|
||||
x="25" y="50" width="40" height="8" rx="1"
|
||||
className="fill-slate-100"
|
||||
animate={{ width: [0, 40, 40, 0] }}
|
||||
transition={{ duration: 4, repeat: Infinity, delay }}
|
||||
/>
|
||||
<motion.rect
|
||||
x="25" y="65" width="60" height="8" rx="1"
|
||||
className="fill-slate-50"
|
||||
animate={{ width: [0, 60, 60, 0] }}
|
||||
transition={{ duration: 4, repeat: Infinity, delay: 0.5 }}
|
||||
/>
|
||||
<motion.circle
|
||||
cx="85" cy="75" r="10"
|
||||
className="fill-slate-900"
|
||||
animate={{ scale: [0.8, 1.1, 0.8] }}
|
||||
transition={{ duration: 2, repeat: Infinity }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ConceptCode: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
{[40, 55, 70, 85].map((y, i) => (
|
||||
<motion.path
|
||||
key={y}
|
||||
d={`M 25 ${y} H ${25 + Math.random() * 60 + 20}`}
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
className="text-slate-200"
|
||||
initial={{ pathLength: 0 }}
|
||||
animate={{ pathLength: [0, 1, 1, 0] }}
|
||||
transition={{ duration: 4, repeat: Infinity, delay: i * 0.2 + delay }}
|
||||
/>
|
||||
))}
|
||||
<motion.path
|
||||
d="M 90 40 L 100 50 L 115 30"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="text-slate-900"
|
||||
animate={{ opacity: [0, 1, 1, 0], scale: [0.8, 1, 1, 0.8] }}
|
||||
transition={{ duration: 4, repeat: Infinity, delay: 1.5 }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ConceptPrice: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="30" y="30" width="60" height="70" rx="2" stroke="currentColor" strokeWidth="1" className="text-slate-200" />
|
||||
<motion.path
|
||||
d="M 40 50 H 80 M 40 65 H 80 M 40 80 H 60"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1"
|
||||
className="text-slate-100"
|
||||
initial={{ pathLength: 0 }}
|
||||
animate={{ pathLength: [0, 1, 1, 0] }}
|
||||
transition={{ duration: 5, repeat: Infinity, delay }}
|
||||
/>
|
||||
<motion.circle
|
||||
cx="85" cy="35" r="15"
|
||||
className="fill-white stroke-slate-900"
|
||||
strokeWidth="1"
|
||||
animate={{ y: [0, -5, 0], rotate: [0, 10, 0] }}
|
||||
transition={{ duration: 4, repeat: Infinity }}
|
||||
/>
|
||||
<text x="78" y="40" className="fill-slate-900 font-bold text-[10px]">€</text>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ConceptWebsite: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="10" y="20" width="100" height="80" rx="4" stroke="currentColor" strokeWidth="1" className="text-slate-200" />
|
||||
<motion.rect
|
||||
x="20" y="35" width="80" height="15" rx="2"
|
||||
className="fill-slate-50"
|
||||
animate={{ opacity: [0.3, 0.6, 0.3] }}
|
||||
transition={{ duration: 3, repeat: Infinity }}
|
||||
/>
|
||||
<motion.div
|
||||
animate={{ y: [0, 10, 0] }}
|
||||
transition={{ duration: 4, repeat: Infinity }}
|
||||
>
|
||||
<rect x="20" y="55" width="35" height="35" rx="2" className="fill-slate-100" />
|
||||
<rect x="65" y="55" width="35" height="35" rx="2" className="fill-slate-100" />
|
||||
</motion.div>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ConceptSystem: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.circle cx="60" cy="60" r="15" className="fill-slate-900" />
|
||||
{[0, 72, 144, 216, 288].map((angle, i) => {
|
||||
const x = 60 + Math.cos((angle * Math.PI) / 180) * 40;
|
||||
const y = 60 + Math.sin((angle * Math.PI) / 180) * 40;
|
||||
return (
|
||||
<React.Fragment key={i}>
|
||||
<motion.line
|
||||
x1="60" y1="60" x2={x} y2={y}
|
||||
stroke="currentColor" strokeWidth="1" className="text-slate-200"
|
||||
animate={{ strokeDashoffset: [0, 10] }}
|
||||
strokeDasharray="2 2"
|
||||
transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
|
||||
/>
|
||||
<motion.circle
|
||||
cx={x} cy={y} r="6"
|
||||
className="fill-white stroke-slate-300"
|
||||
animate={{ scale: [1, 1.2, 1] }}
|
||||
transition={{ duration: 3, repeat: Infinity, delay: i * 0.4 }}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ConceptAutomation: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.g
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 10, repeat: Infinity, ease: "linear" }}
|
||||
style={{ originX: "40px", originY: "60px" }}
|
||||
>
|
||||
<path d="M 40 45 L 50 60 L 40 75 L 30 60 Z" className="fill-slate-200" />
|
||||
</motion.g>
|
||||
<motion.g
|
||||
animate={{ rotate: -360 }}
|
||||
transition={{ duration: 10, repeat: Infinity, ease: "linear" }}
|
||||
style={{ originX: "75px", originY: "65px" }}
|
||||
>
|
||||
<path d="M 75 50 L 85 65 L 75 80 L 65 65 Z" className="fill-slate-400" />
|
||||
</motion.g>
|
||||
<motion.path
|
||||
d="M 10 60 H 110"
|
||||
stroke="currentColor" strokeWidth="1" className="text-slate-100"
|
||||
strokeDasharray="4 4"
|
||||
animate={{ strokeDashoffset: [0, -20] }}
|
||||
transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ConceptMessy: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.path
|
||||
d="M 20 60 C 30 20, 40 100, 50 60 C 60 20, 70 100, 80 60 C 90 20, 100 100, 110 60"
|
||||
stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
animate={{ strokeDashoffset: [0, 20] }}
|
||||
strokeDasharray="4 4"
|
||||
transition={{ duration: 5, repeat: Infinity, ease: "linear" }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 20 40 L 100 80 M 20 80 L 100 40"
|
||||
stroke="currentColor" strokeWidth="1" className="text-slate-200 opacity-50"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const FloatingParticles: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
{[...Array(10)].map((_, i) => (
|
||||
<motion.circle
|
||||
key={i}
|
||||
r={Math.random() * 2 + 1}
|
||||
className="fill-slate-200"
|
||||
initial={{
|
||||
x: Math.random() * 200,
|
||||
y: Math.random() * 200,
|
||||
opacity: 0
|
||||
}}
|
||||
animate={{
|
||||
y: [null, Math.random() * -50 - 20],
|
||||
opacity: [0, 0.5, 0]
|
||||
}}
|
||||
transition={{
|
||||
duration: Math.random() * 5 + 5,
|
||||
repeat: Infinity,
|
||||
delay: Math.random() * 5 + delay,
|
||||
ease: "linear"
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ConceptTarget: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.circle
|
||||
cx="60" cy="60" r="50"
|
||||
stroke="currentColor" strokeWidth="1" className="text-slate-100"
|
||||
animate={{ scale: [1, 1.05, 1] }}
|
||||
transition={{ duration: 4, repeat: Infinity }}
|
||||
/>
|
||||
<motion.circle
|
||||
cx="60" cy="60" r="30"
|
||||
stroke="currentColor" strokeWidth="1" className="text-slate-200"
|
||||
/>
|
||||
<motion.circle
|
||||
cx="60" cy="60" r="10"
|
||||
className="fill-slate-900"
|
||||
animate={{ opacity: [0.5, 1, 0.5] }}
|
||||
transition={{ duration: 2, repeat: Infinity }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
313
src/components/Landing/ExplanatoryIllustrations.tsx
Normal file
313
src/components/Landing/ExplanatoryIllustrations.tsx
Normal file
@@ -0,0 +1,313 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface IllustrationProps {
|
||||
className?: string;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
export const DirectCommunication: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.circle
|
||||
cx="20" cy="60" r="4"
|
||||
className="fill-slate-400"
|
||||
initial={{ scale: 0 }}
|
||||
whileInView={{ scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: delay }}
|
||||
/>
|
||||
<motion.circle
|
||||
cx="100" cy="60" r="4"
|
||||
className="fill-slate-900"
|
||||
initial={{ scale: 0 }}
|
||||
whileInView={{ scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: delay + 0.2 }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 24 60 H 96"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1"
|
||||
className="text-slate-300"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 1, delay: delay + 0.4 }}
|
||||
/>
|
||||
<motion.circle r="2" className="fill-slate-400">
|
||||
<animateMotion
|
||||
dur="3s"
|
||||
repeatCount="indefinite"
|
||||
path="M 24 60 H 96"
|
||||
/>
|
||||
</motion.circle>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const FastPrototyping: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.rect
|
||||
x="20" y="30" width="80" height="60" rx="4"
|
||||
stroke="currentColor" strokeWidth="1"
|
||||
className="text-slate-300"
|
||||
initial={{ pathLength: 0, opacity: 0 }}
|
||||
whileInView={{ pathLength: 1, opacity: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 1, delay: delay }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 20 45 H 100"
|
||||
stroke="currentColor" strokeWidth="1"
|
||||
className="text-slate-200"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: delay + 0.5 }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 45 55 L 75 65 L 45 75 Z"
|
||||
className="fill-slate-200 stroke-slate-300"
|
||||
strokeWidth="1"
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: delay + 0.8 }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 85 37 H 90"
|
||||
stroke="currentColor" strokeWidth="1"
|
||||
className="text-slate-300"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: delay + 1 }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const CleanCode: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.path
|
||||
d="M 30 40 H 70"
|
||||
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
|
||||
className="text-slate-300"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: delay }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 30 55 H 90"
|
||||
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
|
||||
className="text-slate-200"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: delay + 0.2 }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 30 70 H 60"
|
||||
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
|
||||
className="text-slate-300"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: delay + 0.4 }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 30 85 H 80"
|
||||
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
|
||||
className="text-slate-200"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: delay + 0.6 }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 85 45 L 95 55 L 110 35"
|
||||
stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
|
||||
className="text-slate-900"
|
||||
initial={{ pathLength: 0, opacity: 0 }}
|
||||
whileInView={{ pathLength: 1, opacity: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: delay + 1 }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const FixedPrice: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.rect
|
||||
x="35" y="35" width="50" height="50" rx="2"
|
||||
stroke="currentColor" strokeWidth="1"
|
||||
className="text-slate-300"
|
||||
initial={{ pathLength: 0, opacity: 0 }}
|
||||
whileInView={{ pathLength: 1, opacity: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 1, delay: delay }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 45 50 H 75 M 45 60 H 75 M 45 70 H 65"
|
||||
stroke="currentColor" strokeWidth="1"
|
||||
className="text-slate-200"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.8, delay: delay + 0.5 }}
|
||||
/>
|
||||
<motion.circle
|
||||
cx="85" cy="35" r="12"
|
||||
className="fill-white stroke-slate-900"
|
||||
strokeWidth="1"
|
||||
initial={{ scale: 0 }}
|
||||
whileInView={{ scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ type: "spring", stiffness: 200, damping: 10, delay: delay + 1 }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 80 35 L 83 38 L 90 31"
|
||||
stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"
|
||||
className="text-slate-900"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.3, delay: delay + 1.3 }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const WebsitesIllustration: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.rect x="20" y="30" width="80" height="60" rx="2" stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay }} />
|
||||
<motion.path d="M 20 42 H 100" stroke="currentColor" strokeWidth="1" className="text-slate-200"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ delay: delay + 0.5 }} />
|
||||
<motion.rect x="30" y="50" width="25" height="30" rx="1" stroke="currentColor" strokeWidth="1" className="text-slate-200"
|
||||
initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} viewport={{ once: true }} transition={{ delay: delay + 0.8 }} />
|
||||
<motion.path d="M 65 55 H 90 M 65 65 H 90 M 65 75 H 80" stroke="currentColor" strokeWidth="1" className="text-slate-200"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ delay: delay + 1 }} />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const SystemsIllustration: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.path d="M 40 30 L 20 40 V 80 L 40 90 L 60 80 V 40 L 40 30 Z" stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay }} />
|
||||
<motion.path d="M 80 50 L 60 60 V 100 L 80 110 L 100 100 V 60 L 80 50 Z" stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay: delay + 0.3 }} />
|
||||
<motion.path d="M 60 60 L 40 50" stroke="currentColor" strokeWidth="1" strokeDasharray="2 2" className="text-slate-300"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ delay: delay + 0.8 }} />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AutomationIllustration: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.circle cx="45" cy="45" r="15" stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay }} />
|
||||
<motion.circle cx="75" cy="75" r="15" stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay: delay + 0.2 }} />
|
||||
<motion.path d="M 55 55 L 65 65" stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ delay: delay + 0.5 }} />
|
||||
<motion.path d="M 62 58 L 65 65 L 58 62" stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} viewport={{ once: true }} transition={{ delay: delay + 0.7 }} />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const MinimalistArchitect: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.path
|
||||
d="M 40 160 V 60 L 100 30 L 160 60 V 160"
|
||||
stroke="currentColor" strokeWidth="1"
|
||||
className="text-slate-300"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 1.5, delay: delay }}
|
||||
/>
|
||||
<motion.path
|
||||
d="M 40 100 H 160 M 100 30 V 160"
|
||||
stroke="currentColor" strokeWidth="0.5"
|
||||
className="text-slate-200"
|
||||
initial={{ pathLength: 0 }}
|
||||
whileInView={{ pathLength: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 1, delay: delay + 0.5 }}
|
||||
/>
|
||||
<motion.rect
|
||||
x="85" y="120" width="30" height="40"
|
||||
stroke="currentColor" strokeWidth="1"
|
||||
className="text-slate-300"
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: delay + 1, duration: 0.5 }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const DifferenceIllustration: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 200 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
{/* Messy Path */}
|
||||
<motion.path
|
||||
d="M 20 50 C 30 20, 40 80, 50 50 C 60 20, 70 80, 80 50"
|
||||
stroke="currentColor" strokeWidth="1" className="text-slate-200"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 2, delay }}
|
||||
/>
|
||||
{/* Arrow to clean side */}
|
||||
<motion.path
|
||||
d="M 90 50 H 110"
|
||||
stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} viewport={{ once: true }} transition={{ delay: delay + 1 }}
|
||||
/>
|
||||
{/* Clean Path */}
|
||||
<motion.path
|
||||
d="M 120 50 H 180"
|
||||
stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="text-slate-900"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay: delay + 1.5 }}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const TargetGroupIllustration: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.circle cx="60" cy="40" r="20" stroke="currentColor" strokeWidth="1" className="text-slate-200"
|
||||
initial={{ scale: 0 }} whileInView={{ scale: 1 }} viewport={{ once: true }} transition={{ delay }} />
|
||||
<motion.path d="M 30 90 C 30 70, 90 70, 90 90" stroke="currentColor" strokeWidth="1" className="text-slate-200"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ delay: delay + 0.3 }} />
|
||||
<motion.path d="M 50 20 L 60 10 L 70 20" stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} viewport={{ once: true }} transition={{ delay: delay + 0.6 }} />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ContactIllustration: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.rect x="20" y="35" width="80" height="50" rx="2" stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay }} />
|
||||
<motion.path d="M 20 35 L 60 65 L 100 35" stroke="currentColor" strokeWidth="1" className="text-slate-200"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 0.8, delay: delay + 0.5 }} />
|
||||
<motion.circle cx="90" cy="35" r="5" className="fill-green-500"
|
||||
initial={{ scale: 0 }} whileInView={{ scale: 1 }} viewport={{ once: true }} transition={{ type: "spring", delay: delay + 1.2 }} />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const PromiseSectionIllustration: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.path d="M 20 60 L 50 90 L 100 30" stroke="currentColor" strokeWidth="2" className="text-slate-300"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay }} />
|
||||
<motion.path d="M 40 50 H 80 M 40 70 H 70" stroke="currentColor" strokeWidth="1" className="text-slate-100"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ delay: delay + 0.5 }} />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ServicesSectionIllustration: React.FC<IllustrationProps> = ({ className = "", delay = 0 }) => (
|
||||
<svg className={className} viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<motion.rect x="20" y="20" width="80" height="80" rx="4" stroke="currentColor" strokeWidth="1" className="text-slate-200"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay }} />
|
||||
<motion.circle cx="60" cy="60" r="20" stroke="currentColor" strokeWidth="1" className="text-slate-300"
|
||||
initial={{ scale: 0 }} whileInView={{ scale: 1 }} viewport={{ once: true }} transition={{ delay: delay + 0.5 }} />
|
||||
<motion.path d="M 60 40 V 80 M 40 60 H 80" stroke="currentColor" strokeWidth="1" className="text-slate-100"
|
||||
initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ delay: delay + 0.8 }} />
|
||||
</svg>
|
||||
);
|
||||
@@ -1,4 +1,6 @@
|
||||
export * from './AbstractLines';
|
||||
export * from './ExplanatoryIllustrations';
|
||||
export * from './ConceptIllustrations';
|
||||
export * from './ComparisonRow';
|
||||
export * from './FeatureCard';
|
||||
export * from './HeroItem';
|
||||
|
||||
@@ -10,6 +10,7 @@ interface SectionProps {
|
||||
variant?: 'white' | 'gray';
|
||||
borderTop?: boolean;
|
||||
connector?: React.ReactNode;
|
||||
illustration?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Section: React.FC<SectionProps> = ({
|
||||
@@ -21,12 +22,13 @@ export const Section: React.FC<SectionProps> = ({
|
||||
variant = 'white',
|
||||
borderTop = false,
|
||||
connector,
|
||||
illustration,
|
||||
}) => {
|
||||
const bgClass = variant === 'gray' ? 'bg-slate-50' : 'bg-white';
|
||||
const borderClass = borderTop ? 'border-t border-slate-100' : '';
|
||||
|
||||
return (
|
||||
<section className={`relative py-24 md:py-32 ${bgClass} ${borderClass} ${className}`}>
|
||||
<section className={`relative py-24 md:py-32 group ${bgClass} ${borderClass} ${className}`}>
|
||||
<div className="narrow-container">
|
||||
<div className="grid grid-cols-1 md:grid-cols-12 gap-12 md:gap-16">
|
||||
{/* Sidebar: Number & Title */}
|
||||
@@ -56,6 +58,13 @@ export const Section: React.FC<SectionProps> = ({
|
||||
</div>
|
||||
</Reveal>
|
||||
)}
|
||||
{illustration && (
|
||||
<Reveal delay={delay + 0.2}>
|
||||
<div className="pt-12 opacity-20 group-hover:opacity-100 transition-opacity duration-700">
|
||||
{illustration}
|
||||
</div>
|
||||
</Reveal>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user