feat(artifact): refresh button
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
CopyCheck,
|
||||
ImageIcon,
|
||||
OctagonAlert,
|
||||
RefreshCwIcon,
|
||||
ScanSearch,
|
||||
SquircleDashed,
|
||||
} from "lucide-react";
|
||||
@@ -13,7 +14,8 @@ import { useEffect, useState } from "react";
|
||||
import Enka from "#/enka_logo.png";
|
||||
import { SimpleTooltip } from "@/components/tooltip";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { getCardStatus } from "@/lib/api";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { getCardStatus, revalidateCard } from "@/lib/api";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
||||
@@ -21,6 +23,14 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [useWeb, setUseWeb] = useState(false);
|
||||
const [isCached, setIsCached] = useState(true);
|
||||
const [t, setT] = useState(0);
|
||||
|
||||
async function refresh() {
|
||||
setReady(false);
|
||||
setIsCached(false);
|
||||
if (!useWeb) await revalidateCard(sub);
|
||||
setT(Date.now());
|
||||
}
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: for update
|
||||
useEffect(() => {
|
||||
@@ -31,7 +41,7 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
||||
setIsCached(s.cached);
|
||||
if (!s.cached) setError(s.error);
|
||||
});
|
||||
}, [sub, uid]);
|
||||
}, [sub, uid, t]);
|
||||
return (
|
||||
<div className="h-full w-full relative">
|
||||
{!ready && !error && (isCached || useWeb) && (
|
||||
@@ -68,30 +78,44 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<SimpleTooltip text={useWeb ? "สลับเป็นรูปภาพ" : "สลับเป็น Enka"}>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn(
|
||||
"absolute left-1 z-45 bg-[#222a]! backdrop-blur-sm opacity-70 md:opacity-50 hover:opacity-100",
|
||||
useWeb ? "-bottom-19" : "bottom-1",
|
||||
)}
|
||||
size="icon"
|
||||
onClick={() => {
|
||||
setReady(false);
|
||||
setError(null);
|
||||
setUseWeb((x) => !x);
|
||||
}}
|
||||
>
|
||||
{useWeb ? (
|
||||
<ImageIcon />
|
||||
) : (
|
||||
<Image src={Enka} alt="Enka" className="size-5" />
|
||||
)}
|
||||
</Button>
|
||||
</SimpleTooltip>
|
||||
<div
|
||||
className={cn(
|
||||
"absolute left-1 z-45 opacity-70 md:opacity-50 hover:opacity-100 flex gap-1",
|
||||
useWeb ? "-bottom-19" : "bottom-1",
|
||||
)}
|
||||
>
|
||||
<SimpleTooltip text={useWeb ? "สลับเป็นรูปภาพ" : "สลับเป็น Enka"}>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="bg-[#222a]! backdrop-blur-sm"
|
||||
size="icon"
|
||||
onClick={() => {
|
||||
setReady(false);
|
||||
setError(null);
|
||||
setUseWeb((x) => !x);
|
||||
}}
|
||||
>
|
||||
{useWeb ? (
|
||||
<ImageIcon />
|
||||
) : (
|
||||
<Image src={Enka} alt="Enka" className="size-5" />
|
||||
)}
|
||||
</Button>
|
||||
</SimpleTooltip>
|
||||
<SimpleTooltip text="รีเฟรช">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={refresh}
|
||||
disabled={!error && !ready}
|
||||
>
|
||||
{!error && !ready ? <Spinner /> : <RefreshCwIcon />}
|
||||
</Button>
|
||||
</SimpleTooltip>
|
||||
</div>
|
||||
{useWeb ? (
|
||||
<iframe
|
||||
src={`https://enka.network/u/${uid}`}
|
||||
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",
|
||||
@@ -108,7 +132,7 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
||||
)}
|
||||
>
|
||||
<Image
|
||||
src={`/api/card/${sub}`}
|
||||
src={`/api/card/${sub}?t=${t}`}
|
||||
alt={`Enka card for ${sub}`}
|
||||
fill
|
||||
objectFit="contain"
|
||||
|
||||
@@ -229,6 +229,12 @@ export async function random() {
|
||||
else throw "ไม่พบผู้ลงทะเบียนที่ยังไม่ตรวจสอบ";
|
||||
}
|
||||
|
||||
export async function revalidateCard(sub: string) {
|
||||
if (!(await adminCheck())) throw "Unauthorized";
|
||||
await db.delete(cards).where(eq(cards.submission, sub));
|
||||
revalidatePath(`/api/card/${sub}`);
|
||||
}
|
||||
|
||||
export async function tlState(
|
||||
data: Partial<typeof tierlistStates.$inferInsert>,
|
||||
) {
|
||||
|
||||
@@ -27,6 +27,12 @@ const nextConfig: NextConfig = withBundleAnalyzer({
|
||||
hostname: "cards.enka.network",
|
||||
},
|
||||
],
|
||||
localPatterns: [
|
||||
{ pathname: "/api/card/*" },
|
||||
{
|
||||
pathname: "/cdn/*",
|
||||
},
|
||||
],
|
||||
minimumCacheTTL: 86400,
|
||||
},
|
||||
experimental: {
|
||||
|
||||
Reference in New Issue
Block a user