diff --git a/src/assets/images/companies/araymond.png b/src/assets/images/companies/araymond.png new file mode 100644 index 0000000..a4660ed Binary files /dev/null and b/src/assets/images/companies/araymond.png differ diff --git a/src/assets/images/companies/champollion.png b/src/assets/images/companies/champollion.png new file mode 100644 index 0000000..c618ebb Binary files /dev/null and b/src/assets/images/companies/champollion.png differ diff --git a/src/assets/images/companies/dismoi.png b/src/assets/images/companies/dismoi.png new file mode 100644 index 0000000..3c44aac Binary files /dev/null and b/src/assets/images/companies/dismoi.png differ diff --git a/src/assets/images/companies/libeo.png b/src/assets/images/companies/libeo.png new file mode 100644 index 0000000..19d0411 Binary files /dev/null and b/src/assets/images/companies/libeo.png differ diff --git a/src/assets/images/companies/obat.png b/src/assets/images/companies/obat.png new file mode 100644 index 0000000..1f3f81f Binary files /dev/null and b/src/assets/images/companies/obat.png differ diff --git a/src/assets/images/companies/urssaf.png b/src/assets/images/companies/urssaf.png new file mode 100644 index 0000000..8626865 Binary files /dev/null and b/src/assets/images/companies/urssaf.png differ diff --git a/src/assets/images/companies/veepee.png b/src/assets/images/companies/veepee.png new file mode 100644 index 0000000..b356ab3 Binary files /dev/null and b/src/assets/images/companies/veepee.png differ diff --git a/src/content.config.ts b/src/content.config.ts index 6a579f6..d72d472 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -59,6 +59,7 @@ const experiencesCollection = defineCollection({ role: z.string(), company: z.string(), companyUrl: z.string().url().optional(), + logo: z.string().optional(), location: z.string().optional(), startDate: z.string(), endDate: z.string().optional(), diff --git a/src/content/experiences/araymond.ar.md b/src/content/experiences/araymond.ar.md index c6c490e..1208f13 100644 --- a/src/content/experiences/araymond.ar.md +++ b/src/content/experiences/araymond.ar.md @@ -2,6 +2,7 @@ role: "مهندس معماري للواجهات" company: "ARaymond" companyUrl: "https://www.araymond.com/" +logo: "araymond.png" location: "غرونوبل" startDate: "2022-01" endDate: "2023-01" diff --git a/src/content/experiences/araymond.en.md b/src/content/experiences/araymond.en.md index a306194..371a4b5 100644 --- a/src/content/experiences/araymond.en.md +++ b/src/content/experiences/araymond.en.md @@ -2,6 +2,7 @@ role: "Frontend Architect" company: "ARaymond" companyUrl: "https://www.araymond.com/" +logo: "araymond.png" location: "Grenoble" startDate: "2022-01" endDate: "2023-01" diff --git a/src/content/experiences/araymond.md b/src/content/experiences/araymond.md index 57c2457..fa421a4 100644 --- a/src/content/experiences/araymond.md +++ b/src/content/experiences/araymond.md @@ -2,6 +2,7 @@ role: "Architecte frontend" company: "ARaymond" companyUrl: "https://www.araymond.com/" +logo: "araymond.png" location: "Grenoble" startDate: "2022-01" endDate: "2023-01" diff --git a/src/content/experiences/champollion.ar.md b/src/content/experiences/champollion.ar.md index 08ee3cd..3ab5e8f 100644 --- a/src/content/experiences/champollion.ar.md +++ b/src/content/experiences/champollion.ar.md @@ -2,6 +2,7 @@ role: "أستاذ هندسة البرمجيات" company: "جامعة شامبوليون" companyUrl: "https://www.univ-jfc.fr/" +logo: "champollion.png" location: "ألبي" startDate: "2019-09" technologies: ["TypeScript", "JavaScript", "Node.js", "TDD", "Clean Code"] diff --git a/src/content/experiences/champollion.en.md b/src/content/experiences/champollion.en.md index 7c17341..eee1e05 100644 --- a/src/content/experiences/champollion.en.md +++ b/src/content/experiences/champollion.en.md @@ -2,6 +2,7 @@ role: "Software Engineering Professor" company: "Université Champollion" companyUrl: "https://www.univ-jfc.fr/" +logo: "champollion.png" location: "Albi" startDate: "2019-09" technologies: ["TypeScript", "JavaScript", "Node.js", "TDD", "Clean Code"] diff --git a/src/content/experiences/champollion.md b/src/content/experiences/champollion.md index 9a66823..ebac6ba 100644 --- a/src/content/experiences/champollion.md +++ b/src/content/experiences/champollion.md @@ -2,6 +2,7 @@ role: "Enseignant en génie logiciel" company: "Université Champollion" companyUrl: "https://www.univ-jfc.fr/" +logo: "champollion.png" location: "Albi" startDate: "2019-09" technologies: ["TypeScript", "JavaScript", "Node.js", "TDD", "Clean Code"] diff --git a/src/content/experiences/dismoi.ar.md b/src/content/experiences/dismoi.ar.md index edb66be..875a0b9 100644 --- a/src/content/experiences/dismoi.ar.md +++ b/src/content/experiences/dismoi.ar.md @@ -2,6 +2,7 @@ role: "حرفي برمجيات / مؤسس مشارك" company: "DisMoi" companyUrl: "https://github.com/dis-moi" +logo: "dismoi.png" location: "عن بُعد" startDate: "2019-01" endDate: "2021-06" diff --git a/src/content/experiences/dismoi.en.md b/src/content/experiences/dismoi.en.md index 1dcc0b4..891eb4d 100644 --- a/src/content/experiences/dismoi.en.md +++ b/src/content/experiences/dismoi.en.md @@ -2,6 +2,7 @@ role: "Software Craftsman / Cofounder" company: "DisMoi" companyUrl: "https://github.com/dis-moi" +logo: "dismoi.png" location: "Remote" startDate: "2019-01" endDate: "2021-06" diff --git a/src/content/experiences/dismoi.md b/src/content/experiences/dismoi.md index 728dd9a..98571f0 100644 --- a/src/content/experiences/dismoi.md +++ b/src/content/experiences/dismoi.md @@ -2,6 +2,7 @@ role: "Software Craftsman / Cofondateur" company: "DisMoi" companyUrl: "https://github.com/dis-moi" +logo: "dismoi.png" location: "Remote" startDate: "2019-01" endDate: "2021-06" diff --git a/src/content/experiences/libeo.ar.md b/src/content/experiences/libeo.ar.md index d10a484..8434d8e 100644 --- a/src/content/experiences/libeo.ar.md +++ b/src/content/experiences/libeo.ar.md @@ -2,6 +2,7 @@ role: "مهندس برمجيات fullstack" company: "Libeo" companyUrl: "https://www.libeo.io/" +logo: "libeo.png" location: "عن بُعد" startDate: "2021-01" endDate: "2021-06" diff --git a/src/content/experiences/libeo.en.md b/src/content/experiences/libeo.en.md index 8326bd7..3559884 100644 --- a/src/content/experiences/libeo.en.md +++ b/src/content/experiences/libeo.en.md @@ -2,6 +2,7 @@ role: "Fullstack Software Engineer" company: "Libeo" companyUrl: "https://www.libeo.io/" +logo: "libeo.png" location: "Remote" startDate: "2021-01" endDate: "2021-06" diff --git a/src/content/experiences/libeo.md b/src/content/experiences/libeo.md index 25733c8..e8446c9 100644 --- a/src/content/experiences/libeo.md +++ b/src/content/experiences/libeo.md @@ -2,6 +2,7 @@ role: "Ingénieur logiciel fullstack" company: "Libeo" companyUrl: "https://www.libeo.io/" +logo: "libeo.png" location: "Remote" startDate: "2021-01" endDate: "2021-06" diff --git a/src/content/experiences/obat.ar.md b/src/content/experiences/obat.ar.md index 0cbaea6..f832957 100644 --- a/src/content/experiences/obat.ar.md +++ b/src/content/experiences/obat.ar.md @@ -2,6 +2,7 @@ role: "مهندس برمجيات أول" company: "Obat" companyUrl: "https://www.obat.fr/" +logo: "obat.png" location: "عن بُعد" startDate: "2023-02" endDate: "2024-01" diff --git a/src/content/experiences/obat.en.md b/src/content/experiences/obat.en.md index cd856e7..969ee6f 100644 --- a/src/content/experiences/obat.en.md +++ b/src/content/experiences/obat.en.md @@ -2,6 +2,7 @@ role: "Senior Software Engineer" company: "Obat" companyUrl: "https://www.obat.fr/" +logo: "obat.png" location: "Remote" startDate: "2023-02" endDate: "2024-01" diff --git a/src/content/experiences/obat.md b/src/content/experiences/obat.md index ba7c7bd..7c9f302 100644 --- a/src/content/experiences/obat.md +++ b/src/content/experiences/obat.md @@ -2,6 +2,7 @@ role: "Ingénieur logiciel senior" company: "Obat" companyUrl: "https://www.obat.fr/" +logo: "obat.png" location: "Remote" startDate: "2023-02" endDate: "2024-01" diff --git a/src/content/experiences/urssaf.ar.md b/src/content/experiences/urssaf.ar.md index 1630b47..968b958 100644 --- a/src/content/experiences/urssaf.ar.md +++ b/src/content/experiences/urssaf.ar.md @@ -2,6 +2,7 @@ role: "مطوّر رئيسي" company: "Urssaf Caisse nationale" companyUrl: "https://www.urssaf.fr/" +logo: "urssaf.png" location: "عن بُعد / باريس" startDate: "2024-02" technologies: ["TypeScript", "React.js", "Publicodes", "Node.js", "GitHub"] diff --git a/src/content/experiences/urssaf.en.md b/src/content/experiences/urssaf.en.md index c2c800b..e4ecf6b 100644 --- a/src/content/experiences/urssaf.en.md +++ b/src/content/experiences/urssaf.en.md @@ -2,6 +2,7 @@ role: "Lead Developer" company: "Urssaf Caisse nationale" companyUrl: "https://www.urssaf.fr/" +logo: "urssaf.png" location: "Remote / Paris" startDate: "2024-02" technologies: ["TypeScript", "React.js", "Publicodes", "Node.js", "GitHub"] diff --git a/src/content/experiences/urssaf.md b/src/content/experiences/urssaf.md index a85d9b8..24fdafb 100644 --- a/src/content/experiences/urssaf.md +++ b/src/content/experiences/urssaf.md @@ -2,6 +2,7 @@ role: "Lead Developer" company: "Urssaf Caisse nationale" companyUrl: "https://www.urssaf.fr/" +logo: "urssaf.png" location: "Remote / Paris" startDate: "2024-02" technologies: ["TypeScript", "React.js", "Publicodes", "Node.js", "GitHub"] diff --git a/src/content/experiences/veepee-dev.ar.md b/src/content/experiences/veepee-dev.ar.md index 3574e10..1045a64 100644 --- a/src/content/experiences/veepee-dev.ar.md +++ b/src/content/experiences/veepee-dev.ar.md @@ -2,6 +2,7 @@ role: "مطوّر واجهات رئيسي Travel" company: "Veepee" companyUrl: "https://www.veepee.com/" +logo: "veepee.png" location: "باريس" startDate: "2016-02" endDate: "2018-01" diff --git a/src/content/experiences/veepee-dev.en.md b/src/content/experiences/veepee-dev.en.md index d8bb600..a180cac 100644 --- a/src/content/experiences/veepee-dev.en.md +++ b/src/content/experiences/veepee-dev.en.md @@ -2,6 +2,7 @@ role: "Travel Front Lead Developer" company: "Veepee" companyUrl: "https://www.veepee.com/" +logo: "veepee.png" location: "Paris" startDate: "2016-02" endDate: "2018-01" diff --git a/src/content/experiences/veepee-dev.md b/src/content/experiences/veepee-dev.md index 3eb6278..370abaa 100644 --- a/src/content/experiences/veepee-dev.md +++ b/src/content/experiences/veepee-dev.md @@ -2,6 +2,7 @@ role: "Travel Front Lead Developer" company: "Veepee" companyUrl: "https://www.veepee.com/" +logo: "veepee.png" location: "Paris" startDate: "2016-02" endDate: "2018-01" diff --git a/src/content/experiences/veepee-lead.ar.md b/src/content/experiences/veepee-lead.ar.md index 2edb17d..1eef7c3 100644 --- a/src/content/experiences/veepee-lead.ar.md +++ b/src/content/experiences/veepee-lead.ar.md @@ -2,6 +2,7 @@ role: "قائد تقني Travel" company: "Veepee" companyUrl: "https://www.veepee.com/" +logo: "veepee.png" location: "باريس" startDate: "2018-01" endDate: "2019-06" diff --git a/src/content/experiences/veepee-lead.en.md b/src/content/experiences/veepee-lead.en.md index 2e64265..c87fb85 100644 --- a/src/content/experiences/veepee-lead.en.md +++ b/src/content/experiences/veepee-lead.en.md @@ -2,6 +2,7 @@ role: "Travel Tech Lead" company: "Veepee" companyUrl: "https://www.veepee.com/" +logo: "veepee.png" location: "Paris" startDate: "2018-01" endDate: "2019-06" diff --git a/src/content/experiences/veepee-lead.md b/src/content/experiences/veepee-lead.md index a29255c..b12a909 100644 --- a/src/content/experiences/veepee-lead.md +++ b/src/content/experiences/veepee-lead.md @@ -2,6 +2,7 @@ role: "Travel Tech Lead" company: "Veepee" companyUrl: "https://www.veepee.com/" +logo: "veepee.png" location: "Paris" startDate: "2018-01" endDate: "2019-06" diff --git a/src/layouts/main.astro b/src/layouts/main.astro index d89766e..c4df27a 100644 --- a/src/layouts/main.astro +++ b/src/layouts/main.astro @@ -57,8 +57,8 @@ const locale = pathname.startsWith("/en") [data-facet="code"] > section h1, [data-facet="code"] > section h2, - [data-facet="code"] > section h3, - [data-facet="code"] > section strong { + [data-facet="code"] > section h3:not(.exp-card h3):not(.facet-card h3), + [data-facet="code"] > section strong:not(.exp-card strong):not(.facet-card strong) { color: white !important; } @@ -72,8 +72,8 @@ const locale = pathname.startsWith("/en") text-decoration-color: white !important; } - [data-facet="code"] > section > :not(.facet-card) p, - [data-facet="code"] > section > :not(.facet-card) li { + [data-facet="code"] > section p:not(.exp-card p):not(.facet-card p), + [data-facet="code"] > section li:not(.exp-card li):not(.facet-card li) { color: rgba(255, 255, 255, 0.75) !important; } diff --git a/src/pages/ar/برمجة/مسار.astro b/src/pages/ar/برمجة/مسار.astro index f33324e..9c527c2 100644 --- a/src/pages/ar/برمجة/مسار.astro +++ b/src/pages/ar/برمجة/مسار.astro @@ -1,16 +1,37 @@ --- import { getCollection, render } from "astro:content"; +import { Image } from "astro:assets"; import Layout from "../../../layouts/main.astro"; +const logos = import.meta.glob<{ default: ImageMetadata }>('../../../assets/images/companies/*.png', { eager: true }); + +function getLogo(filename?: string) { + if (!filename) return null; + const key = `../../../assets/images/companies/${filename}`; + return logos[key]?.default ?? null; +} + +function getInitials(company: string) { + return company.split(/[\s-]+/).map(w => w[0]).filter(Boolean).slice(0, 2).join('').toUpperCase(); +} + const locale = "ar"; const experiences = (await getCollection("experiences")) .filter((e) => e.data.lang === locale && !e.data.draft) .sort((a, b) => (b.data.startDate > a.data.startDate ? 1 : -1)); -const typeIcons: Record = { - employment: '🏢', freelance: '💼', teaching: '🎓', - community: '🤝', entrepreneurship: '🚀', +const typeLabels: Record = { + employment: 'وظيفة', freelance: 'مستقل', teaching: 'تدريس', + community: 'مجتمع', entrepreneurship: 'ريادة أعمال', +}; + +const typeColors: Record = { + employment: { badge: 'type-badge-blue', border: 'type-border-blue', dot: 'bg-blue-400 border-blue-400/50' }, + freelance: { badge: 'type-badge-amber', border: 'type-border-amber', dot: 'bg-amber-400 border-amber-400/50' }, + teaching: { badge: 'type-badge-emerald', border: 'type-border-emerald', dot: 'bg-emerald-400 border-emerald-400/50' }, + community: { badge: 'type-badge-pink', border: 'type-border-pink', dot: 'bg-pink-400 border-pink-400/50' }, + entrepreneurship: { badge: 'type-badge-purple', border: 'type-border-purple', dot: 'bg-purple-400 border-purple-400/50' }, }; function formatMonth(dateStr: string) { @@ -18,6 +39,17 @@ function formatMonth(dateStr: string) { return new Date(parseInt(year), parseInt(month) - 1) .toLocaleDateString('ar-SA', { year: 'numeric', month: 'short' }); } + +function computeDuration(startStr: string, endStr?: string) { + const [sy, sm] = startStr.split('-').map(Number); + const end = endStr ? endStr.split('-').map(Number) : [new Date().getFullYear(), new Date().getMonth() + 1]; + const totalMonths = (end[0] - sy) * 12 + (end[1] - sm); + const years = Math.floor(totalMonths / 12); + const months = totalMonths % 12; + if (years === 0) return `${months} أشهر`; + if (months === 0) return `${years} سنة`; + return `${years} سنة ${months} أشهر`; +} --- +
- {isOngoing &&
} + {isOngoing &&
}
-
-
- - {typeIcons[exp.data.type] || '💼'} {start} — {end} +
+ {getLogo(exp.data.logo) ? ( + + ) : ( +
+ {getInitials(exp.data.company)} +
+ )} + +
+ + {label} - {exp.data.location && · {exp.data.location}} + + {start} — {end} + + · {duration} + {exp.data.location && · {exp.data.location}}
-

{exp.data.role}

-

+

{exp.data.role}

+

{exp.data.companyUrl ? ( - {exp.data.company} + {exp.data.company} ) : exp.data.company}

-
+
{exp.data.technologies && exp.data.technologies.length > 0 && (
{exp.data.technologies.map((tech: string) => ( - + {tech} ))} @@ -92,3 +149,80 @@ function formatMonth(dateStr: string) {
+ + diff --git a/src/pages/code/parcours.astro b/src/pages/code/parcours.astro index 7c23059..fdf983a 100644 --- a/src/pages/code/parcours.astro +++ b/src/pages/code/parcours.astro @@ -1,16 +1,37 @@ --- import { getCollection, render } from "astro:content"; +import { Image } from "astro:assets"; import Layout from "../../layouts/main.astro"; +const logos = import.meta.glob<{ default: ImageMetadata }>('../../assets/images/companies/*.png', { eager: true }); + +function getLogo(filename?: string) { + if (!filename) return null; + const key = `../../assets/images/companies/${filename}`; + return logos[key]?.default ?? null; +} + +function getInitials(company: string) { + return company.split(/[\s-]+/).map(w => w[0]).filter(Boolean).slice(0, 2).join('').toUpperCase(); +} + const locale = "fr"; const experiences = (await getCollection("experiences")) .filter((e) => e.data.lang === locale && !e.data.draft) .sort((a, b) => (b.data.startDate > a.data.startDate ? 1 : -1)); -const typeIcons: Record = { - employment: '🏢', freelance: '💼', teaching: '🎓', - community: '🤝', entrepreneurship: '🚀', +const typeLabels: Record = { + employment: 'Emploi', freelance: 'Freelance', teaching: 'Enseignement', + community: 'Communauté', entrepreneurship: 'Entrepreneuriat', +}; + +const typeColors: Record = { + employment: { badge: 'type-badge-blue', border: 'type-border-blue', dot: 'bg-blue-400 border-blue-400/50' }, + freelance: { badge: 'type-badge-amber', border: 'type-border-amber', dot: 'bg-amber-400 border-amber-400/50' }, + teaching: { badge: 'type-badge-emerald', border: 'type-border-emerald', dot: 'bg-emerald-400 border-emerald-400/50' }, + community: { badge: 'type-badge-pink', border: 'type-border-pink', dot: 'bg-pink-400 border-pink-400/50' }, + entrepreneurship: { badge: 'type-badge-purple', border: 'type-border-purple', dot: 'bg-purple-400 border-purple-400/50' }, }; function formatMonth(dateStr: string) { @@ -18,6 +39,17 @@ function formatMonth(dateStr: string) { return new Date(parseInt(year), parseInt(month) - 1) .toLocaleDateString('fr-FR', { year: 'numeric', month: 'short' }); } + +function computeDuration(startStr: string, endStr?: string) { + const [sy, sm] = startStr.split('-').map(Number); + const end = endStr ? endStr.split('-').map(Number) : [new Date().getFullYear(), new Date().getMonth() + 1]; + const totalMonths = (end[0] - sy) * 12 + (end[1] - sm); + const years = Math.floor(totalMonths / 12); + const months = totalMonths % 12; + if (years === 0) return `${months} mois`; + if (months === 0) return `${years} an${years > 1 ? 's' : ''}`; + return `${years} an${years > 1 ? 's' : ''} ${months} mois`; +} --- +
- {isOngoing &&
} + {isOngoing &&
}
-
-
- - {typeIcons[exp.data.type] || '💼'} {start} — {end} +
+ {getLogo(exp.data.logo) ? ( + + ) : ( +
+ {getInitials(exp.data.company)} +
+ )} + +
+ + {label} - {exp.data.location && · {exp.data.location}} + + {start} — {end} + + · {duration} + {exp.data.location && · {exp.data.location}}
-

{exp.data.role}

-

+

{exp.data.role}

+

{exp.data.companyUrl ? ( - {exp.data.company} + {exp.data.company} ) : exp.data.company}

-
+
{exp.data.technologies && exp.data.technologies.length > 0 && (
{exp.data.technologies.map((tech: string) => ( - + {tech} ))} @@ -92,3 +149,80 @@ function formatMonth(dateStr: string) {
+ + diff --git a/src/pages/en/code/career.astro b/src/pages/en/code/career.astro index 0bec84b..aad30c5 100644 --- a/src/pages/en/code/career.astro +++ b/src/pages/en/code/career.astro @@ -1,16 +1,37 @@ --- import { getCollection, render } from "astro:content"; +import { Image } from "astro:assets"; import Layout from "../../../layouts/main.astro"; +const logos = import.meta.glob<{ default: ImageMetadata }>('../../../assets/images/companies/*.png', { eager: true }); + +function getLogo(filename?: string) { + if (!filename) return null; + const key = `../../../assets/images/companies/${filename}`; + return logos[key]?.default ?? null; +} + +function getInitials(company: string) { + return company.split(/[\s-]+/).map(w => w[0]).filter(Boolean).slice(0, 2).join('').toUpperCase(); +} + const locale = "en"; const experiences = (await getCollection("experiences")) .filter((e) => e.data.lang === locale && !e.data.draft) .sort((a, b) => (b.data.startDate > a.data.startDate ? 1 : -1)); -const typeIcons: Record = { - employment: '🏢', freelance: '💼', teaching: '🎓', - community: '🤝', entrepreneurship: '🚀', +const typeLabels: Record = { + employment: 'Employment', freelance: 'Freelance', teaching: 'Teaching', + community: 'Community', entrepreneurship: 'Entrepreneurship', +}; + +const typeColors: Record = { + employment: { badge: 'type-badge-blue', border: 'type-border-blue', dot: 'bg-blue-400 border-blue-400/50' }, + freelance: { badge: 'type-badge-amber', border: 'type-border-amber', dot: 'bg-amber-400 border-amber-400/50' }, + teaching: { badge: 'type-badge-emerald', border: 'type-border-emerald', dot: 'bg-emerald-400 border-emerald-400/50' }, + community: { badge: 'type-badge-pink', border: 'type-border-pink', dot: 'bg-pink-400 border-pink-400/50' }, + entrepreneurship: { badge: 'type-badge-purple', border: 'type-border-purple', dot: 'bg-purple-400 border-purple-400/50' }, }; function formatMonth(dateStr: string) { @@ -18,6 +39,17 @@ function formatMonth(dateStr: string) { return new Date(parseInt(year), parseInt(month) - 1) .toLocaleDateString('en-US', { year: 'numeric', month: 'short' }); } + +function computeDuration(startStr: string, endStr?: string) { + const [sy, sm] = startStr.split('-').map(Number); + const end = endStr ? endStr.split('-').map(Number) : [new Date().getFullYear(), new Date().getMonth() + 1]; + const totalMonths = (end[0] - sy) * 12 + (end[1] - sm); + const years = Math.floor(totalMonths / 12); + const months = totalMonths % 12; + if (years === 0) return `${months} mo`; + if (months === 0) return `${years} yr${years > 1 ? 's' : ''}`; + return `${years} yr${years > 1 ? 's' : ''} ${months} mo`; +} --- +
- {isOngoing &&
} + {isOngoing &&
}
-
-
- - {typeIcons[exp.data.type] || '💼'} {start} — {end} +
+ {getLogo(exp.data.logo) ? ( + + ) : ( +
+ {getInitials(exp.data.company)} +
+ )} + +
+ + {label} - {exp.data.location && · {exp.data.location}} + + {start} — {end} + + · {duration} + {exp.data.location && · {exp.data.location}}
-

{exp.data.role}

-

+

{exp.data.role}

+

{exp.data.companyUrl ? ( - {exp.data.company} + {exp.data.company} ) : exp.data.company}

-
+
{exp.data.technologies && exp.data.technologies.length > 0 && (
{exp.data.technologies.map((tech: string) => ( - + {tech} ))} @@ -92,3 +149,80 @@ function formatMonth(dateStr: string) {
+ +