rework of experience
All checks were successful
Build and Deploy Gabriel Kaszewski Portfolio / build-and-deploy-local (push) Successful in 1m8s
All checks were successful
Build and Deploy Gabriel Kaszewski Portfolio / build-and-deploy-local (push) Successful in 1m8s
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
import { Job } from "@/lib/types";
|
||||
import { CircleUserRound, Building, Clock, Microchip } from "lucide-react";
|
||||
import Chip from "./chip";
|
||||
import formatDate from "@/utils/format-date";
|
||||
|
||||
const ExperienceCard = ({ job }: { job: Job }) => (
|
||||
<div className="transition-all duration-300 bg-white/5 backdrop-blur-md border border-white/10 rounded-3xl hover:bg-white/10 hover:border-white/20 shrink-0 snap-center shadow-xl group w-[20rem] max-w-[20rem] flex flex-col gap-2 p-4">
|
||||
<h4 className="flex items-center gap-1 text-2xl">
|
||||
<CircleUserRound /> {job.position}
|
||||
</h4>
|
||||
<h5 className="flex items-center gap-1 text-xl font-light">
|
||||
<Building /> {job.company}
|
||||
</h5>
|
||||
<h6 className="flex items-center gap-1">
|
||||
<Clock />
|
||||
{formatDate(job.start_date)} -{" "}
|
||||
{job.still_working ? "Present" : formatDate(job.end_date!)}
|
||||
</h6>
|
||||
<p className="flex items-center gap-1 font-bold">
|
||||
<Microchip /> Technologies
|
||||
</p>
|
||||
<div className="flex flex-wrap items-center w-full gap-2">
|
||||
{job.technologies.map((tech) => (
|
||||
<Chip key={tech} text={tech} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default ExperienceCard;
|
||||
83
components/experience-timeline.tsx
Normal file
83
components/experience-timeline.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Job } from "@/lib/types";
|
||||
import Chip from "./chip";
|
||||
import formatDate from "@/utils/format-date";
|
||||
|
||||
interface ExperienceTimelineProps {
|
||||
jobs: Job[];
|
||||
newestFirst?: boolean;
|
||||
}
|
||||
|
||||
const ExperienceTimeline = ({ jobs, newestFirst = true }: ExperienceTimelineProps) => {
|
||||
const sorted = [...jobs].sort((a, b) => {
|
||||
const diff = new Date(b.start_date).getTime() - new Date(a.start_date).getTime();
|
||||
return newestFirst ? diff : -diff;
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative w-full max-w-3xl mx-auto flex flex-col gap-0">
|
||||
<div className="absolute left-[9px] top-3 bottom-3 w-px bg-gradient-to-b from-white/30 to-white/0" />
|
||||
{sorted.map((job) => (
|
||||
<div key={job.id} className="flex gap-6 pb-10 last:pb-0">
|
||||
<div className="flex flex-col items-center shrink-0 w-5 pt-1.5 z-10">
|
||||
<div className="w-3 h-3 rounded-full bg-white/40 border border-white/20 shadow-[0_0_8px_rgba(255,255,255,0.2)]" />
|
||||
</div>
|
||||
<div className="flex-1 transition-all duration-300 bg-white/5 backdrop-blur-md border border-white/10 rounded-3xl hover:bg-white/10 hover:border-white/20 shadow-xl group p-5">
|
||||
<div className="flex justify-between items-start flex-wrap gap-1 mb-1">
|
||||
<h4 className="text-lg font-semibold text-white">{job.position}</h4>
|
||||
<span className="text-xs text-white/40">
|
||||
{formatDate(job.start_date)} –{" "}
|
||||
{job.still_working ? "Present" : job.end_date ? formatDate(job.end_date) : "—"}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-white/60 mb-4">{job.company}</p>
|
||||
|
||||
{job.summary && (
|
||||
<p className="text-sm text-white/50 italic mb-4">{job.summary}</p>
|
||||
)}
|
||||
|
||||
{job.sub_phases && job.sub_phases.length > 0 && (
|
||||
<div className="flex flex-col gap-3 mb-4">
|
||||
{job.sub_phases.map((phase) => (
|
||||
<div
|
||||
key={phase.label}
|
||||
className="bg-white/[0.03] border border-white/[0.07] rounded-xl px-4 py-3"
|
||||
>
|
||||
<div className="flex justify-between items-center flex-wrap gap-1 mb-2">
|
||||
<span className="text-[11px] font-semibold uppercase tracking-widest text-white/50">
|
||||
{phase.label}
|
||||
</span>
|
||||
<span className="text-[10px] text-white/30">
|
||||
{formatDate(phase.start_date)} –{" "}
|
||||
{phase.end_date ? formatDate(phase.end_date) : "Present"}
|
||||
</span>
|
||||
</div>
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
{phase.bullets.map((b, i) => (
|
||||
<li key={i} className="text-xs text-white/50 leading-relaxed">
|
||||
{b}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="border-t border-white/10 pt-4 mt-2">
|
||||
<p className="text-[10px] uppercase tracking-widest text-white/30 mb-2">
|
||||
Technologies
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{job.technologies.map((tech) => (
|
||||
<Chip key={tech} text={tech} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExperienceTimeline;
|
||||
@@ -1,22 +1,16 @@
|
||||
import { Job } from "@/lib/types";
|
||||
import ExperienceCard from "@/components/experience-card";
|
||||
import ExperienceTimeline from "@/components/experience-timeline";
|
||||
|
||||
const Experience = ({ jobs }: { jobs: Job[] }) => {
|
||||
return (
|
||||
<div
|
||||
id="experience"
|
||||
className="flex flex-col items-center justify-center gap-4 p-4 rounded w-full"
|
||||
>
|
||||
<h3 className="mt-4 mb-2 text-5xl font-bold tracking-tight text-white">
|
||||
Experience
|
||||
</h3>
|
||||
<div className="flex flex-wrap justify-center gap-4">
|
||||
{jobs.map((job) => (
|
||||
<ExperienceCard key={job.id} job={job} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const Experience = ({ jobs }: { jobs: Job[] }) => (
|
||||
<div
|
||||
id="experience"
|
||||
className="flex flex-col items-center gap-8 p-4 w-full"
|
||||
>
|
||||
<h3 className="mt-4 text-5xl font-bold tracking-tight text-white">
|
||||
Experience
|
||||
</h3>
|
||||
<ExperienceTimeline jobs={jobs} />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Experience;
|
||||
|
||||
Reference in New Issue
Block a user