diff --git a/bun.lockb b/bun.lockb index 75d36cd..b13504a 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index c363840..e967bb1 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "zod": "^4.1.8" }, "devDependencies": { - "@tailwindcss/vite": "next", + "@tailwindcss/vite": "^4.2.4", "@types/bun": "latest", "@types/random-seed": "^0.3.5", "@types/react": "^19.1.13", @@ -59,7 +59,7 @@ "@vitejs/plugin-react": "^5.1.4", "drizzle-kit": "0.31.4", "oxlint": "^1.51.0", - "tailwindcss": "^4.1.13", + "tailwindcss": "^4.2.4", "typescript": "^5.9.2", "vite": "^8.0.0-beta.14", "vite-bundle-analyzer": "^1.2.3", diff --git a/src/Shell.tsx b/src/Shell.tsx index 30ee15d..be57585 100644 --- a/src/Shell.tsx +++ b/src/Shell.tsx @@ -17,8 +17,7 @@ import { useMediaQuery } from "@uidotdev/usehooks"; import Header from "./components/Header"; import { Tag } from "./components/Tag"; import Feed from "./components/Feed/Feed"; -import { useAtom } from "jotai"; -import { loginTokenAtom } from "./atoms"; +import { useWSQuery } from "./hooks"; const drawerWidth = 256; const drawerWidthWithPadding = drawerWidth; @@ -26,7 +25,7 @@ const drawerWidthWithPadding = drawerWidth; const Shell: React.FC = ({ children }) => { const [isOpen, setIsOpen] = useState(false); const drawerRef = useRef(null); - const [loginToken] = useAtom(loginTokenAtom); + const { data: username } = useWSQuery("user.getSelf", null); const x = isOpen ? 0 : -drawerWidthWithPadding; const width = isOpen ? drawerWidthWithPadding : 0; @@ -82,7 +81,7 @@ const Shell: React.FC = ({ children }) => { Play - {loginToken && ( + {username && ( History @@ -92,13 +91,13 @@ const Shell: React.FC = ({ children }) => { Store - {loginToken && ( + {username && ( Collection NEW )} - {loginToken && ( + {username && ( Settings diff --git a/src/components/Auth/RegisterButton.tsx b/src/components/Auth/RegisterButton.tsx index 5eee063..4b1bcc0 100644 --- a/src/components/Auth/RegisterButton.tsx +++ b/src/components/Auth/RegisterButton.tsx @@ -15,7 +15,7 @@ import { useQueryClient } from "@tanstack/react-query"; import PasswordInput from "./PasswordInput"; import { wsClient } from "../../wsClient"; -const RegisterButton = () => { +const RegisterButton = ({ label }: { label?: string }) => { const [isOpen, setIsOpen] = useState(false); const [isLoginMode, setIsLoginMode] = useState(false); const [username, setUsername] = useState(""); @@ -36,7 +36,7 @@ const RegisterButton = () => { diff --git a/src/index.css b/src/index.css index cae1f4b..779bcb7 100644 --- a/src/index.css +++ b/src/index.css @@ -41,107 +41,3 @@ button { .grid-border-b div:not(:nth-last-child(-n + 3)) { @apply border-b border-white/10; } - -/* .game-board { */ -/* display: grid; */ -/* gap: 2px; */ -/* max-width: fit-content; */ -/* } */ -/**/ -/* .game-wrapper { */ -/* display: flex; */ -/* flex-direction: column; */ -/* align-items: center; */ -/* } */ -/**/ -/* .mine-button { */ -/* background-color: #666; */ -/* border: 1px solid black; */ -/* width: 2rem; */ -/* height: 2rem; */ -/* font-size: 1.25rem; */ -/* user-select: none; */ -/* display: flex; */ -/* justify-content: center; */ -/* align-items: center; */ -/* font-weight: bold; */ -/* font-family: monospace; */ -/* box-sizing: border-box; */ -/* transition: all 0.2s ease-in-out; */ -/* } */ -/**/ -/* html { */ -/* background: #111; */ -/* color: #eee; */ -/* } */ -/**/ -/* body { */ -/* margin: auto; */ -/* max-width: 1400px; */ -/* padding: 1rem; */ -/* font-family: monospace; */ -/* } */ -/**/ -/* .timer { */ -/* flex-grow: 1; */ -/* display: flex; */ -/* justify-content: space-between; */ -/* align-items: center; */ -/* font-size: 2rem; */ -/* font-family: monospace; */ -/* } */ -/**/ -/* .footer { */ -/* display: flex; */ -/* flex-direction: column; */ -/* align-items: center; */ -/* font-size: 1rem; */ -/* font-family: monospace; */ -/* } */ -/**/ -/* pre { */ -/* margin: 0; */ -/* } */ -/**/ -/* .stage { */ -/* font-size: 1rem; */ -/* font-family: monospace; */ -/* } */ -/**/ -/* input { */ -/* font-size: 14px; */ -/* margin: 12px; */ -/* padding: 6px 12px 6px 12px; */ -/* border-radius: 0.7em; */ -/* background: #333; */ -/* color: #eee; */ -/* border: 1px solid rgb(251, 21, 242); */ -/**/ -/* } */ -/**/ -/* button { */ -/* color: white; */ -/* font-weight: 600; */ -/* font-size: 14px; */ -/* margin: 12px; */ -/* padding: 6px 12px 6px 12px; */ -/* border-radius: 0.7em; */ -/* background: -webkit-linear-gradient(225deg, rgb(251, 175, 21), rgb(251, 21, 242), */ -/* rgb(21, 198, 251)) 0% 0% / 300% 300%; */ -/* background-size: 200% auto; */ -/* } */ -/**/ -/* button:hover { */ -/* animation: gradient_move 1s ease infinite; */ -/* } */ -/**/ -/**/ -/* .header { */ -/* display: grid; */ -/* grid-template-columns: 1fr 1fr; */ -/* margin-bottom: 1rem; */ -/* } */ -/**/ -/* .scores { */ -/* text-align: right; */ -/* } */ diff --git a/src/main.tsx b/src/main.tsx index 26aafbc..5b3da30 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -15,17 +15,49 @@ import Collection from "./views/collection/Collection.tsx"; import { AnimatePresence } from "motion/react"; import Store from "./views/store/Store.tsx"; import Profile from "./views/profile/Profile.tsx"; +import { useWSQuery } from "./hooks.ts"; +import RegisterButton from "./components/Auth/RegisterButton.tsx"; + +const ProtectedRoute: React.FC<{ + component: React.ComponentType; + path: string; +}> = ({ component: Component, path }) => { + const { data: username, isLoading } = useWSQuery("user.getSelf", null); + + return ( + + {(params) => { + if (isLoading) return null; + if (!username) { + return ( +
+

+ This page is only available to logged-in users. +

+ +
+ ); + } + return ; + }} +
+ ); +}; const setup = async () => { const token = localStorage.getItem("loginToken"); if (token) { try { - await wsClient.dispatch("user.loginWithToken", { + const res = await wsClient.dispatch("user.loginWithToken", { token: JSON.parse(token), }); + if (!res.success) { + localStorage.removeItem("loginToken"); + } } catch (e) { console.error(e); + localStorage.removeItem("loginToken"); } } }; @@ -41,9 +73,9 @@ setup().then(() => { {(params) => } - - - + + + {(params) => } diff --git a/src/views/endless/Endless.tsx b/src/views/endless/Endless.tsx index 0e999ff..a500d7f 100644 --- a/src/views/endless/Endless.tsx +++ b/src/views/endless/Endless.tsx @@ -1,6 +1,6 @@ import { useWSMutation, useWSQuery } from "../../hooks"; import { useAtom } from "jotai"; -import { gameIdAtom, loginTokenAtom } from "../../atoms"; +import { gameIdAtom } from "../../atoms"; import { Button } from "../../components/Button"; import LeaderboardButton from "../../components/LeaderboardButton"; import { ShareButton } from "../../components/ShareButton"; @@ -15,7 +15,6 @@ interface EndlessProps { const Endless: React.FC = (props) => { const [gameId, setGameId] = useAtom(gameIdAtom); - const [loginToken] = useAtom(loginTokenAtom); const { data: game } = useWSQuery("game.getGameState", gameId!, !!gameId); const { data: settings } = useWSQuery("user.getSettings", null); const { data: currentUsername } = useWSQuery("user.getSelf", null); @@ -93,7 +92,7 @@ const Endless: React.FC = (props) => {

Minesweeper Endless

- {loginToken ? ( + {currentUsername ? ( ) : ( - + )}

How to play

diff --git a/src/views/store/Store.tsx b/src/views/store/Store.tsx index 3cb6651..b6c1b17 100644 --- a/src/views/store/Store.tsx +++ b/src/views/store/Store.tsx @@ -18,11 +18,13 @@ import { useEffect } from "react"; import { initParticlesEngine, Particles as ParticlesComponent } from "@tsparticles/react"; import { motion } from "motion/react"; import BounceImg from "../../components/BounceImg"; +import RegisterButton from "../../components/Auth/RegisterButton"; const Store = () => { const openLootbox = useWSMutation("user.openLootbox"); const [lootboxResult, setLootboxResult] = useAtom(lootboxResultAtom); const currentLootbox = lootboxes.find((l) => l.id === lootboxResult?.lootbox); + const { data: username } = useWSQuery("user.getSelf", null); const { refetch } = useWSQuery("user.getOwnGems", null); // this should be run only once per application lifetime @@ -184,18 +186,24 @@ const Store = () => {

- + {username ? ( + + ) : ( +
+ +
+ )} ))} diff --git a/tailwind.config.js b/tailwind.config.js deleted file mode 100644 index e69de29..0000000