All checks were successful
Build and Deploy Gabriel Kaszewski Portfolio / build-and-deploy-local (push) Successful in 1m8s
84 lines
3.4 KiB
TypeScript
84 lines
3.4 KiB
TypeScript
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;
|