home.tsx

1'use client'
2
3import React, { useEffect, useState } from 'react'
4import { motion } from 'framer-motion'
5import Layout from './Layout'
6import { config } from '@/configs/main'
7import markdownStyles from '@/app/styles/markdown.module.css'
8import { DynamicIcon, IconName } from './dynamic-icon'
9
10export function HomePage({ aboutContent }: { aboutContent: string }) {
11	const fadeInUp = {
12		initial: { opacity: 0, y: 20 },
13		animate: { opacity: 1, y: 0 },
14		transition: { duration: 0.6 },
15	}
16
17	const TypingAnimation = ({
18		strings,
19		typingSpeed = 150,
20		deleteSpeed = 75,
21		pauseTime = 2000,
22	}: {
23		strings: string[]
24		typingSpeed?: number
25		deleteSpeed?: number
26		pauseTime?: number
27	}) => {
28		const [displayText, setDisplayText] = useState('')
29		const [currentIndex, setCurrentIndex] = useState(0)
30		const [isDeleting, setIsDeleting] = useState(false)
31
32		useEffect(() => {
33			const timer = setTimeout(
34				() => {
35					const currentString = strings[currentIndex]
36
37					if (isDeleting) {
38						setDisplayText(currentString.substring(0, displayText.length - 1))
39						if (displayText.length === 0) {
40							setIsDeleting(false)
41							setCurrentIndex((prev) => (prev + 1) % strings.length)
42						}
43					} else {
44						setDisplayText(currentString.substring(0, displayText.length + 1))
45						if (displayText.length === currentString.length) {
46							setTimeout(() => setIsDeleting(true), pauseTime)
47						}
48					}
49				},
50				isDeleting ? deleteSpeed : typingSpeed,
51			)
52
53			return () => clearTimeout(timer)
54		}, [
55			displayText,
56			currentIndex,
57			isDeleting,
58			strings,
59			typingSpeed,
60			deleteSpeed,
61			pauseTime,
62		])
63
64		return <span className="typing-text">{displayText}</span>
65	}
66
67	// Sort skills by level
68	config.skills?.sort((a, b) => b.level - a.level)
69
70	return (
71		<Layout>
72			<section
73				id="home"
74				className="flex min-h-screen items-center justify-center"
75			>
76				<motion.div
77					className="text-center"
78					initial="initial"
79					animate="animate"
80					variants={{
81						initial: { opacity: 0 },
82						animate: { opacity: 1, transition: { staggerChildren: 0.2 } },
83					}}
84				>
85					<motion.h1 className="mb-4 text-5xl font-bold" variants={fadeInUp}>
86						{config.name}
87					</motion.h1>
88					<motion.p className="mb-8 text-xl text-gray-300" variants={fadeInUp}>
89						<TypingAnimation strings={config.titles} />
90					</motion.p>
91					<motion.div
92						className="flex justify-center space-x-4"
93						variants={fadeInUp}
94					>
95						{config.socials?.length &&
96							config.socials.map((social) => (
97								<a
98									key={social.name}
99									href={social.url}
100									className="text-gray-300 hover:text-white"
101									style={{ color: social.color || 'inherit' }}
102								>
103									<DynamicIcon
104										name={social.iconName as IconName}
105										size={24}
106										color={social.color}
107									/>
108								</a>
109							))}
110					</motion.div>
111				</motion.div>
112			</section>
113			<section id="about" className="min-h-screen bg-gray-800 py-20">
114				<motion.div
115					className="container mx-auto"
116					initial="initial"
117					whileInView="animate"
118					viewport={{ once: true }}
119					variants={{
120						initial: { opacity: 0 },
121						animate: { opacity: 1, transition: { staggerChildren: 0.2 } },
122					}}
123				>
124					<motion.h2
125						className="mb-8 text-center text-3xl font-bold"
126						variants={fadeInUp}
127					>
128						About Me
129					</motion.h2>
130					<motion.div
131						className={`${markdownStyles.markdown} text-gray-300`}
132						variants={fadeInUp}
133						dangerouslySetInnerHTML={{ __html: aboutContent }}
134					/>
135				</motion.div>
136			</section>
137			<section id="skills" className="min-h-screen py-20">
138				<motion.div
139					className="container mx-auto px-4"
140					initial="initial"
141					whileInView="animate"
142					viewport={{ once: true }}
143					variants={{
144						initial: { opacity: 0 },
145						animate: { opacity: 1, transition: { staggerChildren: 0.2 } },
146					}}
147				>
148					<motion.h2
149						className="mb-12 text-center text-4xl font-bold"
150						variants={fadeInUp}
151					>
152						Skills & Expertise
153					</motion.h2>
154					<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
155						{config.skills?.map((skill) => (
156							<motion.div
157								key={skill.name}
158								className="perspective-1000 group rounded-xl border border-gray-700 bg-gray-800/50 p-6 backdrop-blur-sm transition-all duration-300 ease-out hover:border-blue-500/50"
159								variants={fadeInUp}
160								whileHover={{
161									rotateX: -2,
162									rotateY: 5,
163									scale: 1.02,
164									transition: {
165										duration: 0.2,
166										ease: 'easeOut',
167									},
168								}}
169								whileTap={{ scale: 0.98 }}
170								style={{
171									transformStyle: 'preserve-3d',
172									boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
173								}}
174							>
175								<motion.div
176									className="relative z-10"
177									style={{ transform: 'translateZ(50px)' }}
178								>
179									<div className="mb-4 flex items-center gap-4">
180										<DynamicIcon
181											name={skill.iconName as IconName}
182											size={32}
183											color={skill.color}
184											className="transition-transform duration-300 group-hover:rotate-3 group-hover:scale-110"
185										/>
186										<h3 className="text-2xl font-semibold transition-colors duration-300 group-hover:text-blue-400">
187											{skill.name}
188										</h3>
189									</div>
190									<div className="space-y-3">
191										<p className="text-sm text-gray-300">{skill.description}</p>
192										<div className="h-2 w-full overflow-hidden rounded-full bg-gray-700">
193											<div
194												className="h-2 rounded-full bg-blue-500 transition-all duration-500 ease-out group-hover:bg-blue-400"
195												style={{ width: `${skill.level}%` }}
196											/>
197										</div>
198										<p className="text-right text-sm text-gray-400 transition-colors duration-300 group-hover:text-blue-400">
199											{skill.level}%
200										</p>
201									</div>
202								</motion.div>
203							</motion.div>
204						))}
205					</div>
206				</motion.div>
207			</section>
208		</Layout>
209	)
210}
211