fixed ui bugs and migrated to oxlint

This commit is contained in:
MasterGordon 2026-03-06 22:09:58 +01:00
parent 22b8c147b6
commit 2760d214c1
12 changed files with 65 additions and 56 deletions

34
.oxlintrc.json Normal file
View File

@ -0,0 +1,34 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["react", "react-perf", "promise", "import"],
"categories": {
"correctness": "error",
"suspicious": "warn"
},
"rules": {
"no-shadow": "off",
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"react/display-name": "off",
"react/no-unknown-property": "off",
"import/no-unassigned-import": [
"warn",
{
"allow": [
"**/*.css",
"@pixi/canvas-display",
"@pixi/canvas-extract",
"@pixi/canvas-graphics",
"@pixi/canvas-mesh",
"@pixi/canvas-particle-container",
"@pixi/canvas-prepare",
"@pixi/canvas-renderer",
"@pixi/canvas-sprite-tiling",
"@pixi/canvas-sprite",
"@pixi/canvas-text"
]
}
]
},
"ignorePatterns": ["dist/", "node_modules/"]
}

View File

@ -30,3 +30,8 @@ bun dev
- Questinmark after flag - Questinmark after flag
- Earn points for wins - Earn points for wins
- Powerups - Powerups
## TODOs
- Fix scoreboard modal
- Fix fullscrean

BIN
bun.lockb

Binary file not shown.

View File

@ -1,40 +0,0 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginReact from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
export default [
{
ignores: ["dist/", "node_modules/"],
},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
{
...pluginReact.configs.flat.recommended,
settings: {
react: {
version: "detect",
},
},
},
{
plugins: { "react-hooks": reactHooks },
rules: reactHooks.configs.recommended.rules,
},
{
files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"],
rules: {
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"react/display-name": "off",
"react/no-unknown-property": "off",
},
},
{
languageOptions: {
...pluginReact.configs.flat.recommended.languageOptions,
globals: { ...globals.browser, ...globals.node },
},
},
];

View File

