feat(don): add top donor widget
This commit is contained in:
+9
-2
@@ -1,10 +1,17 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["nextjs"],
|
||||
"plugins": ["nextjs", "react", "import", "typescript"],
|
||||
"rules": {
|
||||
"nextjs/no-html-link-for-pages": "error",
|
||||
"nextjs/next-script-for-ga": "error",
|
||||
"typescript/no-import-type-side-effects": "error",
|
||||
"typescript/consistent-type-imports": "error"
|
||||
"typescript/consistent-type-imports": "error",
|
||||
"typescript/restrict-template-expressions": "off",
|
||||
"typescript/no-floating-promises": "off",
|
||||
"typescript/no-base-to-string": "off",
|
||||
"typescript/unbound-method": "off"
|
||||
},
|
||||
"options": {
|
||||
"typeAware": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@ 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,
|
||||
element as elementEnum,
|
||||
versions,
|
||||
} from "@/lib/db/schema";
|
||||
|
||||
@@ -21,9 +21,10 @@ 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,
|
||||
element as elementEnum,
|
||||
versions,
|
||||
} from "@/lib/db/schema";
|
||||
|
||||
@@ -93,7 +93,7 @@ export function RandomWelcomeMessage() {
|
||||
|
||||
useEffect(() => {
|
||||
setIndex(Math.floor(Math.random() * items.length));
|
||||
}, []);
|
||||
}, [items.length]);
|
||||
|
||||
if (index === -1)
|
||||
return (
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import type { getArtifactConfig } from "@/lib/api";
|
||||
import { setLimit, toggleCheck, toggleLock } from "@/lib/api";
|
||||
import { shared } from "@/lib/comms";
|
||||
import { sse } from "@/lib/db/sse-endpoints";
|
||||
@@ -139,7 +140,7 @@ export function LimitManager({
|
||||
length,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SidebarMenu> & {
|
||||
config: Awaited<ReturnType<typeof import("@/lib/api").getArtifactConfig>>;
|
||||
config: Awaited<ReturnType<typeof getArtifactConfig>>;
|
||||
length: number;
|
||||
}) {
|
||||
return (
|
||||
|
||||
@@ -11,7 +11,10 @@ import { getPostHogClient } from "@/lib/posthog-server";
|
||||
export async function testPopup() {
|
||||
if (!(await adminCheck())) throw new Error("Unauthorized");
|
||||
|
||||
getPostHogClient().capture({ distinctId: "admin", event: "donation_admin_test_popup" });
|
||||
getPostHogClient().capture({
|
||||
distinctId: "admin",
|
||||
event: "donation_admin_test_popup",
|
||||
});
|
||||
|
||||
sse.donate.pub("ping", {
|
||||
id: "test",
|
||||
@@ -24,7 +27,10 @@ export async function testPopup() {
|
||||
export async function reloadWidget() {
|
||||
if (!(await adminCheck())) throw new Error("Unauthorized");
|
||||
|
||||
getPostHogClient().capture({ distinctId: "admin", event: "donation_admin_widget_reload" });
|
||||
getPostHogClient().capture({
|
||||
distinctId: "admin",
|
||||
event: "donation_admin_widget_reload",
|
||||
});
|
||||
|
||||
sse.donate.pub("refresh", null);
|
||||
}
|
||||
@@ -38,7 +44,11 @@ export async function resendPopup(id: string) {
|
||||
.returning();
|
||||
if (!sub) throw new Error("not found");
|
||||
|
||||
getPostHogClient().capture({ distinctId: "admin", event: "donation_admin_resend", properties: { id } });
|
||||
getPostHogClient().capture({
|
||||
distinctId: "admin",
|
||||
event: "donation_admin_resend",
|
||||
properties: { id },
|
||||
});
|
||||
|
||||
sse.donate.pub("ping", {
|
||||
...sub,
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
HoverCardContent,
|
||||
HoverCardTrigger,
|
||||
} from "@/components/ui/hover-card";
|
||||
import { donations } from "@/lib/db/schema";
|
||||
import type { donations } from "@/lib/db/schema";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { ColumnDef } from "@tanstack/react-table";
|
||||
import {
|
||||
@@ -66,16 +66,26 @@ const columns: ColumnDef<typeof donations.$inferSelect>[] = [
|
||||
return (
|
||||
<div className="flex gap-1">
|
||||
<SimpleTooltip text="Send test popup">
|
||||
<ActionButton variant="outline" size="icon-sm" action={() => { posthog.capture("donation_admin_test_popup"); return testPopup(); }}>
|
||||
<ActionButton
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
action={() => {
|
||||
posthog.capture("donation_admin_test_popup");
|
||||
return testPopup();
|
||||
}}
|
||||
>
|
||||
<BugPlay />
|
||||
</ActionButton>
|
||||
</SimpleTooltip>
|
||||
<SimpleTooltip text="Reload all widget">
|
||||
<ActionButton
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
action={() => { posthog.capture("donation_admin_widget_reload"); return reloadWidget(); }}
|
||||
>
|
||||
<ActionButton
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
action={() => {
|
||||
posthog.capture("donation_admin_widget_reload");
|
||||
return reloadWidget();
|
||||
}}
|
||||
>
|
||||
<ChevronsLeftRightEllipsis />
|
||||
</ActionButton>
|
||||
</SimpleTooltip>
|
||||
@@ -92,11 +102,16 @@ const columns: ColumnDef<typeof donations.$inferSelect>[] = [
|
||||
)}
|
||||
>
|
||||
<SimpleTooltip text="Re-send Popup">
|
||||
<ActionButton
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
action={() => { posthog.capture("donation_admin_resend", { id: row.row.original.id }); return resendPopup(row.row.original.id); }}
|
||||
>
|
||||
<ActionButton
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
action={() => {
|
||||
posthog.capture("donation_admin_resend", {
|
||||
id: row.row.original.id,
|
||||
});
|
||||
return resendPopup(row.row.original.id);
|
||||
}}
|
||||
>
|
||||
<MessageCircleWarning />
|
||||
</ActionButton>
|
||||
</SimpleTooltip>
|
||||
|
||||
@@ -113,7 +113,15 @@ export default async function () {
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
const processed = await checkSlip(buffer, $.slip.type, $.amount);
|
||||
if (!processed.success) {
|
||||
ph.capture({ distinctId, event: "donation_slip_check_failed", properties: { amount: $.amount, code: processed.code, message: processed.message } });
|
||||
ph.capture({
|
||||
distinctId,
|
||||
event: "donation_slip_check_failed",
|
||||
properties: {
|
||||
amount: $.amount,
|
||||
code: processed.code,
|
||||
message: processed.message,
|
||||
},
|
||||
});
|
||||
return {
|
||||
error: {
|
||||
where: "slip",
|
||||
@@ -135,7 +143,11 @@ export default async function () {
|
||||
return [{ id: "conflict" }];
|
||||
});
|
||||
if (check.id === "conflict") {
|
||||
ph.capture({ distinctId, event: "donation_slip_conflict", properties: { amount: $.amount } });
|
||||
ph.capture({
|
||||
distinctId,
|
||||
event: "donation_slip_conflict",
|
||||
properties: { amount: $.amount },
|
||||
});
|
||||
return { error: { where: "slip", what: "สลิปนี้ถูกใช้ไปแล้ว" } };
|
||||
}
|
||||
} else {
|
||||
@@ -158,7 +170,11 @@ export default async function () {
|
||||
.then((r) => r.json())
|
||||
.catch((e) => e);
|
||||
if (!res.success) {
|
||||
ph.capture({ distinctId, event: "donation_payment_failed", properties: { amount: $.amount, message: res.message } });
|
||||
ph.capture({
|
||||
distinctId,
|
||||
event: "donation_payment_failed",
|
||||
properties: { amount: $.amount, message: res.message },
|
||||
});
|
||||
return { error: { where: "link", what: res.message } };
|
||||
}
|
||||
}
|
||||
@@ -196,7 +212,11 @@ export default async function () {
|
||||
.catch(() => "conflict");
|
||||
if (res === "conflict") {
|
||||
tx.rollback();
|
||||
ph.capture({ distinctId, event: "donation_artifact_conflict", properties: { amount: $.amount, uid: $.uid } });
|
||||
ph.capture({
|
||||
distinctId,
|
||||
event: "donation_artifact_conflict",
|
||||
properties: { amount: $.amount, uid: $.uid },
|
||||
});
|
||||
return { error: { where: "uid", what: "ไม่สามารถสร้างคิวลัดได้" } };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/components/ui/input-group";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import type { Input } from "@/components/ui/input";
|
||||
import { Kbd } from "@/components/ui/kbd";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
|
||||
@@ -32,7 +32,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { SlipokResponse } from "../../../api";
|
||||
import type { SlipokResponse } from "../../../api";
|
||||
import { getDiscordUsers } from "@/app/api/discord/users/api";
|
||||
import { th } from "zod/v4/locales";
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
import { shared } from "@/lib/comms";
|
||||
import { sse } from "@/lib/db/sse-endpoints";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { getEndgameConfig } from "../api";
|
||||
import { setFree, setLimit, toggleCheck, toggleLock } from "../api";
|
||||
|
||||
export function SidebarLink({
|
||||
@@ -92,7 +93,7 @@ export function LimitManager({
|
||||
length,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SidebarMenu> & {
|
||||
config: Awaited<ReturnType<typeof import("../api").getEndgameConfig>>;
|
||||
config: Awaited<ReturnType<typeof getEndgameConfig>>;
|
||||
length: number;
|
||||
}) {
|
||||
const [dialog, setDialog] = useState(1);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { donations } from "@/lib/db/schema";
|
||||
import { sse } from "@/lib/db/sse-endpoints";
|
||||
import { fileToDataUrl } from "@/lib/utils";
|
||||
import { and, asc, not, sql } from "drizzle-orm";
|
||||
import { NextRequest } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { getPostHogClient } from "@/lib/posthog-server";
|
||||
|
||||
export async function PATCH(req: NextRequest) {
|
||||
@@ -24,7 +24,11 @@ export async function PATCH(req: NextRequest) {
|
||||
.limit(1)
|
||||
.orderBy(asc(donations.id));
|
||||
if (!havent) return;
|
||||
getPostHogClient().capture({ distinctId: String(havent.id), event: "donation_resent", properties: { donation_id: havent.id, amount: havent.amount } });
|
||||
getPostHogClient().capture({
|
||||
distinctId: String(havent.id),
|
||||
event: "donation_resent",
|
||||
properties: { donation_id: havent.id, amount: havent.amount },
|
||||
});
|
||||
sse.donate.pub("ping", {
|
||||
...havent,
|
||||
message: havent.message ?? "",
|
||||
|
||||
@@ -26,6 +26,7 @@ export default function Providers({ children }: { children: React.ReactNode }) {
|
||||
|
||||
export function VersionCheck({ headless = false }: { headless?: boolean }) {
|
||||
const ver = useRef<string>("");
|
||||
// oxlint-disable-next-line typescript/unbound-method
|
||||
const { emit } = use(IccContext);
|
||||
const [debug, setDebug] = shared.state("debug");
|
||||
const [, setConnected] = shared.state("connected");
|
||||
|
||||
@@ -6,7 +6,11 @@ import { eq } from "drizzle-orm";
|
||||
import { getPostHogClient } from "@/lib/posthog-server";
|
||||
|
||||
export async function markRunning(id: string) {
|
||||
getPostHogClient().capture({ distinctId: id, event: "donation_widget_state_playing", properties: { donation_id: id } });
|
||||
getPostHogClient().capture({
|
||||
distinctId: id,
|
||||
event: "donation_widget_state_playing",
|
||||
properties: { donation_id: id },
|
||||
});
|
||||
|
||||
await db
|
||||
.update(donations)
|
||||
@@ -15,7 +19,11 @@ export async function markRunning(id: string) {
|
||||
}
|
||||
|
||||
export async function markDone(id: string) {
|
||||
getPostHogClient().capture({ distinctId: id, event: "donation_widget_state_shown", properties: { donation_id: id } });
|
||||
getPostHogClient().capture({
|
||||
distinctId: id,
|
||||
event: "donation_widget_state_shown",
|
||||
properties: { donation_id: id },
|
||||
});
|
||||
|
||||
await db.update(donations).set({ sent: true }).where(eq(donations.id, id));
|
||||
}
|
||||
|
||||
@@ -48,10 +48,15 @@ export default function () {
|
||||
(tts.onerror = () => r(false))
|
||||
),
|
||||
);
|
||||
if (!ttsAvailable) posthog.capture("donation_widget_tts_failed", { amount: data.amount });
|
||||
if (!ttsAvailable)
|
||||
posthog.capture("donation_widget_tts_failed", { amount: data.amount });
|
||||
console.log("Transitioning in");
|
||||
setMounted(true);
|
||||
posthog.capture("donation_widget_displayed", { amount: data.amount, name_length: data.name.length, has_image: !!data.image });
|
||||
posthog.capture("donation_widget_displayed", {
|
||||
amount: data.amount,
|
||||
name_length: data.name.length,
|
||||
has_image: !!data.image,
|
||||
});
|
||||
console.log("Running SFX");
|
||||
if (sfx.current) {
|
||||
const player = sfx.current;
|
||||
@@ -64,7 +69,10 @@ export default function () {
|
||||
if (ttsAvailable) await new Promise((r) => (tts.onended = r));
|
||||
console.log("Done");
|
||||
markDone(data.id);
|
||||
posthog.capture("donation_widget_animation_end", { amount: data.amount, tts_available: ttsAvailable });
|
||||
posthog.capture("donation_widget_animation_end", {
|
||||
amount: data.amount,
|
||||
tts_available: ttsAvailable,
|
||||
});
|
||||
await new Promise((r) => setTimeout(r, 3000));
|
||||
setMounted(false);
|
||||
await new Promise((r) => setTimeout(r, 1200));
|
||||
@@ -98,7 +106,9 @@ export default function () {
|
||||
} catch {
|
||||
console.error("Heartbeat timed out");
|
||||
setFailed((x) => x + 1);
|
||||
posthog.capture("donation_widget_heartbeat_failure", { fail_count: failed + 1 });
|
||||
posthog.capture("donation_widget_heartbeat_failure", {
|
||||
fail_count: failed + 1,
|
||||
});
|
||||
if (failed > 12) location.reload();
|
||||
}
|
||||
}, 10000);
|
||||
@@ -111,7 +121,7 @@ export default function () {
|
||||
// amount: 1,
|
||||
// message: `เสื้อดำเด้าหน่อย`,
|
||||
// });
|
||||
}, []);
|
||||
}, [failed]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
"use server";
|
||||
|
||||
import { db } from "@/lib/db";
|
||||
import { donations } from "@/lib/db/schema";
|
||||
import { asc, desc } from "drizzle-orm";
|
||||
|
||||
export async function getTopDonate() {
|
||||
const [top] = await db
|
||||
.select({
|
||||
name: donations.name,
|
||||
amount: donations.amount,
|
||||
})
|
||||
.from(donations)
|
||||
.limit(1)
|
||||
.orderBy(desc(donations.amount), asc(donations.id));
|
||||
return top;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
"use client";
|
||||
|
||||
import { sse } from "@/lib/db/sse-endpoints";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { getTopDonate } from "./api";
|
||||
|
||||
type Data = Awaited<ReturnType<typeof getTopDonate>>;
|
||||
|
||||
export default function TopDonateWidget() {
|
||||
const [top, setTop] = useState<Data>();
|
||||
const textRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function update() {
|
||||
void getTopDonate().then(setTop);
|
||||
}
|
||||
queueMicrotask(update);
|
||||
return sse.donate.subMany({
|
||||
update,
|
||||
ping: update,
|
||||
refresh: () => location.reload(),
|
||||
}).clean;
|
||||
}, []);
|
||||
|
||||
// the most idiomatic way possible but it works
|
||||
useEffect(() => {
|
||||
if (!textRef.current) return;
|
||||
var fontSize = 48,
|
||||
count = 0;
|
||||
const el = textRef.current;
|
||||
const interval = setInterval(() => {
|
||||
console.log(el.scrollWidth, el.clientWidth);
|
||||
fontSize = (fontSize * el.clientWidth) / el.scrollWidth;
|
||||
el.style.fontSize = `${fontSize}px`;
|
||||
count++;
|
||||
if (count > 20) clearInterval(interval);
|
||||
}, 100);
|
||||
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">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="currentColor"
|
||||
className="size-10 shrink-0"
|
||||
>
|
||||
<path d="M200-160v-80h560v80H200Zm0-140-51-321q-2 0-4.5.5t-4.5.5q-25 0-42.5-17.5T80-680q0-25 17.5-42.5T140-740q25 0 42.5 17.5T200-680q0 7-1.5 13t-3.5 11l125 56 125-171q-11-8-18-21t-7-28q0-25 17.5-42.5T480-880q25 0 42.5 17.5T540-820q0 15-7 28t-18 21l125 171 125-56q-2-5-3.5-11t-1.5-13q0-25 17.5-42.5T820-740q25 0 42.5 17.5T880-680q0 25-17.5 42.5T820-620q-2 0-4.5-.5t-4.5-.5l-51 321H200Zm68-80h424l26-167-105 46-133-183-133 183-105-46 26 167Zm212 0Z" />
|
||||
</svg>
|
||||
<div ref={textRef} className="min-w-0">
|
||||
{top.name}
|
||||
</div>
|
||||
<div className="text-white">{top.amount}฿</div>
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
);
|
||||
}
|
||||
+1
-1
@@ -343,4 +343,4 @@ process
|
||||
.addListener("uncaughtException", console.error)
|
||||
.addListener("unhandledRejection", console.error);
|
||||
|
||||
process.on(15 as unknown as "SIGTERM", process.exit);
|
||||
process.on(15 as unknown as "SIGTERM", () => process.exit());
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
"drizzle-kit": "^0.31.8",
|
||||
"oxfmt": "^0.52.0",
|
||||
"oxlint": "^1.67.0",
|
||||
"oxlint-tsgolint": "^0.23.0",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.9.3",
|
||||
@@ -467,6 +468,18 @@
|
||||
|
||||
"@oxfmt/binding-win32-x64-msvc": ["@oxfmt/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-q5xL7oeXkZdEtNZWBdvehJcmt+GRu9l2bK40yJs1jJXlqq+r0Hygb1rTjq+FM2o/2xyt4cufH6KRplHp3Jjsvw=="],
|
||||
|
||||
"@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gOs9PVr2wEg4ox9z0aJo+RKhhImW86YL5N6yav8BK/rgPsIrwN/igSZ+pbRr723NFvUNKde9fgMhRA6JrXAOZw=="],
|
||||
|
||||
"@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-kjJ8B+7n4tB9VJdxS5A9GdJt6/bYpzbu4lXp2uO1S3sRmCB5gDEABlGoiePNApRWaW+xqL4b4xgiE727jSLhuA=="],
|
||||
|
||||
"@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-6dCZuKNu135seMXilkRk9SpCx6i1XgmiipYGalLij5WVRX6ZYS8c4xI7preN/zv9fCXhsQclTIMDu2Y/cytTjw=="],
|
||||
|
||||
"@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-3bdilnyA7kmSTjK27rvjIjSxL5SIg3wt7vwNiRkouWB83ytssyKnuGvxSYJxgMEmFpSutzaBzcCUM2jDtPGcgA=="],
|
||||
|
||||
"@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-j+OEp44SVYiQ+ZD+uttsX7u6L9SvmbbQ77SO1pSFCcJlsVMeCk8qZsjhKfGKuT/jIA+ipOJMVs/+pqUfObBWNw=="],
|
||||
|
||||
"@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-5MyjFuqf+g8OUPJBSGWHJtmoWnzFJYyOg4To9WMQshZYEWig/vtu7JtJ03VWnzHv9LJkAUeApY0gVCOywFR/iQ=="],
|
||||
|
||||
"@oxlint/binding-android-arm-eabi": ["@oxlint/[email protected]", "", { "os": "android", "cpu": "arm" }, "sha512-VrSi571rDv1N8HaEDM+DEX8nmT0y9jJo8tzzW13vsOWTx59xQczCIJx68n2zWOXRT5YKZsOZXp4qkHN/10x4mw=="],
|
||||
|
||||
"@oxlint/binding-android-arm64": ["@oxlint/[email protected]", "", { "os": "android", "cpu": "arm64" }, "sha512-l6+NdYxMoRohix5r5bbigW16LPicceCwGcQ6LKKuE1kUdjgFfQolJjrJsQYPFetIs78Gxj/G/f5TEGoTCwj9nQ=="],
|
||||
@@ -1085,6 +1098,8 @@
|
||||
|
||||
"oxlint": ["[email protected]", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.67.0", "@oxlint/binding-android-arm64": "1.67.0", "@oxlint/binding-darwin-arm64": "1.67.0", "@oxlint/binding-darwin-x64": "1.67.0", "@oxlint/binding-freebsd-x64": "1.67.0", "@oxlint/binding-linux-arm-gnueabihf": "1.67.0", "@oxlint/binding-linux-arm-musleabihf": "1.67.0", "@oxlint/binding-linux-arm64-gnu": "1.67.0", "@oxlint/binding-linux-arm64-musl": "1.67.0", "@oxlint/binding-linux-ppc64-gnu": "1.67.0", "@oxlint/binding-linux-riscv64-gnu": "1.67.0", "@oxlint/binding-linux-riscv64-musl": "1.67.0", "@oxlint/binding-linux-s390x-gnu": "1.67.0", "@oxlint/binding-linux-x64-gnu": "1.67.0", "@oxlint/binding-linux-x64-musl": "1.67.0", "@oxlint/binding-openharmony-arm64": "1.67.0", "@oxlint/binding-win32-arm64-msvc": "1.67.0", "@oxlint/binding-win32-ia32-msvc": "1.67.0", "@oxlint/binding-win32-x64-msvc": "1.67.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.22.1", "vite-plus": "*" }, "optionalPeers": ["oxlint-tsgolint", "vite-plus"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-blwwaHPdoH8piQ5/z0KHeoHFR7FZgl12WluKJfu4qFLPkZl6mK04PkLE45Fw1NxfBRSlh40Gu7MkxHUw++ociQ=="],
|
||||
|
||||
"oxlint-tsgolint": ["[email protected]", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.23.0", "@oxlint-tsgolint/darwin-x64": "0.23.0", "@oxlint-tsgolint/linux-arm64": "0.23.0", "@oxlint-tsgolint/linux-x64": "0.23.0", "@oxlint-tsgolint/win32-arm64": "0.23.0", "@oxlint-tsgolint/win32-x64": "0.23.0" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-3mBv3CoPbh8dFbzfDGIWa2ytZjn2v+3EX4aKRXjIhsoGFzG8GCjfRirz3rwZf1wYbZzsNLTSgpw8VjQuWdp/jA=="],
|
||||
|
||||
"p-retry": ["[email protected]", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="],
|
||||
|
||||
"pathe": ["[email protected]", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { MaybePromise } from "bun";
|
||||
import type { MaybePromise } from "bun";
|
||||
import { Check } from "lucide-react";
|
||||
import { ComponentProps, ReactNode, useEffect, useState } from "react";
|
||||
import type { ComponentProps, ReactNode} from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export function ActionButton({
|
||||
|
||||
@@ -146,6 +146,7 @@ export function CdnChooser({
|
||||
if (!file) return setValue("");
|
||||
setMeta(file);
|
||||
})();
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [externalValue]);
|
||||
|
||||
async function choose() {
|
||||
|
||||
@@ -66,6 +66,7 @@ export function ComboBox({
|
||||
</CommandItem>
|
||||
),
|
||||
})),
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
[data],
|
||||
);
|
||||
const queryLower = query.toLowerCase();
|
||||
|
||||
@@ -224,6 +224,7 @@ export default function Component({
|
||||
setZoom(1);
|
||||
}
|
||||
previousValueRef.current = value;
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// oxlint-disable react-hooks/exhaustive-deps
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
|
||||
@@ -173,7 +173,7 @@ function ChartTooltipContent({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
|
||||
"border-border/50 bg-background grid min-w-32 items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -108,6 +108,7 @@ export default function IccProvider({
|
||||
(l) => l !== listener,
|
||||
);
|
||||
},
|
||||
// oxlint-disable-next-line typescript/no-useless-default-assignment
|
||||
emit(k, value = undefined) {
|
||||
(listeners.current[k] || []).map((l) =>
|
||||
l(...([value] as Parameters<typeof l>)),
|
||||
@@ -188,6 +189,7 @@ export const shared = {
|
||||
const { [k]: _, ...rest } = comms.get("inspect") || {};
|
||||
comms.set("inspect", rest);
|
||||
},
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
[],
|
||||
);
|
||||
// value updater
|
||||
@@ -197,6 +199,7 @@ export const shared = {
|
||||
...obj,
|
||||
[k]: typeof v === "string" ? v : JSON.stringify(v),
|
||||
});
|
||||
// oxlint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [v]);
|
||||
},
|
||||
emit<K extends keyof SharedSignals>(
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { SlipokResponse } from "@/app/(ui)/rubgram/api";
|
||||
import type { SlipokResponse } from "@/app/(ui)/rubgram/api";
|
||||
|
||||
const { SLIPOK_API_URL, SLIPOK_API_KEY } = process.env as Record<
|
||||
string,
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
"drizzle-kit": "^0.31.8",
|
||||
"oxfmt": "^0.52.0",
|
||||
"oxlint": "^1.67.0",
|
||||
"oxlint-tsgolint": "^0.23.0",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.9.3"
|
||||
|
||||
Reference in New Issue
Block a user