jalil.arfaoui.net/src/components/SEO.astro

136 lines
3.9 KiB
Text
Raw Normal View History

---
import type { ImageMetadata } from "astro";
import { getAlternateUrls } from "../utils/page-translations";
import defaultOgImage from "../assets/images/jalil-2.jpg";
interface Props {
title: string;
description: string;
ogImage?: ImageMetadata;
ogType?: string;
article?: { publishedTime?: string; tags?: string[] };
noindex?: boolean;
}
const {
title,
description,
ogImage,
ogType = "website",
article,
noindex = false,
} = Astro.props;
const siteUrl = Astro.site!.origin;
const canonicalUrl = new URL(Astro.url.pathname, siteUrl).href;
const imageUrl = new URL((ogImage ?? defaultOgImage).src, siteUrl).href;
// Locale detection
const pathname = Astro.url.pathname.replace(/\/$/, "") || "/";
const locale = pathname.startsWith("/en")
? "en"
: pathname.startsWith("/ar")
? "ar"
: "fr";
const ogLocaleMap: Record<string, string> = {
fr: "fr_FR",
en: "en_US",
ar: "ar_SA",
};
// Hreflang
const alternateUrls = getAlternateUrls(pathname);
// Home pages for WebSite schema
const isHomePage = pathname === "/" || pathname === "/en" || pathname === "/ar";
// Person JSON-LD (on every page)
const personJsonLd = {
"@context": "https://schema.org",
"@type": "Person",
"@id": `${siteUrl}/#person`,
name: "Jalil Arfaoui",
url: siteUrl,
image: imageUrl,
jobTitle: "Software Craftsman",
knowsAbout: [
"Software Craftsmanship",
"TDD",
"DDD",
"Improv Theater",
"Photography",
],
sameAs: [
"https://www.linkedin.com/in/jalil/",
"https://github.com/JalilArfaoui",
"https://gitlab.gnome.org/Jalil",
"https://forge.tiqa.fr/jalil",
"https://framagit.org/jalil",
"https://www.malt.fr/profile/jalilarfaoui?overview",
"https://www.collective.work/profile/jalil-arfaoui-mrr",
"https://500px.com/p/jalilarfaoui",
"https://commons.wikimedia.org/wiki/User:JalilArfaoui",
"https://www.instagram.com/l.i.l.a.j",
"https://x.com/jalilarfaoui",
],
};
// WebSite JSON-LD (only on home pages)
const websiteJsonLd = isHomePage
? {
"@context": "https://schema.org",
"@type": "WebSite",
name: "Jalil Arfaoui",
url: siteUrl,
inLanguage: locale,
author: { "@id": `${siteUrl}/#person` },
}
: null;
---
<!-- Meta tags -->
<meta name="description" content={description} />
<link rel="canonical" href={canonicalUrl} />
{noindex && <meta name="robots" content="noindex, nofollow" />}
<!-- Open Graph -->
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:image" content={imageUrl} />
<meta property="og:type" content={ogType} />
<meta property="og:locale" content={ogLocaleMap[locale]} />
<meta property="og:site_name" content="Jalil Arfaoui" />
{article?.publishedTime && (
<meta property="article:published_time" content={article.publishedTime} />
)}
{article?.tags?.map((tag) => (
<meta property="article:tag" content={tag} />
))}
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@jalilarfaoui" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={imageUrl} />
<!-- Hreflang -->
{alternateUrls && (
<>
<link rel="alternate" hreflang="fr" href={new URL(alternateUrls.fr, siteUrl).href} />
<link rel="alternate" hreflang="en" href={new URL(alternateUrls.en, siteUrl).href} />
<link rel="alternate" hreflang="ar" href={new URL(alternateUrls.ar, siteUrl).href} />
<link rel="alternate" hreflang="x-default" href={new URL(alternateUrls.fr, siteUrl).href} />
</>
)}
<!-- JSON-LD Person -->
<script type="application/ld+json" set:html={JSON.stringify(personJsonLd)} />
<!-- JSON-LD WebSite (home pages only) -->
{websiteJsonLd && (
<script type="application/ld+json" set:html={JSON.stringify(websiteJsonLd)} />
)}