From 5b7ccf0b671e2999b62befc729a3e517a0433728 Mon Sep 17 00:00:00 2001
From: Bertrand Yuan <bert.yuan@outlook.com>
Date: Mon, 15 Dec 2025 23:48:10 +0800
Subject: initial commit -- the front-end prototype

The initial code is base on Anirudh's work.

More to see at:

    https://github.com/techwithanirudh/shadcn-blog

Therefore, the code in this commit is under MIT license.
---
 src/components/json-ld.tsx | 114 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 src/components/json-ld.tsx

(limited to 'src/components/json-ld.tsx')

diff --git a/src/components/json-ld.tsx b/src/components/json-ld.tsx
new file mode 100644
index 0000000..cd30274
--- /dev/null
+++ b/src/components/json-ld.tsx
@@ -0,0 +1,114 @@
+import { title as homeTitle } from '@/app/layout.config';
+import { owner } from '@/app/layout.config';
+import { baseUrl } from '@/lib/constants';
+import type { Post } from '@/lib/source';
+import type { BlogPosting, BreadcrumbList, Graph } from 'schema-dts';
+
+export const PostJsonLd = ({ page }: { page: Post }) => {
+  if (!page) {
+    return null;
+  }
+
+  const url = new URL(page.url, baseUrl.href).href;
+
+  const post: BlogPosting = {
+    '@type': 'BlogPosting',
+    headline: page.data.title,
+    description: page.data.description,
+    image: new URL(`/og/${page.slugs.join('/')}/image.png`, baseUrl.href).href,
+    datePublished: new Date(page.data.date).toISOString(),
+    dateModified: page.data.lastModified
+      ? new Date(page.data.lastModified).toISOString()
+      : undefined,
+    mainEntityOfPage: {
+      '@type': 'WebPage',
+      '@id': url,
+    },
+    author: {
+      '@type': 'Person',
+      name: page.data.author,
+      // url: 'https://techwithanirudh.com/',
+    },
+    publisher: {
+      '@type': 'Person',
+      name: owner,
+      url: 'https://techwithanirudh.com/',
+    },
+  };
+
+  const breadcrumbList: BreadcrumbList = {
+    '@type': 'BreadcrumbList',
+    itemListElement: [
+      {
+        '@type': 'ListItem',
+        position: 1,
+        name: homeTitle,
+        item: baseUrl.href,
+      },
+      {
+        '@type': 'ListItem',
+        position: 2,
+        name: `${homeTitle} | Posts`,
+        item: new URL('/posts', baseUrl.href).href,
+      },
+      {
+        '@type': 'ListItem',
+        position: 3,
+        name: page.data.title,
+        item: url,
+      },
+    ],
+  };
+
+  const graph: Graph = {
+    '@context': 'https://schema.org',
+    '@graph': [post, breadcrumbList],
+  };
+
+  return (
+    <script
+      type='application/ld+json'
+      // biome-ignore lint/security/noDangerouslySetInnerHtml:
+      dangerouslySetInnerHTML={{ __html: JSON.stringify(graph) }}
+    />
+  );
+};
+
+export const TagJsonLd = ({ tag }: { tag: string }) => {
+  const breadcrumbList: BreadcrumbList = {
+    '@type': 'BreadcrumbList',
+    itemListElement: [
+      {
+        '@type': 'ListItem',
+        position: 1,
+        name: homeTitle,
+        item: baseUrl.href,
+      },
+      {
+        '@type': 'ListItem',
+        position: 2,
+        name: `${homeTitle} | Tags`,
+        item: new URL('/tags', baseUrl.href).href,
+      },
+      {
+        '@type': 'ListItem',
+        position: 3,
+        name: `${homeTitle} | Posts tagged with ${tag}`,
+        item: new URL(`/tags/${tag}`, baseUrl.href).href,
+      },
+    ],
+  };
+
+  const graph: Graph = {
+    '@context': 'https://schema.org',
+    '@graph': [breadcrumbList],
+  };
+
+  return (
+    <script
+      type='application/ld+json'
+      // biome-ignore lint/security/noDangerouslySetInnerHtml:
+      dangerouslySetInnerHTML={{ __html: JSON.stringify(graph) }}
+    />
+  );
+};
-- 
cgit v1.2.3

