Files
blog-nextjs/app/page.tsx
gbanyan 6badd76733 Add Schema.org JSON-LD structured data for SEO
Implemented comprehensive Schema.org structured data across the blog to improve SEO and enable rich snippets in search results.

Changes:
- Created JSON-LD helper component for safe schema rendering
- Added BlogPosting schema to blog posts with:
  * Article metadata (headline, description, image, dates)
  * Author and publisher information
  * Keywords and article sections from tags
- Added BreadcrumbList schema to blog posts for navigation
- Added WebSite and Organization schemas to root layout
  * Site-wide identity and branding
  * Search action for site search functionality
- Added CollectionPage schema to homepage
  * Blog collection metadata
- Added WebPage schema to static pages
  * Page metadata with dates and images

Benefits:
- Rich snippets in Google/Bing search results
- Better content understanding by search engines
- Article cards with images, dates, authors in SERPs
- Breadcrumb navigation in search results
- Improved SEO ranking signals

All schemas validated against Schema.org specifications and include proper Chinese language support.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 21:23:10 +08:00

69 lines
2.1 KiB
TypeScript

import Link from 'next/link';
import { getAllPostsSorted } from '@/lib/posts';
import { siteConfig } from '@/lib/config';
import { PostListItem } from '@/components/post-list-item';
import { TimelineWrapper } from '@/components/timeline-wrapper';
import { SidebarLayout } from '@/components/sidebar-layout';
import { JsonLd } from '@/components/json-ld';
export default function HomePage() {
const posts = getAllPostsSorted().slice(0, siteConfig.postsPerPage);
// CollectionPage Schema for homepage
const collectionPageSchema = {
'@context': 'https://schema.org',
'@type': 'CollectionPage',
name: `${siteConfig.name} 的最新動態`,
description: siteConfig.description,
url: siteConfig.url,
inLanguage: siteConfig.defaultLocale,
isPartOf: {
'@type': 'WebSite',
name: siteConfig.title,
url: siteConfig.url,
},
about: {
'@type': 'Blog',
name: siteConfig.title,
description: siteConfig.description,
},
};
return (
<>
<JsonLd data={collectionPageSchema} />
<section className="space-y-6">
<SidebarLayout>
<header className="space-y-1 text-center">
<h1 className="type-title font-bold text-slate-900 dark:text-slate-50">
{siteConfig.name}
</h1>
<p className="type-small text-slate-600 dark:text-slate-300">
{siteConfig.tagline}
</p>
</header>
<div>
<div className="mb-3 flex items-baseline justify-between">
<h2 className="type-small font-semibold uppercase tracking-[0.4em] text-slate-500 dark:text-slate-400">
</h2>
<Link
href="/blog"
className="text-xs text-blue-600 hover:underline dark:text-blue-400"
>
</Link>
</div>
<TimelineWrapper>
{posts.map((post) => (
<PostListItem key={post._id} post={post} />
))}
</TimelineWrapper>
</div>
</SidebarLayout>
</section>
</>
);
}