Files
portfolio/src/layouts/Base.astro
Johan LEROY 155ab2977f
All checks were successful
Deploy production / build-deploy (push) Successful in 24s
feat(stack): grille complète (71 technos) en masonry centré + peaufinage UI
Stack & icônes
- grille unique enrichie (+24 technos) : React, TypeORM, Apache, Gitea,
  GitLab, GitHub Actions, Vite, pnpm, Socket.io, Chart.js, Discord.js,
  Prisma, Sequelize, IntelliJ IDEA, VS Code, Windows, HubSpot, HTML5/CSS3…
- nouvelles catégories « Bases de données & ORM » et « Tests & Qualité »
- 21 icônes simple-icons + tracés monochromes custom VS Code, Windows,
  Playwright ; support du fill-rule dans TechIcon
- mise en page masonry (CSS columns) + titres et puces centrés

Contenu & UI
- Hero : retrait du badge « ouvert aux opportunités »
- About / Contact : reformulation orientée projets
- ProjectCard : statut « en développement »
- typographie : tirets cadratins → virgules (titres, OG, aria-labels)
- ajout du visuel public/images/logo/couverture.png
2026-06-27 13:46:53 +02:00

100 lines
3.7 KiB
Plaintext

---
import "../styles/global.css";
import { social, profile } from "../data/content";
interface Props {
title?: string;
description?: string;
}
const {
title = "Johan Leroy, Développeur fullstack",
description = "Johan Leroy, développeur fullstack basé à Nantes. TypeScript, NestJS, Nuxt/Vue, Next.js. Conception d'applications web performantes, du front à la mise en production.",
} = Astro.props;
const siteUrl = Astro.site?.href ?? "https://johanleroy.fr/";
const canonical = new URL(Astro.url.pathname, siteUrl).href;
const ogImage = new URL("/images/og.png", siteUrl).href;
const ogDescription =
"Développeur fullstack à Nantes. Applications web performantes, propres et scalables.";
// Données structurées (schema.org Person) — aide les moteurs à comprendre la page.
const jsonLd = {
"@context": "https://schema.org",
"@type": "Person",
name: profile.name,
jobTitle: profile.role,
url: siteUrl,
image: ogImage,
email: social.email,
address: { "@type": "PostalAddress", addressLocality: "Nantes", addressCountry: "FR" },
sameAs: [social.github, social.linkedin, social.gitea, social.soundcloud],
knowsAbout: ["TypeScript", "NestJS", "Nuxt", "Next.js", "Vue.js", "Astro", "Docker", "AWS", "Terraform"],
};
---
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{title}</title>
<meta name="description" content={description} />
<meta name="author" content="Johan Leroy" />
<link rel="canonical" href={canonical} />
{/* Open Graph */}
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Johan Leroy" />
<meta property="og:locale" content="fr_FR" />
<meta property="og:title" content={title} />
<meta property="og:description" content={ogDescription} />
<meta property="og:url" content={canonical} />
<meta property="og:image" content={ogImage} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Johan Leroy, Développeur fullstack" />
{/* Twitter */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={ogDescription} />
<meta name="twitter:image" content={ogImage} />
<meta name="theme-color" content="#09090b" />
<link rel="icon" type="image/png" sizes="32x32" href="/images/logo/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/images/logo/favicon-16x16.png" />
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="apple-touch-icon" href="/images/logo/apple-touch-icon.png" />
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script type="application/ld+json" is:inline set:html={JSON.stringify(jsonLd)} />
{/* Thème posé AVANT le premier paint : aucun flash au chargement. */}
<script is:inline>
(function () {
try {
var saved = localStorage.getItem("jl-theme");
var light = saved
? saved === "light"
: window.matchMedia("(prefers-color-scheme: light)").matches;
if (light) {
document.documentElement.setAttribute("data-theme", "light");
var m = document.querySelector('meta[name="theme-color"]');
if (m) m.setAttribute("content", "#fafafa");
}
} catch (e) {}
})();
</script>
</head>
<body>
<div class="halo" aria-hidden="true"></div>
<div class="grain" aria-hidden="true"></div>
<div class="page">
<slot />
</div>
<script>
import "../scripts/app";
</script>
</body>
</html>