Logos clients dans la mini-timeline /code (FR/EN/AR)

This commit is contained in:
Jalil Arfaoui 2026-03-12 00:28:06 +01:00
parent 3d67c2a320
commit f88a17b0ee
3 changed files with 87 additions and 30 deletions

View file

@ -18,6 +18,14 @@ import logoTiqa from "../../../assets/images/logo-tiqa-blanc.png";
const locale = "ar"; const locale = "ar";
const projectsBasePath = getProjectsBasePath(locale); const projectsBasePath = getProjectsBasePath(locale);
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;
}
const experiences = (await getLocalizedCollection("experiences", locale)) const experiences = (await getLocalizedCollection("experiences", locale))
.filter((e) => !e.data.draft) .filter((e) => !e.data.draft)
.sort((a, b) => { .sort((a, b) => {
@ -29,6 +37,7 @@ const experiences = (await getLocalizedCollection("experiences", locale))
const recentExperiences = experiences.filter((e) => e.data.featured).slice(0, 4); const recentExperiences = experiences.filter((e) => e.data.featured).slice(0, 4);
const projects = (await getLocalizedCollection("projects", locale)) const projects = (await getLocalizedCollection("projects", locale))
.filter((p) => !p.data.draft && p.data.category === "dev" && p.data.featured) .filter((p) => !p.data.draft && p.data.category === "dev" && p.data.featured)
.sort((a, b) => b.data.date!.getTime() - a.data.date!.getTime()); .sort((a, b) => b.data.date!.getTime() - a.data.date!.getTime());
@ -83,6 +92,7 @@ function formatMonth(dateStr: string) {
const isOngoing = !exp.data.endDate; const isOngoing = !exp.data.endDate;
const start = formatMonth(exp.data.startDate); const start = formatMonth(exp.data.startDate);
const end = exp.data.endDate ? formatMonth(exp.data.endDate) : 'الحالي'; const end = exp.data.endDate ? formatMonth(exp.data.endDate) : 'الحالي';
const logo = getLogo(exp.data.logo);
return ( return (
<div class="relative pr-7 pb-6 last:pb-0"> <div class="relative pr-7 pb-6 last:pb-0">
<div class:list={[ <div class:list={[
@ -94,16 +104,25 @@ function formatMonth(dateStr: string) {
{isOngoing && ( {isOngoing && (
<div class="absolute right-0 top-1.5 w-2.5 h-2.5 rounded-full translate-x-1/2 bg-purple-400/50 animate-ping" /> <div class="absolute right-0 top-1.5 w-2.5 h-2.5 rounded-full translate-x-1/2 bg-purple-400/50 animate-ping" />
)} )}
<span class:list={[isOngoing ? "text-purple-200" : "text-white/55"]}> <div class="flex items-start justify-between gap-4">
{start} — {end} <div>
</span> <span class:list={[isOngoing ? "text-purple-200" : "text-white/55"]}>
<p class="font-semibold text-white text-lg mt-0.5">{exp.data.role}</p> {start} — {end}
<p class="text-white/55 mt-0.5"> </span>
{exp.data.companyUrl ? ( <p class="font-semibold text-white text-lg mt-0.5">{exp.data.role}</p>
<a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="text-purple-200 hover:text-white transition-colors">{exp.data.company}</a> <p class="text-white/55 mt-0.5">
) : exp.data.company} {exp.data.companyUrl ? (
{exp.data.location && ` · ${exp.data.location}`} <a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="text-purple-200 hover:text-white transition-colors">{exp.data.company}</a>
</p> ) : exp.data.company}
{exp.data.location && ` · ${exp.data.location}`}
</p>
</div>
{logo && (
<div class="shrink-0 w-10 h-10 rounded-lg bg-white p-1 flex items-center justify-center">
<Image src={logo} alt={`شعار ${exp.data.company}`} width={32} height={32} class="rounded object-contain" />
</div>
)}
</div>
</div> </div>
); );
})} })}

View file

@ -18,6 +18,14 @@ import logoTiqa from "../../assets/images/logo-tiqa-blanc.png";
const locale = "fr"; const locale = "fr";
const projectsBasePath = getProjectsBasePath(locale); const projectsBasePath = getProjectsBasePath(locale);
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;
}
const experiences = (await getLocalizedCollection("experiences", locale)) const experiences = (await getLocalizedCollection("experiences", locale))
.filter((e) => !e.data.draft) .filter((e) => !e.data.draft)
.sort((a, b) => { .sort((a, b) => {
@ -29,6 +37,7 @@ const experiences = (await getLocalizedCollection("experiences", locale))
const recentExperiences = experiences.filter((e) => e.data.featured).slice(0, 4); const recentExperiences = experiences.filter((e) => e.data.featured).slice(0, 4);
const projects = (await getLocalizedCollection("projects", locale)) const projects = (await getLocalizedCollection("projects", locale))
.filter((p) => !p.data.draft && p.data.category === "dev" && p.data.featured) .filter((p) => !p.data.draft && p.data.category === "dev" && p.data.featured)
.sort((a, b) => b.data.date!.getTime() - a.data.date!.getTime()); .sort((a, b) => b.data.date!.getTime() - a.data.date!.getTime());
@ -83,6 +92,7 @@ function formatMonth(dateStr: string) {
const isOngoing = !exp.data.endDate; const isOngoing = !exp.data.endDate;
const start = formatMonth(exp.data.startDate); const start = formatMonth(exp.data.startDate);
const end = exp.data.endDate ? formatMonth(exp.data.endDate) : 'Présent'; const end = exp.data.endDate ? formatMonth(exp.data.endDate) : 'Présent';
const logo = getLogo(exp.data.logo);
return ( return (
<div class="relative pl-7 pb-6 last:pb-0"> <div class="relative pl-7 pb-6 last:pb-0">
<div class:list={[ <div class:list={[
@ -94,16 +104,25 @@ function formatMonth(dateStr: string) {
{isOngoing && ( {isOngoing && (
<div class="absolute left-0 top-1.5 w-2.5 h-2.5 rounded-full -translate-x-1/2 bg-purple-400/50 animate-ping" /> <div class="absolute left-0 top-1.5 w-2.5 h-2.5 rounded-full -translate-x-1/2 bg-purple-400/50 animate-ping" />
)} )}
<span class:list={[isOngoing ? "text-purple-200" : "text-white/55"]}> <div class="flex items-start justify-between gap-4">
{start} — {end} <div>
</span> <span class:list={[isOngoing ? "text-purple-200" : "text-white/55"]}>
<p class="font-semibold text-white text-lg mt-0.5">{exp.data.role}</p> {start} — {end}
<p class="text-white/55 mt-0.5"> </span>
{exp.data.companyUrl ? ( <p class="font-semibold text-white text-lg mt-0.5">{exp.data.role}</p>
<a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="text-purple-200 hover:text-white transition-colors">{exp.data.company}</a> <p class="text-white/55 mt-0.5">
) : exp.data.company} {exp.data.companyUrl ? (
{exp.data.location && ` · ${exp.data.location}`} <a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="text-purple-200 hover:text-white transition-colors">{exp.data.company}</a>
</p> ) : exp.data.company}
{exp.data.location && ` · ${exp.data.location}`}
</p>
</div>
{logo && (
<div class="shrink-0 w-10 h-10 rounded-lg bg-white p-1 flex items-center justify-center">
<Image src={logo} alt={`Logo ${exp.data.company}`} width={32} height={32} class="rounded object-contain" />
</div>
)}
</div>
</div> </div>
); );
})} })}

View file

@ -18,6 +18,14 @@ import logoTiqa from "../../../assets/images/logo-tiqa-blanc.png";
const locale = "en"; const locale = "en";
const projectsBasePath = getProjectsBasePath(locale); const projectsBasePath = getProjectsBasePath(locale);
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;
}
const experiences = (await getLocalizedCollection("experiences", locale)) const experiences = (await getLocalizedCollection("experiences", locale))
.filter((e) => !e.data.draft) .filter((e) => !e.data.draft)
.sort((a, b) => { .sort((a, b) => {
@ -29,6 +37,7 @@ const experiences = (await getLocalizedCollection("experiences", locale))
const recentExperiences = experiences.filter((e) => e.data.featured).slice(0, 4); const recentExperiences = experiences.filter((e) => e.data.featured).slice(0, 4);
const projects = (await getLocalizedCollection("projects", locale)) const projects = (await getLocalizedCollection("projects", locale))
.filter((p) => !p.data.draft && p.data.category === "dev" && p.data.featured) .filter((p) => !p.data.draft && p.data.category === "dev" && p.data.featured)
.sort((a, b) => b.data.date!.getTime() - a.data.date!.getTime()); .sort((a, b) => b.data.date!.getTime() - a.data.date!.getTime());
@ -83,6 +92,7 @@ function formatMonth(dateStr: string) {
const isOngoing = !exp.data.endDate; const isOngoing = !exp.data.endDate;
const start = formatMonth(exp.data.startDate); const start = formatMonth(exp.data.startDate);
const end = exp.data.endDate ? formatMonth(exp.data.endDate) : 'Present'; const end = exp.data.endDate ? formatMonth(exp.data.endDate) : 'Present';
const logo = getLogo(exp.data.logo);
return ( return (
<div class="relative pl-7 pb-6 last:pb-0"> <div class="relative pl-7 pb-6 last:pb-0">
<div class:list={[ <div class:list={[
@ -94,16 +104,25 @@ function formatMonth(dateStr: string) {
{isOngoing && ( {isOngoing && (
<div class="absolute left-0 top-1.5 w-2.5 h-2.5 rounded-full -translate-x-1/2 bg-purple-400/50 animate-ping" /> <div class="absolute left-0 top-1.5 w-2.5 h-2.5 rounded-full -translate-x-1/2 bg-purple-400/50 animate-ping" />
)} )}
<span class:list={[isOngoing ? "text-purple-200" : "text-white/55"]}> <div class="flex items-start justify-between gap-4">
{start} — {end} <div>
</span> <span class:list={[isOngoing ? "text-purple-200" : "text-white/55"]}>
<p class="font-semibold text-white text-lg mt-0.5">{exp.data.role}</p> {start} — {end}
<p class="text-white/55 mt-0.5"> </span>
{exp.data.companyUrl ? ( <p class="font-semibold text-white text-lg mt-0.5">{exp.data.role}</p>
<a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="text-purple-200 hover:text-white transition-colors">{exp.data.company}</a> <p class="text-white/55 mt-0.5">
) : exp.data.company} {exp.data.companyUrl ? (
{exp.data.location && ` · ${exp.data.location}`} <a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="text-purple-200 hover:text-white transition-colors">{exp.data.company}</a>
</p> ) : exp.data.company}
{exp.data.location && ` · ${exp.data.location}`}
</p>
</div>
{logo && (
<div class="shrink-0 w-10 h-10 rounded-lg bg-white p-1 flex items-center justify-center">
<Image src={logo} alt={`${exp.data.company} logo`} width={32} height={32} class="rounded object-contain" />
</div>
)}
</div>
</div> </div>
); );
})} })}