chore: oxc
Build and Push Image / build-backend (push) Successful in 52s
Build and Push Image / build-frontend (push) Successful in 2m8s
Build and Push Image / push (push) Successful in 1m24s

This commit is contained in:
2026-06-10 01:44:11 +07:00 Unverified
parent 85aaf6487c
commit a31c8fbb54
117 changed files with 597 additions and 550 deletions
+7 -12
View File
@@ -21,13 +21,8 @@ import { Spinner } from "@/components/ui/spinner";
import { actionLog } from "@/lib/api";
import { adminCheck } from "@/lib/auth";
import { db } from "@/lib/db";
import type {
element} from "@/lib/db/schema";
import {
characters,
element as elementEnum,
versions,
} from "@/lib/db/schema";
import type { element } from "@/lib/db/schema";
import { characters, element as elementEnum, versions } from "@/lib/db/schema";
export default async function CharacterEditPage({
params,
@@ -112,19 +107,19 @@ export default async function CharacterEditPage({
values={{ ...char, stars: char.stars.toString(), element: char.vision }}
>
<div className="flex gap-2">
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="name" label="Name">
<Input placeholder="Traveler (Electro)" autoFocus />
</FormInput>
</div>
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="id" label="ID (change = break)">
<Input placeholder="traveler_electro" disabled />
</FormInput>
</div>
</div>
<div className="flex gap-2">
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="element" label="Element">
<Select>
<SelectTrigger className="w-full">
@@ -185,7 +180,7 @@ export default async function CharacterEditPage({
</FormInput>
<Separator />
<div className="flex gap-2">
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="weapon" label="Weapon" subLabel="(for Amber)">
<Select>
<SelectTrigger className="w-full">
@@ -207,7 +202,7 @@ export default async function CharacterEditPage({
</Select>
</FormInput>
</div>
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="amber" label="Amber ID">
<Input placeholder="10000005-electro" />
</FormInput>
+7 -12
View File
@@ -21,13 +21,8 @@ import { Spinner } from "@/components/ui/spinner";
import { actionLog } from "@/lib/api";
import { adminCheck } from "@/lib/auth";
import { db } from "@/lib/db";
import type {
element} from "@/lib/db/schema";
import {
characters,
element as elementEnum,
versions,
} from "@/lib/db/schema";
import type { element } from "@/lib/db/schema";
import { characters, element as elementEnum, versions } from "@/lib/db/schema";
import { genId } from "./overrides";
export default async function CharacterCreatePage() {
@@ -94,19 +89,19 @@ export default async function CharacterCreatePage() {
<ModalBase title="Create Character">
<FormProvider id="char-create" onSubmit={submit}>
<div className="flex gap-2">
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="name" override={genId} label="Name">
<Input placeholder="Traveler (Electro)" autoFocus />
</FormInput>
</div>
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="id" label="ID">
<Input placeholder="traveler_electro (Automatic)" />
</FormInput>
</div>
</div>
<div className="flex gap-2">
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="element" label="Element">
<Select>
<SelectTrigger className="w-full">
@@ -167,7 +162,7 @@ export default async function CharacterCreatePage() {
</FormInput>
<Separator />
<div className="flex gap-2">
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="weapon" label="Weapon" subLabel="(for Amber)">
<Select>
<SelectTrigger className="w-full">
@@ -189,7 +184,7 @@ export default async function CharacterCreatePage() {
</Select>
</FormInput>
</div>
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="amber" label="Amber ID">
<Input placeholder="10000005-electro" />
</FormInput>
+2 -2
View File
@@ -60,12 +60,12 @@ export default async function TlTypeCreatePage() {
<ModalBase title="Create Tierlist Type">
<FormProvider id="tl-type-create" onSubmit={submit}>
<div className="flex gap-2">
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="name" override={genId} label="Name">
<Input placeholder="Abyss" autoFocus />
</FormInput>
</div>
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<FormInput name="id" label="ID">
<Input placeholder="aby" />
</FormInput>
+3 -3
View File
@@ -157,11 +157,11 @@ export function CdnTable({
}
return (
<div className="flex flex-col gap-2 w-full">
<div className="flex w-full flex-col gap-2">
<div
className={cn(
onChoose ? "h-[calc(70svh-60px)] w-full" : "h-[calc(100svh-60px)]",
"overflow-auto rounded-md bg-[#2225] backdrop-blur-sm border",
"overflow-auto rounded-md border bg-[#2225] backdrop-blur-sm",
)}
>
<DataTable
@@ -240,7 +240,7 @@ export function CdnTable({
/>
</div>
<div className="flex justify-between h-9">
<div className="flex h-9 justify-between">
<div className="flex gap-2">
<SimpleTooltip text="Upload...">
<Button size="icon" onClick={() => fileInputRef.current?.click()}>
+4 -4
View File
@@ -40,11 +40,11 @@ export function CharManager({
}, [query, chars]);
return (
<div className="flex flex-col w-full">
<div className="flex gap-2 justify-center p-2">
<div className="flex w-full flex-col">
<div className="flex justify-center gap-2 p-2">
<SearchBox
filters={filters}
className="bg-input sticky top-2"
className="sticky top-2 bg-input"
onQueryChange={setQuery}
/>
<SimpleTooltip text="เพิ่มตัวละคร" side="right">
@@ -55,7 +55,7 @@ export function CharManager({
</Button>
</SimpleTooltip>
</div>
<div className="flex flex-wrap gap-4 justify-center">
<div className="flex flex-wrap justify-center gap-4">
{filteredChars.map((char) => (
<Link href={`/admin/char/${char.id}`} key={char.id}>
<Avatar char={char} />
+4 -4
View File
@@ -97,7 +97,7 @@ export function RandomWelcomeMessage() {
if (index === -1)
return (
<div className="flex flex-col gap-0.5 mt-1 items-center">
<div className="mt-1 flex flex-col items-center gap-0.5">
<Skeleton className="h-4 w-32" />
<Skeleton className="h-4 w-64" />
</div>
@@ -106,11 +106,11 @@ export function RandomWelcomeMessage() {
const item = items[index];
return (
<div className="flex flex-col gap-0.5 mt-1">
<div className="text-sm flex items-center justify-center">
<div className="mt-1 flex flex-col gap-0.5">
<div className="flex items-center justify-center text-sm">
{item.header}
</div>
<div className="opacity-60 text-xs ">{item.message}</div>
<div className="text-xs opacity-60 ">{item.message}</div>
</div>
);
}
+2 -2
View File
@@ -19,8 +19,8 @@ export default function ErrorPage({
}, [error]);
return (
<div className="h-full w-full m-2 ml-0 border bg-[#2225] backdrop-blur-md rounded-md flex flex-col gap-2 justify-center items-center">
<h2 className="font-bold text-2xl">Something went wrong!</h2>
<div className="m-2 ml-0 flex h-full w-full flex-col items-center justify-center gap-2 rounded-md border bg-[#2225] backdrop-blur-md">
<h2 className="text-2xl font-bold">Something went wrong!</h2>
<Button
onClick={
// Attempt to recover by trying to re-render the segment
+5 -5
View File
@@ -11,23 +11,23 @@ export default async function AdminGuidePage() {
const list = await searchGuide("", true);
return (
<div className="grow-0 flex flex-col pt-5 gap-2 mx-4">
<div className="mx-4 flex grow-0 flex-col gap-2 pt-5">
<Button className="w-fit" asChild>
<Link href={`/admin/guide/create`}>
<PlusIcon />
<span>Add guide</span>
</Link>
</Button>
<div className="grid gap-4 grid-cols-[repeat(auto-fill,minmax(min(300px,calc(100svw-2rem-2px)),1fr))]">
<div className="grid grid-cols-[repeat(auto-fill,minmax(min(300px,calc(100svw-2rem-2px)),1fr))] gap-4">
{list.map((card) => (
<Card
key={card.id}
className={cn(
"bg-card/50 hover:bg-border backdrop-blur-sm transition-colors py-3 sm:py-6 rounded-sm sm:rounded-xl group relative",
"group relative rounded-sm bg-card/50 py-3 backdrop-blur-sm transition-colors hover:bg-border sm:rounded-xl sm:py-6",
card.hidden && "opacity-70",
)}
>
<div className="flex gap-1 absolute opacity-0 group-hover:opacity-100 transition-opacity top-0 right-0 m-2">
<div className="absolute top-0 right-0 m-2 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100">
<Button
size="icon"
variant="outline"
@@ -43,7 +43,7 @@ export default async function AdminGuidePage() {
</div>
<CardHeader className="px-3 sm:px-6">
<CardTitle>{card.name}</CardTitle>
<div className="relative w-full aspect-square mt-2 rounded-sm sm:rounded-lg border overflow-hidden">
<div className="relative mt-2 aspect-square w-full overflow-hidden rounded-sm border sm:rounded-lg">
{card.image && (
<Image
src={`/cdn/${card.image}`}
+1 -1
View File
@@ -278,7 +278,7 @@ async function HealthStatus() {
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<div className="flex justify-between w-full">
<div className="flex w-full justify-between">
<div className="flex gap-1 [&>svg]:size-4 [&>svg]:shrink-0">
{/* Database */}
<SimpleTooltip text="Database">
+10 -10
View File
@@ -126,7 +126,7 @@ export default function AuditLogViewer({
};
return (
<div className="bg-[#2225] h-svh w-full flex flex-col items-center gap-2 p-2 overflow-hidden">
<div className="flex h-svh w-full flex-col items-center gap-2 overflow-hidden bg-[#2225] p-2">
<SearchBox
filters={filters}
className="bg-input"
@@ -144,22 +144,22 @@ export default function AuditLogViewer({
if (el) entryRefs.current.set(log.id, el);
else entryRefs.current.delete(log.id);
}}
className="group hover:bg-[#2225] transition-colors"
className="group transition-colors hover:bg-[#2225]"
>
<div
className={`flex gap-4 px-4 ${isGrouped ? "py-0.5" : "py-3.5"} pb-0.5`}
>
<div className="w-min shrink-0 text-right pt-0.5">
<div className="w-min shrink-0 pt-0.5 text-right">
<span
className={`text-xs whitespace-nowrap invisible ${isGrouped ? "group-hover:visible" : ""}`}
className={`invisible text-xs whitespace-nowrap ${isGrouped ? "group-hover:visible" : ""}`}
>
{formatTime(log.time)}
</span>
</div>
<div className="flex-1 min-w-0">
<div className="min-w-0 flex-1">
{!isGrouped && (
<div className="flex items-baseline gap-2 mb-0.5">
<div className="mb-0.5 flex items-baseline gap-2">
<span className="font-semibold text-white">
{log.author || "System"}
</span>
@@ -174,11 +174,11 @@ export default function AuditLogViewer({
onClick={() => toggleExpand(log.id)}
role="tree"
>
<span className="text-gray-300 leading-relaxed flex items-center gap-2">
<span className="flex items-center gap-2 leading-relaxed text-gray-300">
{log.text}{" "}
{!isExpanded && log.details ? (
<SimpleTooltip text="Click to see details">
<FormIcon className="opacity-80 size-4" />
<FormIcon className="size-4 opacity-80" />
</SimpleTooltip>
) : (
""
@@ -188,7 +188,7 @@ export default function AuditLogViewer({
<Button
variant="ghost"
size="icon"
className="shrink-0 h-6 w-6 text-gray-400 hover:text-gray-200 hover:bg-[#404249]"
className="h-6 w-6 shrink-0 text-gray-400 hover:bg-[#404249] hover:text-gray-200"
>
{isExpanded ? (
<ChevronDown className="h-4 w-4" />
@@ -201,7 +201,7 @@ export default function AuditLogViewer({
{isExpanded && log.details ? (
<div className="mt-2 mb-1">
<pre className="bg-[#1e1f2255] rounded p-3 text-sm text-gray-300 overflow-x-auto border border-[#27282c] font-mono">
<pre className="overflow-x-auto rounded border border-[#27282c] bg-[#1e1f2255] p-3 font-mono text-sm text-gray-300">
{stringify(log.details)}
</pre>
</div>
+21 -21
View File
@@ -45,7 +45,7 @@ function VersionBadge({
className?: string;
}) {
return (
<span className={cn("text-[10px] font-bold leading-none", className)}>
<span className={cn("text-[10px] leading-none font-bold", className)}>
{name?.match(/[0-9.]+$/)?.[1]}
</span>
);
@@ -88,8 +88,8 @@ function DropdownMenu({
return (
<div
className={cn(
"flex flex-col gap-0.5 min-w-40",
depth > 0 && "ml-2 pl-2 border-l border-white/10",
"flex min-w-40 flex-col gap-0.5",
depth > 0 && "ml-2 border-l border-white/10 pl-2",
)}
>
{items.map((item) => {
@@ -106,11 +106,11 @@ function DropdownMenu({
type="button"
onClick={() => setOpenSub(isOpen ? null : item.name)}
className={cn(
"flex items-center gap-2 w-full px-2.5 py-2 rounded-md text-left",
"transition-colors text-[13px]",
"flex w-full items-center gap-2 rounded-md px-2.5 py-2 text-left",
"text-[13px] transition-colors",
active
? "bg-white/15 text-white"
: "text-white/60 hover:text-white hover:bg-white/10",
: "text-white/60 hover:bg-white/10 hover:text-white",
)}
>
<Icon size={16} name={item.name} className="shrink-0" />
@@ -137,11 +137,11 @@ function DropdownMenu({
href={item.href!}
onClick={onClose}
className={cn(
"flex items-center gap-2 px-2.5 py-2 rounded-md",
"transition-colors text-[13px]",
"flex items-center gap-2 rounded-md px-2.5 py-2",
"text-[13px] transition-colors",
active
? "bg-white/15 text-white"
: "text-white/60 hover:text-white hover:bg-white/10",
: "text-white/60 hover:bg-white/10 hover:text-white",
)}
>
<Icon size={16} name={item.name} className="shrink-0" />
@@ -255,8 +255,8 @@ export function AdminNavbar({
return (
<div ref={navRef} className="sticky top-0 z-49">
<div className="flex items-center gap-1 px-2 py-1.5 border-b border-white/10 bg-card/75 backdrop-blur-sm">
<div className="flex items-center gap-1 shrink-0">
<div className="flex items-center gap-1 border-b border-white/10 bg-card/75 px-2 py-1.5 backdrop-blur-sm">
<div className="flex shrink-0 items-center gap-1">
{prefixParent && (
<button
type="button"
@@ -264,8 +264,8 @@ export function AdminNavbar({
setScopeOverride(scopeOverride === "root" ? null : "root")
}
className={cn(
"flex items-center justify-center w-6 h-8 rounded transition-colors opacity-50 hover:opacity-100",
scopeOverride === "root" && "opacity-100 bg-white/15",
"flex h-8 w-6 items-center justify-center rounded opacity-50 transition-colors hover:opacity-100",
scopeOverride === "root" && "bg-white/15 opacity-100",
)}
>
<prefixParent.icon size={14} name={prefixParent.name} />
@@ -275,7 +275,7 @@ export function AdminNavbar({
type="button"
onClick={() => setShowLabels((v) => !v)}
className={cn(
"flex items-center justify-center w-8 h-8 rounded transition-colors",
"flex h-8 w-8 items-center justify-center rounded transition-colors",
showLabels
? "bg-white/15 text-white"
: "text-white/40 hover:text-white/70",
@@ -283,10 +283,10 @@ export function AdminNavbar({
>
{showLabels ? <X size={16} /> : <AlignJustify size={16} />}
</button>
<div className="w-px h-5 bg-white/10 mx-1" />
<div className="mx-1 h-5 w-px bg-white/10" />
</div>
<div className="flex items-center gap-1 overflow-x-auto scrollbar-none flex-1 min-w-0">
<div className="flex min-w-0 flex-1 scrollbar-none items-center gap-1 overflow-x-auto">
{(activeParent ? activeParent.sub! : items).map((item) => {
const Icon = item.icon;
const active = isActive(item, pathname);
@@ -297,7 +297,7 @@ export function AdminNavbar({
<>
<Icon size={18} name={item.name} className="shrink-0" />
{showLabels && (
<span className="text-[11px] whitespace-nowrap leading-none">
<span className="text-[11px] leading-none whitespace-nowrap">
{item.name}
</span>
)}
@@ -305,10 +305,10 @@ export function AdminNavbar({
);
const buttonClass = cn(
"flex items-center gap-1.5 px-2.5 py-1.5 rounded transition-colors shrink-0",
"flex shrink-0 items-center gap-1.5 rounded px-2.5 py-1.5 transition-colors",
active || isOpen
? "bg-white/15 text-white"
: "text-white/50 hover:text-white hover:bg-white/10",
: "text-white/50 hover:bg-white/10 hover:text-white",
);
if (hasSub) {
@@ -340,8 +340,8 @@ export function AdminNavbar({
);
if (!entry || !("sub" in entry) || !entry.sub) return null;
return (
<div className="absolute left-0 right-0 top-full mt-1 z-50">
<div className="rounded-lg border border-white/10 bg-card/95 backdrop-blur-sm p-2 shadow-xl">
<div className="absolute top-full right-0 left-0 z-50 mt-1">
<div className="rounded-lg border border-white/10 bg-card/95 p-2 shadow-xl backdrop-blur-sm">
<DropdownMenu
items={entry.sub}
showLabels={showLabels}
+3 -2
View File
@@ -2,9 +2,10 @@ import { RandomWelcomeMessage } from "./client";
export default function AdminPage() {
return (
<div className="flex h-full w-full justify-center items-center">
<div className="flex h-full w-full items-center justify-center">
<div className="flex flex-col items-center">
<span className="text-4xl font-bold no-translate">ยินดีต้อนรับกลับ!</span>
{/* oxlint-disable-next-line tailwindcss/no-unknown-classes */}
<span className="no-translate text-4xl font-bold">ยินดีต้อนรับกลับ!</span>
<div className="mt-1">
<RandomWelcomeMessage />
</div>
+1 -1
View File
@@ -15,7 +15,7 @@ export default async function () {
const enka = await getEnka();
return (
<div className="grid gap-8 h-full w-full p-2 pl-0">
<div className="grid h-full w-full gap-8 p-2 pl-0">
<Tabs defaultValue="external">
<TabsList className="w-full">
<TabsTrigger value="external">บริการนอก</TabsTrigger>
+3 -3
View File
@@ -34,7 +34,7 @@ export function SettingsServicesSection({
return (
<Section title="บริการนอก">
<div className="flex flex-col gap-2 h-full">
<div className="flex h-full flex-col gap-2">
<div className="flex items-center gap-2">
<Switch checked={enka} onCheckedChange={setEnka} />
เปิดใช้การดึงตัวละครใน Artifact
@@ -44,7 +44,7 @@ export function SettingsServicesSection({
Sync Amber
</Button>
{debug && (
<div className="grid gap-1 rounded-sm border border-dashed p-1 w-fit">
<div className="grid w-fit gap-1 rounded-sm border border-dashed p-1">
<span className="text-sm text-muted-foreground">
Test file input
</span>
@@ -52,7 +52,7 @@ export function SettingsServicesSection({
</div>
)}
{syncResult && (
<pre className="border bg-muted rounded h-full p-2">{syncResult}</pre>
<pre className="h-full rounded border bg-muted p-2">{syncResult}</pre>
)}
</div>
</Section>
+11 -11
View File
@@ -21,7 +21,7 @@ export default async function TierlistManagerPage() {
}));
return (
<div className="grow-0 flex flex-col pt-5 gap-2 mx-2">
<div className="mx-2 flex grow-0 flex-col gap-2 pt-5">
<Button className="w-fit" asChild>
<Link href={`/admin/tl/ver/create`}>
<PlusIcon />
@@ -29,16 +29,16 @@ export default async function TierlistManagerPage() {
</Link>
</Button>
{vers.map((t) => (
<div className="flex flex-col gap-1 group/type" key={t.id}>
<div className="font-semibold text-4xl flex flex-wrap items-center gap-2 w-fit">
<div className="px-2 py-1 border rounded-md bg-[#2228] flex-auto flex flex-wrap items-baseline gap-x-2">
<div className="group/type flex flex-col gap-1" key={t.id}>
<div className="flex w-fit flex-wrap items-center gap-2 text-4xl font-semibold">
<div className="flex flex-auto flex-wrap items-baseline gap-x-2 rounded-md border bg-[#2228] px-2 py-1">
<span className="text-nowrap">{t.name}</span>
<span className="flex items-center gap-1">
<Kbd>{t.id}</Kbd>
<span className="text-xs text-muted-foreground">{t.mode}</span>
</span>
</div>
<div className="md:opacity-0 group-hover/type:opacity-100 transition-opacity flex gap-1">
<div className="flex gap-1 transition-opacity group-hover/type:opacity-100 md:opacity-0">
<SimpleTooltip text="Add version">
<Button asChild>
<Link href={`/admin/tl/ver/${t.id}/create`}>
@@ -57,14 +57,14 @@ export default async function TierlistManagerPage() {
</SimpleTooltip>
</div>
</div>
<div className="flex gap-2 flex-wrap">
<div className="flex flex-wrap gap-2">
{t.versions.map((e) => (
<div
key={e.id}
className={cn(
e.image
? "relative aspect-video w-[calc(100svw-16px)] md:w-60 rounded-sm border group/ver"
: "relative flex items-center justify-center aspect-video w-[calc(100svw-16px)] md:w-60 border rounded-sm bg-[#1118] backdrop-blur-xl font-bold text-4xl group/ver",
? "group/ver relative aspect-video w-[calc(100svw-16px)] rounded-sm border md:w-60"
: "group/ver relative flex aspect-video w-[calc(100svw-16px)] items-center justify-center rounded-sm border bg-[#1118] text-4xl font-bold backdrop-blur-xl md:w-60",
e.hidden && "opacity-50",
)}
>
@@ -74,16 +74,16 @@ export default async function TierlistManagerPage() {
src={`/cdn/${e.image}`}
alt={e.name}
fill
className="rounded-sm border object-cover bg-primary -z-1"
className="-z-1 rounded-sm border bg-primary object-cover"
/>
<div className="flex absolute w-full justify-center bottom-0 py-1 bg-card rounded-b-sm gap-1">
<div className="absolute bottom-0 flex w-full justify-center gap-1 rounded-b-sm bg-card py-1">
{e.name} <Kbd>{e.id}</Kbd>
</div>
</>
) : (
e.name
)}
<div className="md:opacity-0 group-hover/ver:opacity-100 transition-opacity flex gap-1 absolute top-1 right-1">
<div className="absolute top-1 right-1 flex gap-1 transition-opacity group-hover/ver:opacity-100 md:opacity-0">
<SimpleTooltip text="Open in admin">
<Button variant="outline" asChild className="bg-card!">
<Link href={`/tl/${t.id}/${e.id}/admin`} target="_blank">
+9 -9
View File
@@ -43,11 +43,11 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
});
}, [sub, uid, t]);
return (
<div className="h-full w-full relative">
<div className="relative h-full w-full">
{!ready && !error && (isCached || useWeb) && (
<div
className={cn(
"flex flex-col items-center gap-2 absolute left-1/2 -translate-x-1/2 -translate-y-1/2 z-40",
"absolute left-1/2 z-40 flex -translate-x-1/2 -translate-y-1/2 flex-col items-center gap-2",
useWeb ? "top-[calc(50%+80px)]" : "top-1/2",
)}
>
@@ -56,7 +56,7 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
</div>
)}
{error && (
<div className="flex flex-col items-center gap-2 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-40">
<div className="absolute top-1/2 left-1/2 z-40 flex -translate-x-1/2 -translate-y-1/2 flex-col items-center gap-2">
{error.includes("ใหม่") ? (
<SquircleDashed className="size-8 text-orange-500" />
) : (
@@ -69,7 +69,7 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
{!error && !ready && !isCached && !useWeb && (
<div
className={cn(
"flex flex-col items-center gap-2 absolute left-1/2 -translate-x-1/2 -translate-y-1/2 z-40",
"absolute left-1/2 z-40 flex -translate-x-1/2 -translate-y-1/2 flex-col items-center gap-2",
useWeb ? "top-[calc(50%+80px)]" : "top-1/2",
)}
>
@@ -80,7 +80,7 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
<div
className={cn(
"absolute left-1 z-45 opacity-70 md:opacity-50 hover:opacity-100 flex gap-1",
"absolute left-1 z-45 flex gap-1 opacity-70 hover:opacity-100 md:opacity-50",
useWeb ? "-bottom-19" : "bottom-1",
)}
>
@@ -117,8 +117,8 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
<iframe
src={`https://enka.network/u/${uid}?t=${t}`}
className={cn(
"w-full border-0 bg-card -mt-20 h-[calc(100%+5rem)]",
!ready && "grayscale blur-md brightness-50 pointer-events-none",
"-mt-20 h-[calc(100%+5rem)] w-full border-0 bg-card",
!ready && "pointer-events-none blur-md brightness-50 grayscale",
)}
title="Enka Network"
onLoad={() => setReady(true)}
@@ -126,9 +126,9 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
) : (
<div
className={cn(
"w-full h-full border-0 bg-card transition-[filter] portrait:rotate-90 portrait:scale-175",
"h-full w-full border-0 bg-card transition-[filter] portrait:scale-175 portrait:rotate-90",
(!ready || error) &&
"grayscale blur-md brightness-50 pointer-events-none",
"pointer-events-none blur-md brightness-50 grayscale",
)}
>
<Image
+4 -4
View File
@@ -33,10 +33,10 @@ export default async function AdminSubmissionView({
const { enka } = await getArtifactConfig();
if (!sub) notFound();
return (
<div className="p-2 h-full">
<div className="flex flex-col h-full w-full gap-2">
<div className="h-full p-2">
<div className="flex h-full w-full flex-col gap-2">
<div className="flex w-full justify-between gap-2">
<Card className="w-full pb-1 rounded-md">
<Card className="w-full rounded-md pb-1">
<CardHeader>
<CardTitle className="font-bold">
{sub.queue}. {sub.name}
@@ -54,7 +54,7 @@ export default async function AdminSubmissionView({
</Card>
<Avatar char={char} />
</div>
<div className="border rounded-md h-full overflow-hidden">
<div className="h-full overflow-hidden rounded-md border">
{enka && <EnkaBrowser uid={sub.uid} sub={sub.id} />}
</div>
</div>
+1 -1
View File
@@ -83,7 +83,7 @@ export function SidebarLink({
{children}
</HoverCardTrigger>
<HoverCardContent
className="flex flex-col gap-0.5 w-2xl"
className="flex w-2xl flex-col gap-0.5"
side="right"
>
<div className="font-semibold">{submission.name}</div>
+2 -2
View File
@@ -57,7 +57,7 @@ export default async function AdminLayout({
<SidebarProvider>
<Sidebar>
<SidebarHeader>
<div className="flex justify-between items-center">
<div className="flex items-center justify-between">
<b>Admin</b>
<div className="flex gap-1">
<Button
@@ -111,7 +111,7 @@ export default async function AdminLayout({
</Sidebar>
<SidebarInset className="bg-transparent">
{children}
<div className="absolute block md:hidden opacity-50 hover:opacity-100 bottom-15 left-4">
<div className="absolute bottom-15 left-4 block opacity-50 hover:opacity-100 md:hidden">
<SidebarTrigger />
</div>
<Watcher />
+5 -5
View File
@@ -179,7 +179,7 @@ export function CharacterChooser({
<Loader2 className="animate-spin" /> กำลังโหลดตัวละคร...
</Placeholder>
) : !chars.length ? (
<div className="flex gap-2 mb-2">
<div className="mb-2 flex gap-2">
<Placeholder />
<Placeholder />
<Placeholder />
@@ -187,7 +187,7 @@ export function CharacterChooser({
<Placeholder />
</div>
) : (
<div className="flex gap-2 mb-2">
<div className="mb-2 flex gap-2">
<SimpleTooltip text="ค้นหาด้วยตัวเอง">
<Placeholder
className="w-[76.8px] cursor-pointer rounded-sm"
@@ -224,7 +224,7 @@ function Placeholder({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"w-full h-[100.8px] flex gap-2 justify-center items-center rounded-md bg-muted",
"flex h-[100.8px] w-full items-center justify-center gap-2 rounded-md bg-muted",
className,
)}
{...props}
@@ -417,7 +417,7 @@ export function WarningDialog() {
width={500}
height={200}
alt="Guide Image 1"
className="border-2 border-foreground rounded-md"
className="rounded-md border-2 border-foreground"
/>
<center>
@@ -429,7 +429,7 @@ export function WarningDialog() {
width={500}
height={200}
alt="Guide Image 2"
className="border-2 border-foreground rounded-md"
className="rounded-md border-2 border-foreground"
/>
<span className="ml-[60%] md:ml-[65%]">
+4 -3
View File
@@ -20,12 +20,12 @@ export async function LiveButton() {
<TooltipTrigger asChild>
<Link href={url}>
<Button variant="outline" type="button">
<TvMinimalPlay className="text-red-500 animate-pulse" /> LIVE
<TvMinimalPlay className="animate-pulse text-red-500" /> LIVE
</Button>
</Link>
</TooltipTrigger>
<TooltipContent>
<div className="m-2 p-2 flex flex-col gap-2 rounded border bg-card">
<div className="m-2 flex flex-col gap-2 rounded border bg-card p-2">
<Image
height={thumbnails.height * (targetWidth / thumbnails.width)}
width={targetWidth}
@@ -34,7 +34,8 @@ export async function LiveButton() {
className="rounded border"
/>
<div
className="truncate line-clamp-2"
// oxlint-disable-next-line tailwindcss/no-conflicting-classes
className="line-clamp-2 truncate"
style={{ maxWidth: targetWidth }}
>
{title}
+13 -13
View File
@@ -67,7 +67,7 @@ export default async function ArtifactFormPage({
const editing = q && searchEdit === q.editToken && q.edits < 5;
return (
<div className="flex justify-around items-center h-svh">
<div className="flex h-svh items-center justify-around">
{/*
<div className="hidden md:block p-5">
<div className="aspect-video w-110"></div>
@@ -78,14 +78,14 @@ export default async function ArtifactFormPage({
""
) : q ? (
<Blocker>
<div className="flex gap-1 flex-col items-center">
<span className="font-bold text-3xl">คิวของคุณคือหมายเลข</span>
<span className="font-bold text-5xl">{q.queue}</span>
<div className="flex flex-col items-center gap-1">
<span className="text-3xl font-bold">คิวของคุณคือหมายเลข</span>
<span className="text-5xl font-bold">{q.queue}</span>
</div>
{q.edits < 5 && !q.checked ? (
<SimpleTooltip text="แก้ไข">
<Button
className="absolute bottom-0 right-0 m-2"
className="absolute right-0 bottom-0 m-2"
variant="outline"
size="icon"
asChild
@@ -97,7 +97,7 @@ export default async function ArtifactFormPage({
</SimpleTooltip>
) : (
<Button
className="absolute bottom-0 right-0 m-2 bg-red-500/50!"
className="absolute right-0 bottom-0 m-2 bg-red-500/50!"
variant="outline"
disabled
>
@@ -108,13 +108,13 @@ export default async function ArtifactFormPage({
</Blocker>
) : config.locked ? (
<Blocker>
<span className="font-bold text-3xl">ยังไม่เปิดรับคิว</span>
<span className="text-3xl font-bold">ยังไม่เปิดรับคิว</span>
</Blocker>
) : config.limit >= 0 && count >= config.limit ? (
<Blocker>
<div className="flex gap-1 flex-col items-center">
<span className="font-bold text-3xl">คิวเต็มแล้ว</span>
<span className="font-bold text-2xl">ต้องโดเนทลัดคิวแล้วล่ะ</span>
<div className="flex flex-col items-center gap-1">
<span className="text-3xl font-bold">คิวเต็มแล้ว</span>
<span className="text-2xl font-bold">ต้องโดเนทลัดคิวแล้วล่ะ</span>
<SimpleTooltip text="โดเนทลัดคิว ขั้นต่ำ 10 บาท" side="bottom">
<Link
href="https://tipme.in.th/536d969652666273c2fa85ad"
@@ -122,7 +122,7 @@ export default async function ArtifactFormPage({
rel="noreferrer"
>
<Button
className="bg-emerald-600! border-white! animate-pulse"
className="animate-pulse border-white! bg-emerald-600!"
type="button"
>
<CircleDollarSign />
@@ -223,7 +223,7 @@ export default async function ArtifactFormPage({
</div>
</ArtifactFormWrapper>
</CardContent>
<CardFooter className="flex gap-2 justify-between">
<CardFooter className="flex justify-between gap-2">
<div className="flex gap-2">
<SimpleTooltip text="โดเนทลัดคิว ขั้นต่ำ 10 บาท">
<Link
@@ -256,7 +256,7 @@ export default async function ArtifactFormPage({
</Suspense>
)}
</div>
<div className="flex gap-2 items-center">
<div className="flex items-center gap-2">
<Kbd>
{count} / {config.limit < 0 ? "∞" : config.limit} คิว
</Kbd>
+4 -4
View File
@@ -98,7 +98,7 @@ const columns: ColumnDef<typeof donations.$inferSelect>[] = [
className={cn(
"flex gap-1",
row.row.original.uid ||
"opacity-0 group-hover:opacity-100 transition-opacity",
"opacity-0 transition-opacity group-hover:opacity-100",
)}
>
<SimpleTooltip text="Re-send Popup">
@@ -149,8 +149,8 @@ export function DonateAdminPage({
}, [router]);
return (
<div className="mx-auto w-full max-w-[max(1280px,90%)] flex flex-col">
<span className="flex items-center text-3xl font-semibold gap-1 pt-1 pb-2">
<div className="mx-auto flex w-full max-w-[max(1280px,90%)] flex-col">
<span className="flex items-center gap-1 pt-1 pb-2 text-3xl font-semibold">
<BitcoinIcon size={32} />
Donate List
</span>
@@ -158,7 +158,7 @@ export function DonateAdminPage({
columns={columns}
emptyDescription="No donation came in yet."
data={data}
className="w-full max-h-[calc(100vh-93px)] overflow-y-auto backdrop-blur-sm bg-black/25"
className="max-h-[calc(100vh-93px)] w-full overflow-y-auto bg-black/25 backdrop-blur-sm"
></DataTable>
</div>
);
+12 -12
View File
@@ -248,14 +248,14 @@ export default async function () {
//#region TSX
return (
<div className="flex items-center justify-center min-h-svh">
<div className="p-5 bg-card border rounded-md w-full max-w-md">
<div className="flex min-h-svh items-center justify-center">
<div className="w-full max-w-md rounded-md border bg-card p-5">
<FormProvider id="tip" inDialog={false} onSubmit={submit}>
<div className="flex flex-col items-center sm:flex-row sm:items-end gap-2">
<div className="flex flex-col items-center gap-2 sm:flex-row sm:items-end">
<FormInput name="image" className="w-fit">
<Cropper />
</FormInput>
<div className="grid gap-4 [&>label]:-mb-2 grow w-full">
<div className="grid w-full grow gap-4 [&>label]:-mb-2">
<FormInput name="name" label="ชื่อ" subLabel="ไม่จำเป็น">
<Input placeholder="Anonymous" />
</FormInput>
@@ -274,7 +274,7 @@ export default async function () {
{!artifactConfig.locked && (
<>
<FormInput name="artifact">
<FormWrapper className="flex gap-2 items-center">
<FormWrapper className="flex items-center gap-2">
<Checkbox />
ลัดคิวเสือกไอดีชาวบ้าน
</FormWrapper>
@@ -292,11 +292,11 @@ export default async function () {
tabs={[
{
label: (
<span className="flex gap-1 items-center">
<span className="flex items-center gap-1">
<Image
src={TruemoneyIcon}
alt="Truemoney"
className="w-12 h-6 object-cover"
className="h-6 w-12 object-cover"
/>
TrueMoney
</span>
@@ -305,7 +305,7 @@ export default async function () {
},
{
label: (
<span className="flex gap-1 items-center">
<span className="flex items-center gap-1">
<QrCodeIcon className="size-6" />
PromptPay
</span>
@@ -320,14 +320,14 @@ export default async function () {
</FormInput>
</FormChoice>
<FormChoice value="pp">
<div className="flex gap-2 w-full pb-2">
<div className="flex w-full gap-2 pb-2">
<Image
src={PromptpayImage}
alt="Promptpay QR Code"
className="rounded max-w-32 shrink-0"
className="max-w-32 shrink-0 rounded"
/>
<div className="flex flex-col shrink-0 relative">
<span className="font-bold text-sm">บัญชีรับโดเนท</span>
<div className="relative flex shrink-0 flex-col">
<span className="text-sm font-bold">บัญชีรับโดเนท</span>
<span className="text-sm text-muted-foreground">
ผู้รับ: นาย พัชรพล พลพันธุ์
</span>
+5 -5
View File
@@ -26,9 +26,9 @@ export default function Page() {
function PageSkeleton() {
return (
<div className="min-h-svh flex flex-col justify-center">
<div className="max-w-4xl w-full mx-auto flex flex-col gap-4 p-4">
<div className="flex justify-center items-end gap-4 mt-6">
<div className="flex min-h-svh flex-col justify-center">
<div className="mx-auto flex w-full max-w-4xl flex-col gap-4 p-4">
<div className="mt-6 flex items-end justify-center gap-4">
<Skeleton className="h-36 w-36 rounded-xl" />
<Skeleton className="h-48 w-36 rounded-xl" />
<Skeleton className="h-32 w-36 rounded-xl" />
@@ -73,8 +73,8 @@ async function Content() {
);
return (
<div className="min-h-svh flex flex-col justify-center">
<div className="max-w-4xl mx-auto flex flex-col gap-4 p-4">
<div className="flex min-h-svh flex-col justify-center">
<div className="mx-auto flex max-w-4xl flex-col gap-4 p-4">
<Podium data={podium} />
<TopDonateTable data={list} />
</div>
+3 -3
View File
@@ -36,7 +36,7 @@ export function Podium({ data }: { data: TopDonateRow[] }) {
const order = [data[1], data[0], data[2]].filter(Boolean);
return (
<div className="flex justify-center items-end gap-4 mt-6">
<div className="mt-6 flex items-end justify-center gap-4">
{order.map((donor, index) => {
const rank = index === 0 ? 1 : index === 1 ? 0 : 2;
const s = styles[rank];
@@ -52,14 +52,14 @@ export function Podium({ data }: { data: TopDonateRow[] }) {
)}
</div>
<Card
className={`${s.border} ${s.bg} ${s.height} w-36 flex flex-col items-center justify-end pb-0 backdrop-blur-md`}
className={`${s.border} ${s.bg} ${s.height} flex w-36 flex-col items-center justify-end pb-0 backdrop-blur-md`}
>
<CardContent className="flex flex-col items-center gap-2 p-4">
<Avatar className="size-10">
<AvatarImage src={donor.image} />
<AvatarFallback>{initial}</AvatarFallback>
</Avatar>
<span className="font-semibold text-sm truncate w-full text-center">
<span className="w-full truncate text-center text-sm font-semibold">
{donor.name}
</span>
<span className={`text-lg font-bold ${s.text}`}>
+1 -1
View File
@@ -37,7 +37,7 @@ export function TopDonateTable({ data }: { data: TopDonateRow[] }) {
columns={columns}
data={data}
emptyDescription="No donations yet."
className="w-full h-full max-h-[calc(100svh-264px)] overflow-y-auto backdrop-blur-md"
className="h-full max-h-[calc(100svh-264px)] w-full overflow-y-auto backdrop-blur-md"
/>
);
}
+8 -8
View File
@@ -38,19 +38,19 @@ export function GuideList({
);
return (
<div className="flex justify-center h-svh">
<div className="w-full xl:max-w-2/3 border flex flex-col">
<div className="flex h-svh justify-center">
<div className="flex w-full flex-col border xl:max-w-2/3">
<div>
<Link
href="/"
className="border-b p-3 font-semibold leading-none flex items-center gap-2"
className="flex items-center gap-2 border-b p-3 leading-none font-semibold"
>
<Compass className="opacity-50" />
ไกด์ตัวละคร
</Link>
</div>
<div className="p-4 pb-2">
<InputGroup className="w-full h-10">
<InputGroup className="h-10 w-full">
<InputGroupInput
placeholder="ค้นหา..."
onChange={(ev) => setSearch(ev.target.value)}
@@ -62,23 +62,23 @@ export function GuideList({
</div>
<div
className={cn(
"grid gap-4 p-4 grid-cols-[repeat(auto-fill,minmax(min(300px,calc(100svw-2rem-2px)),1fr))] overflow-auto transition-opacity",
"grid grid-cols-[repeat(auto-fill,minmax(min(300px,calc(100svw-2rem-2px)),1fr))] gap-4 overflow-auto p-4 transition-opacity",
loading === 1 && "opacity-50",
)}
>
{list.length === 0 && loading === 0 ? (
<div className="col-span-full flex flex-col items-center justify-center py-20 text-muted-foreground">
<SearchX className="w-16 h-16 mb-4 opacity-50" />
<SearchX className="mb-4 h-16 w-16 opacity-50" />
<p className="text-2xl font-semibold">ไม่พบตัวละครที่ค้นหา</p>
<p className="text-lg ">ลองคำอื่นที่ความหมายใกล้เคียงกันดูนะ</p>
</div>
) : (
list.map((card) => (
<Link href={card.link} key={card.id} target="_blank">
<Card className="bg-card/50 hover:bg-border backdrop-blur-sm transition-colors py-3 sm:py-6 rounded-sm sm:rounded-xl">
<Card className="rounded-sm bg-card/50 py-3 backdrop-blur-sm transition-colors hover:bg-border sm:rounded-xl sm:py-6">
<CardHeader className="px-3 sm:px-6">
<CardTitle>{card.name}</CardTitle>
<div className="relative w-full aspect-square mt-2 rounded-sm sm:rounded-lg border overflow-hidden">
<div className="relative mt-2 aspect-square w-full overflow-hidden rounded-sm border sm:rounded-lg">
{card.image && (
<Image
src={`/cdn/${card.image}`}
+1 -1
View File
@@ -16,7 +16,7 @@ export default async function UiLayout({
<Image
src={Background}
alt="Background"
className="z-[-1] opacity-40 object-cover fixed top-0 left-0 w-full h-fit min-h-dvh"
className="fixed top-0 left-0 z-[-1] h-fit min-h-dvh w-full object-cover opacity-40"
/>
<StarsRenderer />
<Providers>
+2 -2
View File
@@ -83,7 +83,7 @@ export default function LoginPage({
setLoading(false);
}
return (
<div className="bg-[#1117] backdrop-blur-lg flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
<div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-[#1117] p-6 backdrop-blur-lg md:p-10">
<div className="w-full max-w-sm">
<div className="flex flex-col gap-6">
<form onSubmit={submit} method="POST">
@@ -147,7 +147,7 @@ export default function LoginPage({
</div>
</div>
</form>
<div className="text-muted-foreground *:[a]:hover:text-primary text-center text-xs text-balance *:[a]:underline *:[a]:underline-offset-4">
<div className="text-center text-xs text-balance text-muted-foreground *:[a]:underline *:[a]:underline-offset-4 *:[a]:hover:text-primary">
Any attempts to bruteforce the system
<br />
will result in consequences.
+7 -7
View File
@@ -27,8 +27,8 @@ export function Navbar() {
return (
<div
className={cn(
"flex gap-2 p-2 rounded-lg absolute border bg-card",
mobile && pathname === "/guide" ? "right-2 top-2" : "left-3 top-3",
"absolute flex gap-2 rounded-lg border bg-card p-2",
mobile && pathname === "/guide" ? "top-2 right-2" : "top-3 left-3",
)}
>
<Item icon={<Home size={16} />} name="หน้าหลัก" href="/" divide />
@@ -65,20 +65,20 @@ function Item({
return (
<Link
className={cn(
"group transition-[width] flex gap-1",
divide && "border-r-2 -mr-1 pr-1",
"group flex gap-1 transition-[width]",
divide && "-mr-1 border-r-2 pr-1",
)}
href={href}
>
{icon}{" "}
<span
className={cn(
"overflow-hidden whitespace-nowrap text-xs",
"overflow-hidden text-xs whitespace-nowrap",
"max-w-0 opacity-0",
"group-hover:max-w-40 group-hover:opacity-100",
"transition-all duration-300 ease-out delay-200",
"transition-all delay-200 duration-300 ease-out",
"-mr-1",
divide || last || "border-r-2 -mr-3 pr-1",
divide || last || "-mr-3 border-r-2 pr-1",
divide && "group-hover:mr-0",
)}
>
+12 -12
View File
@@ -14,14 +14,14 @@ import { cn } from "@/lib/utils";
export default function Home() {
return (
<div className="flex w-full justify-center">
<div className="max-w-6xl w-full mx-auto flex flex-col min-h-dvh">
<div className="mx-auto flex min-h-dvh w-full max-w-6xl flex-col">
<section>
<center>
<Link href="https://www.youtube.com/@Genshinmaichaigamemurtur">
<Image
src={Banner}
alt="Banner"
className="rounded-t-xl mt-24 w-3/4 sm:w-125"
className="mt-24 w-3/4 rounded-t-xl sm:w-125"
width={500}
height={100}
fetchPriority="high"
@@ -30,7 +30,7 @@ export default function Home() {
</center>
</section>
<div className="flex flex-wrap justify-evenly my-10 gap-5">
<div className="my-10 flex flex-wrap justify-evenly gap-5">
<HomeLink
name="เสือกไอดีชาวบ้าน"
desc="ระบบลงคิวดูอาร์ติแฟกต์เกนชินในไลฟ์สตรีม"
@@ -67,14 +67,14 @@ export default function Home() {
logo={DonateLogo}
/>
</div>
<footer className="text-muted-foreground h-full flex flex-col justify-end pb-3 md:justify-center">
<div className="flex justify-between flex-col text-center gap-2 sm:flex-row sm:text-left">
<span className="text-sm my-auto">
<footer className="flex h-full flex-col justify-end pb-3 text-muted-foreground md:justify-center">
<div className="flex flex-col justify-between gap-2 text-center sm:flex-row sm:text-left">
<span className="my-auto text-sm">
buzz.sudloh.com is not affiliated with HoYoverse. Game content
<br />
and materials are trademarks and copyrights of HoYoverse.
</span>
<div className="flex gap-2 justify-center sm:justify-start">
<div className="flex justify-center gap-2 sm:justify-start">
<Link
href="https://git.dgnr.us/astral/buzz"
className="my-auto"
@@ -91,7 +91,7 @@ export default function Home() {
viewBox="5.67 143.05 628.65 387.55"
width={24}
height={24}
className="fill-current hover:fill-white w-6 h-5 mx-auto"
className="mx-auto h-5 w-6 fill-current hover:fill-white"
>
<title>Gitea</title>
<g>
@@ -119,7 +119,7 @@ export default function Home() {
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
className="fill-current hover:fill-white w-5 mx-auto"
className="mx-auto w-5 fill-current hover:fill-white"
>
<title>Discord</title>
<path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z" />
@@ -154,7 +154,7 @@ function HomeLink({
<Link
href={href}
className={cn(
"flex flex-col p-8 md:p-10 text-center",
"flex flex-col p-8 text-center md:p-10",
disabled && "pointer-events-none brightness-50",
className,
)}
@@ -162,11 +162,11 @@ function HomeLink({
<Image
src={logo}
alt={name}
className="w-48 h-24 sm:w-50 sm:h-40 object-contain hover:scale-110 transition-transform duration-100"
className="h-24 w-48 object-contain transition-transform duration-100 hover:scale-110 sm:h-40 sm:w-50"
width={200}
height={200}
/>
<span className="md:hidden block visible text-lg md:text-xs">
<span className="visible block text-lg md:hidden md:text-xs">
{name}
</span>
</Link>
@@ -20,8 +20,8 @@ export function DataViewer({
);
return (
<div className="relative max-h-[60svh] overflow-auto rounded-xl border bg-black/40 p-4 text-xs font-mono leading-relaxed">
<div className="sticky -top-2 -mr-2 flex justify-end -mt-10">
<div className="relative max-h-[60svh] overflow-auto rounded-xl border bg-black/40 p-4 font-mono text-xs leading-relaxed">
<div className="sticky -top-2 -mt-10 -mr-2 flex justify-end">
<Button
variant="ghost"
size="icon"
@@ -32,7 +32,7 @@ export function DataViewer({
<CopyButton text={yaml} />
</div>
<pre className="whitespace-pre-wrap wrap-break-word">{yaml}</pre>
<pre className="wrap-break-word whitespace-pre-wrap">{yaml}</pre>
</div>
);
}
@@ -64,8 +64,8 @@ export default async function ({
);
return (
<div className="flex flex-col sm:flex-row h-full p-2">
<div className="flex flex-1 justify-center items-center p-5">
<div className="flex h-full flex-col p-2 sm:flex-row">
<div className="flex flex-1 items-center justify-center p-5">
<div className="relative rounded border border-dashed border-white">
<Image
src={`/api/slip/${entry.slip?.id}`}
@@ -74,10 +74,10 @@ export default async function ({
width={1000}
height={1000}
/>
<div className="absolute top-0 left-0 bottom-0 right-0 backdrop-blur-lg hover:opacity-0 transition-opacity" />
<div className="absolute top-0 right-0 bottom-0 left-0 backdrop-blur-lg transition-opacity hover:opacity-0" />
</div>
</div>
<div className="flex justify-center items-center flex-1">
<div className="flex flex-1 items-center justify-center">
<Card>
<CardHeader>
<CardTitle>จ่าย {entry.price} บาท</CardTitle>
@@ -48,7 +48,7 @@ export default async function ({
</Suspense>
<SidebarInset className="bg-transparent">
{children}
<div className="absolute block md:hidden opacity-50 hover:opacity-100 bottom-1 left-1">
<div className="absolute bottom-1 left-1 block opacity-50 hover:opacity-100 md:hidden">
<SidebarTrigger />
</div>
<Watcher />
@@ -94,7 +94,7 @@ async function ThisSidebar({ round }: { round: number }) {
<span>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<div className="bg-sidebar-primary text-sidebar-foreground flex aspect-square size-8 items-center justify-center rounded-lg">
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-foreground">
<ReceiptText className="size-4" />
</div>
</DropdownMenuTrigger>
@@ -122,14 +122,14 @@ async function ThisSidebar({ round }: { round: number }) {
<span className="font-medium">ประวัติสลิปรายได้</span>
<span>รอบที่ {round}</span>
</div>
<div className="flex ml-auto h-full justify-evenly items-center">
<div className="ml-auto flex h-full items-center justify-evenly">
{round <= min ? (
<ChevronLeft className="size-4 text-muted-foreground" />
) : (
<SimpleTooltip text="รอบก่อนหน้า" side="right">
<Link
href={`/rubgram/admin/slip/${round - 1}`}
className="h-full flex items-center"
className="flex h-full items-center"
>
<ChevronLeft className="size-4" />
</Link>
@@ -141,7 +141,7 @@ async function ThisSidebar({ round }: { round: number }) {
<SimpleTooltip text="รอบถัดไป" side="right">
<Link
href={`/rubgram/admin/slip/${round + 1}`}
className="h-full flex items-center"
className="flex h-full items-center"
>
<ChevronRight className="size-4" />
</Link>
@@ -39,7 +39,7 @@ export function CurrencyInput(props: ComponentProps<typeof Input>) {
export function PriceInput() {
const { values, setValue } = useFormContext();
return (
<div className="flex flex-col gap-2 grow">
<div className="flex grow flex-col gap-2">
<Label htmlFor="rg-price">Price</Label>
<InputGroup>
<InputGroupInput
@@ -135,7 +135,7 @@ export function SlipUpload({
{isSelected ? (
<SimpleTooltip text="Unselect">
<X
className="hover:text-red-500 pointer-events-auto!"
className="pointer-events-auto! hover:text-red-500"
onClick={() => {
setValue(null);
onValueChange?.(null);
@@ -183,7 +183,7 @@ export function UserSelect({
}, [bump]);
return (
<div className="flex gap-1 w-full">
<div className="flex w-full gap-1">
<VirtualizedComboBox
onValueSelect={onValueChange}
defaultValue={value}
+2 -2
View File
@@ -13,7 +13,7 @@ import { Spinner } from "@/components/ui/spinner";
import { debugUploadSlip, discordCall } from "../../api";
export function Evernight() {
return <div className="h-full w-full relative"></div>;
return <div className="relative h-full w-full"></div>;
}
export function CopyButton({ text }: { text: string }) {
@@ -73,7 +73,7 @@ export function DebugSlipUpload({ sid }: { sid: string }) {
return (
<>
<button
className="flex flex-col justify-center items-center border rounded-md w-40 bg-card cursor-pointer"
className="flex w-40 cursor-pointer flex-col items-center justify-center rounded-md border bg-card"
onClick={() => ref.current?.click()}
type="button"
>
+9 -9
View File
@@ -48,10 +48,10 @@ export default async function AdminSubmissionView({
const typesMap = Object.fromEntries(types.map((v) => [v.id, v.display]));
return (
<div className="p-2 h-full">
<div className="flex flex-col h-full w-full gap-2">
<div className="h-full p-2">
<div className="flex h-full w-full flex-col gap-2">
<div className="flex w-full justify-between gap-2">
<Card className="w-full pb-1 rounded-md">
<Card className="w-full rounded-md pb-1">
<CardHeader>
<CardTitle>
{sub.queue}. {sub.name}
@@ -80,23 +80,23 @@ export default async function AdminSubmissionView({
{sub.slip ? (
<Dialog>
<DialogTrigger asChild>
<div className="border rounded-md w-40 relative overflow-hidden hover:opacity-100 opacity-80 transition-opacity cursor-pointer">
<div className="relative w-40 cursor-pointer overflow-hidden rounded-md border opacity-80 transition-opacity hover:opacity-100">
<Image
src={`/api/slip/${sub.slip}`}
alt="Slip"
fill
className="blur-md brightness-50"
/>
<div className="flex flex-col justify-center items-center absolute top-0 left-0 right-0 bottom-0">
<div className="absolute top-0 right-0 bottom-0 left-0 flex flex-col items-center justify-center">
<ExternalLink />
เปิดสลิป
</div>
</div>
</DialogTrigger>
<DialogContent className="h-full max-w-dvw! flex flex-col bg-[#2225] backdrop-blur-xs">
<DialogContent className="flex h-full max-w-dvw! flex-col bg-[#2225] backdrop-blur-xs">
<DialogTitle className="h-min">สลิป</DialogTitle>
<DialogClose asChild>
<div className="h-full w-full flex grow justify-center relative">
<div className="relative flex h-full w-full grow justify-center">
<Image
src={`/api/slip/${sub.slip}`}
alt="Slip"
@@ -120,7 +120,7 @@ export default async function AdminSubmissionView({
</DialogContent>
</Dialog>
) : sub.price <= 0 ? (
<div className="flex flex-col justify-center items-center border rounded-md w-40 bg-card">
<div className="flex w-40 flex-col items-center justify-center rounded-md border bg-card">
<BadgeDollarSign />
ฟรี
</div>
@@ -128,7 +128,7 @@ export default async function AdminSubmissionView({
<DebugSlipUpload sid={sub.id} />
)}
</div>
<div className="border rounded-md h-full overflow-hidden">
<div className="h-full overflow-hidden rounded-md border">
<Evernight />
</div>
</div>
+2 -2
View File
@@ -68,7 +68,7 @@ export default async function AdminLayout({
<SidebarProvider>
<Sidebar>
<SidebarHeader>
<div className="flex justify-between items-center">
<div className="flex items-center justify-between">
<b>Admin</b>
<div className="flex gap-1">
<Button variant="ghost" size="icon" className="size-8" asChild>
@@ -132,7 +132,7 @@ export default async function AdminLayout({
<SidebarInset className="bg-transparent">
<ErrorBoundary errorComponent={ErrorModal}>{modal}</ErrorBoundary>
{children}
<div className="absolute block md:hidden opacity-50 hover:opacity-100 bottom-1 left-1">
<div className="absolute bottom-1 left-1 block opacity-50 hover:opacity-100 md:hidden">
<SidebarTrigger />
</div>
<Watcher />
+4 -4
View File
@@ -48,10 +48,10 @@ export function WelcomeScreening({
</Button>
</RulesDialog>
<span className="text-gray-600 text-xs">
<span className="text-xs text-gray-600">
กำลังล็อกอินในฐานะ <b className="text-gray-300">{session.display}</b>{" "}
<button
className="text-gray-400 hover:text-gray-300 underline cursor-pointer"
className="cursor-pointer text-gray-400 underline hover:text-gray-300"
onClick={loginDiscord}
type="button"
>
@@ -68,7 +68,7 @@ export function WelcomeScreening({
loginDiscord();
}}
>
<span className="flex justify-between w-full items-center">
<span className="flex w-full items-center justify-between">
ล็อคอินผ่าน Discord
<LogIn />
</span>
@@ -119,7 +119,7 @@ export function ServiceSelector({
</MultiSelectGroup>
</MultiSelectContent>
</MultiSelect>
<span className="text-xs text-muted-foreground -mt-1">
<span className="-mt-1 text-xs text-muted-foreground">
เลือกทั้ง {types.length} อย่าง ลดให้ {allDiscount} บาท
</span>
<select
+18 -18
View File
@@ -122,18 +122,18 @@ export default async function EndgamePage() {
: [];
return (
<div className="flex flex-col justify-center gap-2 items-center h-svh">
<div className="flex h-svh flex-col items-center justify-center gap-2">
<Card className="w-full max-w-md">
{q ? (
!q.paid ? (
""
) : (
<Blocker>
<div className="flex gap-1 flex-col items-center">
<span className="font-bold text-3xl">คิวของคุณคือหมายเลข</span>
<span className="font-bold text-5xl">{q.queue}</span>
<div className="flex flex-col items-center gap-1">
<span className="text-3xl font-bold">คิวของคุณคือหมายเลข</span>
<span className="text-5xl font-bold">{q.queue}</span>
{canExpire && (
<span className="text-muted-foreground flex gap-1 items-center">
<span className="flex items-center gap-1 text-muted-foreground">
<SimpleTooltip text="มีบางคิวก่อนหน้าของคุณยังไม่ได้ชำระเงิน">
<AlertCircle size={16} />
</SimpleTooltip>
@@ -145,12 +145,12 @@ export default async function EndgamePage() {
)
) : config.locked ? (
<Blocker>
<span className="font-bold text-3xl">ยังไม่เปิดรับคิว</span>
<span className="text-3xl font-bold">ยังไม่เปิดรับคิว</span>
</Blocker>
) : config.full ? (
<Blocker>
<div className="flex gap-1 flex-col items-center">
<span className="font-bold text-3xl">คิวเต็มแล้ว</span>
<div className="flex flex-col items-center gap-1">
<span className="text-3xl font-bold">คิวเต็มแล้ว</span>
</div>
</Blocker>
) : (
@@ -177,15 +177,15 @@ export default async function EndgamePage() {
<CardContent>
{q ? (
<EndgameFormWrapper id="mainform" type="payment">
<div className="flex flex-col gap-2 items-center">
<div className="flex gap-2 w-full">
<div className="flex flex-col items-center gap-2">
<div className="flex w-full gap-2">
<Image
src={PromptpayImage}
alt="Promptpay QR Code"
className="rounded max-w-32 shrink-0"
className="max-w-32 shrink-0 rounded"
/>
<div className="flex flex-col shrink-0 relative">
<span className="font-bold text-lg">
<div className="relative flex shrink-0 flex-col">
<span className="text-lg font-bold">
ยอดชำระ {q.price} บาท{" "}
{q.expires && (
<Kbd suppressHydrationWarning>
@@ -249,7 +249,7 @@ export default async function EndgamePage() {
</EndgameFormWrapper>
)}
</CardContent>
<CardFooter className="flex gap-2 justify-between">
<CardFooter className="flex justify-between gap-2">
<div className="flex gap-2">
<SimpleTooltip text="ลัดคิว 50 บาท (ไม่รวมยอดที่ต้องจ่าย)">
<Link
@@ -261,7 +261,7 @@ export default async function EndgamePage() {
variant="outline"
className={
config.limit >= 0 && count >= config.limit
? "bg-emerald-600! border-white! animate-pulse"
? "animate-pulse border-white! bg-emerald-600!"
: ""
}
type="button"
@@ -307,7 +307,7 @@ export default async function EndgamePage() {
<LiveButton />
</Suspense>
</div>
<div className="flex gap-2 items-center">
<div className="flex items-center gap-2">
{!q && <PriceEstimation />}
<Kbd>
{count} / {config.limit < 0 ? "∞" : config.limit} คิว
@@ -328,11 +328,11 @@ export default async function EndgamePage() {
</div>
</CardFooter>
</Card>
<span className="p-1 text-xs m-1 border rounded-sm">
<span className="m-1 rounded-sm border p-1 text-xs">
หากติดปัญหา โปรดแจ้งผ่านทาง
<a
href="https://discord.gg/HQwDXNhxuK"
className="underline text-green-200"
className="text-green-200 underline"
>
ช่องดิสคอร์ด
</a>
+1 -1
View File
@@ -34,7 +34,7 @@ export function TierListCell({
<SortableContext id={cellId} items={items} strategy={rectSortingStrategy}>
<div
ref={setNodeRef}
className="flex flex-wrap p-1 gap-2 items-start content-start"
className="flex flex-wrap content-start items-start gap-2 p-1"
style={{
minHeight: `${tileSize + 8}px`,
}}
+9 -9
View File
@@ -86,7 +86,7 @@ export function Draggable({
>
<div className="relative">
<SimpleTooltip text="คลิกขวาเพื่อลบ">
<div className="absolute justify-center items-center top-0 left-0 bottom-0 right-0 rounded bg-[#0005] flex opacity-0 hover:opacity-100 transition-opacity text-red-500">
<div className="absolute top-0 right-0 bottom-0 left-0 flex items-center justify-center rounded bg-[#0005] text-red-500 opacity-0 transition-opacity hover:opacity-100">
<Trash />
</div>
</SimpleTooltip>
@@ -157,7 +157,7 @@ export function Draggable({
<div
key={p}
style={{ width: badgeSize, height: badgeSize }}
className={`bg-[#2228] ${p} absolute rounded border flex items-center justify-center`}
className={`bg-[#2228] ${p} absolute flex items-center justify-center rounded border`}
>
<MessageSquareText
style={{
@@ -194,12 +194,12 @@ export function Draggable({
</PopoverTrigger>
<PopoverContent
side="right"
className="bg-[#2225] backdrop-blur-md p-1"
className="bg-[#2225] p-1 backdrop-blur-md"
>
<div className="flex gap-2">
{editable && (
<div className="flex flex-col justify-between shrink-0 gap-2">
<div className="grid grid-cols-2 gap-1 h-min items-stretch">
<div className="flex shrink-0 flex-col justify-between gap-2">
<div className="grid h-min grid-cols-2 items-stretch gap-1">
{badges
.filter(
(b) =>
@@ -217,7 +217,7 @@ export function Draggable({
width={32}
height={32}
className={cn(
"border rounded hover:brightness-110 hover:backdrop-brightness-300 cursor-pointer",
"cursor-pointer rounded border hover:brightness-110 hover:backdrop-brightness-300",
assignedBadges.includes(e.id) &&
"backdrop-brightness-500",
)}
@@ -227,7 +227,7 @@ export function Draggable({
<button
key={`B${e.id}`}
className={cn(
"border rounded hover:brightness-110 hover:backdrop-brightness-300 flex justify-center items-center font-bold cursor-pointer min-w-8 min-h-8",
"flex min-h-8 min-w-8 cursor-pointer items-center justify-center rounded border font-bold hover:brightness-110 hover:backdrop-brightness-300",
assignedBadges.includes(e.id) &&
"backdrop-brightness-500",
)}
@@ -244,7 +244,7 @@ export function Draggable({
target="_blank"
rel="noreferrer noopener"
>
<Button variant="outline" className="p-1 w-full">
<Button variant="outline" className="w-full p-1">
<Image
src={AmberIcon}
alt="Amber"
@@ -261,7 +261,7 @@ export function Draggable({
)}
<Textarea
placeholder="Comment..."
className="aspect-square bg-card resize-none disabled:opacity-90"
className="aspect-square resize-none bg-card disabled:opacity-90"
value={comment}
onChange={(ev) => {
setDirty(500);
+1 -1
View File
@@ -14,7 +14,7 @@ export function TlStatusOverlay({
}) {
return (
<div
className="absolute top-0 right-0 m-1 rounded bg-[#2225] backdrop-blur-sm border px-1 py-0.5 text-sm transition-colors z-30 pointer-events-none flex gap-1 items-center"
className="pointer-events-none absolute top-0 right-0 z-30 m-1 flex items-center gap-1 rounded border bg-[#2225] px-1 py-0.5 text-sm backdrop-blur-sm transition-colors"
style={{
color:
ev.upload || ev.download
+25 -25
View File
@@ -99,7 +99,7 @@ function Untiered({
<div ref={ref}>
<div
ref={setNodeRef}
className={`flex flex-wrap ${open ? "p-1" : ""} gap-2 bg-[#0005] overflow-auto`}
className={`flex flex-wrap ${open ? "p-1" : ""} gap-2 overflow-auto bg-[#0005]`}
style={{
maxHeight: `${(tileSize + 4) * 3 + 4}px`,
}}
@@ -403,7 +403,7 @@ export function TierList({
onDragStart={(e) => setDragging(e.active.id as string)}
onDragEnd={handleDragEnd}
>
<div className="flex flex-col justify-between h-full">
<div className="flex h-full flex-col justify-between">
{/*}<Blocker inner className="not-portrait:hidden md:hidden">
<div className="flex flex-col items-center font-bold text-2xl gap-16">
<Smartphone size={128} className="animate-phonerotate" />
@@ -417,7 +417,7 @@ export function TierList({
alt="Disclaimer"
fill
priority
className="object-contain bg-[#000A]"
className="bg-[#000A] object-contain"
/>
<Button
variant="outline"
@@ -432,7 +432,7 @@ export function TierList({
) : (
""
)}
<div className="flex-1 min-h-0 overflow-auto">
<div className="min-h-0 flex-1 overflow-auto">
<div
className={`grid w-full *:border`}
style={{
@@ -442,7 +442,7 @@ export function TierList({
>
<div
className={cn(
"text-center font-semibold py-1 relative transition-colors duration-200",
"relative py-1 text-center font-semibold transition-colors duration-200",
deleteMode ? "bg-red-500/30" : "bg-[#0005]",
)}
style={{ gridColumn: "1 / -1" }}
@@ -454,21 +454,21 @@ export function TierList({
</span>
<span className="text-green-400">{version.deprecates}</span>
{deleteMode && (
<span className="text-red-500 font-semibold ml-2">
<span className="ml-2 font-semibold text-red-500">
<TriangleAlert className="inline" /> (คุณอยู่ในโหมดลบตัวละคร)
</span>
)}
<span className="font-normal absolute right-0">
<span className="absolute right-0 font-normal">
{user && !editable && (
<SimpleTooltip text="ไปหน้าแก้ไข (Admin)">
<Link href={`/tl/${type.id}/${version.id}/admin`}>
<Pencil className="text-gray-400 size-4" />
<Pencil className="size-4 text-gray-400" />
</Link>
</SimpleTooltip>
)}
</span>
</div>
<div className="grid place-items-center bg-[#2225] cursor-pointer">
<div className="grid cursor-pointer place-items-center bg-[#2225]">
<Dialog>
<DropdownMenu>
<DropdownMenuTrigger asChild>
@@ -509,10 +509,10 @@ export function TierList({
</DialogHeader>
<div className="flex justify-between">
<div className="flex flex-col gap-2">
<div className="grid gap-2 group">
<div className="group grid gap-2">
<span className="flex gap-1">
ขนาดตัวละคร{" "}
<span className="flex gap-1 text-muted-foreground md:opacity-0 group-hover:opacity-100 transition-opacity">
<span className="flex gap-1 text-muted-foreground transition-opacity group-hover:opacity-100 md:opacity-0">
(px){" "}
{tileSizeSetting ? (
""
@@ -556,10 +556,10 @@ export function TierList({
</Button>
</div>
</div>
<div className="grid gap-2 group">
<div className="group grid gap-2">
<span>
ขนาดเครื่องหมาย{" "}
<span className="text-muted-foreground md:opacity-0 group-hover:opacity-100 transition-opacity">
<span className="text-muted-foreground transition-opacity group-hover:opacity-100 md:opacity-0">
(px)
</span>
</span>
@@ -599,18 +599,18 @@ export function TierList({
"rgba(200,124,36) linear-gradient(136deg,rgba(49,43,71,.5294117647058824),transparent)",
width: tileSize,
}}
className="rounded aspect-square relative"
className="relative aspect-square rounded"
>
<Image src={Qiqi} alt="Qiqi" fill />
<Image
className="bg-[#2225] backdrop-blur-sm bottom-0.5 left-0.5 absolute rounded border"
className="absolute bottom-0.5 left-0.5 rounded border bg-[#2225] backdrop-blur-sm"
src={BadgeSSS}
alt="Test Badge"
width={badgeSize}
height={badgeSize}
/>
<Image
className="bg-[#2225] backdrop-blur-sm bottom-0.5 right-0.5 absolute border rounded"
className="absolute right-0.5 bottom-0.5 rounded border bg-[#2225] backdrop-blur-sm"
src={BadgeSP}
alt="Test Badge"
width={badgeSize}
@@ -626,7 +626,7 @@ export function TierList({
{columns.map((c) => (
<div
key={`C${c.id}`}
className="bg-[#0005] text-2xl font-bold flex items-center justify-center relative"
className="relative flex items-center justify-center bg-[#0005] text-2xl font-bold"
ref={colRef}
>
{c.image ? (
@@ -635,7 +635,7 @@ export function TierList({
alt={c.name}
width={200}
height={100}
className="p-2 object-contain w-full h-auto max-h-13"
className="h-auto max-h-13 w-full object-contain p-2"
/>
) : (
c.name
@@ -644,14 +644,14 @@ export function TierList({
))}
{tiers.map((t) => (
<Fragment key={`T${t.id}`}>
<div className="bg-[#0005] text-4xl font-bold flex items-center justify-center">
<div className="flex items-center justify-center bg-[#0005] text-4xl font-bold">
{t.image ? (
<Image
src={`/cdn/${t.image}`}
alt={t.name}
height={100}
width={100}
className="object-contain max-w-12"
className="max-w-12 object-contain"
sizes="4"
/>
) : (
@@ -696,10 +696,10 @@ export function TierList({
<Button
onClick={() => setUntieredOpen(!untieredOpen)}
variant="outline"
className="rounded-none flex"
className="flex rounded-none"
>
{editable && untieredOpen && <div className="w-9 h-4" />}
<span className="w-full flex gap-1 items-center justify-center">
{editable && untieredOpen && <div className="h-4 w-9" />}
<span className="flex w-full items-center justify-center gap-1">
({placements.untiered.length}) ตัวละครที่ไม่ได้อยู่ในเทียร์
{untieredOpen ? (
<ChevronDown className="ml-1" />
@@ -709,7 +709,7 @@ export function TierList({
</span>
{editable && untieredOpen && (
<div
className="flex gap-2 items-center justify-center"
className="flex items-center justify-center gap-2"
onClick={(ev) => ev.stopPropagation()}
>
<SimpleTooltip text="เพิ่มตัวละคร">
@@ -723,7 +723,7 @@ export function TierList({
.sort((a, b) => a.label.localeCompare(b.label))}
className="w-full bg-transparent! hover:bg-accent!"
trigger={
<CopyPlus className="text-emerald-400 pointer-events-auto!" />
<CopyPlus className="pointer-events-auto! text-emerald-400" />
}
onValueSelect={(v) => {
setPlacements((x) => ({
+10 -10
View File
@@ -46,40 +46,40 @@ export default async function TierlistSelectionPage({
.where(eq(tierlistTypes.id, typeId));
return (
<div className="max-w-7xl min-h-full flex flex-col gap-6 mx-auto py-8 px-4">
<div className="mx-auto flex min-h-full max-w-7xl flex-col gap-6 px-4 py-8">
{vers.map((t) => (
<div className="flex flex-col gap-1" key={t.id}>
<Link
href="/tl"
className="flex hover:underline cursor-default text-muted-foreground"
className="flex cursor-default text-muted-foreground hover:underline"
>
<ArrowLeft /> กลับไปหน้าแรก
</Link>
<div className="font-bold text-4xl">
<div className="px-2 py-1 border w-fit rounded-md bg-[#2228]">
<div className="text-4xl font-bold">
<div className="w-fit rounded-md border bg-[#2228] px-2 py-1">
{t.name}
<span className="text-sm text-muted-foreground ml-2">
<span className="ml-2 text-sm text-muted-foreground">
{t.mode}
</span>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2">
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{t.versions.map((e) => (
<Link href={`/tl/${t.id}/${e.id}`} key={e.id}>
{e.image ? (
<div className="relative aspect-video w-full rounded-lg border overflow-hidden">
<div className="relative aspect-video w-full overflow-hidden rounded-lg border">
<Image
src={`/cdn/${e.image}`}
alt={e.name}
fill
className="rounded-sm border object-cover bg-primary"
className="rounded-sm border bg-primary object-cover"
/>
<div className="flex absolute w-full justify-center bottom-0 py-1 bg-black/50 rounded-b-sm">
<div className="absolute bottom-0 flex w-full justify-center rounded-b-sm bg-black/50 py-1">
{e.name}
</div>
</div>
) : (
<div className="flex items-center justify-center aspect-video border rounded-sm bg-[#1118] backdrop-blur-xl font-bold text-5xl">
<div className="flex aspect-video items-center justify-center rounded-sm border bg-[#1118] text-5xl font-bold backdrop-blur-xl">
{e.name}
</div>
)}
+9 -9
View File
@@ -44,7 +44,7 @@ export default async function TierlistSelectionPage() {
.orderBy(tierlistTypes.id);
return (
<div className="max-w-full min-h-full flex flex-col justify-center gap-2 mx-2">
<div className="mx-2 flex min-h-full max-w-full flex-col justify-center gap-2">
<center className="mb-2">
<Link href="/">
<Image
@@ -59,16 +59,16 @@ export default async function TierlistSelectionPage() {
</center>
{vers.map((t) => (
<div className="flex flex-col gap-1" key={t.id}>
<Link href={`/tl/${t.id}`} className="font-bold text-4xl w-fit">
<Link href={`/tl/${t.id}`} className="w-fit text-4xl font-bold">
<div className="flex items-center gap-2">
<div className="px-2 py-1 border rounded-md bg-[#2228]">
<div className="rounded-md border bg-[#2228] px-2 py-1">
{t.name}
<span className="text-sm text-muted-foreground ml-2">
<span className="ml-2 text-sm text-muted-foreground">
{t.mode}
</span>
</div>
<SimpleTooltip text="ดูเทียร์ลิสต์ของคอนเทนต์นี้ทั้งหมด">
<span className="absolute right-0 m-8 text-sm font-normal text-blue-400 ml-2 hover:underline ">
<span className="absolute right-0 m-8 ml-2 text-sm font-normal text-blue-400 hover:underline ">
ดูทั้งหมด
<ArrowRight className="inline-block size-4" />
</span>
@@ -76,7 +76,7 @@ export default async function TierlistSelectionPage() {
</div>
</Link>
<HorizontalDiv>
<div className="flex gap-2 max-w-full">
<div className="flex max-w-full gap-2">
{t.versions.map((e) => (
<Link href={`/tl/${t.id}/${e.id}`} key={e.id}>
{e.image ? (
@@ -85,14 +85,14 @@ export default async function TierlistSelectionPage() {
src={`/cdn/${e.image}`}
alt={e.name}
fill
className="rounded-sm border object-cover bg-primary"
className="rounded-sm border bg-primary object-cover"
/>
<div className="flex absolute w-full justify-center bottom-0 py-1 bg-black/50 rounded-b-sm">
<div className="absolute bottom-0 flex w-full justify-center rounded-b-sm bg-black/50 py-1">
{e.name}
</div>
</div>
) : (
<div className="flex items-center justify-center aspect-video w-60 border rounded-sm bg-[#1118] backdrop-blur-xl font-bold text-4xl">
<div className="flex aspect-video w-60 items-center justify-center rounded-sm border bg-[#1118] text-4xl font-bold backdrop-blur-xl">
{e.name}
</div>
)}
+1 -1
View File
@@ -94,7 +94,7 @@ export function VersionCheck({ headless = false }: { headless?: boolean }) {
}, [headless, setConnected, setUpdated, readyForUpdate, emit]);
return debug ? (
<div className="absolute bottom-0 right-0 m-2 px-1 rounded flex flex-col gap-2 bg-card border active:pointer-events-none opacity-20 hover:opacity-100 transition-opacity">
<div className="absolute right-0 bottom-0 m-2 flex flex-col gap-2 rounded border bg-card px-1 opacity-20 transition-opacity hover:opacity-100 active:pointer-events-none">
Buzz ({ver.current.split("-")[0] || "..."})
<pre>{stringify(debugData, null, 2)}</pre>
</div>
+10 -10
View File
@@ -59,18 +59,18 @@ export default function ErrorPage({
<Image
src={Background}
alt="Background"
className="z-[-1] opacity-20 object-cover fixed top-0 left-0 w-full h-full"
className="fixed top-0 left-0 z-[-1] h-full w-full object-cover opacity-20"
/>
<div className="h-full w-full bg-[#8225] backdrop-hue-rotate-60 backdrop-blur-md flex flex-col gap-2 justify-center items-center">
<div className="h-full flex flex-col gap-2 justify-center items-center">
<div className="p-4 pb-12 bg-white shadow-lg rounded-sm rotate-1 max-sm:landscape:hidden">
<div className="flex h-full w-full flex-col items-center justify-center gap-2 bg-[#8225] backdrop-blur-md backdrop-hue-rotate-60">
<div className="flex h-full flex-col items-center justify-center gap-2">
<div className="rotate-1 rounded-sm bg-white p-4 pb-12 shadow-lg max-sm:landscape:hidden">
<Image
src={Dottore}
alt="Dottore"
className="bg-gray-300 w-64 h-64 vintage-filter"
className="vintage-filter h-64 w-64 bg-gray-300"
/>
</div>
<h2 className="font-bold text-2xl">เกิดข้อผิดพลาดขึ้น</h2>
<h2 className="text-2xl font-bold">เกิดข้อผิดพลาดขึ้น</h2>
<span>{message || <Skeleton className="h-6 w-40" />}</span>
<div className="flex gap-2">
<Link href="/">
@@ -101,16 +101,16 @@ export default function ErrorPage({
</Button>
</div>
</div>
<div className="flex gap-1 items-center">
<div className="flex items-center gap-1">
<Link href="https://status.sudloh.com" className="m-2 mr-0">
<Button variant="link" className="text-secondary-foreground">
<Activity />
สถานะเว็บไซต์
</Button>
</Link>
<div className="h-6/10 w-px bg-border mr-2"></div>
<div className="mr-2 h-6/10 w-px bg-border"></div>
{health ? (
<div className="flex gap-1 [&>svg]:size-4 [&>svg]:shrink-0 items-center">
<div className="flex items-center gap-1 [&>svg]:size-4 [&>svg]:shrink-0">
<SimpleTooltip text="ฐานข้อมูล">
<Database
className={
@@ -135,7 +135,7 @@ export default function ErrorPage({
</SimpleTooltip>
</div>
) : (
<div className="flex gap-1 items-center">
<div className="flex items-center gap-1">
<Skeleton className="size-4 rounded-xs" />
<Skeleton className="size-4 rounded-xs" />
<Skeleton className="size-4 rounded-xs" />
+2 -2
View File
@@ -31,9 +31,9 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en" className="h-full dark">
<html lang="en" className="dark h-full">
<body
className={`${anuphan.variable} ${geistMono.variable} font-sans antialiased h-full`}
className={`${anuphan.variable} ${geistMono.variable} h-full font-sans antialiased`}
>
{children}
</body>
+5 -5
View File
@@ -31,19 +31,19 @@ export default function ErrorPage() {
<Image
src={Background}
alt="Background"
className="z-[-1] opacity-20 object-cover fixed top-0 left-0 w-full h-full"
className="fixed top-0 left-0 z-[-1] h-full w-full object-cover opacity-20"
/>
<div className="h-full w-full bg-[#2225] backdrop-grayscale backdrop-blur-md flex flex-col gap-2 justify-center items-center">
<div className="p-4 pb-12 bg-white shadow-lg rounded-sm max-sm:landscape:hidden">
<div className="flex h-full w-full flex-col items-center justify-center gap-2 bg-[#2225] backdrop-blur-md backdrop-grayscale">
<div className="rounded-sm bg-white p-4 pb-12 shadow-lg max-sm:landscape:hidden">
<Image
src={Dottore}
alt="Dottore"
className="bg-gray-300 w-64 h-64 vintage-filter"
className="vintage-filter h-64 w-64 bg-gray-300"
width={256}
height={256}
/>
</div>
<h2 className="font-bold text-2xl">404 ไม่พบหน้านี้</h2>
<h2 className="text-2xl font-bold">404 ไม่พบหน้านี้</h2>
<span>{message || <Skeleton className="h-6 w-40" />}</span>
<div className="flex gap-2">
<Link href="/">
+2 -1
View File
@@ -1,3 +1,4 @@
// oxlint-disable tailwindcss/no-unknown-classes
import { Kanit } from "next/font/google";
import { Watcher } from "@/app/(ui)/artifact/admin/client";
import { VersionCheck } from "@/app/client";
@@ -20,7 +21,7 @@ export default async function ArtifactCountWidget() {
return (
<div
className={`${kanit.variable} w-screen h-screen font-medium`}
className={`${kanit.variable} h-screen w-screen font-medium`}
style={{
fontFamily: "Kanit",
}}
+8 -8
View File
@@ -127,10 +127,10 @@ export default function () {
<>
<AnimatePresence>
{mounted && (
<div className="flex items-center justify-center h-full">
<div className="flex h-full items-center justify-center">
<div className="relative w-162.5 overflow-hidden">
<motion.div
className="absolute left-1/2 top-1/2 z-10 -translate-1/2"
className="absolute top-1/2 left-1/2 z-10 -translate-1/2"
initial={{ top: "200%", rotateZ: "600deg" }}
animate={{ top: "50%", rotateZ: "0deg" }}
exit={{ opacity: 0, transition: { delay: 0, duration: 1 } }}
@@ -152,16 +152,16 @@ export default function () {
</motion.div>
</motion.div>
<motion.div
className="rounded-4xl bg-black/80 p-5 flex gap-3 max-w-162.5 h-39 overflow-hidden mx-auto"
className="mx-auto flex h-39 max-w-162.5 gap-3 overflow-hidden rounded-4xl bg-black/80 p-5"
initial={{ width: 0, padding: 0 }}
animate={{ width: "100%", padding: "20px" }}
exit={{ opacity: 0, transition: { delay: 0, duration: 1 } }}
transition={{ delay: 1, duration: 1, ease: "circOut" }}
>
<div className="aspect-square size-32 shrink-0 rounded-2xl" />
<div className="flex flex-col font-semibold text-3xl min-w-0">
<div className="flex min-w-0 flex-col text-3xl font-semibold">
<motion.span
className="text-[#CB5959] whitespace-nowrap"
className="whitespace-nowrap text-[#CB5959]"
initial={{ paddingTop: "20px" }}
animate={{ paddingTop: 0 }}
transition={{ delay: 1, duration: 1, ease: "circOut" }}
@@ -171,10 +171,10 @@ export default function () {
</motion.span>
<motion.span
className={cn(
"whitespace-break-spaces wrap-break-word h-20 w-full",
"h-20 w-full wrap-break-word whitespace-break-spaces",
(message ?? "").length > 80
? "text-xl line-clamp-3"
: "text-3xl line-clamp-2",
? "line-clamp-3 text-xl"
: "line-clamp-2 text-3xl",
)}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
+1 -1
View File
@@ -38,7 +38,7 @@ export default function TopDonateWidget() {
return () => clearInterval(interval);
}, [textRef, top]);
return top ? (
<div className="grid grid-cols-[40px_minmax(0,1fr)_max-content] w-94.5 max-w-94.5 h-18.75 *:self-center gap-1 text-5xl font-semibold bg-black/75 rounded-full p-2 px-3 text-[#FFBA00] border-4 border-white">
<div className="grid h-18.75 w-94.5 max-w-94.5 grid-cols-[40px_minmax(0,1fr)_max-content] gap-1 rounded-full border-4 border-white bg-black/75 p-2 px-3 text-5xl font-semibold text-[#FFBA00] *:self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
+2 -1
View File
@@ -1,3 +1,4 @@
// oxlint-disable tailwindcss/no-unknown-classes
import { Kanit } from "next/font/google";
import { Watcher } from "@/app/(ui)/rubgram/admin/client";
import { VersionCheck } from "@/app/client";
@@ -20,7 +21,7 @@ export default async function ArtifactCountWidget() {
return (
<div
className={`${kanit.variable} w-screen h-screen font-medium`}
className={`${kanit.variable} h-screen w-screen font-medium`}
style={{
fontFamily: "Kanit",
}}