@ -8,7 +8,7 @@
"dev:backend": "bun run backend/index.ts --watch --hot", "dev:backend": "bun run backend/index.ts --watch --hot",
"dev:client": "vite", "dev:client": "vite",
"build": "tsc -b && vite build", "build": "tsc -b && vite build",
"lint": "eslint", "lint": "oxlint",
"preview": "vite preview", "preview": "vite preview",
"drizzle:schema": "drizzle-kit generate", "drizzle:schema": "drizzle-kit generate",
"drizzle:migrate": "bun run backend/migrate.ts", "drizzle:migrate": "bun run backend/migrate.ts",
@ -51,8 +51,6 @@
"zod": "^4.1.8" "zod": "^4.1.8"
}, },
"devDependencies": { "devDependencies": {
"@eslint/compat": "^1.3.2",
"@eslint/js": "^9.35.0",
"@tailwindcss/vite": "next", "@tailwindcss/vite": "next",
"@types/bun": "latest", "@types/bun": "latest",
"@types/random-seed": "^0.3.5", "@types/random-seed": "^0.3.5",
@ -60,13 +58,9 @@
"@types/react-dom": "^19.1.9", "@types/react-dom": "^19.1.9",
"@vitejs/plugin-react-swc": "^4.0.1", "@vitejs/plugin-react-swc": "^4.0.1",
"drizzle-kit": "0.31.4", "drizzle-kit": "0.31.4",
"eslint": "^9.35.0", "oxlint": "^1.51.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "5.2.0",
"globals": "^16.4.0",
"tailwindcss": "^4.1.13", "tailwindcss": "^4.1.13",
"typescript": "^5.9.2", "typescript": "^5.9.2",
"typescript-eslint": "^8.44.0",
"vite": "^7.1.5", "vite": "^7.1.5",
"vite-bundle-analyzer": "^1.2.3", "vite-bundle-analyzer": "^1.2.3",
"vite-imagetools": "^8.0.0" "vite-imagetools": "^8.0.0"

View File

@ -64,6 +64,7 @@ const LoginButton = () => {
token: res.token, token: res.token,
}); });
await queryClient.resetQueries(); await queryClient.resetQueries();
return;
}) })
.catch((e) => { .catch((e) => {
setError(e); setError(e);

View File

@ -83,6 +83,7 @@ const RegisterButton = () => {
}); });
await queryClient.resetQueries(); await queryClient.resetQueries();
setIsOpen(false); setIsOpen(false);
return;
}) })
.catch((e) => { .catch((e) => {
setError(e); setError(e);

View File

@ -143,6 +143,19 @@ const Board: React.FC<BoardProps> = (props) => {
const viewportRef = useRef<PixiViewport>(null); const viewportRef = useRef<PixiViewport>(null);
const [zenMode, setZenMode] = useState(false); const [zenMode, setZenMode] = useState(false);
// Force resize when zen mode changes - the layout needs time to settle
useEffect(() => {
const timeout = setTimeout(() => {
if (ref.current) {
setWidth(ref.current.clientWidth);
setHeight(ref.current.clientHeight);
if (viewportRef.current) onViewportChange(viewportRef.current);
}
}, 50);
return () => clearTimeout(timeout);
}, [zenMode, onViewportChange]);
useEffect(() => { useEffect(() => {
if (ref.current) { if (ref.current) {
ref.current.addEventListener("wheel", (e) => { ref.current.addEventListener("wheel", (e) => {
@ -187,7 +200,7 @@ const Board: React.FC<BoardProps> = (props) => {
<div <div
className={cn( className={cn(
"w-full h-[70vh] overflow-hidden outline-white/40 outline-2 flex flex-col", "w-full h-[70vh] overflow-hidden outline-white/40 outline-2 flex flex-col",
zenMode && "fixed top-0 left-0 z-50 right-0 bottom-0 h-[100vh]", zenMode && "fixed top-0 left-0 z-50 w-[100vw] h-[100vh]",
props.className, props.className,
)} )}
style={{ style={{
@ -225,6 +238,7 @@ const Board: React.FC<BoardProps> = (props) => {
</div> </div>
{theme && ( {theme && (
<Application <Application
key={`${width}-${height}`}
hello hello
forceFallbackAdapter={!!props.width} forceFallbackAdapter={!!props.width}
width={width} width={width}

View File

@ -28,7 +28,7 @@ const LeaderboardButton = ({
<DialogHeader> <DialogHeader>
<DialogTitle>Leaderboard</DialogTitle> <DialogTitle>Leaderboard</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="grid grid-cols-[min-content_2fr_1fr] grid-border-b"> <div className="grid grid-cols-[min-content_2fr_1fr] grid-border-b overflow-y-auto max-h-[60vh]">
{leaderboard?.map((_, i) => ( {leaderboard?.map((_, i) => (
<Fragment key={i}> <Fragment key={i}>
<div className="p-4 text-white/80 text-right">{i + 1}.</div> <div className="p-4 text-white/80 text-right">{i + 1}.</div>

View File

@ -65,6 +65,7 @@ const PixiViewport = (props: ViewportProps) => {
viewport.off("zoomed-end"); viewport.off("zoomed-end");
}; };
}, [clamp, clampZoom, onViewportChange, viewportRef, app.renderer]); }, [clamp, clampZoom, onViewportChange, viewportRef, app.renderer]);
if (!app.renderer) return null; if (!app.renderer) return null;
return ( return (
<pixiViewport <pixiViewport

View File

@ -31,7 +31,7 @@ const setup = async () => {
}; };
setup().then(() => { setup().then(() => {
createRoot(document.getElementById("root")!).render( return createRoot(document.getElementById("root")!).render(
<StrictMode> <StrictMode>
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<Shell> <Shell>

View File

@ -15,7 +15,7 @@ import { Rarity } from "../../components/Rarity";
import { lootboxResultAtom } from "../../atoms"; import { lootboxResultAtom } from "../../atoms";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useEffect } from "react"; import { useEffect } from "react";
import Particles, { initParticlesEngine } from "@tsparticles/react"; import { initParticlesEngine, Particles as ParticlesComponent } from "@tsparticles/react";
import { motion } from "motion/react"; import { motion } from "motion/react";
import BounceImg from "../../components/BounceImg"; import BounceImg from "../../components/BounceImg";
@ -29,9 +29,8 @@ const Store = () => {
useEffect(() => { useEffect(() => {
const cb = async () => { const cb = async () => {
const { loadSlim } = await import("@tsparticles/slim"); const { loadSlim } = await import("@tsparticles/slim");
const { loadSeaAnemonePreset } = await import( const { loadSeaAnemonePreset } =
"@tsparticles/preset-sea-anemone" await import("@tsparticles/preset-sea-anemone");
);
initParticlesEngine(async (engine) => { initParticlesEngine(async (engine) => {
// you can initiate the tsParticles instance (engine) here, adding custom shapes or presets // you can initiate the tsParticles instance (engine) here, adding custom shapes or presets
// this loads the tsparticles package bundle, it's the easiest method for getting everything ready // this loads the tsparticles package bundle, it's the easiest method for getting everything ready
@ -60,7 +59,7 @@ const Store = () => {
</DialogTitle> </DialogTitle>
</DialogHeader> </DialogHeader>
<div className="absolute flex h-full w-full flex-col items-center justify-center"> <div className="absolute flex h-full w-full flex-col items-center justify-center">
<Particles <ParticlesComponent
className="rounded-md" className="rounded-md"
id="tsparticles" id="tsparticles"
options={{ options={{