refonte: portfolio statique Astro (design moderne développeur)
Some checks failed
Deploy production / build-deploy (push) Failing after 56s

- Remplace l'ancien Astro hybrid + admin par un site one-page statique (sortie static)
- Thème clair/sombre sans flash, contenu typé (src/data/content.ts), zéro admin
- Icônes simple-icons (SVG monochrome), polices auto-hébergées (RGPD)
- SEO complet : canonical, Open Graph, Twitter Card, JSON-LD Person, robots.txt, sitemap.xml, image OG 1200x630
- CI Gitea de déploiement FTPS vers Plesk (.gitea/workflows/prod.yml)
This commit is contained in:
Johan LEROY
2026-06-19 16:03:09 +02:00
parent dc4e3820c4
commit ce17bf590b
189 changed files with 1836 additions and 9872 deletions

308
src/data/content.ts Normal file
View File

@@ -0,0 +1,308 @@
/* ============================================================
Contenu du portfolio — SOURCE DE VÉRITÉ unique.
Pour modifier le site (textes, projets, expériences…),
c'est ici que ça se passe. Tout est typé.
============================================================ */
export type ProjectStatus = "live" | "archived" | "oss";
export interface Project {
id: string;
title: string;
subtitle: string;
desc: string;
stack: string[];
status: ProjectStatus;
link?: string;
img?: string;
}
export interface Experience {
company: string;
logo: string;
role: string;
period: string;
duration: string;
desc: string;
missions: string[];
stack: string[];
current?: boolean;
}
export interface Formation {
title: string;
school: string;
period: string;
desc?: string;
}
export interface StackGroup {
label: string;
items: string[]; // noms de technos, résolus en icônes par <TechIcon/>
}
export interface Interest {
name: string;
note: string;
icon: "gamepad" | "film" | "music" | "code";
}
export const profile = {
name: "Johan Leroy",
role: "Développeur fullstack",
lede:
"Je conçois et développe des applications web performantes, propres et scalables — du front jusqu'à la mise en production. Basé à Nantes, profil « builder » : open-source, auto-hébergement, projets perso.",
bio:
"Développeur fullstack passionné par les technologies modernes. J'aime construire des produits complets — penser l'archi, soigner l'expérience, déployer et maintenir. J'expérimente en continu via mes projets perso, mes services auto-hébergés et l'open-source.",
};
export const social = {
email: "contact@johanleroy.fr",
github: "https://github.com/JohanLeroy",
gitea: "https://git.lidge.fr/johanleroy",
linkedin: "https://www.linkedin.com/in/johan-leroy-472409180/",
site: "https://johanleroy.fr",
};
/* URL du bouton « café » — à remplacer par le service retenu
(Buy Me a Coffee, Ko-fi, Liberapay, PayPal.me, Stripe…). */
export const coffeeUrl = "https://buymeacoffee.com/johanleroy";
export const stats = [
{ n: "~3 ans", l: "d'expérience pro" },
{ n: "6+", l: "projets livrés" },
{ n: "8+", l: "services auto-hébergés" },
{ n: "OSS", l: "contributeur open-source" },
];
export const projectsFeatured: Project[] = [
{
id: "techos",
title: "Techos",
subtitle: "Plateforme hébergement & domaines",
desc:
"Plateforme client + admin de gestion d'hébergement web et de domaines pour une association, bâtie sur WHMCS. Design system « Liquid Glass » clair/sombre.",
stack: ["Next.js 16", "React 19", "NestJS 11", "Tailwind 4", "shadcn/ui", "Redis", "WHMCS API"],
status: "live",
link: "https://techos-asso.fr",
img: "/images/projets/techos.png",
},
{
id: "amarea",
title: "Amarea Tattoo",
subtitle: "Site du studio de tatouage Amarea",
desc:
"Site vitrine + gestion pour un studio de tatouage. Architecture découplée SPA + API REST avec gestion de médias.",
stack: ["Vue 3", "Vite", "NestJS 11", "TypeORM", "MariaDB", "Tailwind 4"],
status: "live",
},
{
id: "lidge",
title: "Lidge",
subtitle: "Portail d'abonnements aux services auto-hébergés",
desc:
"Plateforme perso pour gérer les abonnements à mes services auto-hébergés (Jellyfin, Cloud, Vault, Mail, Git…) avec SSO, tickets et workflow d'accès.",
stack: ["Nuxt 3", "NestJS 11", "TypeORM", "MariaDB", "JWT", "Nodemailer"],
status: "live",
},
];
export const projectsOther: Project[] = [
{
id: "arboretum",
title: "Arboretum",
subtitle: "Pilotage de worktrees git + agents IA",
desc:
"Outil open-source : dashboard web pour piloter des worktrees git et des sessions d'agents IA. Lancé en npx, propulsé par un daemon Node.",
stack: ["Node.js", "Vue 3", "TypeScript", "npx"],
status: "oss",
link: "https://github.com/JohanLeroy",
},
{
id: "ksauce",
title: "Bot Discord KSauce",
subtitle: "Bot communautaire Discord",
desc:
"Bot Discord pour la communauté KSauce : commandes, modération et fonctionnalités sur-mesure.",
stack: ["Node.js", "TypeScript", "Discord.js"],
status: "live",
},
{
id: "lplv",
title: "Liberty Pour La Vie",
subtitle: "Site associatif",
desc: "Site web complet pour l'association Liberty Pour La Vie. Projet désormais fermé.",
stack: ["Java", "Spring Boot", "Thymeleaf", "Bootstrap", "MariaDB"],
status: "archived",
img: "/images/projets/lplv.png",
},
{
id: "mvg",
title: "Mon Voisin Geek",
subtitle: "Site vitrine",
desc: "Site vitrine simple pour Mon Voisin Geek. Projet désormais fermé.",
stack: ["Angular", "Tailwind CSS", "Express.js", "MariaDB"],
status: "archived",
img: "/images/projets/monvoisingeek.png",
},
];
export const experiences: Experience[] = [
{
company: "Almeria",
logo: "/images/entreprises/almeria.png",
role: "Développeur",
period: "Depuis 2023",
duration: "3 ans",
desc: "Conception et développement d'applications web et de logiciels d'intégration ERP.",
missions: [
"Analyse, conception & développement d'applications web",
"Création de logiciels d'intégration ERP",
"Maintenance & évolution des solutions",
],
stack: ["Angular", "Express.js", "NestJS", "SQL Server", "MariaDB"],
current: true,
},
{
company: "CEREMA",
logo: "/images/entreprises/cerema.png",
role: "Technicien évaluation — mesure trafic & mobilité",
period: "2021 — 2023",
duration: "2 ans",
desc: "Installation de capteurs et analyse de données de mobilité.",
missions: [
"Pose de capteurs provisoires (mobilité)",
"Optimisation des données et outils numériques",
"Analyse du trafic & de la mobilité",
],
stack: ["Analyse de données", "PHP", "MariaDB"],
},
{
company: "Réseau SNCF",
logo: "/images/entreprises/sncf.png",
role: "Agent télécom",
period: "2019 — 2021",
duration: "2 ans",
desc:
"Maintenance des équipements de sonorisation, d'affichage et de téléphonie sur le réseau ferroviaire.",
missions: [
"Maintenance préventive & corrective",
"Affichage dynamique en gare",
"Téléphonie sur les voies",
],
stack: ["Télécoms", "Maintenance", "Audio", "Affichage"],
},
{
company: "Novoferm",
logo: "/images/entreprises/novoferm.png",
role: "Stage développeur",
period: "2019",
duration: "7 semaines",
desc:
"Application web de récupération de fichiers SharePoint ; réparation et configuration de postes, imprimantes et téléphones.",
missions: [],
stack: [],
},
{
company: "Pivot Point",
logo: "/images/entreprises/pivotpoint.png",
role: "Stage développeur",
period: "2018",
duration: "1 semaine",
desc: "Développement d'un site internet en PHP.",
missions: [],
stack: ["PHP"],
},
{
company: "Actemium",
logo: "/images/entreprises/actemium.png",
role: "Stage développeur",
period: "2018",
duration: "1 semaine",
desc: "Développement d'applications Windows d'automatisation.",
missions: [],
stack: [],
},
];
export const formation: Formation[] = [
{
title: "Concepteur Développeur d'Applications",
school: "Campus ENI — Nantes",
period: "Depuis 2023",
desc: "Conception & dév d'applications web/mobiles, architecture logicielle, gestion de projet.",
},
{
title: "BTS Systèmes Numériques",
school: "Saint Félix La Salle — Nantes",
period: "2021 — 2023",
desc: "Systèmes électroniques & informatiques, informatique industrielle & réseaux.",
},
{
title: "BAC PRO Systèmes Numériques",
school: "Saint Félix La Salle — Nantes",
period: "2018 — 2021",
desc: "Systèmes électroniques & réseaux, installation & maintenance.",
},
{
title: "Diplôme National du Brevet",
school: "Saint Père en Retz",
period: "avant 2018",
},
];
export const stackMain: StackGroup[] = [
{ label: "Langages", items: ["TypeScript", "JavaScript", "Java", "Python", "PHP"] },
{ label: "Frameworks", items: ["NestJS", "Nuxt", "Next.js", "Vue.js", "Angular", "Tailwind CSS", "Astro"] },
{ label: "Bases de données", items: ["MariaDB", "MySQL", "PostgreSQL", "Redis"] },
{ label: "Outils & DevOps", items: ["Docker", "Git", "AWS", "Terraform", "NGINX", "Plesk"] },
{ label: "IDE & Éditeurs", items: ["WebStorm", "PhpStorm", "PyCharm", "Claude Code"] },
{ label: "Systèmes", items: ["Debian", "Ubuntu", "macOS"] },
];
export const stackSecondary: StackGroup[] = [
{ label: "Langages", items: ["C#", "C++", "Dart", "Kotlin"] },
{ label: "Frameworks & libs", items: ["Spring", "Symfony", "Express.js", "FastAPI", "Flutter", "GraphQL", "Vuetify", "Bootstrap"] },
{ label: "Bases de données", items: ["MongoDB", "SQLite"] },
{ label: "Services & outils", items: ["Firebase", "Swagger", "Postman", "Stripe"] },
];
export const softTech = [
"Dév. Frontend",
"Dév. Backend",
"Analyse & traitement de données",
"Mise en production",
"Analyse de BDD",
"Modélisation UML",
"Maquettage",
"Sécurité",
];
export const softHuman = [
"Gestion de projet",
"Travail en équipe",
"Communication",
"Autonomie",
"Organisation",
"Adaptation",
"Veille techno",
];
export const interests: Interest[] = [
{ name: "Jeux vidéo", note: "// détente", icon: "gamepad" },
{ name: "Films & Séries", note: "// veille culture", icon: "film" },
{ name: "Musique électronique / DJing", note: "// loisir", icon: "music" },
{ name: "Projets personnels", note: "// always building", icon: "code" },
];
/* Texte tapé dans le mockup terminal du hero (état final = contenu no-JS). */
export const terminalText = `$ whoami
johan-leroy
$ cat about.json
{
"name": "Johan Leroy",
"role": "Développeur fullstack",
"stack": ["TypeScript", "NestJS", "Nuxt", "Next.js"],
"location": "Nantes, France",
"status": "ouvert aux opportunités"
}`;