first commit
Made-with: Cursor
This commit is contained in:
199
frontend/components/public/JsonLd.tsx
Normal file
199
frontend/components/public/JsonLd.tsx
Normal file
@@ -0,0 +1,199 @@
|
||||
interface JsonLdProps {
|
||||
data: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export function JsonLd({ data }: JsonLdProps) {
|
||||
return (
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const siteUrl =
|
||||
process.env.NEXT_PUBLIC_SITE_URL || "https://belgianbitcoinembassy.org";
|
||||
|
||||
export function OrganizationJsonLd() {
|
||||
return (
|
||||
<JsonLd
|
||||
data={{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Organization",
|
||||
name: "Belgian Bitcoin Embassy",
|
||||
url: siteUrl,
|
||||
logo: `${siteUrl}/og-default.png`,
|
||||
description:
|
||||
"Belgium's sovereign Bitcoin community. Monthly meetups, education, and curated Nostr content.",
|
||||
sameAs: ["https://t.me/belgianbitcoinembassy"],
|
||||
address: {
|
||||
"@type": "PostalAddress",
|
||||
addressLocality: "Antwerp",
|
||||
addressCountry: "BE",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function WebSiteJsonLd() {
|
||||
return (
|
||||
<JsonLd
|
||||
data={{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
name: "Belgian Bitcoin Embassy",
|
||||
url: siteUrl,
|
||||
description:
|
||||
"Belgium's sovereign Bitcoin community. Monthly meetups, education, and curated Nostr content.",
|
||||
publisher: {
|
||||
"@type": "Organization",
|
||||
name: "Belgian Bitcoin Embassy",
|
||||
logo: { "@type": "ImageObject", url: `${siteUrl}/og-default.png` },
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface BlogPostingJsonLdProps {
|
||||
title: string;
|
||||
description: string;
|
||||
slug: string;
|
||||
publishedAt?: string;
|
||||
authorName?: string;
|
||||
}
|
||||
|
||||
export function BlogPostingJsonLd({
|
||||
title,
|
||||
description,
|
||||
slug,
|
||||
publishedAt,
|
||||
authorName,
|
||||
}: BlogPostingJsonLdProps) {
|
||||
return (
|
||||
<JsonLd
|
||||
data={{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
headline: title,
|
||||
description,
|
||||
url: `${siteUrl}/blog/${slug}`,
|
||||
...(publishedAt ? { datePublished: publishedAt } : {}),
|
||||
author: {
|
||||
"@type": "Person",
|
||||
name: authorName || "Belgian Bitcoin Embassy",
|
||||
},
|
||||
publisher: {
|
||||
"@type": "Organization",
|
||||
name: "Belgian Bitcoin Embassy",
|
||||
logo: { "@type": "ImageObject", url: `${siteUrl}/og-default.png` },
|
||||
},
|
||||
image: `${siteUrl}/og?title=${encodeURIComponent(title)}&type=blog`,
|
||||
mainEntityOfPage: {
|
||||
"@type": "WebPage",
|
||||
"@id": `${siteUrl}/blog/${slug}`,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface EventJsonLdProps {
|
||||
name: string;
|
||||
description?: string;
|
||||
startDate: string;
|
||||
location?: string;
|
||||
url: string;
|
||||
imageUrl?: string;
|
||||
}
|
||||
|
||||
export function EventJsonLd({
|
||||
name,
|
||||
description,
|
||||
startDate,
|
||||
location,
|
||||
url,
|
||||
imageUrl,
|
||||
}: EventJsonLdProps) {
|
||||
return (
|
||||
<JsonLd
|
||||
data={{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Event",
|
||||
name,
|
||||
description: description || `Bitcoin meetup: ${name}`,
|
||||
startDate,
|
||||
eventAttendanceMode: "https://schema.org/OfflineEventAttendanceMode",
|
||||
eventStatus: "https://schema.org/EventScheduled",
|
||||
...(location
|
||||
? {
|
||||
location: {
|
||||
"@type": "Place",
|
||||
name: location,
|
||||
address: {
|
||||
"@type": "PostalAddress",
|
||||
addressLocality: location,
|
||||
addressCountry: "BE",
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
organizer: {
|
||||
"@type": "Organization",
|
||||
name: "Belgian Bitcoin Embassy",
|
||||
url: siteUrl,
|
||||
},
|
||||
image:
|
||||
imageUrl || `${siteUrl}/og?title=${encodeURIComponent(name)}&type=event`,
|
||||
url,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface FaqJsonLdProps {
|
||||
items: { question: string; answer: string }[];
|
||||
}
|
||||
|
||||
export function FaqPageJsonLd({ items }: FaqJsonLdProps) {
|
||||
if (items.length === 0) return null;
|
||||
return (
|
||||
<JsonLd
|
||||
data={{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
mainEntity: items.map((item) => ({
|
||||
"@type": "Question",
|
||||
name: item.question,
|
||||
acceptedAnswer: {
|
||||
"@type": "Answer",
|
||||
text: item.answer,
|
||||
},
|
||||
})),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface BreadcrumbItem {
|
||||
name: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
export function BreadcrumbJsonLd({ items }: { items: BreadcrumbItem[] }) {
|
||||
return (
|
||||
<JsonLd
|
||||
data={{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: items.map((item, index) => ({
|
||||
"@type": "ListItem",
|
||||
position: index + 1,
|
||||
name: item.name,
|
||||
item: `${siteUrl}${item.href}`,
|
||||
})),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user