feat : add thanks page

This commit is contained in:
2026-09-04 20:48:55 +07:00 Unverified
parent 06d0287433
commit ba3e81e9cc
8 changed files with 199 additions and 6 deletions
+181
View File
@@ -0,0 +1,181 @@
import type { Metadata } from "next";
import Image from "next/image";
import Link from "next/link";
import { ExternalLinkIcon } from "lucide-react";
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
type ThanksProfile = {
username: string;
role: string;
profile: string;
link: string;
};
const specialThanks: ThanksProfile[] = [
{
username: "Buzz",
role: "Calculator & Guide Creator",
profile: "buzz.png",
link: "https://www.youtube.com/@Genshinmaichaigamemurtur",
},
{
username: "Gunshin",
role: "Developer",
profile: "gunshin.gif",
link: "https://gunshiz.top"
},
{
username: "Keqing Kung",
role: "Data Entry",
profile: "keqing.png",
link: "https://discord.com/users/860156010361520138",
},
{
username: "Mple",
role: "Data Entry",
profile: "mple.png",
link: "https://discord.com/users/527126736651943946",
}
];
export const metadata: Metadata = {
title: "Special Thanks",
description: "ขอบคุณทุกคนที่มีส่วนช่วยให้ Buzz Guide เกิดขึ้นได้",
};
function getInitials(username: string) {
return username.trim().slice(0, 2).toUpperCase();
}
export default function ThanksPage() {
return (
<div className="min-h-svh bg-background">
<header className="border-b">
<div className="mx-auto flex min-h-16 w-full max-w-6xl items-center px-4 sm:px-6">
<Link
href="/"
className="flex min-h-11 items-center gap-3 rounded-lg font-heading font-semibold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
>
<Image
src="/icon.png"
alt=""
width={36}
height={36}
className="size-9 object-contain"
/>
<span>ไกด์เกนชินไม่ใช่เกมมือถือ</span>
</Link>
</div>
</header>
<main className="mx-auto flex w-full max-w-6xl flex-col gap-10 px-4 py-12 sm:px-6 sm:py-16">
<header className="mx-auto flex max-w-2xl flex-col gap-3 text-center">
<h1 className="font-heading text-4xl font-semibold tracking-tight sm:text-5xl">
Special Thanks
</h1>
<p className="text-lg leading-8 text-muted-foreground">
ขอบคุณทุกคนที่มอบแรงสนับสนุนและเวลาให้เว็บไซต์นี้เกิดขึ้นได้
</p>
</header>
<Card className="w-full gap-0 py-0 sm:flex-row sm:items-center">
<CardHeader className="grid-cols-[auto_1fr] items-center gap-x-4 gap-y-1 py-4 text-left sm:flex-1">
<Image
src="/thanks/astral.png"
alt="Astral Hosting"
width={128}
height={128}
className="row-span-2 size-16 object-contain"
/>
<CardTitle className="text-xl sm:text-2xl">
Astral Hosting
</CardTitle>
<CardDescription className="font-medium">
ผู้สนับสนุนหลักด้าน Hosting
</CardDescription>
</CardHeader>
<CardContent className="pb-4 sm:max-w-md sm:py-4">
<p className="leading-6 text-muted-foreground">
ขอบคุณที่สนับสนุนระบบ Hosting ให้ Buzz Guide ออนไลน์และพร้อมใช้งาน
</p>
</CardContent>
<CardFooter className="justify-center sm:self-stretch sm:border-t-0 sm:border-l">
<Button
nativeButton={false}
render={
<Link href="https://astrxl.dev" target="_blank" rel="noreferrer" />
}
>
เยี่ยมชม Astral
<ExternalLinkIcon data-icon="inline-end" />
</Button>
</CardFooter>
</Card>
{specialThanks.length > 0 ? (
<section
aria-label="รายชื่อผู้สนับสนุน"
className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3"
>
{specialThanks.map((person) => (
<Card key={person.username}>
<CardHeader className="justify-items-center text-center">
<Avatar className="size-20">
<AvatarImage
src={`/thanks/${person.profile}`}
alt={`รูปโปรไฟล์ของ ${person.username}`}
/>
<AvatarFallback>{getInitials(person.username)}</AvatarFallback>
</Avatar>
<CardTitle className="mt-2">{person.username}</CardTitle>
{person.role ? (
<CardDescription>{person.role}</CardDescription>
) : null}
</CardHeader>
<CardContent>
<p className="text-center text-muted-foreground">
ขอบคุณที่เป็นส่วนสำคัญของ Buzz Guide
</p>
</CardContent>
<CardFooter>
<Button
className="w-full"
variant="outline"
nativeButton={false}
render={
<a
href={person.link}
target="_blank"
rel="noreferrer"
/>
}
>
ดูโปรไฟล์
<ExternalLinkIcon data-icon="inline-end" />
</Button>
</CardFooter>
</Card>
))}
</section>
) : (
<div>I am sigma number one</div>
)}
</main>
</div>
);
}
+15 -3
View File
@@ -47,9 +47,8 @@ export function GuideOverviewForm({
id: guide.coverMediaId, id: guide.coverMediaId,
url: guide.coverUrl, url: guide.coverUrl,
}); });
const invalidYoutubeUrl = Boolean( const youtubeVideo = parseYouTubeUrl(youtubeUrl.trim());
youtubeUrl.trim() && !parseYouTubeUrl(youtubeUrl.trim()), const invalidYoutubeUrl = Boolean(youtubeUrl.trim() && !youtubeVideo);
);
const value = { coverMediaId: cover.id, overview, youtubeUrl }; const value = { coverMediaId: cover.id, overview, youtubeUrl };
const incompleteIssues = [ const incompleteIssues = [
!cover.id ? "กรุณาอัปโหลด Guide Image" : null, !cover.id ? "กรุณาอัปโหลด Guide Image" : null,
@@ -156,6 +155,19 @@ export function GuideOverviewForm({
{invalidYoutubeUrl ? ( {invalidYoutubeUrl ? (
<FieldError>กรุณาใส่ลิงก์วิดีโอ YouTube ที่ถูกต้อง</FieldError> <FieldError>กรุณาใส่ลิงก์วิดีโอ YouTube ที่ถูกต้อง</FieldError>
) : null} ) : null}
{youtubeVideo ? (
<div className="aspect-video w-full overflow-hidden rounded-xl border bg-muted">
<iframe
src={youtubeVideo.embedUrl}
title={`ตัวอย่างวิดีโอไกด์ ${guide.name}`}
loading="lazy"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
className="size-full"
/>
</div>
) : null}
</Field> </Field>
</FieldGroup> </FieldGroup>
</CardContent> </CardContent>
+3 -3
View File
@@ -284,7 +284,7 @@ function TeamCard({
tabIndex={exporting ? -1 : undefined} tabIndex={exporting ? -1 : undefined}
aria-label={`เปิดข้อมูลอาวุธ ${member.weapon.name} บน Lunaris`} aria-label={`เปิดข้อมูลอาวุธ ${member.weapon.name} บน Lunaris`}
className={cn( className={cn(
"relative col-span-2 aspect-square scale-110 overflow-hidden rounded-md bg-muted outline-none", "relative aspect-square scale-110 overflow-hidden rounded-md bg-muted outline-none sm:col-span-2",
rarityGradientClass(member.weapon.rarity), rarityGradientClass(member.weapon.rarity),
)} )}
> >
@@ -303,7 +303,7 @@ function TeamCard({
</Kbd> </Kbd>
</a> </a>
) : ( ) : (
<div className="col-span-2 aspect-square rounded-md border bg-muted" /> <div className="aspect-square rounded-md border bg-muted sm:col-span-2" />
)} )}
<TeamArtifactIcon <TeamArtifactIcon
first={member.artifact} first={member.artifact}
@@ -311,7 +311,7 @@ function TeamCard({
eager={exporting} eager={exporting}
linked={!exporting} linked={!exporting}
sizes="64px" sizes="64px"
className="col-span-2" className="sm:col-span-2"
/> />
</div> </div>
</div> </div>
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB