- Installe @astrojs/sitemap ; integre dans astro.config.mjs avec filtre /api/ - Ajoute site: 'https://trans-former.fr' pour canonical absolues - BaseLayout : props ogImage + canonical + isArticle + articleDate ; meta description/canonical/robots/OG/Twitter Card complets ; suppression doublons - manifeste.astro : passe isArticle=true pour Schema.org Article - public/robots.txt : open index + GPTBot/ClaudeBot/Google-Extended/Applebot-Extended/PerplexityBot explicites
119 lines
3.9 KiB
Plaintext
119 lines
3.9 KiB
Plaintext
---
|
|
import '../styles/global.css';
|
|
import Footer from '../components/astro/Footer.astro';
|
|
import SiteHeader from '../components/astro/SiteHeader.astro';
|
|
|
|
interface Props {
|
|
title?: string;
|
|
description?: string;
|
|
ogImage?: string;
|
|
canonical?: string;
|
|
/** Article JSON-LD : passer true sur les pages articles (manifeste, etc.) */
|
|
isArticle?: boolean;
|
|
articleDate?: string;
|
|
articleDescription?: string;
|
|
}
|
|
|
|
const {
|
|
title,
|
|
description,
|
|
ogImage,
|
|
canonical,
|
|
isArticle = false,
|
|
articleDate,
|
|
articleDescription,
|
|
} = Astro.props;
|
|
|
|
const SITE_NAME = 'trans-former.fr';
|
|
const SITE_URL = 'https://trans-former.fr';
|
|
const DEFAULT_DESC = "Architecture, ecologie, politique : un commun a construire ensemble. Manifeste et infrastructure vivante de Jules NENY.";
|
|
const DEFAULT_OG = '/og-default.png';
|
|
|
|
const fullTitle = title ? `${title} - ${SITE_NAME}` : SITE_NAME;
|
|
const finalDesc = description || DEFAULT_DESC;
|
|
const finalCanonical = canonical || new URL(Astro.url.pathname, SITE_URL).href;
|
|
const finalOg = ogImage || DEFAULT_OG;
|
|
const finalOgAbsolute = finalOg.startsWith('http') ? finalOg : `${SITE_URL}${finalOg}`;
|
|
|
|
const websiteSchema = {
|
|
"@context": "https://schema.org",
|
|
"@type": "WebSite",
|
|
"name": SITE_NAME,
|
|
"url": SITE_URL,
|
|
"author": {
|
|
"@type": "Person",
|
|
"name": "Jules NENY",
|
|
"url": `${SITE_URL}/a-propos`,
|
|
"sameAs": [
|
|
"https://www.instagram.com/julesneny/",
|
|
"https://www.instagram.com/aep.politique/",
|
|
"https://julesneny.substack.com",
|
|
"https://git.trans-former.fr/jules"
|
|
]
|
|
},
|
|
"description": DEFAULT_DESC
|
|
};
|
|
|
|
const articleSchema = isArticle ? {
|
|
"@context": "https://schema.org",
|
|
"@type": "Article",
|
|
"headline": title || SITE_NAME,
|
|
"author": { "@type": "Person", "name": "Jules NENY" },
|
|
"datePublished": articleDate || "2026-05-01",
|
|
"publisher": { "@type": "Organization", "name": SITE_NAME },
|
|
"description": articleDescription || finalDesc
|
|
} : null;
|
|
---
|
|
<!doctype html>
|
|
<html lang="fr" class="h-screen">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
<meta name="generator" content={Astro.generator} />
|
|
|
|
<!-- SEO primaire -->
|
|
<title>{fullTitle}</title>
|
|
<meta name="description" content={finalDesc} />
|
|
<link rel="canonical" href={finalCanonical} />
|
|
<meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large" />
|
|
|
|
<!-- Open Graph -->
|
|
<meta property="og:type" content={isArticle ? "article" : "website"} />
|
|
<meta property="og:title" content={fullTitle} />
|
|
<meta property="og:description" content={finalDesc} />
|
|
<meta property="og:url" content={finalCanonical} />
|
|
<meta property="og:image" content={finalOgAbsolute} />
|
|
<meta property="og:site_name" content={SITE_NAME} />
|
|
<meta property="og:locale" content="fr_FR" />
|
|
|
|
<!-- Twitter Card -->
|
|
<meta name="twitter:card" content="summary_large_image" />
|
|
<meta name="twitter:title" content={fullTitle} />
|
|
<meta name="twitter:description" content={finalDesc} />
|
|
<meta name="twitter:image" content={finalOgAbsolute} />
|
|
|
|
<!-- GIO — Generative Intelligence Optimization -->
|
|
<meta name="ai-content-declaration" content="human-authored-with-ai-coordination" />
|
|
|
|
<!-- Schema.org WebSite -->
|
|
<script type="application/ld+json" set:html={JSON.stringify(websiteSchema)} />
|
|
|
|
<!-- Schema.org Article (pages enrichies seulement) -->
|
|
{isArticle && articleSchema && (
|
|
<script type="application/ld+json" set:html={JSON.stringify(articleSchema)} />
|
|
)}
|
|
</head>
|
|
<body class="m-0 bg-white text-neutral-900 antialiased h-screen flex flex-col overflow-hidden">
|
|
<div class="flex-shrink-0">
|
|
<SiteHeader />
|
|
</div>
|
|
<div class="flex-1 flex flex-col min-h-0 overflow-hidden">
|
|
<slot />
|
|
</div>
|
|
<div class="flex-shrink-0">
|
|
<Footer />
|
|
</div>
|
|
</body>
|
|
</html>
|