feat(animation-sources): add content-driven guide system

This commit is contained in:
Poyraz
2026-08-29 17:33:25 +03:00
parent 4ffcaf18cd
commit a019910d61
15 changed files with 1850 additions and 49 deletions
@@ -0,0 +1,96 @@
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { AnimationSourceDetailContent } from "@/components/animation-source-detail-content";
import { ArticleJsonLd } from "@/components/json-ld";
import {
getAnimationSourceBySlug,
listAnimationSources,
} from "@/data/animation-sources";
const SITE_URL =
process.env.NEXT_PUBLIC_SITE_URL || "https://poyrazavsever.com";
type AnimationSourceDetailPageProps = {
params: Promise<{ locale: string; slug: string }>;
};
function getLocalizedPath(locale: string, slug: string) {
const localePrefix = locale === "tr" ? "" : `/${locale}`;
return `${localePrefix}/animation-sources/${slug}`;
}
export async function generateStaticParams() {
const sources = await listAnimationSources();
return sources.map((source) => ({
locale: source.lang,
slug: source.slug,
}));
}
export const dynamicParams = false;
export async function generateMetadata({
params,
}: AnimationSourceDetailPageProps): Promise<Metadata> {
const { locale, slug } = await params;
const source = await getAnimationSourceBySlug(slug, locale);
if (!source) {
return { title: locale === "en" ? "Source not found" : "Kaynak bulunamadı" };
}
const url = `${SITE_URL}${getLocalizedPath(locale, source.slug)}`;
return {
title: source.title,
description: source.excerpt,
alternates: { canonical: url },
openGraph: {
title: source.title,
description: source.excerpt,
url,
type: "article",
publishedTime: source.date,
authors: [source.author],
images: [
{
url: source.coverImage,
width: 720,
height: 720,
alt: source.title,
},
],
},
twitter: {
card: "summary_large_image",
title: source.title,
description: source.excerpt,
images: [source.coverImage],
},
};
}
export default async function AnimationSourceDetailPage({
params,
}: AnimationSourceDetailPageProps) {
const { locale, slug } = await params;
const source = await getAnimationSourceBySlug(slug, locale);
if (!source) notFound();
const url = `${SITE_URL}${getLocalizedPath(locale, source.slug)}`;
return (
<>
<ArticleJsonLd
title={source.title}
description={source.excerpt}
url={url}
image={source.coverImage}
datePublished={source.date}
authorName={source.author}
/>
<AnimationSourceDetailContent source={source} />
</>
);
}
+45
View File
@@ -0,0 +1,45 @@
import type { Metadata } from "next";
import { getTranslations } from "next-intl/server";
import { AnimationSourcesContent } from "@/components/animation-sources-content";
import { listAnimationSources } from "@/data/animation-sources";
type AnimationSourcesPageProps = {
params: Promise<{ locale: string }>;
};
export async function generateMetadata({
params,
}: AnimationSourcesPageProps): Promise<Metadata> {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: "AnimationSources" });
return {
title: t("title"),
description: t("description"),
alternates: {
canonical: "/animation-sources",
},
};
}
export default async function AnimationSourcesPage({
params,
}: AnimationSourcesPageProps) {
const { locale } = await params;
const [sources, t] = await Promise.all([
listAnimationSources(locale),
getTranslations({ locale, namespace: "AnimationSources" }),
]);
return (
<AnimationSourcesContent
sources={sources}
labels={{
title: t("title"),
description: t("description"),
empty: t("empty"),
itemCount: t("itemCount", { count: sources.length }),
}}
/>
);
}
+21 -2
View File
@@ -1,11 +1,15 @@
import { listBlogDetails } from "@/data/blog-detail";
import { listAnimationSources } from "@/data/animation-sources";
import type { MetadataRoute } from "next";
const SITE_URL =
process.env.NEXT_PUBLIC_SITE_URL || "https://poyrazavsever.com";
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await listBlogDetails();
const [posts, animationSources] = await Promise.all([
listBlogDetails(),
listAnimationSources(),
]);
const staticRoutes: MetadataRoute.Sitemap = [
{
@@ -62,6 +66,12 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
changeFrequency: "monthly",
priority: 0.4,
},
{
url: `${SITE_URL}/animation-sources`,
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.7,
},
];
const blogRoutes: MetadataRoute.Sitemap = posts.map((post) => ({
@@ -71,5 +81,14 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
priority: 0.7,
}));
return [...staticRoutes, ...blogRoutes];
const animationSourceRoutes: MetadataRoute.Sitemap = animationSources.map(
(source) => ({
url: `${SITE_URL}${source.lang === "en" ? "/en" : ""}/animation-sources/${source.slug}`,
lastModified: source.date ? new Date(source.date) : new Date(),
changeFrequency: "monthly",
priority: 0.6,
}),
);
return [...staticRoutes, ...blogRoutes, ...animationSourceRoutes];
}