chore: oxc
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()}>
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}`}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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%]">
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}`}>
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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}
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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`,
|
||||
}}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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="/">
|
||||
|
||||
@@ -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",
|
||||
}}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user