Fix real Biome bugs: inner declarations, dup keys, assign-in-expr, implicit any, cookie, a11y svg/keyboard, json
Local Build and Deploy / deploy (push) Successful in 51s
Local Build and Deploy / deploy (push) Successful in 51s
This commit is contained in:
1 parent
8d5c8ec96f
commit
59b63d6e70
19 files changed
+76
-44
No files matched your search
@@ -1,14 +1,22 @@
|
|||||||
(() => {
|
(() => {
|
||||||
|
let theme: string | null = null;
|
||||||
|
let defaultDark = false;
|
||||||
|
let navbarColor: string | null = null;
|
||||||
|
let navbarTextColor: string | null = null;
|
||||||
try {
|
try {
|
||||||
var s = localStorage.getItem("theme");
|
theme = localStorage.getItem("theme");
|
||||||
var dd = document.querySelector('meta[name="theme-default-dark"]');
|
const dd = document.querySelector('meta[name="theme-default-dark"]');
|
||||||
var defaultDark = dd ? dd.getAttribute("content") === "true" : false;
|
defaultDark = dd ? dd.getAttribute("content") === "true" : false;
|
||||||
if (s === "dark" || (!s && defaultDark))
|
navbarColor = localStorage.getItem("navbarColor");
|
||||||
document.documentElement.classList.add("dark");
|
navbarTextColor = localStorage.getItem("navbarTextColor");
|
||||||
var nc = localStorage.getItem("navbarColor"),
|
|
||||||
nt = localStorage.getItem("navbarTextColor");
|
|
||||||
if (nc) document.documentElement.style.setProperty("--color-navbar", nc);
|
|
||||||
if (nt)
|
|
||||||
document.documentElement.style.setProperty("--color-navbar-text", nt);
|
|
||||||
} catch (_e) {}
|
} catch (_e) {}
|
||||||
|
if (theme === "dark" || (!theme && defaultDark))
|
||||||
|
document.documentElement.classList.add("dark");
|
||||||
|
if (navbarColor)
|
||||||
|
document.documentElement.style.setProperty("--color-navbar", navbarColor);
|
||||||
|
if (navbarTextColor)
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--color-navbar-text",
|
||||||
|
navbarTextColor,
|
||||||
|
);
|
||||||
})();
|
})();
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
|
||||||
|
export async function setLocaleCookie(code: string): Promise<void> {
|
||||||
|
const store = await cookies();
|
||||||
|
store.set("NEXT_LOCALE", code, {
|
||||||
|
path: "/",
|
||||||
|
maxAge: 31536000,
|
||||||
|
sameSite: "strict",
|
||||||
|
secure: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -48,7 +48,9 @@ export default async function AdminHousekeeping({
|
|||||||
.split(",")
|
.split(",")
|
||||||
.map((i) => Number(i.trim()))
|
.map((i) => Number(i.trim()))
|
||||||
.filter((i) => !Number.isNaN(i));
|
.filter((i) => !Number.isNaN(i));
|
||||||
importIds.forEach((id) => selectedIds.add(id));
|
importIds.forEach((id) => {
|
||||||
|
selectedIds.add(id);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function PollForm({ defaultValues }: PollFormProps) {
|
|||||||
// biome-ignore lint/suspicious/noExplicitAny: explicitly chosen here, see surrounding code
|
// biome-ignore lint/suspicious/noExplicitAny: explicitly chosen here, see surrounding code
|
||||||
function onSubmit(data: any) {
|
function onSubmit(data: any) {
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
run(() => updatePoll({ id: defaultValues?.id!, ...data }), {
|
run(() => updatePoll({ id: defaultValues!.id, ...data }), {
|
||||||
successMessage: "Poll updated!",
|
successMessage: "Poll updated!",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export default async function AdminRadioApiKeysPage() {
|
|||||||
<Link href="/admin/radio/autodj">{t("autoDj")}</Link> ·{" "}
|
<Link href="/admin/radio/autodj">{t("autoDj")}</Link> ·{" "}
|
||||||
<Link href="/admin/radio/embed">{t("embed")}</Link> ·{" "}
|
<Link href="/admin/radio/embed">{t("embed")}</Link> ·{" "}
|
||||||
<Link href="/admin/radio/points">{t("points")}</Link> ·{" "}
|
<Link href="/admin/radio/points">{t("points")}</Link> ·{" "}
|
||||||
<Link href="/admin/radio/monitoring">{t("monitoring")}</Link>
|
<Link href="/admin/radio/monitoring">{t("monitoring.title")}</Link>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section className="mt-6">
|
<section className="mt-6">
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ export default async function AdminRadioAutoDjPage() {
|
|||||||
htmlFor="new_title"
|
htmlFor="new_title"
|
||||||
style={{ display: "block", fontWeight: 700 }}
|
style={{ display: "block", fontWeight: 700 }}
|
||||||
>
|
>
|
||||||
{t("autoDjForm.title")}
|
{t("autoDjForm.trackTitle")}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="new_title"
|
id="new_title"
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ import {
|
|||||||
captureOrder,
|
captureOrder,
|
||||||
creditsPerUnit,
|
creditsPerUnit,
|
||||||
isPayPalConfigured,
|
isPayPalConfigured,
|
||||||
|
type CaptureResult,
|
||||||
} from "@/lib/services/paypal";
|
} from "@/lib/services/paypal";
|
||||||
import {
|
import {
|
||||||
authorizeTopupCapture,
|
authorizeTopupCapture,
|
||||||
claimTopupDelivery,
|
claimTopupDelivery,
|
||||||
TopupCaptureError,
|
TopupCaptureError,
|
||||||
|
type AuthorizedTopup,
|
||||||
} from "@/lib/services/paypal-topup";
|
} from "@/lib/services/paypal-topup";
|
||||||
import { rcon } from "@/lib/services/rcon";
|
import { rcon } from "@/lib/services/rcon";
|
||||||
import { sendCurrency } from "@/lib/services/send-currency";
|
import { sendCurrency } from "@/lib/services/send-currency";
|
||||||
@@ -72,7 +74,7 @@ export async function POST(req: Request): Promise<Response> {
|
|||||||
|
|
||||||
// The create endpoint records ownership before returning the approval URL.
|
// The create endpoint records ownership before returning the approval URL.
|
||||||
// Do not let a signed-in user submit somebody else's approved order id.
|
// Do not let a signed-in user submit somebody else's approved order id.
|
||||||
let authorized;
|
let authorized: AuthorizedTopup;
|
||||||
try {
|
try {
|
||||||
authorized = await authorizeTopupCapture(
|
authorized = await authorizeTopupCapture(
|
||||||
userId,
|
userId,
|
||||||
@@ -138,7 +140,7 @@ export async function POST(req: Request): Promise<Response> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let result;
|
let result: CaptureResult;
|
||||||
try {
|
try {
|
||||||
result = await captureOrder(orderId);
|
result = await captureOrder(orderId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ import { useEffect } from "react";
|
|||||||
* stays), shows a friendly card, and offers a reset. The raw error is logged to
|
* stays), shows a friendly card, and offers a reset. The raw error is logged to
|
||||||
* the console, never shown to the user.
|
* the console, never shown to the user.
|
||||||
*/
|
*/
|
||||||
export default function Error({
|
export default function ErrorPage({
|
||||||
error,
|
error,
|
||||||
reset,
|
reset,
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
+6
-2
@@ -205,7 +205,9 @@ summary,
|
|||||||
letter-spacing: 0.03em;
|
letter-spacing: 0.03em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out;
|
transition:
|
||||||
|
color 0.15s ease-in-out,
|
||||||
|
background-color 0.15s ease-in-out;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
.nav-item:hover {
|
.nav-item:hover {
|
||||||
@@ -223,7 +225,9 @@ summary,
|
|||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
@apply block py-2.5 px-4 text-sm font-semibold rounded-lg mx-1;
|
@apply block py-2.5 px-4 text-sm font-semibold rounded-lg mx-1;
|
||||||
color: var(--color-dropdown-text-readable, var(--color-text-readable));
|
color: var(--color-dropdown-text-readable, var(--color-text-readable));
|
||||||
transition: background-color 0.1s ease-in-out, color 0.1s ease-in-out;
|
transition:
|
||||||
|
background-color 0.1s ease-in-out,
|
||||||
|
color 0.1s ease-in-out;
|
||||||
}
|
}
|
||||||
.dropdown-item:hover {
|
.dropdown-item:hover {
|
||||||
background-color: color-mix(in srgb, var(--color-primary) 12%, transparent);
|
background-color: color-mix(in srgb, var(--color-primary) 12%, transparent);
|
||||||
|
|||||||
@@ -117,11 +117,12 @@ export default async function HelpCategoryPage({
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{/* content is author-supplied HTML — sanitised server-side. */}
|
{/* content is author-supplied HTML — sanitised server-side. */}
|
||||||
<div
|
{/* biome-ignore lint/security/noDangerouslySetInnerHtml: sanitised article body */}
|
||||||
style={{ lineHeight: 1.7 }}
|
<div
|
||||||
dangerouslySetInnerHTML={{ __html: sanitize(content) }}
|
style={{ lineHeight: 1.7 }}
|
||||||
/>
|
dangerouslySetInnerHTML={{ __html: sanitize(content) }}
|
||||||
|
/>
|
||||||
|
|
||||||
{hasButton ? (
|
{hasButton ? (
|
||||||
<div style={{ clear: "both", marginTop: "1rem" }}>
|
<div style={{ clear: "both", marginTop: "1rem" }}>
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import type { CSSProperties } from "react";
|
import type { CSSProperties, ReactNode } from "react";
|
||||||
import { claimReferral } from "@/actions/referral";
|
import { claimReferral } from "@/actions/referral";
|
||||||
import {
|
import {
|
||||||
ContentCard,
|
ContentCard,
|
||||||
@@ -70,7 +70,7 @@ export default async function MePage({
|
|||||||
|
|
||||||
const { claimed, error } = await searchParams;
|
const { claimed, error } = await searchParams;
|
||||||
|
|
||||||
let content;
|
let content: ReactNode;
|
||||||
try {
|
try {
|
||||||
// --- Account + reward config -----------------------------------------
|
// --- Account + reward config -----------------------------------------
|
||||||
const [user, imagerBase, neededRaw, amountRaw, currencyRaw] =
|
const [user, imagerBase, neededRaw, amountRaw, currencyRaw] =
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import Image from "next/image";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useLocale } from "next-intl";
|
import { useLocale } from "next-intl";
|
||||||
import { useEffect, useMemo, useRef, useState, useTransition } from "react";
|
import { useEffect, useMemo, useRef, useState, useTransition } from "react";
|
||||||
|
import { setLocaleCookie } from "@/actions/set-locale";
|
||||||
|
|
||||||
const LOCALES: { code: string; label: string; lang: string }[] = [
|
const LOCALES: { code: string; label: string; lang: string }[] = [
|
||||||
{ code: "nl", label: "Nederlands", lang: "nl" },
|
{ code: "nl", label: "Nederlands", lang: "nl" },
|
||||||
@@ -66,8 +67,10 @@ export function LanguageSwitcher() {
|
|||||||
|
|
||||||
function switchLocale(code: string) {
|
function switchLocale(code: string) {
|
||||||
if (code === locale) return;
|
if (code === locale) return;
|
||||||
document.cookie = `NEXT_LOCALE=${code};path=/;max-age=31536000;samesite=strict;secure`;
|
startTransition(async () => {
|
||||||
startTransition(() => router.refresh());
|
await setLocaleCookie(code);
|
||||||
|
router.refresh();
|
||||||
|
});
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { type ReactNode, useRef } from "react";
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import { type ReactNode, useRef } from "react";
|
||||||
|
|
||||||
interface MobileNavProps {
|
interface MobileNavProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -37,7 +36,7 @@ export function MobileNav({
|
|||||||
hover:bg-[color-mix(in_srgb,var(--color-primary)_12%,transparent)]
|
hover:bg-[color-mix(in_srgb,var(--color-primary)_12%,transparent)]
|
||||||
active:scale-[0.96]
|
active:scale-[0.96]
|
||||||
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary-readable,var(--color-primary))] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-navbar)]"
|
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary-readable,var(--color-primary))] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-navbar)]"
|
||||||
aria-label={"Menu"}
|
aria-label={menuLabel}
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
className="w-6 h-6 details-open:hidden"
|
className="w-6 h-6 details-open:hidden"
|
||||||
@@ -97,8 +96,7 @@ export function MobileNav({
|
|||||||
<span
|
<span
|
||||||
className="text-sm font-extrabold uppercase tracking-wide"
|
className="text-sm font-extrabold uppercase tracking-wide"
|
||||||
style={{
|
style={{
|
||||||
color:
|
color: "var(--color-navbar-text-readable, var(--color-text))",
|
||||||
"var(--color-navbar-text-readable, var(--color-text))",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{brandLabel}
|
{brandLabel}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { type ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
interface NavDropdownProps {
|
interface NavDropdownProps {
|
||||||
label: string;
|
label: string;
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ function Currency({
|
|||||||
amount: number;
|
amount: number;
|
||||||
label: string;
|
label: string;
|
||||||
}) {
|
}) {
|
||||||
const textColor = "var(--color-navbar-text-readable, var(--color-navbar-text))";
|
const textColor =
|
||||||
|
"var(--color-navbar-text-readable, var(--color-navbar-text))";
|
||||||
const valueColor =
|
const valueColor =
|
||||||
"var(--color-navbar-text-readable, var(--color-navbar-text, var(--color-text)))";
|
"var(--color-navbar-text-readable, var(--color-navbar-text, var(--color-text)))";
|
||||||
|
|
||||||
@@ -24,7 +25,10 @@ function Currency({
|
|||||||
className={`h-[20px] w-[20px] sm:h-[25px] sm:w-[25px] rounded-full outline-offset-[3px] ${icon}`}
|
className={`h-[20px] w-[20px] sm:h-[25px] sm:w-[25px] rounded-full outline-offset-[3px] ${icon}`}
|
||||||
/>
|
/>
|
||||||
<div style={{ color: textColor }}>
|
<div style={{ color: textColor }}>
|
||||||
<span className="font-semibold text-xs sm:text-sm" style={{ color: valueColor }}>
|
<span
|
||||||
|
className="font-semibold text-xs sm:text-sm"
|
||||||
|
style={{ color: valueColor }}
|
||||||
|
>
|
||||||
{amount.toLocaleString()}
|
{amount.toLocaleString()}
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
<span className="hidden sm:inline text-xs">{label}</span>
|
<span className="hidden sm:inline text-xs">{label}</span>
|
||||||
|
|||||||
@@ -152,5 +152,5 @@ export class DbService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const db = globalForDb._db ?? (globalForDb._db = new DbService());
|
export const db = globalForDb._db ?? new DbService();
|
||||||
if (env.NODE_ENV !== "production") globalForDb._db = db;
|
if (env.NODE_ENV !== "production") globalForDb._db = db;
|
||||||
+2
-3
@@ -22,9 +22,8 @@ function createRedis(): Redis | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const redis: Redis | null =
|
export const redis: Redis | null =
|
||||||
globalForRedis.redis !== undefined
|
globalForRedis.redis !== undefined ? globalForRedis.redis : createRedis();
|
||||||
? globalForRedis.redis
|
if (globalForRedis.redis === undefined) globalForRedis.redis = redis;
|
||||||
: (globalForRedis.redis = createRedis());
|
|
||||||
|
|
||||||
export async function withRedis<T>(
|
export async function withRedis<T>(
|
||||||
fallback: () => Promise<T>,
|
fallback: () => Promise<T>,
|
||||||
|
|||||||
@@ -1462,7 +1462,6 @@
|
|||||||
"apiKeys": "API Keys",
|
"apiKeys": "API Keys",
|
||||||
"points": "Points",
|
"points": "Points",
|
||||||
"autoDj": "AutoDJ",
|
"autoDj": "AutoDJ",
|
||||||
"monitoring": "Monitoring",
|
|
||||||
"user": "User",
|
"user": "User",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
"posted": "Posted",
|
"posted": "Posted",
|
||||||
@@ -1652,7 +1651,7 @@
|
|||||||
"active": "Active",
|
"active": "Active",
|
||||||
"inactive": "Inactive",
|
"inactive": "Inactive",
|
||||||
"addTrack": "Add track",
|
"addTrack": "Add track",
|
||||||
"title": "Title",
|
"trackTitle": "Title",
|
||||||
"titlePlaceholder": "Track title",
|
"titlePlaceholder": "Track title",
|
||||||
"artist": "Artist",
|
"artist": "Artist",
|
||||||
"album": "Album",
|
"album": "Album",
|
||||||
|
|||||||
@@ -1462,7 +1462,6 @@
|
|||||||
"apiKeys": "API-sleutels",
|
"apiKeys": "API-sleutels",
|
||||||
"points": "Punten",
|
"points": "Punten",
|
||||||
"autoDj": "AutoDJ",
|
"autoDj": "AutoDJ",
|
||||||
"monitoring": "Monitoring",
|
|
||||||
"user": "User",
|
"user": "User",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
"posted": "Posted",
|
"posted": "Posted",
|
||||||
@@ -1652,7 +1651,7 @@
|
|||||||
"active": "Active",
|
"active": "Active",
|
||||||
"inactive": "Inactive",
|
"inactive": "Inactive",
|
||||||
"addTrack": "Add track",
|
"addTrack": "Add track",
|
||||||
"title": "Title",
|
"trackTitle": "Title",
|
||||||
"titlePlaceholder": "Track title",
|
"titlePlaceholder": "Track title",
|
||||||
"artist": "Artist",
|
"artist": "Artist",
|
||||||
"album": "Album",
|
"album": "Album",
|
||||||
|
|||||||
Reference in new issue
Block a user