- Add sitemap.ts and robots.ts - pageMetadata() helper: consistent title, canonical URL, Open Graph, Twitter card and feed alternate on every page - Generated OG images: a site card, and per post either the cover image or a branded title card (pre-rendered at build) - BlogPosting JSON-LD on post pages - Fail fast with a clear error when SITE_URL is missing Content loading: - Validate post frontmatter at build time and normalize dates to ISO (fixes invalid <time datetime> values) - Add draft: true support (drafts only render in development) - Cache markdown rendering so metadata and page share one render - Replace the three copy-pasted about/projects/setup pages with a shared MarkdownPage component
41 lines
1.4 KiB
TypeScript
41 lines
1.4 KiB
TypeScript
import type { MetadataRoute } from 'next'
|
|
import { SITE_URL } from '@/app/metadata'
|
|
import { getAllCategories } from '@/lib/categories'
|
|
import { getAllPostsMeta } from '@/lib/posts'
|
|
import { getAllTags } from '@/lib/tags'
|
|
import { slugify } from '@/utils/slug'
|
|
|
|
export default function sitemap(): MetadataRoute.Sitemap {
|
|
const posts = getAllPostsMeta()
|
|
const lastPostUpdate = posts
|
|
.map((post) => post.updated ?? post.date)
|
|
.toSorted()
|
|
.at(-1)
|
|
|
|
return [
|
|
{ url: SITE_URL, lastModified: lastPostUpdate, changeFrequency: 'weekly', priority: 1 },
|
|
...['about', 'projects', 'setup'].map((page) => ({
|
|
url: `${SITE_URL}/${page}`,
|
|
changeFrequency: 'monthly' as const,
|
|
priority: 0.8,
|
|
})),
|
|
...posts.map((post) => ({
|
|
url: `${SITE_URL}/posts/${post.slug}`,
|
|
lastModified: post.updated ?? post.date,
|
|
changeFrequency: 'monthly' as const,
|
|
priority: 0.9,
|
|
})),
|
|
{ url: `${SITE_URL}/categories`, changeFrequency: 'weekly', priority: 0.4 },
|
|
...Object.keys(getAllCategories()).map((category) => ({
|
|
url: `${SITE_URL}/categories/${slugify(category)}`,
|
|
changeFrequency: 'weekly' as const,
|
|
priority: 0.3,
|
|
})),
|
|
{ url: `${SITE_URL}/tags`, changeFrequency: 'weekly', priority: 0.4 },
|
|
...Object.keys(getAllTags()).map((tag) => ({
|
|
url: `${SITE_URL}/tags/${slugify(tag)}`,
|
|
changeFrequency: 'weekly' as const,
|
|
priority: 0.3,
|
|
})),
|
|
]
|
|
}
|