Compare commits

..

No commits in common. "6714bb62a67f9c318f0669f3319f8d02c01670f1" and "578c6733db92c4ff03a0750c93cadfdfd1516432" have entirely different histories.

12 changed files with 59 additions and 87 deletions

View file

@ -14,35 +14,28 @@ const { title, description, technologies, featured = false, detailUrl, lang = 'f
const isRtl = lang === 'ar'; const isRtl = lang === 'ar';
const readMoreLabel = t('projects', 'readMore', lang); const readMoreLabel = t('projects', 'readMore', lang);
const primaryTechs = technologies?.slice(0, 3) ?? [];
const secondaryTechs = technologies?.slice(3) ?? [];
--- ---
<a href={detailUrl} class:list={[ <a href={detailUrl} class:list={[
"project-card group relative rounded-2xl border p-6 flex flex-col h-full transition-all duration-300 hover:scale-[1.02] no-underline overflow-hidden", "facet-card rounded-2xl border p-6 flex flex-col h-full transition-all duration-300 hover:scale-[1.02] no-underline",
featured featured
? "bg-white/[0.10] border-purple-300/20" ? "bg-white/[0.12] border-purple-300/20 hover:bg-white/[0.18] hover:border-purple-300/30"
: "bg-white/[0.05] border-white/[0.08]", : "bg-white/[0.06] border-white/[0.1] hover:bg-white/[0.12] hover:border-white/[0.2]",
]}> ]}>
<div class="mb-3"> <div class="mb-2">
<h3 class="text-xl font-bold text-white"> <h3 class="text-lg font-bold text-white">
{title} {title}
</h3> </h3>
</div> </div>
<p class="text-white/60 leading-relaxed flex-1 mb-5"> <p class="text-sm text-white/60 leading-relaxed flex-1 mb-4">
{description} {description}
</p> </p>
{(primaryTechs.length > 0 || secondaryTechs.length > 0) && ( {technologies && technologies.length > 0 && (
<div class="flex flex-wrap gap-1.5 mb-5"> <div class="flex flex-wrap gap-1.5 mb-4">
{primaryTechs.map((tech) => ( {technologies.map((tech) => (
<span class="inline-block px-2.5 py-1 text-xs font-medium rounded-full bg-purple-400/15 text-purple-200 border border-purple-300/15"> <span class="inline-block px-2 py-0.5 text-xs rounded-full bg-white/[0.08] text-white/60 border border-white/[0.08]">
{tech}
</span>
))}
{secondaryTechs.map((tech) => (
<span class="inline-block px-2.5 py-1 text-xs rounded-full bg-white/[0.05] text-white/40 border border-white/[0.06]">
{tech} {tech}
</span> </span>
))} ))}
@ -57,11 +50,3 @@ const secondaryTechs = technologies?.slice(3) ?? [];
)} )}
</span> </span>
</a> </a>
<style>
.project-card:hover {
background: rgba(255, 255, 255, 0.12);
border-color: rgba(168, 85, 247, 0.25);
box-shadow: 0 0 24px rgba(168, 85, 247, 0.08), 0 4px 16px rgba(0, 0, 0, 0.2);
}
</style>

View file

@ -1,7 +0,0 @@
---
---
<li class="flex items-start gap-4">
<span class="w-4 h-0.5 bg-purple-400/60 mt-3 flex-shrink-0"></span>
<span><slot /></span>
</li>

View file

@ -7,7 +7,6 @@ startDate: "2022-01"
endDate: "2023-01" endDate: "2023-01"
technologies: ["TypeScript", "React.js", "Redux", "Nx", "Vite"] technologies: ["TypeScript", "React.js", "Redux", "Nx", "Vite"]
type: "freelance" type: "freelance"
featured: true
lang: "ar" lang: "ar"
--- ---

View file

@ -7,7 +7,6 @@ startDate: "2022-01"
endDate: "2023-01" endDate: "2023-01"
technologies: ["TypeScript", "React.js", "Redux", "Nx", "Vite"] technologies: ["TypeScript", "React.js", "Redux", "Nx", "Vite"]
type: "freelance" type: "freelance"
featured: true
lang: "en" lang: "en"
--- ---

View file

@ -7,7 +7,6 @@ startDate: "2022-01"
endDate: "2023-01" endDate: "2023-01"
technologies: ["TypeScript", "React.js", "Redux", "Nx", "Vite"] technologies: ["TypeScript", "React.js", "Redux", "Nx", "Vite"]
type: "freelance" type: "freelance"
featured: true
lang: "fr" lang: "fr"
--- ---

View file

@ -6,7 +6,6 @@ location: "ألبي"
startDate: "2019-09" startDate: "2019-09"
technologies: ["TypeScript", "JavaScript", "Node.js", "TDD", "Clean Code"] technologies: ["TypeScript", "JavaScript", "Node.js", "TDD", "Clean Code"]
type: "teaching" type: "teaching"
featured: true
lang: "ar" lang: "ar"
--- ---

View file

@ -6,7 +6,6 @@ location: "Albi"
startDate: "2019-09" startDate: "2019-09"
technologies: ["TypeScript", "JavaScript", "Node.js", "TDD", "Clean Code"] technologies: ["TypeScript", "JavaScript", "Node.js", "TDD", "Clean Code"]
type: "teaching" type: "teaching"
featured: true
lang: "en" lang: "en"
--- ---

View file

@ -6,7 +6,6 @@ location: "Albi"
startDate: "2019-09" startDate: "2019-09"
technologies: ["TypeScript", "JavaScript", "Node.js", "TDD", "Clean Code"] technologies: ["TypeScript", "JavaScript", "Node.js", "TDD", "Clean Code"]
type: "teaching" type: "teaching"
featured: true
lang: "fr" lang: "fr"
--- ---

View file

@ -17,8 +17,8 @@ const recommendationCount = (await getCollection("recommendations")).length;
--- ---
<Layout <Layout
title="جليل عرفاوي - مطوّر • مصوّر • ممثل ارتجالي" title="جليل عرفاوي - حِرَفي برمجة • ممثل ارتجالي • مصوّر"
description="جليل عرفاوي: مطوّر مستقل (Software Craftsmanship، TDD، DDD)، مصوّر وممثل مقيم في ألبي، فرنسا." description="جليل عرفاوي: مطوّر مستقل (Software Craftsmanship، TDD، DDD)، ممثل ارتجالي ومصوّر مقيم في ألبي، فرنسا."
> >
<!-- Hero Section --> <!-- Hero Section -->
<div dir="rtl" lang="ar" class="relative z-20 w-full max-w-6xl mx-auto mt-16 px-7 md:mt-24 lg:mt-32 xl:px-0"> <div dir="rtl" lang="ar" class="relative z-20 w-full max-w-6xl mx-auto mt-16 px-7 md:mt-24 lg:mt-32 xl:px-0">
@ -28,7 +28,7 @@ const recommendationCount = (await getCollection("recommendations")).length;
جليل عرفاوي جليل عرفاوي
</h1> </h1>
<h2 class="mb-6 text-xl font-medium text-neutral-600 dark:text-neutral-300 md:text-2xl"> <h2 class="mb-6 text-xl font-medium text-neutral-600 dark:text-neutral-300 md:text-2xl">
مطوّر • مصوّر • ممثل حِرَفي برمجة • ممثل ارتجالي • مصوّر
</h2> </h2>
<p class="mb-8 text-lg text-neutral-600 dark:text-neutral-400 leading-relaxed"> <p class="mb-8 text-lg text-neutral-600 dark:text-neutral-400 leading-relaxed">
أكتب الكود من أجل عالم أكثر عدلًا، وأصعد على الخشبة لأجل الباقي. أو العكس. أكتب الكود من أجل عالم أكثر عدلًا، وأصعد على الخشبة لأجل الباقي. أو العكس.

View file

@ -5,7 +5,6 @@ import Layout from "../../layouts/main.astro";
import Link from "../../components/Link.astro"; import Link from "../../components/Link.astro";
import FeaturedRecommendation from "../../components/code/FeaturedRecommendation.astro"; import FeaturedRecommendation from "../../components/code/FeaturedRecommendation.astro";
import ProjectCard from "../../components/code/ProjectCard.astro"; import ProjectCard from "../../components/code/ProjectCard.astro";
import ValueItem from "../../components/code/ValueItem.astro";
import { getProjectBaseSlug, getProjectsBasePath } from "../../utils/i18n"; import { getProjectBaseSlug, getProjectsBasePath } from "../../utils/i18n";
import logoTiqa from "../../assets/images/logo-tiqa-blanc.png"; import logoTiqa from "../../assets/images/logo-tiqa-blanc.png";
@ -16,7 +15,7 @@ const experiences = (await getCollection("experiences"))
.filter((e) => e.data.lang === locale && !e.data.draft) .filter((e) => e.data.lang === locale && !e.data.draft)
.sort((a, b) => (b.data.startDate > a.data.startDate ? 1 : -1)); .sort((a, b) => (b.data.startDate > a.data.startDate ? 1 : -1));
const recentExperiences = experiences.filter((e) => e.data.featured).slice(0, 4); const recentExperiences = experiences.slice(0, 4);
const projects = (await getCollection("projects")) const projects = (await getCollection("projects"))
.filter((p) => p.data.lang === locale && !p.data.draft && p.data.category === "dev" && p.data.featured) .filter((p) => p.data.lang === locale && !p.data.draft && p.data.category === "dev" && p.data.featured)
@ -45,10 +44,8 @@ function formatMonth(dateStr: string) {
> >
<section class="relative z-20 max-w-3xl mx-auto my-16 px-7 lg:px-0"> <section class="relative z-20 max-w-3xl mx-auto my-16 px-7 lg:px-0">
<div class="mb-16"> <div class="mb-16">
<span class="inline-block px-3 py-1 text-sm text-purple-200/80 bg-white/[0.06] border border-white/[0.08] rounded-full mb-5">Développeur freelance · Albi</span> <h1 class="text-4xl sm:text-5xl font-semibold text-white font-display tracking-wide">Artisan du logiciel</h1>
<h1 class="text-5xl sm:text-6xl font-semibold text-white font-display tracking-wide">Artisan du logiciel</h1> <div class="mt-6 space-y-4 text-lg text-white/60 leading-relaxed max-w-2xl">
<div class="mt-6 mb-6 w-16 h-0.5 bg-gradient-to-r from-purple-400 to-transparent rounded-full"></div>
<div class="space-y-4 text-lg text-white/60 leading-relaxed max-w-2xl">
<p> <p>
TDD, Clean Code, Domain-Driven Design : c'est ma façon de construire du logiciel. J'accompagne les équipes comme développeur senior, tech lead ou coach technique. Ma stack : TypeScript/JavaScript, mais aussi PHP et Elixir. TDD, Clean Code, Domain-Driven Design : c'est ma façon de construire du logiciel. J'accompagne les équipes comme développeur senior, tech lead ou coach technique. Ma stack : TypeScript/JavaScript, mais aussi PHP et Elixir.
</p> </p>
@ -66,42 +63,30 @@ function formatMonth(dateStr: string) {
<h2 class="text-2xl font-bold text-white ">Parcours</h2> <h2 class="text-2xl font-bold text-white ">Parcours</h2>
<a href="/code/parcours" class="text-sm text-purple-200 hover:text-white transition-colors">Voir tout &rarr;</a> <a href="/code/parcours" class="text-sm text-purple-200 hover:text-white transition-colors">Voir tout &rarr;</a>
</div> </div>
<div class="relative ml-3"> <div class="divide-y divide-white/[0.08]">
<div class="absolute left-0 top-1.5 bottom-1.5 w-px bg-purple-300/20"></div>
{recentExperiences.map((exp) => { {recentExperiences.map((exp) => {
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';
return ( return (
<div class="relative pl-7 pb-6 last:pb-0"> <div class="py-4 first:pt-0 last:pb-0">
<div class:list={[ <div class="flex items-start justify-between gap-4">
"absolute left-0 top-1.5 w-2.5 h-2.5 rounded-full -translate-x-1/2 border-2", <div class="min-w-0">
isOngoing <p class="font-semibold text-white text-sm">{exp.data.role}</p>
? "bg-purple-400 border-purple-400/50 shadow-[0_0_8px_rgba(168,85,247,0.4)]" <p class="text-sm text-white/45 mt-0.5">
: "bg-transparent border-purple-300/30"
]} />
{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" />
)}
<span class:list={[isOngoing ? "text-purple-200" : "text-white/55"]}>
{start} — {end}
</span>
<p class="font-semibold text-white text-lg mt-0.5">{exp.data.role}</p>
<p class="text-white/55 mt-0.5">
{exp.data.companyUrl ? ( {exp.data.companyUrl ? (
<a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="text-purple-200 hover:text-white transition-colors">{exp.data.company}</a> <a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="text-purple-200 hover:text-white transition-colors">{exp.data.company}</a>
) : exp.data.company} ) : exp.data.company}
{exp.data.location && ` · ${exp.data.location}`} {exp.data.location && ` · ${exp.data.location}`}
</p> </p>
</div> </div>
<span class:list={["text-sm whitespace-nowrap flex-shrink-0", isOngoing ? "text-purple-200" : "text-white/35"]}>
{start} — {end}
</span>
</div>
</div>
); );
})} })}
<div class="relative pl-7 pt-2 flex items-center gap-3">
<span class="text-purple-300/40 tracking-[0.3em]">...</span>
<a href="/code/parcours" class="text-purple-200 hover:text-white transition-colors">
Voir le parcours complet &rarr;
</a>
</div>
</div> </div>
</div> </div>
@ -147,12 +132,27 @@ function formatMonth(dateStr: string) {
<div class="mb-16"> <div class="mb-16">
<h2 class="text-2xl font-bold text-white mb-6">Valeurs & Approche</h2> <h2 class="text-2xl font-bold text-white mb-6">Valeurs & Approche</h2>
<ul class="space-y-4 text-white/80"> <ul class="space-y-3 text-white/60">
<ValueItem>Le mouvement <Link href="http://manifesto.softwarecraftsmanship.org/#/fr-fr" external>Software Craftsmanship</Link></ValueItem> <li class="flex items-start gap-3">
<ValueItem>L'utilité sociale du développeur</ValueItem> <span class="w-1 h-1 rounded-full bg-purple-300/60 mt-2.5 flex-shrink-0"></span>
<ValueItem>Être fier de son travail, mais sans égo</ValueItem> <span>Le mouvement <Link href="http://manifesto.softwarecraftsmanship.org/#/fr-fr" external>Software Craftsmanship</Link></span>
<ValueItem>Approche <strong class="text-white">Domain Driven Design</strong></ValueItem> </li>
<ValueItem>Organisation <Link href="https://agilemanifesto.org/iso/fr/manifesto.html" external>agile</Link> : itération et amélioration continue</ValueItem> <li class="flex items-start gap-3">
<span class="w-1 h-1 rounded-full bg-purple-300/60 mt-2.5 flex-shrink-0"></span>
<span>L'utilité sociale du développeur</span>
</li>
<li class="flex items-start gap-3">
<span class="w-1 h-1 rounded-full bg-purple-300/60 mt-2.5 flex-shrink-0"></span>
<span>Être fier de son travail, mais sans égo</span>
</li>
<li class="flex items-start gap-3">
<span class="w-1 h-1 rounded-full bg-purple-300/60 mt-2.5 flex-shrink-0"></span>
<span>Approche <strong class="text-white">Domain Driven Design</strong></span>
</li>
<li class="flex items-start gap-3">
<span class="w-1 h-1 rounded-full bg-purple-300/60 mt-2.5 flex-shrink-0"></span>
<span>Organisation <Link href="https://agilemanifesto.org/iso/fr/manifesto.html" external>agile</Link> : itération et amélioration continue</span>
</li>
</ul> </ul>
</div> </div>

View file

@ -17,8 +17,8 @@ const recommendationCount = (await getCollection("recommendations")).length;
--- ---
<Layout <Layout
title="Jalil Arfaoui - Software Craftsman • Photographer • Improv Actor" title="Jalil Arfaoui - Software Craftsman • Improv Actor • Photographer"
description="Jalil Arfaoui: freelance developer (Software Craftsmanship, TDD, DDD), photographer and actor based in Albi, France." description="Jalil Arfaoui: freelance developer (Software Craftsmanship, TDD, DDD), improv actor and photographer based in Albi, France."
> >
<!-- Hero Section --> <!-- Hero Section -->
<div class="relative z-20 w-full max-w-6xl mx-auto mt-16 px-7 md:mt-24 lg:mt-32 xl:px-0"> <div class="relative z-20 w-full max-w-6xl mx-auto mt-16 px-7 md:mt-24 lg:mt-32 xl:px-0">
@ -28,7 +28,7 @@ const recommendationCount = (await getCollection("recommendations")).length;
Jalil Arfaoui Jalil Arfaoui
</h1> </h1>
<h2 class="mb-6 text-xl font-medium text-neutral-600 dark:text-neutral-300 md:text-2xl"> <h2 class="mb-6 text-xl font-medium text-neutral-600 dark:text-neutral-300 md:text-2xl">
Software Craftsman • Photographer • Actor Software Craftsman • Improv Actor • Photographer
</h2> </h2>
<p class="mb-8 text-lg text-neutral-600 dark:text-neutral-400 leading-relaxed"> <p class="mb-8 text-lg text-neutral-600 dark:text-neutral-400 leading-relaxed">
I write code for a fairer world and get on stage for the rest. Or the other way around. I write code for a fairer world and get on stage for the rest. Or the other way around.

View file

@ -17,8 +17,8 @@ const recommendationCount = (await getCollection("recommendations")).length;
--- ---
<Layout <Layout
title="Jalil Arfaoui - Développeur artisan • Photographe • Comédien improvisateur" title="Jalil Arfaoui - Développeur artisan • Comédien improvisateur • Photographe"
description="Jalil Arfaoui : développeur freelance, photographe et comédien improvisateur basé à Albi." description="Jalil Arfaoui : développeur freelance (Software Craftsmanship, TDD, DDD), comédien improvisateur et photographe basé à Albi."
> >
<!-- Hero Section --> <!-- Hero Section -->
<div class="relative z-20 w-full max-w-6xl mx-auto mt-16 px-7 md:mt-24 lg:mt-32 xl:px-0"> <div class="relative z-20 w-full max-w-6xl mx-auto mt-16 px-7 md:mt-24 lg:mt-32 xl:px-0">
@ -28,7 +28,7 @@ const recommendationCount = (await getCollection("recommendations")).length;
Jalil Arfaoui Jalil Arfaoui
</h1> </h1>
<h2 class="mb-6 text-xl font-medium text-neutral-600 dark:text-neutral-300 md:text-2xl"> <h2 class="mb-6 text-xl font-medium text-neutral-600 dark:text-neutral-300 md:text-2xl">
Développeur • Photographe • Comédien Développeur artisan • Comédien improvisateur • Photographe
</h2> </h2>
<p class="mb-8 text-lg text-neutral-600 dark:text-neutral-400 leading-relaxed"> <p class="mb-8 text-lg text-neutral-600 dark:text-neutral-400 leading-relaxed">
Je code pour un monde plus juste et je monte sur scène pour le reste. Ou l'inverse. Je code pour un monde plus juste et je monte sur scène pour le reste. Ou l'inverse.