|
1 | 1 | import React, { useState } from 'react'; |
2 | | -import { Github, Linkedin, Mail, Code2, Terminal, Database, Globe, ExternalLink } from 'lucide-react'; |
| 2 | +import { Github, Linkedin, Mail, ExternalLink } from 'lucide-react'; |
| 3 | + |
3 | 4 | import { BlogSection } from './components/BlogSection'; |
4 | | -import { useIntersectionObserver } from './hooks/useIntersectionObserver'; |
| 5 | + |
5 | 6 | import { WebGLBackground } from './components/WebGLBackground'; |
| 7 | +import cvData from './data/cv'; |
| 8 | + |
6 | 9 |
|
7 | | -function SkillCard({ icon, title, items }: { icon: React.ReactNode; title: string; items: string[] }) { |
8 | | - const cardRef = useIntersectionObserver({ threshold: 0.2 }); |
| 10 | +// Utility components for rendering sections |
| 11 | +function SectionTitle({ children }: { children: React.ReactNode }) { |
| 12 | + return <h2 className="text-3xl md:text-4xl font-bold text-center mb-12">{children}</h2>; |
| 13 | +} |
9 | 14 |
|
| 15 | +function EducationSection() { |
10 | 16 | return ( |
11 | | - <div ref={cardRef} className="hidden-element p-6 rounded-xl bg-white/5 backdrop-blur-sm hover:bg-white/10 transition-all duration-300 hover:scale-105 transform"> |
12 | | - <div className="flex items-center gap-4 mb-4"> |
13 | | - {icon} |
14 | | - <h3 className="text-xl font-semibold">{title}</h3> |
| 17 | + <section className="min-h-screen py-20 snap-start"> |
| 18 | + <div className="container mx-auto px-4"> |
| 19 | + <SectionTitle>Education</SectionTitle> |
| 20 | + <div className="space-y-8 max-w-3xl mx-auto"> |
| 21 | + {cvData.education.map((edu, i) => ( |
| 22 | + <div key={i} className="bg-white/5 rounded-xl p-6"> |
| 23 | + <div className="flex flex-col md:flex-row md:justify-between md:items-center mb-2"> |
| 24 | + <div> |
| 25 | + <h3 className="text-xl font-semibold">{edu.degree}</h3> |
| 26 | + <p className="text-gray-300">{edu.institution}</p> |
| 27 | + </div> |
| 28 | + <span className="text-gray-400 text-sm mt-2 md:mt-0">{edu.date}</span> |
| 29 | + </div> |
| 30 | + {edu.honors && edu.honors.length > 0 && ( |
| 31 | + <ul className="text-gray-400 text-sm mb-2 list-disc ml-5"> |
| 32 | + {edu.honors.map((h, j) => <li key={j}>{h}</li>)} |
| 33 | + </ul> |
| 34 | + )} |
| 35 | + {edu.relevantCourses && edu.relevantCourses.length > 0 && ( |
| 36 | + <div className="text-gray-300 text-sm"> |
| 37 | + <span className="font-semibold">Relevant Courses:</span> {edu.relevantCourses.join(', ')} |
| 38 | + </div> |
| 39 | + )} |
| 40 | + </div> |
| 41 | + ))} |
| 42 | + </div> |
15 | 43 | </div> |
16 | | - <ul className="space-y-2"> |
17 | | - {items.map((item) => ( |
18 | | - <li key={item} className="text-gray-300">{item}</li> |
19 | | - ))} |
20 | | - </ul> |
21 | | - </div> |
| 44 | + </section> |
| 45 | + ); |
| 46 | +} |
| 47 | + |
| 48 | +function SkillsSection() { |
| 49 | + return ( |
| 50 | + <section className="min-h-screen py-20 snap-start"> |
| 51 | + <div className="container mx-auto px-4"> |
| 52 | + <SectionTitle>Core Skills</SectionTitle> |
| 53 | + <div className="grid grid-cols-1 md:grid-cols-2 gap-8 max-w-4xl mx-auto"> |
| 54 | + <div className="bg-white/5 rounded-xl p-6"> |
| 55 | + <h3 className="text-xl font-semibold mb-2">Hard Skills</h3> |
| 56 | + <ul className="flex flex-wrap gap-2"> |
| 57 | + {cvData.skills.hard.map((skill, i) => ( |
| 58 | + <li key={i} className="px-3 py-1 rounded-full bg-blue-500/20 text-blue-300 text-sm">{skill}</li> |
| 59 | + ))} |
| 60 | + </ul> |
| 61 | + </div> |
| 62 | + <div className="bg-white/5 rounded-xl p-6"> |
| 63 | + <h3 className="text-xl font-semibold mb-2">Soft Skills</h3> |
| 64 | + <ul className="flex flex-wrap gap-2"> |
| 65 | + {cvData.skills.soft.map((skill, i) => ( |
| 66 | + <li key={i} className="px-3 py-1 rounded-full bg-teal-500/20 text-teal-300 text-sm">{skill}</li> |
| 67 | + ))} |
| 68 | + </ul> |
| 69 | + </div> |
| 70 | + </div> |
| 71 | + </div> |
| 72 | + </section> |
22 | 73 | ); |
23 | 74 | } |
24 | 75 |
|
25 | | -function ProjectCard({ title, description, tech, link }: { title: string; description: string; tech: string[]; link: string }) { |
26 | | - const cardRef = useIntersectionObserver({ threshold: 0.2 }); |
| 76 | +function ExperienceSection() { |
| 77 | + return ( |
| 78 | + <section className="min-h-screen py-20 snap-start"> |
| 79 | + <div className="container mx-auto px-4"> |
| 80 | + <SectionTitle>Experience</SectionTitle> |
| 81 | + <div className="space-y-8 max-w-3xl mx-auto"> |
| 82 | + {cvData.experience.map((exp, i) => ( |
| 83 | + <div key={i} className="bg-white/5 rounded-xl p-6"> |
| 84 | + <div className="flex flex-col md:flex-row md:justify-between md:items-center mb-2"> |
| 85 | + <div> |
| 86 | + <h3 className="text-lg font-semibold">{exp.title}</h3> |
| 87 | + <p className="text-gray-300">{exp.organization}</p> |
| 88 | + </div> |
| 89 | + <span className="text-gray-400 text-sm mt-2 md:mt-0">{exp.date}</span> |
| 90 | + </div> |
| 91 | + {exp.description.length > 0 && ( |
| 92 | + <ul className="text-gray-400 text-sm list-disc ml-5"> |
| 93 | + {exp.description.map((d, j) => <li key={j}>{d}</li>)} |
| 94 | + </ul> |
| 95 | + )} |
| 96 | + </div> |
| 97 | + ))} |
| 98 | + </div> |
| 99 | + </div> |
| 100 | + </section> |
| 101 | + ); |
| 102 | +} |
27 | 103 |
|
| 104 | +function ProjectsSection() { |
28 | 105 | return ( |
29 | | - <div ref={cardRef} className="hidden-element p-6 rounded-xl bg-white/5 backdrop-blur-sm hover:bg-white/10 transition-all duration-300 hover:scale-105 transform h-full"> |
30 | | - <h3 className="text-xl font-semibold mb-3">{title}</h3> |
31 | | - <p className="text-gray-300 mb-4">{description}</p> |
32 | | - <div className="flex flex-wrap gap-2 mb-4"> |
33 | | - {tech.map((item) => ( |
34 | | - <span key={item} className="px-3 py-1 rounded-full bg-blue-500/20 text-blue-300 text-sm"> |
35 | | - {item} |
36 | | - </span> |
37 | | - ))} |
| 106 | + <section className="min-h-screen py-20 snap-start"> |
| 107 | + <div className="container mx-auto px-4"> |
| 108 | + <SectionTitle>Projects</SectionTitle> |
| 109 | + <div className="space-y-8 max-w-3xl mx-auto"> |
| 110 | + {cvData.projects.map((proj, i) => ( |
| 111 | + <div key={i} className="bg-white/5 rounded-xl p-6"> |
| 112 | + <h3 className="text-lg font-semibold mb-2">{proj.title}</h3> |
| 113 | + <ul className="text-gray-300 text-sm mb-2 list-disc ml-5"> |
| 114 | + {proj.description.map((desc, j) => <li key={j}>{desc}</li>)} |
| 115 | + </ul> |
| 116 | + {proj.links && proj.links.length > 0 && ( |
| 117 | + <div className="flex flex-wrap gap-3 mt-2"> |
| 118 | + {proj.links.map((l, k) => ( |
| 119 | + <a key={k} href={l.url} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 text-blue-400 hover:text-blue-300 transition-colors underline"> |
| 120 | + {l.label} <ExternalLink size={14} /> |
| 121 | + </a> |
| 122 | + ))} |
| 123 | + </div> |
| 124 | + )} |
| 125 | + </div> |
| 126 | + ))} |
| 127 | + </div> |
38 | 128 | </div> |
39 | | - <a |
40 | | - href={link} |
41 | | - className="inline-flex items-center gap-2 text-blue-400 hover:text-blue-300 transition-colors" |
42 | | - > |
43 | | - View Project <ExternalLink size={16} /> |
44 | | - </a> |
45 | | - </div> |
| 129 | + </section> |
| 130 | + ); |
| 131 | +} |
| 132 | + |
| 133 | +function CertificationsSection() { |
| 134 | + return ( |
| 135 | + <section className="py-20 snap-start"> |
| 136 | + <div className="container mx-auto px-4"> |
| 137 | + <SectionTitle>Certifications, Courses & Workshops</SectionTitle> |
| 138 | + <ul className="flex flex-wrap gap-2 max-w-4xl mx-auto justify-center"> |
| 139 | + {cvData.certifications.map((cert, i) => ( |
| 140 | + <li key={i} className="px-3 py-1 rounded-full bg-purple-500/20 text-purple-300 text-sm mb-2">{cert.name}</li> |
| 141 | + ))} |
| 142 | + </ul> |
| 143 | + </div> |
| 144 | + </section> |
| 145 | + ); |
| 146 | +} |
| 147 | + |
| 148 | +function ClubsSection() { |
| 149 | + return ( |
| 150 | + <section className="py-20 snap-start"> |
| 151 | + <div className="container mx-auto px-4"> |
| 152 | + <SectionTitle>Clubs & Leadership</SectionTitle> |
| 153 | + <div className="flex flex-wrap gap-4 justify-center"> |
| 154 | + {cvData.clubs.map((club, i) => ( |
| 155 | + <div key={i} className="bg-white/5 rounded-xl p-4 min-w-[220px]"> |
| 156 | + <h4 className="font-semibold text-lg mb-1">{club.name}</h4> |
| 157 | + <div className="text-gray-300 text-sm mb-1">{club.role}</div> |
| 158 | + <div className="text-gray-400 text-xs">{club.date}</div> |
| 159 | + </div> |
| 160 | + ))} |
| 161 | + </div> |
| 162 | + </div> |
| 163 | + </section> |
46 | 164 | ); |
47 | 165 | } |
48 | 166 |
|
@@ -76,33 +194,23 @@ function App() { |
76 | 194 | </div> |
77 | 195 | </header> |
78 | 196 |
|
79 | | - {/* Skills Section */} |
80 | | - <section className="min-h-screen py-20 snap-start"> |
81 | | - <div className="container mx-auto px-4"> |
82 | | - <h2 className="text-3xl md:text-4xl font-bold text-center mb-16">Technical Skills</h2> |
83 | | - <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8"> |
84 | | - <SkillCard icon={<Code2 size={32} />} title="Languages" items={["Python", "C++", "R", "Matlab"]} /> |
85 | | - <SkillCard icon={<Terminal size={32} />} title="Tools" items={["Git", "Docker", "Linux", "VS Code"]} /> |
86 | | - <SkillCard icon={<Database size={32} />} title="Databases" items={["MySQL", "MongoDB"]} /> |
87 | | - <SkillCard icon={<Globe size={32} />} title="Web" items={["Flask", "Django", "React", "HTML/CSS"]} /> |
88 | | - </div> |
89 | | - </div> |
90 | | - </section> |
| 197 | + {/* Education Section */} |
| 198 | + <EducationSection /> |
91 | 199 |
|
92 | | - {/* Projects Section */} |
93 | | - <section className="min-h-screen py-20 snap-start"> |
94 | | - <div className="container mx-auto px-4"> |
95 | | - <h2 className="text-3xl md:text-4xl font-bold text-center mb-16">Featured Projects</h2> |
96 | | - <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> |
97 | | - <ProjectCard |
98 | | - title="TBD" |
99 | | - description="TBD" |
100 | | - tech={["TBD"]} |
101 | | - link="https://github.com" |
102 | | - /> |
103 | | - </div> |
104 | | - </div> |
105 | | - </section> |
| 200 | + {/* Skills Section */} |
| 201 | + <SkillsSection /> |
| 202 | + |
| 203 | + {/* Experience Section */} |
| 204 | + <ExperienceSection /> |
| 205 | + |
| 206 | + {/* Projects Section */} |
| 207 | + <ProjectsSection /> |
| 208 | + |
| 209 | + {/* Certifications Section */} |
| 210 | + <CertificationsSection /> |
| 211 | + |
| 212 | + {/* Clubs Section */} |
| 213 | + <ClubsSection /> |
106 | 214 |
|
107 | 215 | {/* Blog Section */} |
108 | 216 | <div className="snap-start"> |
|
0 commit comments