Files
portfolio/lib/sitemap.ts
2026-01-12 15:27:35 +00:00

71 lines
2.2 KiB
TypeScript

import { prisma } from "@/lib/prisma";
import { locales } from "@/i18n/locales";
import { getBaseUrl } from "@/lib/seo";
export type SitemapEntry = {
url: string;
lastModified: string;
changefreq?: "daily" | "weekly" | "monthly" | "yearly";
priority?: number;
};
export function generateSitemapXml(entries: SitemapEntry[]): string {
const xmlHeader = '<?xml version="1.0" encoding="UTF-8"?>';
const urlsetOpen = '<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">';
const urlsetClose = "</urlset>";
const urlEntries = entries
.map((e) => {
const changefreq = e.changefreq ?? "monthly";
const priority = typeof e.priority === "number" ? e.priority : 0.8;
return `
<url>
<loc>${e.url}</loc>
<lastmod>${e.lastModified}</lastmod>
<changefreq>${changefreq}</changefreq>
<priority>${priority.toFixed(1)}</priority>
</url>`;
})
.join("");
return `${xmlHeader}${urlsetOpen}${urlEntries}${urlsetClose}`;
}
export async function getSitemapEntries(): Promise<SitemapEntry[]> {
const baseUrl = getBaseUrl();
const nowIso = new Date().toISOString();
const staticPaths = ["", "/projects", "/legal-notice", "/privacy-policy"];
const staticEntries: SitemapEntry[] = locales.flatMap((locale) =>
staticPaths.map((p) => {
const path = p === "" ? `/${locale}` : `/${locale}${p}`;
return {
url: `${baseUrl}${path}`,
lastModified: nowIso,
changefreq: p === "" ? "weekly" : p === "/projects" ? "weekly" : "yearly",
priority: p === "" ? 1.0 : p === "/projects" ? 0.8 : 0.5,
};
}),
);
// Projects: for each project slug we publish per locale (same slug)
const projects = await prisma.project.findMany({
where: { published: true },
select: { slug: true, updatedAt: true },
orderBy: { updatedAt: "desc" },
});
const projectEntries: SitemapEntry[] = projects.flatMap((p) => {
const lastModified = (p.updatedAt ?? new Date()).toISOString();
return locales.map((locale) => ({
url: `${baseUrl}/${locale}/projects/${p.slug}`,
lastModified,
changefreq: "monthly",
priority: 0.7,
}));
});
return [...staticEntries, ...projectEntries];
}