feat: add JSON-LD structured data
- BaseLayout: WebPage schema on every page + canonical URL - Homepages: WebSite schema - GeneratorLayout: SoftwareApplication + BreadcrumbList schemas - Add <slot name='head'> to BaseLayout for child-injected head content
This commit is contained in:
@@ -18,6 +18,16 @@ const { title = T.defaultTitle, description = T.defaultDesc } = Astro.props;
|
||||
const pathWithoutLocale = Astro.url.pathname.replace(/^\/ru/, "") || "/";
|
||||
const enUrl = `https://randify.pro${getRelativeLocaleUrl("en", pathWithoutLocale)}`;
|
||||
const ruUrl = `https://randify.pro${getRelativeLocaleUrl("ru", pathWithoutLocale)}`;
|
||||
const canonicalUrl = `https://randify.pro${Astro.url.pathname}`;
|
||||
|
||||
const webPageSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
name: title,
|
||||
description: description,
|
||||
url: canonicalUrl,
|
||||
inLanguage: lang,
|
||||
};
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
@@ -33,12 +43,18 @@ const ruUrl = `https://randify.pro${getRelativeLocaleUrl("ru", pathWithoutLocale
|
||||
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="canonical" href={canonicalUrl} />
|
||||
<link rel="alternate" hreflang="en" href={enUrl} />
|
||||
<link rel="alternate" hreflang="ru" href={ruUrl} />
|
||||
<meta name="verification" content="er9ndnv9ih7agmh8" />
|
||||
<script
|
||||
type="application/ld+json"
|
||||
set:html={JSON.stringify(webPageSchema)}
|
||||
/>
|
||||
<meta name="theme-color" content="#534AB7" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<slot name="head" />
|
||||
<title>{title}</title>
|
||||
<Analytics />
|
||||
<script>
|
||||
|
||||
@@ -14,12 +14,56 @@ const { generator } = Astro.props;
|
||||
const lang = (Astro.currentLocale as Lang) || "en";
|
||||
const T = useT(lang);
|
||||
const isRu = lang === "ru";
|
||||
|
||||
const canonicalUrl = `https://randify.pro${Astro.url.pathname}`;
|
||||
|
||||
const appSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "SoftwareApplication",
|
||||
name: isRu ? generator.ruTitle : generator.title,
|
||||
applicationCategory: "UtilityApplication",
|
||||
operatingSystem: "Any",
|
||||
offers: {
|
||||
"@type": "Offer",
|
||||
price: "0",
|
||||
priceCurrency: "USD",
|
||||
},
|
||||
inLanguage: ["en", "ru"],
|
||||
description: isRu ? generator.ruDescription : generator.description,
|
||||
url: canonicalUrl,
|
||||
};
|
||||
|
||||
const breadcrumbSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 1,
|
||||
name: "Randify.pro",
|
||||
item: "https://randify.pro/",
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 2,
|
||||
name: isRu ? generator.ruTitle : generator.title,
|
||||
item: canonicalUrl,
|
||||
},
|
||||
],
|
||||
};
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={isRu ? generator.ruSeoTitle : generator.seoTitle}
|
||||
description={isRu ? generator.ruSeoDescription : generator.seoDescription}
|
||||
>
|
||||
<Fragment slot="head">
|
||||
<script type="application/ld+json" set:html={JSON.stringify(appSchema)} />
|
||||
<script
|
||||
type="application/ld+json"
|
||||
set:html={JSON.stringify(breadcrumbSchema)}
|
||||
/>
|
||||
</Fragment>
|
||||
<div class="max-w-2xl mx-auto px-4 py-12 sm:py-20">
|
||||
<nav aria-label="Breadcrumb" class="mb-10">
|
||||
<a
|
||||
|
||||
@@ -8,9 +8,23 @@ import type { Lang } from "@/i18n/translations";
|
||||
|
||||
const lang = (Astro.currentLocale as Lang) || "en";
|
||||
const T = useT(lang);
|
||||
|
||||
const webSiteSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
name: "Randify.pro",
|
||||
url: "https://randify.pro/",
|
||||
description: T.defaultDesc,
|
||||
inLanguage: lang,
|
||||
};
|
||||
---
|
||||
|
||||
<BaseLayout>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
set:html={JSON.stringify(webSiteSchema)}
|
||||
slot="head"
|
||||
/>
|
||||
<div class="max-w-4xl mx-auto px-4 py-12 sm:py-20">
|
||||
<header class="mb-12">
|
||||
<div class="flex items-center gap-2 mb-6">
|
||||
|
||||
@@ -8,9 +8,23 @@ import type { Lang } from "@/i18n/translations";
|
||||
|
||||
const lang = (Astro.currentLocale as Lang) || "en";
|
||||
const T = useT(lang);
|
||||
|
||||
const webSiteSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
name: "Randify.pro",
|
||||
url: "https://randify.pro/",
|
||||
description: T.defaultDesc,
|
||||
inLanguage: lang,
|
||||
};
|
||||
---
|
||||
|
||||
<BaseLayout>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
set:html={JSON.stringify(webSiteSchema)}
|
||||
slot="head"
|
||||
/>
|
||||
<div class="max-w-4xl mx-auto px-4 py-12 sm:py-20">
|
||||
<header class="mb-12">
|
||||
<div class="flex items-center gap-2 mb-6">
|
||||
|
||||
Reference in New Issue
Block a user