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