feat : add sitemao and some SEO
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
# Public site origin used for SEO metadata, sitemap, and robots.txt.
|
||||||
|
BASE_URL=https://guide.sudloh.com
|
||||||
|
|
||||||
# Local-only demo mode serves sanitized fixtures and bypasses external services.
|
# Local-only demo mode serves sanitized fixtures and bypasses external services.
|
||||||
# Keep this false in every deployed environment.
|
# Keep this false in every deployed environment.
|
||||||
BUZZ_DEMO_MODE=false
|
BUZZ_DEMO_MODE=false
|
||||||
|
|||||||
+3
-1
@@ -4,6 +4,7 @@ import { Anuphan, Geist_Mono } from "next/font/google";
|
|||||||
import { DeploymentUpdateNotifier } from "@/components/deployment-update-notifier";
|
import { DeploymentUpdateNotifier } from "@/components/deployment-update-notifier";
|
||||||
import { PageProgress } from "@/components/page-progress";
|
import { PageProgress } from "@/components/page-progress";
|
||||||
import { Toaster } from "@/components/ui/sonner";
|
import { Toaster } from "@/components/ui/sonner";
|
||||||
|
import { siteUrl } from "@/lib/site-url";
|
||||||
|
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
@@ -19,12 +20,13 @@ const geistMono = Geist_Mono({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
metadataBase: new URL("https://guide.sudloh.com"),
|
metadataBase: new URL(siteUrl),
|
||||||
title: {
|
title: {
|
||||||
default: "Buzz Guide",
|
default: "Buzz Guide",
|
||||||
template: "%s",
|
template: "%s",
|
||||||
},
|
},
|
||||||
description: "ไกด์ตัวละครจากช่องเกนชินไม่ใช่เกมมือถือ",
|
description: "ไกด์ตัวละครจากช่องเกนชินไม่ใช่เกมมือถือ",
|
||||||
|
keywords: ["เกนชิน", "เกนชินไม่ใช่เกมมือถือ", "Buzz", "ไกด์", "สุดหล่อ"],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({ children }: LayoutProps<"/">) {
|
export default function RootLayout({ children }: LayoutProps<"/">) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { MetadataRoute } from "next";
|
import type { MetadataRoute } from "next";
|
||||||
|
|
||||||
|
import { siteUrl } from "@/lib/site-url";
|
||||||
|
|
||||||
export default function robots(): MetadataRoute.Robots {
|
export default function robots(): MetadataRoute.Robots {
|
||||||
return {
|
return {
|
||||||
rules: {
|
rules: {
|
||||||
@@ -7,5 +9,6 @@ export default function robots(): MetadataRoute.Robots {
|
|||||||
allow: "/",
|
allow: "/",
|
||||||
disallow: ["/admin", "/api", "/register"],
|
disallow: ["/admin", "/api", "/register"],
|
||||||
},
|
},
|
||||||
|
sitemap: `${siteUrl}/sitemap.xml`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import type { MetadataRoute } from "next";
|
||||||
|
import { connection } from "next/server";
|
||||||
|
|
||||||
|
import { getCachedPublicGuideCards } from "@/lib/cache/public";
|
||||||
|
import { siteUrl } from "@/lib/site-url";
|
||||||
|
|
||||||
|
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||||
|
await connection();
|
||||||
|
const guides = await getCachedPublicGuideCards();
|
||||||
|
|
||||||
|
return [
|
||||||
|
{ url: siteUrl },
|
||||||
|
...guides.map((guide) => ({
|
||||||
|
url: `${siteUrl}/${encodeURIComponent(guide.slug)}`,
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
const configuredBaseUrl = process.env.BASE_URL?.trim();
|
||||||
|
|
||||||
|
if (!configuredBaseUrl) {
|
||||||
|
throw new Error("BASE_URL is required for site metadata and sitemaps.");
|
||||||
|
}
|
||||||
|
|
||||||
|
export const siteUrl = new URL(configuredBaseUrl).origin;
|
||||||
Reference in New Issue
Block a user