Skip to content

Commit b3f3a55

Browse files
committed
feat: add scroll-triggered fade-up animations to all landing page sections
1 parent e9d6975 commit b3f3a55

File tree

6 files changed

+170
-52
lines changed

6 files changed

+170
-52
lines changed

components/sections/ArchitectureSection.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"use client";
2+
3+
import { motion } from "framer-motion";
14
import { Container } from "@/components/layout/Container";
25
import { FileText, Image as ImageIcon, Table, ChevronDown } from "lucide-react";
36

@@ -6,7 +9,13 @@ export function ArchitectureSection() {
69
<section id="architecture" className="py-20">
710
<Container>
811
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
9-
<div className="space-y-6">
12+
<motion.div
13+
initial={{ opacity: 0, y: 24 }}
14+
whileInView={{ opacity: 1, y: 0 }}
15+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
16+
viewport={{ once: true, amount: 0.3 }}
17+
className="space-y-6"
18+
>
1019
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
1120
Component-Correlation Tree
1221
</h2>
@@ -39,9 +48,15 @@ export function ArchitectureSection() {
3948
</span>
4049
</li>
4150
</ul>
42-
</div>
51+
</motion.div>
4352

44-
<div className="relative bg-secondary/20 rounded-xl p-8 border border-secondary">
53+
<motion.div
54+
initial={{ opacity: 0, y: 24 }}
55+
whileInView={{ opacity: 1, y: 0 }}
56+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1], delay: 0.05 }}
57+
viewport={{ once: true, amount: 0.3 }}
58+
className="relative bg-secondary/20 rounded-xl p-8 border border-secondary"
59+
>
4560
{/* Tree Visualization */}
4661
<div className="flex flex-col items-center space-y-4">
4762
{/* Root */}
@@ -78,7 +93,7 @@ export function ArchitectureSection() {
7893
</div>
7994
</div>
8095
</div>
81-
</div>
96+
</motion.div>
8297
</div>
8398
</Container>
8499
</section>

components/sections/DemoSection.tsx

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,67 @@
11
"use client";
22

3+
import { motion } from "framer-motion";
34
import { Container } from "@/components/layout/Container";
45

56
export function DemoSection() {
67
return (
78
<section id="demo" className="py-20 bg-secondary/30">
89
<Container>
910
<div className="flex flex-col items-center space-y-8">
10-
<div className="text-center space-y-4 max-w-3xl">
11+
<motion.div
12+
initial={{ opacity: 0, y: 24 }}
13+
whileInView={{ opacity: 1, y: 0 }}
14+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
15+
viewport={{ once: true, amount: 0.3 }}
16+
className="text-center space-y-4 max-w-3xl"
17+
>
1118
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
1219
See MoDora in Action
1320
</h2>
1421
<p className="text-lg text-muted-foreground">
1522
From raw documents to grounded answers. MoDora parses, structures, and reasons over your data.
1623
</p>
17-
</div>
24+
</motion.div>
1825

19-
<div className="relative w-full aspect-video rounded-xl overflow-hidden shadow-2xl border bg-background">
26+
<motion.div
27+
initial={{ opacity: 0, y: 24 }}
28+
whileInView={{ opacity: 1, y: 0 }}
29+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1], delay: 0.05 }}
30+
viewport={{ once: true, amount: 0.3 }}
31+
className="relative w-full aspect-video rounded-xl overflow-hidden shadow-2xl border bg-background"
32+
>
2033
<iframe
2134
src="https://player.vimeo.com/video/1168527529?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479"
2235
frameBorder="0"
2336
allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media"
2437
className="absolute inset-0 w-full h-full"
2538
title="MoDora_Demo"
2639
></iframe>
27-
</div>
40+
</motion.div>
2841

29-
<div className="grid grid-cols-2 md:grid-cols-5 gap-4 w-full max-w-4xl pt-8">
42+
<motion.div
43+
initial={{ opacity: 0, y: 24 }}
44+
whileInView={{ opacity: 1, y: 0 }}
45+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1], delay: 0.1 }}
46+
viewport={{ once: true, amount: 0.3 }}
47+
className="grid grid-cols-2 md:grid-cols-5 gap-4 w-full max-w-4xl pt-8"
48+
>
3049
{["Upload", "Parse", "Tree Build", "Retrieval", "Answer"].map((step, i) => (
31-
<div key={step} className="flex flex-col items-center space-y-2">
50+
<motion.div
51+
key={step}
52+
initial={{ opacity: 0, y: 16 }}
53+
whileInView={{ opacity: 1, y: 0 }}
54+
transition={{ duration: 0.45, ease: [0.22, 1, 0.36, 1], delay: i * 0.05 }}
55+
viewport={{ once: true, amount: 0.2 }}
56+
className="flex flex-col items-center space-y-2"
57+
>
3258
<div className="flex items-center justify-center w-8 h-8 rounded-full bg-primary/10 text-primary font-bold text-sm">
3359
{i + 1}
3460
</div>
3561
<span className="text-sm font-medium">{step}</span>
36-
</div>
62+
</motion.div>
3763
))}
38-
</div>
64+
</motion.div>
3965
</div>
4066
</Container>
4167
</section>

