feat : create share function for comment
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import type { ReactNode } from "react";
|
||||
import Link from "next/link";
|
||||
import { ArrowLeftIcon } from "lucide-react";
|
||||
|
||||
import Image from "@/components/ui/resilient-image";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { SiteHeader } from "@/components/public/site-header";
|
||||
import { SiteFooter } from "@/components/public/site-footer";
|
||||
import { ScrollableNav } from "@/components/public/scrollable-nav";
|
||||
import { LiveRefresh } from "@/components/live-refresh";
|
||||
import type { PublicGuideSummary } from "@/lib/guides/queries";
|
||||
import { commentNavigationSection } from "@/lib/comments/navigation";
|
||||
import { navigationIconPath } from "@/lib/navigation";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export function publicSectionTitle(slug: string, fallback: string): string {
|
||||
if (slug === "weapon") return "Weapons";
|
||||
if (slug === "artifact") return "Artifacts";
|
||||
if (slug === "constellations") return "Constellations";
|
||||
if (slug === "team") return "Team calc";
|
||||
if (slug === "comment") return "Comment";
|
||||
return fallback;
|
||||
}
|
||||
|
||||
export function GuidePageShell({
|
||||
guide,
|
||||
sections: guideSections,
|
||||
section,
|
||||
preview = false,
|
||||
children,
|
||||
}: {
|
||||
guide: Pick<PublicGuideSummary, "id" | "slug" | "name" | "characterKey" | "coverUrl">;
|
||||
sections: Pick<PublicGuideSummary["sections"][number], "id" | "slug" | "title">[];
|
||||
section?: string;
|
||||
preview?: boolean;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const sections = preview ? guideSections : [...guideSections, commentNavigationSection(guide.id)];
|
||||
const baseHref = preview ? `/admin/${guide.characterKey}/preview` : `/${guide.slug}`;
|
||||
const currentPageTitle = section
|
||||
? publicSectionTitle(section, sections.find((item) => item.slug === section)?.title ?? section)
|
||||
: "Overview";
|
||||
return (
|
||||
<div className="flex min-h-svh flex-col bg-background">
|
||||
<LiveRefresh endpoint={`/api/events/page/${guide.id}`} />
|
||||
<SiteHeader editHref={`/admin/${guide.characterKey}`} guideId={guide.id} />
|
||||
{preview ? (
|
||||
<div className="mx-auto w-full max-w-7xl px-4 pt-4 sm:px-6 lg:px-8">
|
||||
<Alert>
|
||||
<AlertTitle>Preview</AlertTitle>
|
||||
<AlertDescription>หน้านี้แสดงข้อมูลที่บันทึกล่าสุดและเปิดดูได้เฉพาะผู้ดูแล</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="sticky top-0 z-40 bg-background/95 supports-backdrop-filter:backdrop-blur">
|
||||
<div className="mx-auto flex min-h-12 w-full max-w-7xl items-center gap-3 px-4 sm:min-h-16 sm:px-6 lg:px-8">
|
||||
<Button variant="ghost" size="icon" className="max-sm:size-11" render={<Link href={preview ? `/admin/${guide.characterKey}` : "/"} />} nativeButton={false} aria-label={preview ? "กลับหน้าแก้ไข" : "กลับหน้ารวม"}>
|
||||
<ArrowLeftIcon />
|
||||
</Button>
|
||||
<div className="relative size-10 shrink-0 overflow-hidden rounded-lg border sm:size-16">
|
||||
<Image
|
||||
src={guide.coverUrl}
|
||||
alt={guide.name}
|
||||
fill
|
||||
sizes="(min-width: 640px) 64px, 40px"
|
||||
className="object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex min-w-0 flex-1 flex-col items-start gap-1">
|
||||
<p className="truncate text-sm text-muted-foreground">
|
||||
{guide.name}
|
||||
</p>
|
||||
<p className="max-w-full truncate font-heading text-lg font-semibold sm:text-2xl">
|
||||
{currentPageTitle}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<ScrollableNav
|
||||
ariaLabel={`เมนูคู่มือ ${guide.name}`}
|
||||
activeKey={section ?? "overview"}
|
||||
className="min-h-11 w-full rounded-xl border bg-card p-1 sm:p-2"
|
||||
>
|
||||
<Link
|
||||
href={baseHref}
|
||||
aria-current={!section ? "page" : undefined}
|
||||
className={cn(
|
||||
"flex min-h-11 shrink-0 items-center gap-2 whitespace-nowrap rounded-md px-3 text-sm transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
||||
!section
|
||||
? "bg-primary/15 font-semibold text-primary"
|
||||
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
||||
)}
|
||||
prefetch={false}
|
||||
>
|
||||
<Image
|
||||
src={navigationIconPath("overview")!}
|
||||
alt=""
|
||||
width={20}
|
||||
height={20}
|
||||
className="size-5 object-contain"
|
||||
/>
|
||||
Overview
|
||||
</Link>
|
||||
{sections.map((item) => (
|
||||
<Link
|
||||
key={item.id}
|
||||
href={`${baseHref}/${item.slug}`}
|
||||
aria-current={section === item.slug ? "page" : undefined}
|
||||
className={cn(
|
||||
"flex min-h-11 shrink-0 items-center gap-2 whitespace-nowrap rounded-md px-3 text-sm transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
||||
section === item.slug
|
||||
? "bg-primary/15 font-semibold text-primary"
|
||||
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
||||
)}
|
||||
prefetch={false}
|
||||
>
|
||||
{navigationIconPath(item.slug) ? (
|
||||
<Image
|
||||
src={navigationIconPath(item.slug)!}
|
||||
alt=""
|
||||
width={20}
|
||||
height={20}
|
||||
className="size-5 object-contain"
|
||||
/>
|
||||
) : null}
|
||||
{publicSectionTitle(item.slug, item.title)}
|
||||
</Link>
|
||||
))}
|
||||
</ScrollableNav>
|
||||
</div>
|
||||
</div>
|
||||
<main className="mx-auto w-full max-w-7xl p-4 sm:p-6 lg:p-10">
|
||||
{children}
|
||||
</main>
|
||||
<SiteFooter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user