Skip to content

Commit bd48f1b

Browse files
authored
Merge pull request #47 from carsonSgit/exp-page
feat: Experience page
2 parents 53164e5 + a9b82b1 commit bd48f1b

16 files changed

+349
-30
lines changed

src/App.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,11 @@ import React from 'react';
22
import Hero from './Components/Home/Hero/Hero';
33
import Project from './Components/Projects/Projects';
44
import About from './Components/About/About';
5+
import Experience from './Components/Experience/Experience';
56
import { Route, Routes } from 'react-router-dom';
67
import Navbar from './Components/Navbar';
78
import './App.scss';
89

9-
const Home = () => <></>;
10-
const Abouts = () => <></>;
11-
const Projects = () => <></>;
12-
const Contact = () => <></>;
13-
1410
const App: React.FC = () => {
1511
return (
1612
<div className="App">
@@ -19,7 +15,7 @@ const App: React.FC = () => {
1915
<Route path="/" element={<Hero />} />
2016
<Route path="/about" element={<About />} />
2117
<Route path="/projects" element={<Project />} />
22-
<Route path="/contact" element={<Contact />} />
18+
<Route path="/stats" element={<Experience />} />
2319
</Routes>
2420
</div>
2521
);

src/Components/Data/navbarLinks.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const links = [
2+
{ path: '/', label: 'HOME' },
3+
{ path: '/about', label: 'ABOUT' },
4+
{ path: '/projects', label: 'PROJECTS' },
5+
{ path: '/stats', label: 'STATS' },
6+
];

src/Components/Experience/Experience.scss

Whitespace-only changes.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
import ExperienceTimeline from './ExperienceTimeline';
3+
import './Experience.scss';
4+
5+
const Experience = () => (
6+
<div className="experience-page">
7+
<ExperienceTimeline />
8+
</div>
9+
);
10+
11+
export default Experience;
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
$primary-color: #2af598;
2+
$secondary-color: #00715f;
3+
$tertiary-color: #33b072;
4+
$quaternary-color: #95b9b0;
5+
$background-color: #262f2aec;
6+
$text-color: #fafff0;
7+
$font-color: #a2aa94;
8+
9+
.timeline {
10+
position: relative;
11+
padding: 20px 0;
12+
margin-left: 10px;
13+
display: flex;
14+
flex-direction: column;
15+
align-items: flex-start;
16+
17+
@media (max-width: 768px) {
18+
margin-left: 20px;
19+
}
20+
21+
@media (max-width: 430px) {
22+
margin-left: 15px;
23+
padding: 10px 0;
24+
}
25+
}
26+
27+
.timeline-item {
28+
position: relative;
29+
margin-right: 20px;
30+
margin-bottom: 30px;
31+
padding-left: 20px;
32+
background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(245,245,245,0.1) 200%);
33+
border-radius: 8px;
34+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
35+
overflow: hidden;
36+
position: relative;
37+
transform-origin: left center;
38+
39+
&:hover {
40+
background: linear-gradient(90deg, rgba(255,255,255,0.1) 0%, rgba(245,245,245,0.2) 200%);
41+
transform: translateY(-5px);
42+
transition: transform 0.3s ease-in-out, background 0.3s ease-in-out;
43+
}
44+
45+
.timeline-content {
46+
padding-left: 10px;
47+
margin-right: 20px;
48+
color: $text-color;
49+
border-left: 2px solid $primary-color;
50+
51+
h3 {
52+
font-size: 1.5em;
53+
margin-bottom: 3px;
54+
color: darken($primary-color, 20%);
55+
transition: color 0.3s ease-in-out;
56+
57+
@media (max-width: 768px) {
58+
font-size: 1.3em;
59+
}
60+
61+
@media (max-width: 430px) {
62+
font-size: 1.1em;
63+
}
64+
}
65+
66+
p {
67+
font-size: 1em;
68+
color: lighten($font-color, 30%);
69+
70+
@media (max-width: 768px) {
71+
font-size: 0.9em;
72+
}
73+
74+
@media (max-width: 430px) {
75+
font-size: 0.8em;
76+
}
77+
}
78+
}
79+
80+
.timeline-company {
81+
color: lighten($secondary-color, 10%);
82+
}
83+
.timeline-institution {
84+
color: lighten($secondary-color, 10%);
85+
}
86+
87+
.timeline-atsign {
88+
color: $text-color;
89+
}
90+
91+
.timeline-date {
92+
margin-top: 5px;
93+
font-size: 0.9em;
94+
color: $quaternary-color;
95+
}
96+
}
97+
98+
.timeline-step {
99+
position: absolute;
100+
left: -12px;
101+
top: 0;
102+
height: 100%;
103+
display: flex;
104+
align-items: center;
105+
}
106+
107+
.timeline-section {
108+
margin-left: 30px;
109+
margin-right: 30px;
110+
}
111+
112+
.timeline-section-title {
113+
font-size: 2em;
114+
color: $text-color;
115+
margin-bottom: 15px;
116+
padding-left: 10px;
117+
font-weight: bold;
118+
119+
@media (max-width: 768px) {
120+
font-size: 1.7em;
121+
}
122+
123+
@media (max-width: 430px) {
124+
font-size: 1.4em;
125+
}
126+
}
127+
128+
.timeline-stats {
129+
margin-top: 10px;
130+
margin-bottom:10px;
131+
display: flex;
132+
flex-direction: column;
133+
134+
.stat-item {
135+
font-size: 0.9em;
136+
color: $text-color;
137+
margin-bottom: 5px;
138+
139+
strong {
140+
color: $primary-color;
141+
}
142+
}
143+
}
144+
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { motion, useAnimation } from 'framer-motion';
2+
import { useEffect } from 'react';
3+
import { education } from '../Data/education';
4+
import { experience } from '../Data/experience';
5+
import { statistics } from '../Data/statistics';
6+
import './ExperienceTimeline.scss';
7+
8+
const ExperienceTimeline = () => {
9+
const controls = useAnimation();
10+
11+
useEffect(() => {
12+
controls.start((i) => ({
13+
opacity: 1,
14+
y: 0,
15+
transition: { delay: i * 0.2 },
16+
}));
17+
}, [controls]);
18+
19+
return (
20+
<div className="timeline">
21+
<motion.div className="particle-background" />
22+
23+
<div className="timeline-section">
24+
<h2 className="timeline-section-title">Education</h2>
25+
{education.map((item, index) => (
26+
<motion.div
27+
key={index}
28+
custom={index}
29+
initial={{ opacity: 0, y: 20 }}
30+
animate={controls}
31+
exit={{ opacity: 0, y: 20 }}
32+
className="timeline-item"
33+
>
34+
<div className="timeline-step education-step"></div>
35+
<div className="timeline-content">
36+
<h3>{item.title} <span className="timeline-atsign">@ </span><span className="timeline-institution">{item.institution}</span></h3>
37+
<div className="timeline-date">{item.date}</div>
38+
<p>{item.description}</p>
39+
<div className="timeline-stats">
40+
{Object.entries(statistics[item.statsKey] || {}).map(([key, value]: [string, number | string]) => (
41+
<div key={key} className="stat-item">
42+
<strong>{value}</strong> {key.replace(/([A-Z])/g, ' $1').toLowerCase()}
43+
</div>
44+
))}
45+
</div>
46+
</div>
47+
</motion.div>
48+
))}
49+
</div>
50+
51+
<div className="timeline-section">
52+
<h2 className="timeline-section-title">Experience</h2>
53+
{experience.map((item, index) => (
54+
<motion.div
55+
key={index}
56+
custom={index + education.length}
57+
initial={{ opacity: 0, y: 20 }}
58+
animate={controls}
59+
exit={{ opacity: 0, y: 20 }}
60+
className="timeline-item"
61+
>
62+
<div className="timeline-step experience-step"></div>
63+
<div className="timeline-content">
64+
<h3>{item.title} <span className="timeline-atsign">@ </span><span className="timeline-company">{item.company}</span></h3>
65+
<div className="timeline-date">{item.date}</div>
66+
<p>{item.description}</p>
67+
<div className="timeline-stats">
68+
{Object.entries(statistics[item.statsKey] || {}).map(([key, value]: [string, number | string]) => (
69+
<div key={key} className="stat-item">
70+
<strong>{value}</strong> {key.replace(/([A-Z])/g, ' $1').toLowerCase()}
71+
</div>
72+
))}
73+
</div>
74+
</div>
75+
</motion.div>
76+
))}
77+
</div>
78+
</div>
79+
);
80+
};
81+
82+
export default ExperienceTimeline;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { Project } from './projects';
2+
3+
export interface ProjectItemProps {
4+
project: Project;
5+
}

src/Components/Interfaces/projects.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export interface Project {
2+
image: string;
3+
title: string;
4+
languages: string;
5+
description: string;
6+
github?: string;
7+
website?: string;
8+
}

src/Components/Interfaces/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export type Statistics = {
2+
[key: string]: {
3+
[key: string]: number | string;
4+
} | null;
5+
};

src/Components/Navbar.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
import React, { useState } from 'react';
22
import { NavLink } from 'react-router-dom';
33
import { FaBars, FaTimes } from 'react-icons/fa';
4+
import { links } from './Data/navbarLinks';
45
import './Navbar.scss';
56

67
const Navbar: React.FC = () => {
78
const [menuOpen, setMenuOpen] = useState(false);
89

9-
const links = [
10-
{ path: '/', label: 'HOME' },
11-
{ path: '/about', label: 'ABOUT' },
12-
{ path: '/projects', label: 'PROJECTS' },
13-
{ path: '/contact', label: 'RESUME' },
14-
];
15-
1610
const toggleMenu = () => {
1711
setMenuOpen(!menuOpen);
1812
};

0 commit comments

Comments
 (0)