components/sections/FeaturesSection.tsx

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"use client";
2+
3+
import { motion } from "framer-motion";
14
import { Container } from "@/components/layout/Container";
25
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
36
import { FileSearch, Network, Quote, Library } from "lucide-react";
@@ -30,30 +33,50 @@ export function FeaturesSection() {
3033
<section id="features" className="py-20">
3134
<Container>
3235
<div className="space-y-12">
33-
<div className="text-center space-y-4 max-w-3xl mx-auto">
36+
<motion.div
37+
initial={{ opacity: 0, y: 24 }}
38+
whileInView={{ opacity: 1, y: 0 }}
39+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
40+
viewport={{ once: true, amount: 0.3 }}
41+
className="text-center space-y-4 max-w-3xl mx-auto"
42+
>
3443
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
3544
Key Features
3645
</h2>
3746
<p className="text-lg text-muted-foreground">
3847
Built for depth and accuracy. MoDora goes beyond simple text matching.
3948
</p>
40-
</div>
49+
</motion.div>
4150

42-
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
43-
{features.map((feature) => (
44-
<Card key={feature.title} className="border-none shadow-lg bg-secondary/20 hover:bg-secondary/40 transition-colors">
45-
<CardHeader>
46-
<feature.icon className="h-10 w-10 text-primary mb-2" />
47-
<CardTitle>{feature.title}</CardTitle>
48-
</CardHeader>
49-
<CardContent>
50-
<p className="text-muted-foreground">
51-
{feature.description}
52-
</p>
53-
</CardContent>
54-
</Card>
51+
<motion.div
52+
initial={{ opacity: 0, y: 24 }}
53+
whileInView={{ opacity: 1, y: 0 }}
54+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1], delay: 0.05 }}
55+
viewport={{ once: true, amount: 0.2 }}
56+
className="grid grid-cols-1 md:grid-cols-2 gap-6"
57+
>
58+
{features.map((feature, index) => (
59+
<motion.div
60+
key={feature.title}
61+
initial={{ opacity: 0, y: 16 }}
62+
whileInView={{ opacity: 1, y: 0 }}
63+
transition={{ duration: 0.45, ease: [0.22, 1, 0.36, 1], delay: index * 0.06 }}
64+
viewport={{ once: true, amount: 0.2 }}
65+
>
66+
<Card className="border-none shadow-lg bg-secondary/20 hover:bg-secondary/40 transition-colors">
67+
<CardHeader>
68+
<feature.icon className="h-10 w-10 text-primary mb-2" />
69+
<CardTitle>{feature.title}</CardTitle>
70+
</CardHeader>
71+
<CardContent>
72+
<p className="text-muted-foreground">
73+
{feature.description}
74+
</p>
75+
</CardContent>
76+
</Card>
77+
</motion.div>
5578
))}
56-
</div>
79+
</motion.div>
5780
</div>
5881
</Container>
5982
</section>

components/sections/HowItWorksSection.tsx

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"use client";
2+
3+
import { motion } from "framer-motion";
14
import { Container } from "@/components/layout/Container";
25
import { Upload, ScanLine, GitFork, Search, MessageSquare } from "lucide-react";
36

@@ -34,31 +37,50 @@ export function HowItWorksSection() {
3437
<section id="how-it-works" className="py-20 bg-slate-50 dark:bg-slate-900/50">
3538
<Container>
3639
<div className="space-y-12">
37-
<div className="text-center space-y-4">
40+
<motion.div
41+
initial={{ opacity: 0, y: 24 }}
42+
whileInView={{ opacity: 1, y: 0 }}
43+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
44+
viewport={{ once: true, amount: 0.3 }}
45+
className="text-center space-y-4"
46+
>
3847
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
3948
How It Works
4049
</h2>
4150
<p className="text-lg text-muted-foreground">
4251
The MoDora Pipeline
4352
</p>
44-
</div>
53+
</motion.div>
4554

46-
<div className="relative">
55+
<motion.div
56+
initial={{ opacity: 0, y: 24 }}
57+
whileInView={{ opacity: 1, y: 0 }}
58+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1], delay: 0.05 }}
59+
viewport={{ once: true, amount: 0.3 }}
60+
className="relative"
61+
>
4762
{/* Connecting Line (Desktop) */}
4863
<div className="hidden md:block absolute top-1/2 left-0 w-full h-0.5 bg-border -translate-y-1/2 z-0" />
4964

