151 lines
4.3 KiB
TypeScript
151 lines
4.3 KiB
TypeScript
import { motion } from 'motion/react';
|
|
import { useTranslation } from '../i18n';
|
|
import {
|
|
SiReact,
|
|
SiTypescript,
|
|
SiNodedotjs,
|
|
SiPython,
|
|
SiFirebase,
|
|
SiPostgresql,
|
|
SiDocker,
|
|
SiGit,
|
|
} from 'react-icons/si';
|
|
import styles from './About.module.css';
|
|
|
|
const techStack = [
|
|
{ name: 'React', icon: SiReact },
|
|
{ name: 'TypeScript', icon: SiTypescript },
|
|
{ name: 'Node.js', icon: SiNodedotjs },
|
|
{ name: 'Python', icon: SiPython },
|
|
{ name: 'Firebase', icon: SiFirebase },
|
|
{ name: 'PostgreSQL', icon: SiPostgresql },
|
|
{ name: 'Docker', icon: SiDocker },
|
|
{ name: 'Git', icon: SiGit },
|
|
];
|
|
|
|
const containerVariants = {
|
|
hidden: { opacity: 0 },
|
|
visible: {
|
|
opacity: 1,
|
|
transition: { staggerChildren: 0.1 },
|
|
},
|
|
};
|
|
|
|
const itemVariants = {
|
|
hidden: { opacity: 0, y: 20 },
|
|
visible: {
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: { duration: 0.4 },
|
|
},
|
|
};
|
|
|
|
export function About() {
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<main className={styles.about}>
|
|
{/* Hero Section */}
|
|
<section className={styles.hero}>
|
|
<div className="container">
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 30 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6 }}
|
|
>
|
|
<h1 className={styles.title}>{t.about.title}</h1>
|
|
<p className={styles.subtitle}>{t.about.subtitle}</p>
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Intro Section */}
|
|
<section className={styles.intro}>
|
|
<div className="container">
|
|
<motion.div
|
|
className={styles.introContent}
|
|
initial={{ opacity: 0, y: 30 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.5 }}
|
|
>
|
|
<p className={styles.introText}>{t.about.intro}</p>
|
|
<p className={styles.introText}>{t.about.experience}</p>
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Skills Section */}
|
|
<section className={styles.skills}>
|
|
<div className="container">
|
|
<motion.div
|
|
className={styles.sectionHeader}
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.5 }}
|
|
>
|
|
<h2>{t.about.skills.title}</h2>
|
|
<p>{t.about.skills.subtitle}</p>
|
|
</motion.div>
|
|
|
|
<motion.div
|
|
className={styles.techGrid}
|
|
variants={containerVariants}
|
|
initial="hidden"
|
|
whileInView="visible"
|
|
viewport={{ once: true }}
|
|
>
|
|
{techStack.map((tech) => (
|
|
<motion.div
|
|
key={tech.name}
|
|
className={styles.techCard}
|
|
variants={itemVariants}
|
|
whileHover={{ scale: 1.05, y: -4 }}
|
|
>
|
|
<span className={styles.techIcon}><tech.icon /></span>
|
|
<span className={styles.techName}>{tech.name}</span>
|
|
</motion.div>
|
|
))}
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Values Section */}
|
|
<section className={styles.values}>
|
|
<div className="container">
|
|
<motion.div
|
|
className={styles.sectionHeader}
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.5 }}
|
|
>
|
|
<h2>{t.about.values.title}</h2>
|
|
</motion.div>
|
|
|
|
<motion.div
|
|
className={styles.valuesGrid}
|
|
variants={containerVariants}
|
|
initial="hidden"
|
|
whileInView="visible"
|
|
viewport={{ once: true }}
|
|
>
|
|
{t.about.values.items.map((value, index) => (
|
|
<motion.div
|
|
key={index}
|
|
className={styles.valueCard}
|
|
variants={itemVariants}
|
|
>
|
|
<div className={styles.valueNumber}>0{index + 1}</div>
|
|
<h3 className={styles.valueTitle}>{value.title}</h3>
|
|
<p className={styles.valueDescription}>{value.description}</p>
|
|
</motion.div>
|
|
))}
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
);
|
|
}
|