feat. added dates & roles to work experience
This commit is contained in:
@@ -160,7 +160,7 @@ export default function AdminPage() {
|
||||
"projects.json": { name: "", description: "", link: "", open_source: false },
|
||||
"mini_projects.json": { title: "", description: "", why: "" },
|
||||
"experience.json": { name: "", type: "experience", description: "" },
|
||||
"real_work.json": { company: "", summary: "" }
|
||||
"real_work.json": { company: "", role: "", from: "", until: "", summary: "" }
|
||||
};
|
||||
setData([templates[selectedFile], ...data]);
|
||||
};
|
||||
@@ -333,6 +333,18 @@ export default function AdminPage() {
|
||||
<label className="text-xs font-bold text-gray-500 uppercase">Company</label>
|
||||
<input type="text" value={item.company || ""} onChange={(e) => updateEntry(idx, "company", e.target.value)} className="w-full bg-black/40 border border-white/10 rounded-lg p-2 text-sm" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-bold text-gray-500 uppercase">Role</label>
|
||||
<input type="text" value={item.role || ""} onChange={(e) => updateEntry(idx, "role", e.target.value)} className="w-full bg-black/40 border border-white/10 rounded-lg p-2 text-sm" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-bold text-gray-500 uppercase">From</label>
|
||||
<input type="text" value={item.from || ""} onChange={(e) => updateEntry(idx, "from", e.target.value)} className="w-full bg-black/40 border border-white/10 rounded-lg p-2 text-sm" placeholder="YYYY-MM" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-bold text-gray-500 uppercase">Until</label>
|
||||
<input type="text" value={item.until || ""} onChange={(e) => updateEntry(idx, "until", e.target.value)} className="w-full bg-black/40 border border-white/10 rounded-lg p-2 text-sm" placeholder="YYYY-MM or Present" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="text-xs font-bold text-gray-500 uppercase">URL</label>
|
||||
<input type="text" value={item.url || ""} onChange={(e) => updateEntry(idx, "url", e.target.value)} className="w-full bg-black/40 border border-white/10 rounded-lg p-2 text-sm" />
|
||||
|
||||
@@ -6,7 +6,50 @@ interface WorkExperienceProps {
|
||||
realWork: RealWork[];
|
||||
}
|
||||
|
||||
function getWorkDateTimestamp(dateValue?: string) {
|
||||
if (!dateValue) return Number.NEGATIVE_INFINITY;
|
||||
const timestamp = Date.parse(dateValue);
|
||||
return Number.isNaN(timestamp) ? Number.NEGATIVE_INFINITY : timestamp;
|
||||
}
|
||||
|
||||
function getSortTimestamp(entry: RealWork) {
|
||||
if (!entry.until || entry.until.trim().toLowerCase() === "present") {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
}
|
||||
const untilTimestamp = getWorkDateTimestamp(entry.until);
|
||||
if (untilTimestamp !== Number.NEGATIVE_INFINITY) return untilTimestamp;
|
||||
return getWorkDateTimestamp(entry.from);
|
||||
}
|
||||
|
||||
function formatWorkDate(dateValue: string) {
|
||||
const yearMonthMatch = /^(\d{4})-(\d{2})$/.exec(dateValue.trim());
|
||||
if (yearMonthMatch) {
|
||||
const year = Number.parseInt(yearMonthMatch[1], 10);
|
||||
const monthIndex = Number.parseInt(yearMonthMatch[2], 10) - 1;
|
||||
if (monthIndex >= 0 && monthIndex <= 11) {
|
||||
return new Date(Date.UTC(year, monthIndex, 1)).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
timeZone: "UTC",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const timestamp = Date.parse(dateValue);
|
||||
if (Number.isNaN(timestamp)) return dateValue;
|
||||
return new Date(timestamp).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
});
|
||||
}
|
||||
|
||||
export function WorkExperience({ realWork }: WorkExperienceProps) {
|
||||
const sortedRealWork = [...realWork].sort(
|
||||
(a, b) =>
|
||||
getSortTimestamp(b) - getSortTimestamp(a) ||
|
||||
getWorkDateTimestamp(b.from) - getWorkDateTimestamp(a.from),
|
||||
);
|
||||
|
||||
return (
|
||||
<section className="w-full max-w-4xl mx-auto px-4 space-y-8">
|
||||
<div className="text-center space-y-2">
|
||||
@@ -24,13 +67,28 @@ export function WorkExperience({ realWork }: WorkExperienceProps) {
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{realWork.map((entry, index) => (
|
||||
{sortedRealWork.map((entry, index) => (
|
||||
<div
|
||||
key={`${entry.company}-${index}`}
|
||||
className="p-6 md:p-8 rounded-2xl bg-gradient-to-br from-cyan-500/10 to-blue-500/5 backdrop-blur-sm border border-cyan-500/20 space-y-5"
|
||||
>
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
|
||||
<h3 className="text-2xl font-semibold text-white">{entry.company}</h3>
|
||||
<div>
|
||||
<h3 className="text-2xl font-semibold text-white">{entry.company}</h3>
|
||||
{entry.role ? (
|
||||
<p className="text-sm font-medium text-cyan-200/90 mt-1">{entry.role}</p>
|
||||
) : null}
|
||||
{entry.from || entry.until ? (
|
||||
<p className="text-xs font-medium uppercase tracking-wide text-cyan-300/80 mt-1">
|
||||
{entry.from ? formatWorkDate(entry.from) : "Unknown"} -{" "}
|
||||
{entry.until
|
||||
? entry.until.trim().toLowerCase() === "present"
|
||||
? "Present"
|
||||
: formatWorkDate(entry.until)
|
||||
: "Present"}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
{entry.url ? (
|
||||
<a
|
||||
href={entry.url}
|
||||
|
||||
@@ -34,6 +34,9 @@ export interface Project {
|
||||
|
||||
export interface RealWork {
|
||||
company: string;
|
||||
role?: string;
|
||||
from?: string;
|
||||
until?: string;
|
||||
url?: string;
|
||||
summary: string;
|
||||
tags?: string[];
|
||||
|
||||
Reference in New Issue
Block a user