5065
<div className="grid grid-cols-1 md:grid-cols-5 gap-8 relative z-10">
5166
{steps.map((step, index) => (
52-
<div key={step.title} className="flex flex-col items-center text-center bg-background p-6 rounded-lg border shadow-sm">
67+
<motion.div
68+
key={step.title}
69+
initial={{ opacity: 0, y: 16 }}
70+
whileInView={{ opacity: 1, y: 0 }}
71+
transition={{ duration: 0.45, ease: [0.22, 1, 0.36, 1], delay: index * 0.06 }}
72+
viewport={{ once: true, amount: 0.2 }}
73+
className="flex flex-col items-center text-center bg-background p-6 rounded-lg border shadow-sm"
74+
>
5375
<div className="h-12 w-12 rounded-full bg-primary/10 flex items-center justify-center text-primary mb-4">
5476
<step.icon className="h-6 w-6" />
5577
</div>
5678
<h3 className="font-semibold mb-2">{step.title}</h3>
5779
<p className="text-sm text-muted-foreground">{step.description}</p>
58-
</div>
80+
</motion.div>
5981
))}
6082
</div>
61-
</div>
83+
</motion.div>
6284
</div>
6385
</Container>
6486
</section>

components/sections/OpenSourceSection.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"use client";
2+
3+
import { motion } from "framer-motion";
14
import { Container } from "@/components/layout/Container";
25
import { Button } from "@/components/ui/button";
36
import { Github } from "lucide-react";
@@ -7,7 +10,13 @@ export function OpenSourceSection() {
710
return (
811
<section className="py-20 bg-primary text-primary-foreground">
912
<Container>
10-
<div className="flex flex-col items-center text-center space-y-8">
13+
<motion.div
14+
initial={{ opacity: 0, y: 24 }}
15+
whileInView={{ opacity: 1, y: 0 }}
16+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
17+
viewport={{ once: true, amount: 0.3 }}
18+
className="flex flex-col items-center text-center space-y-8"
19+
>
1120
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
1221
Proudly Open Source
1322
</h2>
@@ -20,7 +29,7 @@ export function OpenSourceSection() {
2029
Star on GitHub
2130
</Link>
2231
</Button>
23-
</div>
32+
</motion.div>
2433
</Container>
2534
</section>
2635
);

components/sections/UseCasesSection.tsx

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
"use client";
2+
3+
import { motion } from "framer-motion";
14
import { Container } from "@/components/layout/Container";
25
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
36
import { Microscope, TrendingUp, Code, BookOpen } from "lucide-react";
@@ -30,30 +33,50 @@ export function UseCasesSection() {
3033
<section id="use-cases" className="py-20 bg-slate-50 dark:bg-slate-900/50">
3134
<Container>
3235
<div className="space-y-12">
33-
<div className="text-center space-y-4 max-w-3xl mx-auto">
36+
<motion.div
37+
initial={{ opacity: 0, y: 24 }}
38+
whileInView={{ opacity: 1, y: 0 }}
39+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
40+
viewport={{ once: true, amount: 0.3 }}
41+
className="text-center space-y-4 max-w-3xl mx-auto"
42+
>
3443
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
3544
Use Cases
3645
</h2>
3746
<p className="text-lg text-muted-foreground">
3847
MoDora is designed for information-dense environments.
3948
</p>
40-
</div>
49+
</motion.div>
4150

42-
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
43-
{useCases.map((useCase) => (
44-
<Card key={useCase.title} className="hover:shadow-lg transition-shadow">
45-
<CardHeader>
46-
<useCase.icon className="h-8 w-8 text-primary mb-2" />
47-
<CardTitle className="text-xl">{useCase.title}</CardTitle>
48-
</CardHeader>
49-
<CardContent>
50-
<p className="text-sm text-muted-foreground">
51-
{useCase.description}
52-
</p>
53-
</CardContent>
54-
</Card>
51+
<motion.div
52+
initial={{ opacity: 0, y: 24 }}
53+
whileInView={{ opacity: 1, y: 0 }}
54+
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1], delay: 0.05 }}
55+
viewport={{ once: true, amount: 0.2 }}
56+
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6"
57+
>
58+
{useCases.map((useCase, index) => (
59+
<motion.div
60+
key={useCase.title}
61+
initial={{ opacity: 0, y: 16 }}
62+
whileInView={{ opacity: 1, y: 0 }}
63+
transition={{ duration: 0.45, ease: [0.22, 1, 0.36, 1], delay: index * 0.06 }}
64+
viewport={{ once: true, amount: 0.2 }}
65+
>
66+
<Card className="hover:shadow-lg transition-shadow">
67+
<CardHeader>
68+
<useCase.icon className="h-8 w-8 text-primary mb-2" />
69+
<CardTitle className="text-xl">{useCase.title}</CardTitle>
70+
</CardHeader>
71+
<CardContent>
72+
<p className="text-sm text-muted-foreground">
73+
{useCase.description}
74+
</p>
75+
</CardContent>
76+
</Card>
77+
</motion.div>
5578
))}
56-
</div>
79+
</motion.div>
5780
</div>
5881
</Container>
5982
</section>

0 commit comments

Comments
 (0)