refonte: portfolio statique Astro (design moderne développeur)
Some checks failed
Deploy production / build-deploy (push) Failing after 56s
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:
99
src/layouts/Base.astro
Normal file
99
src/layouts/Base.astro
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
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],
|
||||
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>
|
||||
Reference in New Issue
Block a user