Skip to content

Commit 71dec85

Browse files
feat: improve landing page sections
1 parent a4e1737 commit 71dec85

File tree

5 files changed

+211
-159
lines changed

5 files changed

+211
-159
lines changed

Diff for: src/components/Home/PageNavigation.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,23 @@ export const PageNavigation = () => {
1919
}
2020

2121
const NavLink = ({ href, label }: { href: string; label: string }) => {
22+
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
23+
e.preventDefault()
24+
const targetId = href.substring(1)
25+
const targetElement = document.getElementById(targetId)
26+
27+
if (targetElement) {
28+
targetElement.scrollIntoView({
29+
behavior: 'smooth',
30+
block: 'start',
31+
})
32+
}
33+
}
34+
2235
return (
2336
<motion.a
2437
href={href}
38+
onClick={handleClick}
2539
className="relative px-2 !text-primary"
2640
whileHover={{ scale: 1.05 }}
2741
whileTap={{ scale: 0.95 }}

Diff for: src/components/Home/Sections/AdditionalFeaturesSection.tsx

+163-118
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,138 @@
11
import Link from 'next/link'
2-
import { useContext } from 'react'
2+
import { useContext, ReactNode } from 'react'
33
import { motion } from 'framer-motion'
44
import { useInView } from 'react-intersection-observer'
55

66
import { ModalContext } from 'src/contexts'
77
import { PlayType } from 'src/types'
88
import { StarIcon, TuringIcon } from 'src/components/Icons/icons'
99

10+
const animationVariants = {
11+
container: {
12+
hidden: { opacity: 0 },
13+
visible: {
14+
opacity: 1,
15+
transition: {
16+
staggerChildren: 0.1,
17+
},
18+
},
19+
},
20+
item: {
21+
hidden: { y: 30, opacity: 0 },
22+
visible: {
23+
y: 0,
24+
opacity: 1,
25+
transition: { duration: 0.3, ease: 'easeOut' },
26+
},
27+
},
28+
fadeIn: (delay = 0) => ({
29+
initial: { opacity: 0, y: -10 },
30+
animate: (inView: boolean) =>
31+
inView ? { opacity: 1, y: 0 } : { opacity: 0, y: -10 },
32+
transition: { duration: 0.3, delay, ease: 'easeOut' },
33+
}),
34+
}
35+
1036
interface AdditionalFeaturesSectionProps {
1137
id: string
1238
}
1339

40+
type FeatureActionType =
41+
| { type: 'link'; href: string; label: string }
42+
| { type: 'button'; onClick: () => void; label: string }
43+
44+
interface Feature {
45+
icon: ReactNode
46+
title: string
47+
description: string
48+
action: FeatureActionType
49+
iconBgColor: string
50+
iconTextColor: string
51+
}
52+
53+
// Feature Card Component
54+
const FeatureCard = ({
55+
feature,
56+
variants,
57+
}: {
58+
feature: Feature
59+
variants: any
60+
}) => {
61+
const { icon, title, description, action, iconBgColor, iconTextColor } =
62+
feature
63+
64+
return (
65+
<motion.div
66+
className="hover:scale-102 flex flex-col rounded-lg bg-background-2 p-5 shadow-lg transition-transform duration-200"
67+
variants={variants}
68+
>
69+
<div
70+
className={`mb-4 flex h-12 w-12 items-center justify-center rounded-full ${iconBgColor} p-2`}
71+
>
72+
<div className={`h-7 w-7 ${iconTextColor}`}>{icon}</div>
73+
</div>
74+
<h3 className="mb-3 text-xl font-bold">{title}</h3>
75+
<p className="mb-5 flex-grow text-primary/80">{description}</p>
76+
77+
{action.type === 'link' ? (
78+
<motion.div
79+
whileHover={{ scale: 1.05 }}
80+
whileTap={{ scale: 0.95 }}
81+
transition={{ duration: 0.2 }}
82+
>
83+
<Link
84+
href={action.href}
85+
className="mt-auto inline-flex items-center justify-center rounded-md bg-background-3 px-5 py-3 font-medium"
86+
>
87+
{action.label}
88+
</Link>
89+
</motion.div>
90+
) : (
91+
<motion.button
92+
onClick={action.onClick}
93+
className="mt-auto inline-flex items-center justify-center rounded-md bg-background-3 px-5 py-3 font-medium"
94+
whileHover={{ scale: 1.05 }}
95+
whileTap={{ scale: 0.95 }}
96+
transition={{ duration: 0.2 }}
97+
>
98+
{action.label}
99+
</motion.button>
100+
)}
101+
</motion.div>
102+
)
103+
}
104+
105+
const SectionHeader = ({ inView }: { inView: boolean }) => {
106+
const fadeInVariants = animationVariants.fadeIn
107+
108+
return (
109+
<div className="max-w-3xl text-left">
110+
<motion.div
111+
{...fadeInVariants(0)}
112+
animate={fadeInVariants(0).animate(inView)}
113+
className="mb-2 inline-block rounded-full bg-human-3/10 px-4 py-1 text-sm font-medium text-human-3"
114+
>
115+
More Features
116+
</motion.div>
117+
<motion.h2
118+
className="mb-4 text-3xl font-bold md:text-4xl lg:text-5xl"
119+
{...fadeInVariants(0.1)}
120+
animate={fadeInVariants(0.1).animate(inView)}
121+
>
122+
Explore other ways to use Maia
123+
</motion.h2>
124+
<motion.p
125+
className="max-w-2xl text-lg text-primary/80"
126+
{...fadeInVariants(0.2)}
127+
animate={fadeInVariants(0.2).animate(inView)}
128+
>
129+
Maia offers a range of innovative tools to help you understand human
130+
chess and improve your skills
131+
</motion.p>
132+
</div>
133+
)
134+
}
135+
14136
export const AdditionalFeaturesSection = ({
15137
id,
16138
}: AdditionalFeaturesSectionProps) => {
@@ -24,138 +146,61 @@ export const AdditionalFeaturesSection = ({
24146
setPlaySetupModalProps({ playType: 'handAndBrain' as PlayType })
25147
}
26148

27-
// Animation variants for staggered animations
28-
const containerVariants = {
29-
hidden: { opacity: 0 },
30-
visible: {
31-
opacity: 1,
32-
transition: {
33-
staggerChildren: 0.1,
149+
const features: Feature[] = [
150+
{
151+
icon: <StarIcon />,
152+
title: 'Openings Practice',
153+
description:
154+
"Drill chess openings against Maia models calibrated to specific rating levels, allowing you to practice against opponents similar to those you'll face.",
155+
action: { type: 'link', href: '/openings', label: 'Practice Openings' },
156+
iconBgColor: 'bg-human-3/10',
157+
iconTextColor: 'text-human-3',
158+
},
159+
{
160+
icon: <TuringIcon />,
161+
title: 'Hand & Brain',
162+
description:
163+
'Team up with Maia in this collaborative chess variant. You can be the "Hand" making moves while Maia is the "Brain" selecting pieces, or vice versa.',
164+
action: {
165+
type: 'button',
166+
onClick: startHandBrainGame,
167+
label: 'Play Hand & Brain',
34168
},
169+
iconBgColor: 'bg-engine-3/10',
170+
iconTextColor: 'text-engine-3',
35171
},
36-
}
37-
38-
const itemVariants = {
39-
hidden: { y: 30, opacity: 0 },
40-
visible: {
41-
y: 0,
42-
opacity: 1,
43-
transition: { duration: 0.3, ease: 'easeOut' },
172+
{
173+
icon: <TuringIcon />,
174+
title: 'Bot or Not',
175+
description:
176+
'Test your ability to distinguish between human and AI chess play. This Turing test for chess helps you understand the differences between human and engine moves.',
177+
action: { type: 'link', href: '/turing', label: 'Try Bot or Not' },
178+
iconBgColor: 'bg-human-4/10',
179+
iconTextColor: 'text-human-4',
44180
},
45-
}
181+
]
46182

47183
return (
48184
<section
49185
id={id}
50186
className="relative w-full flex-col items-center overflow-hidden bg-background-1 py-16"
51187
ref={ref}
52188
>
53-
<div className="container mx-auto px-4">
54-
<div className="mb-14 max-w-3xl text-left">
55-
<motion.div
56-
initial={{ opacity: 0, y: -10 }}
57-
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: -10 }}
58-
transition={{ duration: 0.3 }}
59-
className="mb-2 inline-block rounded-full bg-human-3/10 px-4 py-1 text-sm font-medium text-human-3"
60-
>
61-
More Features
62-
</motion.div>
63-
<motion.h2
64-
className="mb-4 text-3xl font-bold md:text-4xl lg:text-5xl"
65-
initial={{ opacity: 0, y: -10 }}
66-
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: -10 }}
67-
transition={{ duration: 0.3, delay: 0.1 }}
68-
>
69-
Explore other ways to use Maia
70-
</motion.h2>
71-
<motion.p
72-
className="max-w-2xl text-lg text-primary/80"
73-
initial={{ opacity: 0, y: -10 }}
74-
animate={inView ? { opacity: 1, y: 0 } : { opacity: 0, y: -10 }}
75-
transition={{ duration: 0.3, delay: 0.2 }}
76-
>
77-
Maia offers a range of innovative tools to help you understand human
78-
chess and improve your skills
79-
</motion.p>
80-
</div>
81-
189+
<div className="mx-auto flex w-full max-w-[90%] flex-col px-4">
190+
<SectionHeader inView={inView} />
82191
<motion.div
83192
className="grid gap-6 md:grid-cols-3"
84-
variants={containerVariants}
193+
variants={animationVariants.container}
85194
initial="hidden"
86195
animate={inView ? 'visible' : 'hidden'}
87196
>
88-
{/* Openings Feature */}
89-
<motion.div
90-
className="hover:scale-102 flex flex-col rounded-lg bg-background-2 p-5 shadow-lg transition-transform duration-200"
91-
variants={itemVariants}
92-
>
93-
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-human-3/10 p-2">
94-
<div className="h-7 w-7 text-human-3">
95-
<StarIcon />
96-
</div>
97-
</div>
98-
<h3 className="mb-3 text-xl font-bold">Openings Practice</h3>
99-
<p className="mb-5 flex-grow text-primary/80">
100-
Drill chess openings against Maia models calibrated to specific
101-
rating levels, allowing you to practice against opponents similar
102-
to those you&apos;ll face.
103-
</p>
104-
<Link
105-
href="/openings"
106-
className="mt-auto inline-flex items-center justify-center rounded-md bg-background-3 px-5 py-3 font-medium transition duration-200 hover:bg-background-4"
107-
>
108-
Practice Openings
109-
</Link>
110-
</motion.div>
111-
112-
{/* Hand & Brain Feature */}
113-
<motion.div
114-
className="hover:scale-102 flex flex-col rounded-lg bg-background-2 p-5 shadow-lg transition-transform duration-200"
115-
variants={itemVariants}
116-
>
117-
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-engine-3/10 p-2">
118-
<div className="h-7 w-7 text-engine-3">
119-
<TuringIcon />
120-
</div>
121-
</div>
122-
<h3 className="mb-3 text-xl font-bold">Hand & Brain</h3>
123-
<p className="mb-5 flex-grow text-primary/80">
124-
Team up with Maia in this collaborative chess variant. You can be
125-
the &quot;Hand&quot; making moves while Maia is the
126-
&quot;Brain&quot; selecting pieces, or vice versa.
127-
</p>
128-
<button
129-
onClick={startHandBrainGame}
130-
className="mt-auto inline-flex items-center justify-center rounded-md bg-background-3 px-5 py-3 font-medium transition duration-200 hover:bg-background-4"
131-
>
132-
Play Hand & Brain
133-
</button>
134-
</motion.div>
135-
136-
{/* Bot or Not Feature */}
137-
<motion.div
138-
className="hover:scale-102 flex flex-col rounded-lg bg-background-2 p-5 shadow-lg transition-transform duration-200"
139-
variants={itemVariants}
140-
>
141-
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-human-4/10 p-2">
142-
<div className="h-7 w-7 text-human-4">
143-
<TuringIcon />
144-
</div>
145-
</div>
146-
<h3 className="mb-3 text-xl font-bold">Bot or Not</h3>
147-
<p className="mb-5 flex-grow text-primary/80">
148-
Test your ability to distinguish between human and AI chess play.
149-
This Turing test for chess helps you understand the differences
150-
between human and engine moves.
151-
</p>
152-
<Link
153-
href="/turing"
154-
className="mt-auto inline-flex items-center justify-center rounded-md bg-background-3 px-5 py-3 font-medium transition duration-200 hover:bg-background-4"
155-
>
156-
Try Bot or Not
157-
</Link>
158-
</motion.div>
197+
{features.map((feature, index) => (
198+
<FeatureCard
199+
key={index}
200+
feature={feature}
201+
variants={animationVariants.item}
202+
/>
203+
))}
159204
</motion.div>
160205
</div>
161206
</section>

0 commit comments

Comments
 (0)