20% battery left

This commit is contained in:
Dreamgineer
2025-11-18 16:24:00 -05:00 Unverified
parent 27b8336295
commit fb031da1ef
19 changed files with 262 additions and 74 deletions
+2 -2
View File
@@ -24,7 +24,7 @@ import {
SidebarProvider,
} from "@/components/ui/sidebar";
import { getArtifactConfig, random, wipe } from "@/lib/api";
import { apiAuthCheck } from "@/lib/auth";
import { adminCheck } from "@/lib/auth";
import { db } from "@/lib/db";
import { submissions } from "@/lib/db/schema";
import { LimitManager, SubmissionList, Watcher } from "./client";
@@ -34,7 +34,7 @@ export default async function AdminLayout({
}: {
children: React.ReactNode;
}) {
if (!(await apiAuthCheck())) redirect("/");
if (!(await adminCheck())) redirect("/");
const subs = await db
.select({
id: submissions.id,
+3
View File
@@ -27,8 +27,11 @@ export async function getEndgameConfig() {
const full = ngm?.limit !== -1 && count >= (ngm?.limit || 0);
return {
// @ts-expect-error
locked: false,
// @ts-expect-error
limit: -1,
// @ts-expect-error
enka: false,
count,
full,
+2 -2
View File
@@ -46,7 +46,7 @@ export default function Home() {
<ItemTitle>
<span className="hidden md:block">เสือกไอดีชาวบ้าน</span>
<span className="block md:hidden">
ตรวจแฟลกเกนชินรายแพทช์
ตรวจแฟกต์เกนชินรายแพทช์
</span>
</ItemTitle>
<ItemDescription className="line-clamp-none hidden md:block">
@@ -110,7 +110,7 @@ export default function Home() {
</CardContent>
<CardFooter>
<p className="text-xs text-center text-muted-foreground">
buzz.gunshiz.top is not affiliated with HoYoverse. Game content
buzz.sudloh.com is not affiliated with HoYoverse. Game content
and materials are trademarks and copyrights of HoYoverse.
</p>
</CardFooter>
+7 -11
View File
@@ -7,13 +7,7 @@ import {
useDroppable,
} from "@dnd-kit/core";
import { rectSortingStrategy, SortableContext } from "@dnd-kit/sortable";
import {
Calculator,
ChevronDown,
ChevronUp,
Smartphone,
X,
} from "lucide-react";
import { Calculator, ChevronDown, ChevronUp, X } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import {
@@ -53,6 +47,7 @@ import {
TooltipTrigger,
} from "@/components/ui/tooltip";
import { tlPlacements, tlState } from "@/lib/api";
import { comms } from "@/lib/comms";
import type {
characters,
tierlistBadges,
@@ -127,6 +122,7 @@ export function TierList({
download: boolean;
ev: "unknown" | "connecting" | "ready";
}>({ upload: false, download: false, ev: "unknown" });
const [updated] = comms.var("updated");
//#region error handling
useEffect(() => {
@@ -345,14 +341,14 @@ export function TierList({
onDragEnd={handleDragEnd}
>
<div className="flex flex-col justify-between h-full">
<Blocker inner className="not-portrait:hidden md:hidden">
{/*}<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" />
โปรดปรับจอเป็นแนวนอน
</div>
</Blocker>
{version.disclaimer && disclaimer ? (
<Blocker inner className="hidden not-portrait:block md:block">
</Blocker>*/}
{version.disclaimer && disclaimer && !updated ? (
<Blocker inner className=" not-portrait:block md:block">
<Image
src={`/cdn/${version.disclaimer}`}
alt="Disclaimer"
+4 -4
View File
@@ -3,10 +3,6 @@ import { sse } from "@/lib/utils";
const VERSION = crypto.randomUUID();
export function GET({ signal }: Request) {
sse.publish(VERSION, {
topic: "active",
event: "version",
});
// +1 because this connection is not yet counted
sse.publish(sse.count("active") + 1, {
topic: "active",
@@ -18,6 +14,10 @@ export function GET({ signal }: Request) {
// no need to -1 because this connection is already removed
sse.publish(sse.count("active"), { topic: "active", event: "count" });
},
motd: {
data: VERSION,
event: "version",
},
signal,
});
}
+2 -3
View File
@@ -1,12 +1,11 @@
import { apiAuthCheck } from "@/lib/auth";
import { adminCheck } from "@/lib/auth";
import { sse } from "@/lib/utils";
export async function GET(
_req: Request,
{ params }: { params: Promise<{ topic: string }> },
) {
if (!(await apiAuthCheck()))
return new Response("Unauthorized", { status: 401 });
if (!(await adminCheck())) return new Response("Unauthorized", { status: 401 });
const { topic } = await params;
return sse.new(topic);
}
+37 -15
View File
@@ -5,6 +5,7 @@ import { useEffect, useState } from "react";
import { useKey } from "react-use";
import ReconnectingEventSource from "reconnecting-eventsource";
import { toast } from "sonner";
import { stringify } from "yaml";
import CommsProvider, { comms } from "@/lib/comms";
export default function Providers({ children }: { children: React.ReactNode }) {
@@ -20,39 +21,58 @@ export default function Providers({ children }: { children: React.ReactNode }) {
);
}
export function VersionCheck() {
export function VersionCheck({ headless = false }: { headless?: boolean }) {
const [version, setVersion] = useState<string>();
const [count, setCount] = useState<string | number>("...");
const [debug, setDebug] = comms.var("debug");
const [, setConnected] = comms.var("connected");
const [, setUpdated] = comms.var("updated");
const [debugData] = comms.raw();
const [readyForUpdate, setReadyForUpdate] = useState(false);
useKey("F2", () => {
setDebug((x) => !x);
if (!headless) setDebug((x) => !x);
});
// console.log(`Debug mode ${debug ? "enabled" : "disabled"}`);
useEffect(() => {
if (!readyForUpdate && window.location.hash === "#update") {
setUpdated(true);
toast.success("คุณอยู่ในเวอร์ชั่นล่าสุดแล้ว");
const url = new URL(window.location.href);
url.hash = "";
window.history.replaceState("", "", url);
}
const es = new ReconnectingEventSource(`/api/active`, {});
es.addEventListener("version", (d) => {
setConnected(true);
const newVersion = JSON.parse(d.data);
if (!version) console.log("Client version:", newVersion);
console.log("Server version:", newVersion);
if (version && newVersion !== version)
toast("เวอร์ชั่นใหม่ออกแล้ว", {
description: "โปรดรีโหลดเพื่อใช้งานต่อ",
action: {
label: "Reload",
// Do a full reload
onClick: () => window.location.reload(),
},
duration: Infinity,
});
if (version && newVersion !== version) {
setReadyForUpdate(true);
window.location.hash = "#update";
if (headless) window.location.reload();
else
toast("มีอัปเดตใหม่พร้อมใช้งาน", {
description: "กดรีโหลดเพื่ออัปเดตเวอร์ชันล่าสุด",
action: {
label: "รีโหลด",
// Do a full reload
onClick: () => window.location.reload(),
},
duration: Infinity,
});
}
if (newVersion !== version) setVersion(newVersion);
});
es.addEventListener("count", (d) => {
const count = JSON.parse(d.data);
setCount(count);
});
es.onerror = () =>
es.onerror = () => {
setConnected(false);
toast.promise(
new Promise((r) => {
es.onopen = r;
@@ -63,12 +83,14 @@ export function VersionCheck() {
duration: 500,
},
);
};
return () => es.close();
}, [version]);
}, [version, headless, setConnected, setUpdated, readyForUpdate]);
return debug ? (
<div className="absolute bottom-0 right-0 m-2 px-1 rounded flex gap-2 bg-card border active:pointer-events-none opacity-20 hover:opacity-100 transition-opacity">
<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">
{count} ผู้ใช้งานออนไลน์
<pre>{stringify(debugData, null, 2)}</pre>
</div>
) : (
""
+1 -1
View File
@@ -92,7 +92,7 @@ export default function ErrorPage({
</Button>
</div>
</div>
<Link href="https://status.gunshiz.top" className="m-2">
<Link href="https://status.sudloh.com" className="m-2">
<Button variant="link" className="text-secondary-foreground">
<Activity />
สถานะเว็บไซต์
+1 -1
View File
@@ -13,7 +13,7 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
metadataBase: new URL(process.env.BASE_URL || "https://buzz.gunshiz.top"),
metadataBase: new URL(process.env.BASE_URL || "https://buzz.sudloh.com"),
title: "เกนชินไม่ใช่เกมมือถือ",
description: "ระบบอีเวนท์ของเกนชินไม่ใช่เกมมือถือ",
icons: `/favicon.webp`, // TODO: CHANGE BACK TO buzz
+1 -1
View File
@@ -68,7 +68,7 @@ export default function ErrorPage() {
กลับหน้าแรก
</Button>
</Link>
<Link href="https://status.gunshiz.top">
<Link href="https://status.sudloh.com">
<Button variant="link" className="text-secondary-foreground">
<Activity />
สถานะเว็บไซต์
+20 -3
View File
@@ -1,16 +1,33 @@
import { Kanit } from "next/font/google";
import { Watcher } from "@/app/(ui)/artifact/admin/client";
import { VersionCheck } from "@/app/client";
import AutoFitText from "@/components/fit";
import { getArtifactConfig } from "@/lib/api";
import { db } from "@/lib/db";
import { submissions } from "@/lib/db/schema";
const kanit = Kanit({
variable: "--font-kanit",
subsets: ["latin", "thai"],
weight: ["100", "200", "300", "400", "500", "600", "700"],
});
export default async function ArtifactCountWidget() {
const config = await getArtifactConfig();
const count = await db.$count(submissions);
const display = `${count} / ${config.limit < 0 ? "∞" : config.limit}`;
return (
<span className="p-1">
{count} / {config.limit < 0 ? "∞" : config.limit}
<div
className={`${kanit.variable} w-screen h-screen font-medium`}
style={{
fontFamily: "Kanit",
}}
>
<AutoFitText className="count">{display}</AutoFitText>
<Watcher />
</span>
<VersionCheck headless />
</div>
);
}