feat : comment feature
CI / Verify (push) Successful in 2m30s
CI / Build immutable images and deploy (push) Successful in 3m9s

This commit is contained in:
2026-10-08 01:40:08 +07:00 Unverified
parent 8c8815cda5
commit 5812d99715
65 changed files with 27013 additions and 10 deletions
+5
View File
@@ -0,0 +1,5 @@
import { CommentBoardSkeleton } from "@/components/comments/comment-skeleton";
export default function Loading() {
return <div className="mx-auto w-full max-w-7xl p-4 sm:p-6 lg:p-10"><CommentBoardSkeleton /></div>;
}
+46
View File
@@ -0,0 +1,46 @@
import { Suspense } from "react";
import type { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import { connection } from "next/server";
import Image from "@/components/ui/resilient-image";
import { SiteHeader } from "@/components/public/site-header";
import { SiteFooter } from "@/components/public/site-footer";
import { ScrollableNav } from "@/components/public/scrollable-nav";
import { CommentBoardContent } from "@/components/comments/comment-board-content";
import { CommentBoardSkeleton } from "@/components/comments/comment-skeleton";
import { getCachedPublicGuideSummary } from "@/lib/cache/public";
import { commentNavigationSection } from "@/lib/comments/navigation";
import { navigationIconPath } from "@/lib/navigation";
import { cn } from "@/lib/utils";
export const instant = false;
type Props = { params: Promise<{ character: string }> };
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const guide = await getCachedPublicGuideSummary((await params).character);
return { title: guide ? `${guide.name}` : "ไม่พบไกด์" };
}
export default async function GuideCommentPage({ params }: Props) {
await connection();
const guide = await getCachedPublicGuideSummary((await params).character);
if (!guide) notFound();
const target = `guide:${guide.id}`;
const sections = [{ id: "overview", slug: "", title: "Overview" }, ...guide.sections, commentNavigationSection(guide.id)];
return <div className="flex min-h-svh flex-col bg-background">
<SiteHeader editHref={`/admin/${guide.characterKey}`} guideId={guide.id} />
<main className="mx-auto flex w-full max-w-7xl flex-1 flex-col gap-6 p-4 sm:p-6 lg:p-10">
<header className="flex items-center gap-3"><Image src={guide.coverUrl} alt="" width={64} height={64} className="size-16 rounded-lg object-cover" />
<div><p className="text-sm text-muted-foreground">{guide.name}</p><h1 className="font-heading text-3xl font-semibold">ความคิดเห็น</h1></div>
</header>
<ScrollableNav ariaLabel={`เมนูคู่มือ ${guide.name}`} activeKey="comment" className="min-h-11 w-full rounded-xl border bg-card p-1 sm:p-2">
{sections.map((section) => <Link key={section.id} href={`/${guide.slug}${section.slug ? `/${section.slug}` : ""}`} prefetch={false}
aria-current={section.slug === "comment" ? "page" : undefined}
className={cn("flex min-h-11 shrink-0 items-center gap-2 rounded-md px-3 text-sm", section.slug === "comment" ? "bg-primary/15 font-semibold text-primary" : "text-muted-foreground hover:bg-muted")}>
{navigationIconPath(section.slug || "overview") && <Image src={navigationIconPath(section.slug || "overview")!} alt="" width={20} height={20} className="size-5 object-contain" />}
{section.title}
</Link>)}
</ScrollableNav>
<Suspense fallback={<CommentBoardSkeleton />}><CommentBoardContent target={target} /></Suspense>
</main><SiteFooter />
</div>;
}