From bd45a979f2a4558aa848c87339736bad8eb28313 Mon Sep 17 00:00:00 2001 From: samlyme Date: Thu, 25 Sep 2025 15:04:18 -0700 Subject: [PATCH 001/279] remove game import debug --- backend/app/main.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/backend/app/main.py b/backend/app/main.py index f5ce61a..3ac02a3 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -5,9 +5,6 @@ from backend.app.dependencies.db import init_db from backend.app.routers import auth -import game -print("🟡",game) - app = FastAPI() # This flag will save you from a lot of gray hairs. From 09b71340cc017c30bea85de2497b275475b19a14 Mon Sep 17 00:00:00 2001 From: samlyme Date: Thu, 25 Sep 2025 15:04:29 -0700 Subject: [PATCH 002/279] refactor exceptions --- backend/app/dependencies/lobbies.py | 47 +++++----- backend/app/routers/lobbies.py | 10 +- backend/app/utils/exceptions.py | 139 ++++++++++++++++------------ 3 files changed, 111 insertions(+), 85 deletions(-) diff --git a/backend/app/dependencies/lobbies.py b/backend/app/dependencies/lobbies.py index 772bf1c..15330e8 100644 --- a/backend/app/dependencies/lobbies.py +++ b/backend/app/dependencies/lobbies.py @@ -53,22 +53,22 @@ def __init__( async def delete(self, user: api.UserProfile) -> None: if user != self.host: - raise LobbyPermissionError(user, self.id) + raise LobbyPermissionError(user=user, lobby_id=self.id) await self.manager._delete(self.id) async def set_lobby_options( - self, host: api.UserProfile, lobby_options: api.LobbyOptions + self, user: api.UserProfile, lobby_options: api.LobbyOptions ) -> None: - if host != self.host: - raise LobbyPermissionError(host, self.id) + if user != self.host: + raise LobbyPermissionError(user=user, lobby_id=self.id) # TODO: make this actually do something. self.lobby_options = lobby_options - async def set_game_options(self, host: api.UserProfile, game_options: Any) -> None: - if host != self.host: - raise LobbyPermissionError(host, self.id) + async def set_game_options(self, user: api.UserProfile, game_options: Any) -> None: + if user != self.host: + raise LobbyPermissionError(user=user, lobby_id=self.id) if self.status == "active": # TODO: make exception for this @@ -77,19 +77,19 @@ async def set_game_options(self, host: api.UserProfile, game_options: Any) -> No # TODO: make this actually do something. self.game_options = game_options - async def join(self, guest: api.UserProfile) -> None: + async def join(self, user: api.UserProfile) -> None: if self.guest: - raise LobbyJoinError(guest, self.id, "Lobby already full") + raise LobbyJoinError(user=user, lobby_id=self.id, reason="Lobby already full") - self.guest = guest - self.manager._add_user(guest, self.id) + self.guest = user + self.manager._add_user(user, self.id) async def leave(self, user: api.UserProfile) -> None: if user == self.host: - raise LobbyLeaveError(user, self.id, "Host can not leave lobby.") + raise LobbyLeaveError(user=user, lobby_id=self.id, reason="Host can not leave lobby.") if user != self.guest: - raise LobbyLeaveError(user, self.id, "User is not guest of this lobby.") + raise LobbyLeaveError(user=user, lobby_id=self.id, reason="User is not guest of this lobby.") self.guest = None if self.guest_ws: @@ -99,10 +99,10 @@ async def leave(self, user: api.UserProfile) -> None: async def start(self, user: api.UserProfile) -> None: if user != self.host: - raise LobbyPermissionError(user, self.id) + raise LobbyPermissionError(user=user, lobby_id=self.id) if not self.guest: - raise LobbyStartError(user, self.id, "Lobby not full. Need guest.") + raise LobbyStartError(user=user, lobby_id=self.id, reason="Lobby not full. Need guest.") self.status = "active" self.game = game_factory(self.game_options) @@ -125,7 +125,7 @@ async def set_websocket(self, websocket: WebSocket, user: api.UserProfile) -> No elif user == self.guest: self.guest_ws = websocket else: - raise LobbyPermissionError(user, self.id) + raise LobbyPermissionError(user=user, lobby_id=self.id) await self.broadcast_lobby() if self.game: @@ -137,7 +137,7 @@ async def remove_websocket(self, user: api.UserProfile) -> None: elif user == self.guest: self.guest_ws = None else: - raise LobbyPermissionError(user, self.id) + raise LobbyPermissionError(user=user, lobby_id=self.id) async def broadcast_lobby(self) -> None: packet: api.LobbyPacket = api.LobbyPacket(content=self.to_profile()) @@ -229,7 +229,7 @@ def user_color(self, user: api.UserProfile) -> api.Color: # TODO: implement bett elif user == self.guest: return "w" if self.game_options.host_color == "b" else "b" else: - raise LobbyPermissionError(user, self.id) + raise LobbyPermissionError(user=user, lobby_id=self.id) # NOTE: In future, this should be in redis @@ -259,7 +259,7 @@ def _remove_user(self, user: api.UserProfile): async def _delete(self, lobby_id: api.LobbyId): lobby = await self.get(lobby_id) if not lobby: - raise LobbyNotFoundError(lobby_id) + raise LobbyNotFoundError(lobby_id=lobby_id) del self.lobbies[lobby_id] @@ -274,7 +274,7 @@ async def _delete(self, lobby_id: api.LobbyId): async def create(self, host: api.UserProfile) -> api.LobbyId: if host.uuid in self.active_users: - raise LobbyCreateError(user=host, lobby_id=self.active_users[host.uuid]) + raise LobbyCreateError(user=host, existing_lobby_id=self.active_users[host.uuid]) lobby_id = generate_lobby_id() while lobby_id in self.lobbies: @@ -294,7 +294,7 @@ async def create(self, host: api.UserProfile) -> api.LobbyId: async def get_lobby(lobby_id: api.LobbyId) -> Lobby: out = await lobby_manager.get(lobby_id) if not out: - raise LobbyNotFoundError(lobby_id) + raise LobbyNotFoundError(lobby_id=lobby_id) return out @@ -309,7 +309,10 @@ async def f(): out = await lobby_manager.get(lobby_id) if not out: - raise LobbyCreateError(user, lobby_id) + # This case should never be reached because the lobby_manager.create + # method already handles errors in lobby creation. If an error + # occurs here, that means that the lboby was created, but not saved. + raise Exception("Critical error in lobby dependency.") return out.to_profile() diff --git a/backend/app/routers/lobbies.py b/backend/app/routers/lobbies.py index d3d38cd..23880d7 100644 --- a/backend/app/routers/lobbies.py +++ b/backend/app/routers/lobbies.py @@ -5,7 +5,7 @@ import backend.app.schemas.types as api from backend.app.utils.exceptions import ( - IllegalMoveException, + IllegalMoveError, LobbyCreateError, LobbyJoinError, LobbyLeaveError, @@ -78,13 +78,13 @@ async def delete_lobby(user: CurrentUserDep, lobby: LobbyDep) -> None: async def move(user: CurrentUserDep, lobby: LobbyDep, move: api.Move) -> None: try: await lobby.make_move(user, move) - except IllegalMoveException as e: - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=e.message) + except IllegalMoveError as e: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=e.detail) @router.post("/{lobby_id}/bid") async def bid(user: CurrentUserDep, lobby: LobbyDep, bid: api.Bid) -> None: try: await lobby.make_bid(user, bid) - except IllegalMoveException as e: - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=e.message) + except IllegalMoveError as e: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=e.detail) diff --git a/backend/app/utils/exceptions.py b/backend/app/utils/exceptions.py index dbcb799..32c9ed2 100644 --- a/backend/app/utils/exceptions.py +++ b/backend/app/utils/exceptions.py @@ -1,99 +1,122 @@ +# exceptions.py + +from typing import Any, Mapping import backend.app.schemas.types as api +# ---------- Base types ---------- + class LobbyError(Exception): """Base exception for all lobby-related errors.""" - def __init__(self, message: str, detail: dict | None = None): + def __init__(self, message: str, *, detail: Mapping[str, Any] | None = None): + # Keep Exception(args) clean: one human-readable message. super().__init__(message) - self.detail = detail if detail is not None else {} + # Preserve an immutable-ish snapshot as a plain dict. + self.detail: dict[str, Any] = dict(detail or {}) -class LobbyNotFoundError(LobbyError): +# ---------- Concrete lobby errors ---------- + +class LobbyNotFoundError(LobbyError, LookupError): """Raised when a lobby with the given ID does not exist.""" - def __init__(self, lobby_id: api.LobbyId): - super().__init__(f"Lobby '{lobby_id}' not found.") - self.detail = {"lobby_id": lobby_id, "reson": "This lobby does not exist."} + def __init__(self, *, lobby_id: api.LobbyId): + self.lobby_id = lobby_id + super().__init__( + f"Lobby '{lobby_id}' not found", + detail={"lobby_id": lobby_id, "reason": "lobby_missing"}, + ) -class LobbyPermissionError(LobbyError): - """Raised when a non-host user tries performing host actions on lobby.""" +class LobbyPermissionError(LobbyError, PermissionError): + """Raised when a non-host user attempts host-only actions.""" - def __init__(self, user: api.UserProfile, lobby_id: api.LobbyId): + def __init__(self, *, user: api.UserProfile, lobby_id: api.LobbyId): + self.user_id = user + self.lobby_id = lobby_id super().__init__( - f"User {user} does not have permission to manage Lobby '{lobby_id}'" + f"User '{user}' is not permitted to manage lobby '{lobby_id}'", + detail={"lobby_id": lobby_id, "user": user, "reason": "not_host"}, ) - self.detail = { - "lobby_id": lobby_id, - "user": user.model_dump(mode="json"), - } class LobbyCreateError(LobbyError): - """Raised when Lobby creation fails because user is in existing lobby.""" + """Raised when lobby creation fails due to existing membership.""" - def __init__(self, user: api.UserProfile, lobby_id: api.LobbyId): + def __init__(self, *, user: api.UserProfile, existing_lobby_id: api.LobbyId): + self.user_id = user + self.existing_lobby_id = existing_lobby_id super().__init__( - f"User {user} can't create new Lobby because user is already in Lobby '{lobby_id}'" + ( + f"User '{user}' cannot create a new lobby because they are already " + f"in lobby '{existing_lobby_id}'" + ), + detail={ + "user": user, + "existing_lobby_id": existing_lobby_id, + "reason": "already_in_lobby", + }, ) - self.detail = { - "lobby_id": lobby_id, - "user": user.model_dump(mode="json"), - } class LobbyJoinError(LobbyError): - """Raised when a user can not join their requested lobby.""" + """Raised when a user cannot join the requested lobby.""" - def __init__(self, user: api.UserProfile, lobby_id: api.LobbyId, reason: str = ""): - super().__init__( - f"User {user} can't join Lobby '{lobby_id}' because '{reason}'." - ) - self.detail = { - "lobby_id": lobby_id, - "user": user.model_dump(mode="json"), - "reason": reason, - } + def __init__(self, *, user: api.UserProfile, lobby_id: api.LobbyId, reason: str | None = None): + self.user_id = user + self.lobby_id = lobby_id + self.reason = reason + msg = f"User '{user}' cannot join lobby '{lobby_id}'" + if reason: + msg += f": {reason}" + super().__init__(msg, detail={"lobby_id": lobby_id, "user": user, "reason": reason}) class LobbyLeaveError(LobbyError): - """Raised when a user can not leave their requested lobby.""" + """Raised when a user cannot leave the requested lobby.""" - def __init__(self, user: api.UserProfile, lobby_id: api.LobbyId, reason: str = ""): - super().__init__( - f"User {user} can't leave Lobby '{lobby_id}' because '{reason}'." - ) - self.detail = { - "lobby_id": lobby_id, - "user": user.model_dump(mode="json"), - "reason": reason, - } + def __init__(self, *, user: api.UserProfile, lobby_id: api.LobbyId, reason: str | None = None): + self.user_id = user + self.lobby_id = lobby_id + self.reason = reason + msg = f"User '{user}' cannot leave lobby '{lobby_id}'" + if reason: + msg += f": {reason}" + super().__init__(msg, detail={"lobby_id": lobby_id, "user": user, "reason": reason}) class LobbyStartError(LobbyError): - """Raised when a user a lobby can't be started""" + """Raised when a lobby cannot be started.""" - def __init__(self, user: api.UserProfile, lobby_id: api.LobbyId, reason: str = ""): - super().__init__( - f"User {user} can't start Lobby '{lobby_id}' because '{reason}'." - ) - self.detail = { - "lobby_id": lobby_id, - "user": user.model_dump(mode="json"), - "reason": reason, - } + def __init__(self, *, user: api.UserProfile, lobby_id: api.LobbyId, reason: str | None = None): + self.user_id = user + self.lobby_id = lobby_id + self.reason = reason + msg = f"User '{user}' cannot start lobby '{lobby_id}'" + if reason: + msg += f": {reason}" + super().__init__(msg, detail={"lobby_id": lobby_id, "user": user, "reason": reason}) +# ---------- Game errors ---------- + class GameError(Exception): - """Base exception for all lobby-related errors.""" + """Base exception for all game-related errors.""" - def __init__(self, message: str, detail: dict | None = None): + def __init__(self, message: str, *, detail: Mapping[str, Any] | None = None): super().__init__(message) - self.detail = detail if detail is not None else {} + self.detail: dict[str, Any] = dict(detail or {}) + +class IllegalMoveError(GameError, ValueError): + """Raised when a move violates game rules.""" -class IllegalMoveException(GameError): - def __init__(self, message: str, detail: dict | None = None): - super().__init__(message, detail) - self.message = message + def __init__(self, *, move: str | dict[str, Any], reason: str | None = None): + self.move = move + self.reason = reason + msg = "Illegal move" + # Keep message compact, attach specifics as attributes/detail. + if reason: + msg += f": {reason}" + super().__init__(msg, detail={"move": move, "reason": reason}) From 6604c89cc9f8943721cd090a8dadb1ad1fd28004 Mon Sep 17 00:00:00 2001 From: samlyme Date: Thu, 25 Sep 2025 15:36:01 -0700 Subject: [PATCH 003/279] update http status codes --- backend/app/routers/lobbies.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/app/routers/lobbies.py b/backend/app/routers/lobbies.py index 23880d7..55862b2 100644 --- a/backend/app/routers/lobbies.py +++ b/backend/app/routers/lobbies.py @@ -23,7 +23,7 @@ async def create_lobby(dep: CreateLobbyDep) -> api.LobbyProfile: try: return await dep() except LobbyCreateError as e: - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=e.detail) + raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=e.detail) @router.get("") @@ -43,7 +43,7 @@ async def join_lobby(user: CurrentUserDep, lobby: LobbyDep) -> api.LobbyProfile: return lobby.to_profile() # TODO: Refactor to use app-level exception handlers. except LobbyJoinError as e: - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=e.detail) + raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=e.detail) @router.post("/{lobby_id}/start") @@ -51,8 +51,10 @@ async def start_lobby(user: CurrentUserDep, lobby: LobbyDep) -> api.LobbyProfile try: await lobby.start(user) return lobby.to_profile() - except (LobbyPermissionError, LobbyStartError) as e: + except LobbyPermissionError as e: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=e.detail) + except LobbyStartError as e: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=e.detail) @router.post("/{lobby_id}/leave") From 31cf2fdb64b40575e3e32d64e16d31dc4c35af99 Mon Sep 17 00:00:00 2001 From: samlyme Date: Fri, 26 Sep 2025 00:16:20 -0700 Subject: [PATCH 004/279] Use dev shell script --- backend/dev.sh | 1 + 1 file changed, 1 insertion(+) create mode 100755 backend/dev.sh diff --git a/backend/dev.sh b/backend/dev.sh new file mode 100755 index 0000000..923c5d3 --- /dev/null +++ b/backend/dev.sh @@ -0,0 +1 @@ +uv run --package backend uvicorn backend.app.main:app --reload --port 8000 \ No newline at end of file From 0c6f1bf6412daeda7e8b6326088156a80a68c0c4 Mon Sep 17 00:00:00 2001 From: samlyme Date: Fri, 26 Sep 2025 00:27:26 -0700 Subject: [PATCH 005/279] Use balatro font --- frontend/src/App.css | 13 +++++++++++++ frontend/src/assets/fonts/balatro.otf.woff2 | Bin 0 -> 3764 bytes frontend/src/index.css | 3 +-- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 frontend/src/assets/fonts/balatro.otf.woff2 diff --git a/frontend/src/App.css b/frontend/src/App.css index cd66e5f..e75f973 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -5,6 +5,19 @@ text-align: center; } +@font-face { + font-family: 'Balatro'; + src: url('./assets/fonts/balatro.otf.woff2') format('woff2'); + font-weight: normal; + font-style: normal; +} + +body { + background-color: #F2F0EF; + color: #1E1E1E; + font-family: 'Balatro'; +} + /* make the container a flex row */ .game { display: flex; diff --git a/frontend/src/assets/fonts/balatro.otf.woff2 b/frontend/src/assets/fonts/balatro.otf.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..a7ceb34584e8af77fd282bbc36ba69a1759b8a45 GIT binary patch literal 3764 zcmV;l4omTOPew9NR8&s@01mVO2><{906ByJ01j&a0RR9100000000000000000000 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 Date: Fri, 26 Sep 2025 23:22:48 -0700 Subject: [PATCH 006/279] use balatro font --- frontend/index.html | 2 +- frontend/src/App.css | 46 +++++++++++++++++++++++-- frontend/src/App.tsx | 68 ++++++++++++++++--------------------- frontend/src/pages/Auth.tsx | 4 +-- frontend/src/pages/Home.tsx | 23 ++++++++----- 5 files changed, 91 insertions(+), 52 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index e4b78ea..9f963aa 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,7 @@ - Vite + React + TS + Auction Chess
diff --git a/frontend/src/App.css b/frontend/src/App.css index e75f973..b815310 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -13,11 +13,53 @@ } body { - background-color: #F2F0EF; - color: #1E1E1E; + background-color: #1E1E1E; + color: #F2F0EF; font-family: 'Balatro'; } +h1 { + font-size: 4rem; +} + +h2 { + font-size: 3.5rem; +} + +h3 { + font-size: 3rem; +} + +h4 { + font-size: 2.5rem; +} + +h5 { + font-size: 2rem; +} + +h6 { + font-size: 1.5rem; +} + +button { + margin: 1rem; + padding: 0.5rem; + border: none; + border-radius: 0.25rem; + color: #F2F0EF; + font-family: 'Balatro'; + font-size: large; +} + +.green { + background-color: #60BB64; +} + +.red { + background-color: #F35043; +} + /* make the container a flex row */ .game { display: flex; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 77fe93c..7ca53af 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -13,61 +13,53 @@ import LayoutWithHeader from "./layouts/LayoutWithHeader"; function App() { return ( // The wrapper divs are used for the sizing. -
-
-
- - - -
-
+
+ + +
- ) + ); } -function MainContext({ children }: { children: ReactNode}) { - return ( - - {children} - - ) +function MainContext({ children }: { children: ReactNode }) { + return {children}; } function ServerUpdatesContext({ children }: { children: ReactNode }) { - const {lobbyId} = useParams() + const { lobbyId } = useParams(); return ( - - {children} - - ) + {children} + ); } function Content() { return ( -
- - - }> - }/> - }/> - }/> - - }/> +
+ + + + } /> + } /> + + }> - } /> + + - }/> - - }/> + } + /> - - - -
+ } /> + +
+
+
); - } export default App; diff --git a/frontend/src/pages/Auth.tsx b/frontend/src/pages/Auth.tsx index fc3a782..9fd1b2b 100644 --- a/frontend/src/pages/Auth.tsx +++ b/frontend/src/pages/Auth.tsx @@ -12,9 +12,9 @@ function Auth() { return (
-

Login

+

Login

-

Signup

+

Signup

) diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index 721c3d6..4d00604 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -1,21 +1,26 @@ -import { Link, useNavigate } from "react-router"; -import { useEffect } from "react"; +import { Navigate, useNavigate } from "react-router"; import useAuth from "../hooks/useAuth"; function Home() { const { token } = useAuth(); + const navigate = useNavigate(); - useEffect(() => { - if (token) navigate("/lobbies") - }, [navigate, token]) + if (token) { + return + } return (
-

Welcome to Auction Chess

- -

login/signup

- +

Welcome to Auction Chess!

+ + +
+ A unique chess variant with pricing, bluffing, and illegal moves. +
+ + +
) } From fa97291116d32f0e97aee13e87e37983c98c4738 Mon Sep 17 00:00:00 2001 From: samlyme Date: Sat, 27 Sep 2025 00:14:20 -0700 Subject: [PATCH 007/279] import base ui --- frontend/bun.lock | 21 ++++ frontend/package.json | 1 + frontend/src/App.css | 14 +-- frontend/src/App.tsx | 4 +- frontend/src/index.module.css | 188 ++++++++++++++++++++++++++++++++++ frontend/src/pages/Auth.tsx | 156 ++++++++++++---------------- frontend/src/theme.css | 33 ++++++ 7 files changed, 316 insertions(+), 101 deletions(-) create mode 100644 frontend/src/index.module.css create mode 100644 frontend/src/theme.css diff --git a/frontend/bun.lock b/frontend/bun.lock index e2f7082..90ed6a0 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -4,6 +4,7 @@ "": { "name": "frontend", "dependencies": { + "@base-ui-components/react": "^1.0.0-beta.3", "@types/uuid": "^10.0.0", "jwt-decode": "^4.0.0", "react": "^19.1.0", @@ -27,6 +28,12 @@ }, }, "packages": { + "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], + + "@base-ui-components/react": ["@base-ui-components/react@1.0.0-beta.3", "", { "dependencies": { "@babel/runtime": "^7.28.3", "@base-ui-components/utils": "0.1.1", "@floating-ui/react-dom": "^2.1.6", "@floating-ui/utils": "^0.2.10", "reselect": "^5.1.1", "tabbable": "^6.2.0", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-4sAq6zmDA9ixV2HRjjeM1+tSEw5R6nvGjXUQmFoQnC3DZLEUdwO94gWDmUDdpoDuChn27jdbaJs9F0Ih4w2UAA=="], + + "@base-ui-components/utils": ["@base-ui-components/utils@0.1.1", "", { "dependencies": { "@babel/runtime": "^7.28.3", "@floating-ui/utils": "^0.2.10", "reselect": "^5.1.1", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-HWXZA8upEKgrdL1rQqxWu1H+2tB2cXzY2jCxvgnpUv3eoWN2jldhXxMZnXIjZF7jahGxSWXfSIM/qskiTWFFxA=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.25.5", "", { "os": "android", "cpu": "arm" }, "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA=="], @@ -95,6 +102,14 @@ "@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.2", "", { "dependencies": { "@eslint/core": "^0.15.0", "levn": "^0.4.1" } }, "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg=="], + "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.7.4", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="], + + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.6", "", { "dependencies": { "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], @@ -375,6 +390,8 @@ "react-router": ["react-router@7.6.2", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w=="], + "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], @@ -399,6 +416,8 @@ "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="], + "tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -413,6 +432,8 @@ "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="], + "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], "vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="], diff --git a/frontend/package.json b/frontend/package.json index 47f4642..0c95c7a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@base-ui-components/react": "^1.0.0-beta.3", "@types/uuid": "^10.0.0", "jwt-decode": "^4.0.0", "react": "^19.1.0", diff --git a/frontend/src/App.css b/frontend/src/App.css index b815310..4a78abc 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,4 +1,4 @@ -#root { +/* #root { max-width: 1280px; margin: 0 auto; padding: 2rem; @@ -10,13 +10,13 @@ src: url('./assets/fonts/balatro.otf.woff2') format('woff2'); font-weight: normal; font-style: normal; -} +} */ -body { +/* body { background-color: #1E1E1E; color: #F2F0EF; - font-family: 'Balatro'; -} + font-family: 'Balatro', 'Inter'; +} */ h1 { font-size: 4rem; @@ -42,7 +42,7 @@ h6 { font-size: 1.5rem; } -button { +/* button { margin: 1rem; padding: 0.5rem; border: none; @@ -58,7 +58,7 @@ button { .red { background-color: #F35043; -} +} */ /* make the container a flex row */ .game { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 7ca53af..558fd5d 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -34,7 +34,7 @@ function ServerUpdatesContext({ children }: { children: ReactNode }) { function Content() { return ( -
+ <> @@ -58,7 +58,7 @@ function Content() { -
+ ); } diff --git a/frontend/src/index.module.css b/frontend/src/index.module.css new file mode 100644 index 0000000..b4568e2 --- /dev/null +++ b/frontend/src/index.module.css @@ -0,0 +1,188 @@ + + +.Tabs { + border: 1px solid var(--color-gray-200); + border-radius: 0.375rem; +} + +.List { + display: flex; + position: relative; + z-index: 0; + padding-inline: 0.25rem; + gap: 0.25rem; + box-shadow: inset 0 -1px var(--color-gray-200); +} + +.Tab { + display: flex; + align-items: center; + justify-content: center; + border: 0; + margin: 0; + outline: 0; + background: none; + appearance: none; + color: var(--color-gray-600); + font-family: inherit; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 500; + user-select: none; + white-space: nowrap; + word-break: keep-all; + padding-inline: 0.5rem; + padding-block: 0; + height: 2rem; + + &[data-selected] { + color: var(--color-gray-900); + } + + @media (hover: hover) { + &:hover { + color: var(--color-gray-900); + } + } + + &:focus-visible { + position: relative; + + &::before { + content: ''; + position: absolute; + inset: 0.25rem 0; + border-radius: 0.25rem; + outline: 2px solid var(--color-blue); + outline-offset: -1px; + } + } +} + +.Indicator { + position: absolute; + z-index: -1; + left: 0; + top: 50%; + translate: var(--active-tab-left) -50%; + width: var(--active-tab-width); + height: 1.5rem; + border-radius: 0.25rem; + background-color: var(--color-gray-100); + transition-property: translate, width; + transition-duration: 200ms; + transition-timing-function: ease-in-out; +} + +.Panel { + position: relative; + display: flex; + align-items: center; + justify-content: center; + height: 8rem; + outline: 0; + + &:focus-visible { + outline: 2px solid var(--color-blue); + outline-offset: -1px; + border-radius: 0.375rem; + } + + &[hidden] { + display: none; + } +} + +.Icon { + width: 2.5rem; + height: 2.5rem; + color: var(--color-gray-300); +} + +.Form { + display: flex; + flex-direction: column; + gap: 1rem; + width: 100%; + max-width: 16rem; +} + +.Field { + display: flex; + flex-direction: column; + align-items: start; + gap: 0.25rem; +} + +.Label { + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 500; + color: var(--color-gray-900); +} + +.Input { + box-sizing: border-box; + padding-left: 0.875rem; + margin: 0; + border: 1px solid var(--color-gray-200); + width: 100%; + height: 2.5rem; + border-radius: 0.375rem; + font-family: inherit; + font-size: 1rem; + background-color: transparent; + color: var(--color-gray-900); + + &:focus { + outline: 2px solid var(--color-blue); + outline-offset: -1px; + } +} + +.Error { + font-size: 0.875rem; + line-height: 1.25rem; + color: var(--color-red-800); +} + +.Button { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + height: 2.5rem; + padding: 0 0.875rem; + margin: 0; + outline: 0; + border: 1px solid var(--color-gray-200); + border-radius: 0.375rem; + background-color: var(--color-gray-50); + font-family: inherit; + font-size: 1rem; + font-weight: 500; + line-height: 1.5rem; + color: var(--color-gray-900); + user-select: none; + + @media (hover: hover) { + &:hover { + background-color: var(--color-gray-100); + } + } + + &:active { + background-color: var(--color-gray-100); + } + + &:disabled { + cursor: not-allowed; + color: var(--color-gray-400); + background-color: var(--color-gray-100); + } + + &:focus-visible { + outline: 2px solid var(--color-blue); + outline-offset: -1px; + } +} diff --git a/frontend/src/pages/Auth.tsx b/frontend/src/pages/Auth.tsx index 9fd1b2b..5e8acc4 100644 --- a/frontend/src/pages/Auth.tsx +++ b/frontend/src/pages/Auth.tsx @@ -1,8 +1,11 @@ -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { useNavigate } from "react-router"; import useAuth from "../hooks/useAuth"; +import { Field, Form, Tabs } from "@base-ui-components/react"; -function Auth() { +import styles from "../index.module.css"; + +export default function Auth() { const { token } = useAuth(); const navigate = useNavigate(); @@ -12,106 +15,75 @@ function Auth() { return (
-

Login

- -

Signup

- + + + Login + Sign Up + + + + + + + + + + +
) } function Login() { - const [username, setUsername] = useState(''); - const [password, setPassword] = useState(''); - - const { login } = useAuth(); - - const handleSubmit = (event: React.FormEvent) => { - event.preventDefault(); - console.log('Attempting to log in with:'); - console.log('Username:', username); - console.log('Password:', password); - - login({ - username: username, - password: password, - }) - } - return ( -
-
-
- - setUsername(e.target.value)} + + + Username + -
-
- - setPassword(e.target.value)} + + + + Password + -
- -
-
- ); + + + + ) } -function SignUp() { - const [username, setUsername] = useState(''); - const [password, setPassword] = useState(''); - - const { signup } = useAuth(); - - const handleSubmit = (event: React.FormEvent) => { - event.preventDefault(); - console.log('Attempting to signup with:'); - console.log('Username:', username); - console.log('Password:', password); - - signup({ - username: username, - password: password, - }) - } - +function Signup() { return ( -
-
-
- - setUsername(e.target.value)} + + + Username + -
-
- - setPassword(e.target.value)} + Password + -
- -
-
- ); - -} -export default Auth; \ No newline at end of file + + + + + ) +} \ No newline at end of file diff --git a/frontend/src/theme.css b/frontend/src/theme.css new file mode 100644 index 0000000..1f83588 --- /dev/null +++ b/frontend/src/theme.css @@ -0,0 +1,33 @@ +:root { + --color-blue: oklch(45% 50% 264deg); + --color-red: oklch(50% 55% 31deg); + + --color-gray-50: oklch(98.42% 0.0034 247.86deg); + --color-gray-100: oklch(12% 9.5% 264deg / 5%); + --color-gray-200: oklch(12% 9% 264deg / 8%); + --color-gray-300: oklch(12% 8.5% 264deg / 17%); + --color-gray-400: oklch(12% 8% 264deg / 38%); + --color-gray-500: oklch(12% 7.5% 264deg / 50%); + --color-gray-600: oklch(12% 7% 264deg / 67%); + --color-gray-700: oklch(12% 6% 264deg / 77%); + --color-gray-800: oklch(12% 5% 264deg / 85%); + --color-gray-900: oklch(12% 5% 264deg / 90%); + --color-gray-950: oklch(12% 5% 264deg / 95%); + + @media (prefers-color-scheme: dark) { + --color-blue: oklch(69% 50% 264deg); + --color-red: oklch(80% 55% 31deg); + + --color-gray-50: oklch(17% 1% 264deg); + --color-gray-100: oklch(28% 3% 264deg / 65%); + --color-gray-200: oklch(31% 3% 264deg / 80%); + --color-gray-300: oklch(35% 3% 264deg / 80%); + --color-gray-400: oklch(47% 3.5% 264deg / 80%); + --color-gray-500: oklch(64% 4% 264deg / 80%); + --color-gray-600: oklch(82% 4% 264deg / 80%); + --color-gray-700: oklch(92% 4.5% 264deg / 80%); + --color-gray-800: oklch(93% 3.5% 264deg / 85%); + --color-gray-900: oklch(95% 2% 264deg / 90%); + --color-gray-950: oklch(94% 1.5% 264deg / 95%); + } +} From f158b9981f78f3e7eb2052a1484bf5c431301770 Mon Sep 17 00:00:00 2001 From: samlyme Date: Sun, 28 Sep 2025 13:19:13 -0700 Subject: [PATCH 008/279] update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6285193..1f4c8fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store .env *.o -__pycache__ \ No newline at end of file +__pycache__ +**.egg-info \ No newline at end of file From 4b88d5154a592dbd3f1318e4804762a89556bff7 Mon Sep 17 00:00:00 2001 From: samlyme Date: Sun, 28 Sep 2025 13:22:03 -0700 Subject: [PATCH 009/279] revert base ui --- frontend/index.html | 2 +- frontend/src/App.css | 48 ++------------------------ frontend/src/App.tsx | 68 +++++++++++++++++++++---------------- frontend/src/pages/Auth.tsx | 7 ++++ frontend/src/pages/Home.tsx | 23 +++++-------- 5 files changed, 58 insertions(+), 90 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 9f963aa..e4b78ea 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,7 @@ - Auction Chess + Vite + React + TS
diff --git a/frontend/src/App.css b/frontend/src/App.css index 4a78abc..d739bfa 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -12,54 +12,12 @@ font-style: normal; } */ -/* body { - background-color: #1E1E1E; - color: #F2F0EF; - font-family: 'Balatro', 'Inter'; -} */ - -h1 { - font-size: 4rem; -} - -h2 { - font-size: 3.5rem; -} - -h3 { - font-size: 3rem; -} - -h4 { - font-size: 2.5rem; -} - -h5 { - font-size: 2rem; -} - -h6 { - font-size: 1.5rem; -} - -/* button { - margin: 1rem; - padding: 0.5rem; - border: none; - border-radius: 0.25rem; - color: #F2F0EF; +body { + background-color: #F2F0EF; + color: #1E1E1E; font-family: 'Balatro'; - font-size: large; } -.green { - background-color: #60BB64; -} - -.red { - background-color: #F35043; -} */ - /* make the container a flex row */ .game { display: flex; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 558fd5d..77fe93c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -13,53 +13,61 @@ import LayoutWithHeader from "./layouts/LayoutWithHeader"; function App() { return ( // The wrapper divs are used for the sizing. -
- - - +
+
+
+ + + +
+
- ); + ) } -function MainContext({ children }: { children: ReactNode }) { - return {children}; +function MainContext({ children }: { children: ReactNode}) { + return ( + + {children} + + ) } function ServerUpdatesContext({ children }: { children: ReactNode }) { - const { lobbyId } = useParams(); + const {lobbyId} = useParams() return ( - {children} - ); + + {children} + + ) } function Content() { return ( - <> - - - - } /> - } /> - - }> +
+ + + }> + }/> + }/> + }/> + + }/> - } /> - - - } - /> + }/> + + }/> - } /> - - - - + + + +
); + } export default App; diff --git a/frontend/src/pages/Auth.tsx b/frontend/src/pages/Auth.tsx index 5e8acc4..ae4423b 100644 --- a/frontend/src/pages/Auth.tsx +++ b/frontend/src/pages/Auth.tsx @@ -15,6 +15,7 @@ export default function Auth() { return (
+<<<<<<< HEAD Login @@ -30,6 +31,12 @@ export default function Auth() { +======= +

Login

+ +

Signup

+ +>>>>>>> parent of 76144dd (use balatro font)
) } diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index 4d00604..721c3d6 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -1,26 +1,21 @@ -import { Navigate, useNavigate } from "react-router"; +import { Link, useNavigate } from "react-router"; +import { useEffect } from "react"; import useAuth from "../hooks/useAuth"; function Home() { const { token } = useAuth(); - const navigate = useNavigate(); - if (token) { - return - } + useEffect(() => { + if (token) navigate("/lobbies") + }, [navigate, token]) return (
-

Welcome to Auction Chess!

- - -
- A unique chess variant with pricing, bluffing, and illegal moves. -
- - - +

Welcome to Auction Chess

+ +

login/signup

+
) } From 99f2bd931bb64454a37948fe95eb03d3859ba614 Mon Sep 17 00:00:00 2001 From: samlyme Date: Sun, 28 Sep 2025 13:23:56 -0700 Subject: [PATCH 010/279] remove baseui --- frontend/bun.lock | 21 --------------------- frontend/package.json | 1 - 2 files changed, 22 deletions(-) diff --git a/frontend/bun.lock b/frontend/bun.lock index 90ed6a0..e2f7082 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -4,7 +4,6 @@ "": { "name": "frontend", "dependencies": { - "@base-ui-components/react": "^1.0.0-beta.3", "@types/uuid": "^10.0.0", "jwt-decode": "^4.0.0", "react": "^19.1.0", @@ -28,12 +27,6 @@ }, }, "packages": { - "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], - - "@base-ui-components/react": ["@base-ui-components/react@1.0.0-beta.3", "", { "dependencies": { "@babel/runtime": "^7.28.3", "@base-ui-components/utils": "0.1.1", "@floating-ui/react-dom": "^2.1.6", "@floating-ui/utils": "^0.2.10", "reselect": "^5.1.1", "tabbable": "^6.2.0", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-4sAq6zmDA9ixV2HRjjeM1+tSEw5R6nvGjXUQmFoQnC3DZLEUdwO94gWDmUDdpoDuChn27jdbaJs9F0Ih4w2UAA=="], - - "@base-ui-components/utils": ["@base-ui-components/utils@0.1.1", "", { "dependencies": { "@babel/runtime": "^7.28.3", "@floating-ui/utils": "^0.2.10", "reselect": "^5.1.1", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-HWXZA8upEKgrdL1rQqxWu1H+2tB2cXzY2jCxvgnpUv3eoWN2jldhXxMZnXIjZF7jahGxSWXfSIM/qskiTWFFxA=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.25.5", "", { "os": "android", "cpu": "arm" }, "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA=="], @@ -102,14 +95,6 @@ "@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.2", "", { "dependencies": { "@eslint/core": "^0.15.0", "levn": "^0.4.1" } }, "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg=="], - "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], - - "@floating-ui/dom": ["@floating-ui/dom@1.7.4", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="], - - "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.6", "", { "dependencies": { "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw=="], - - "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], - "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], @@ -390,8 +375,6 @@ "react-router": ["react-router@7.6.2", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w=="], - "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], - "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], @@ -416,8 +399,6 @@ "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="], - "tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -432,8 +413,6 @@ "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - "use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="], - "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], "vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="], diff --git a/frontend/package.json b/frontend/package.json index 0c95c7a..47f4642 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,7 +10,6 @@ "preview": "vite preview" }, "dependencies": { - "@base-ui-components/react": "^1.0.0-beta.3", "@types/uuid": "^10.0.0", "jwt-decode": "^4.0.0", "react": "^19.1.0", From 2a0ae59107273daeff100a190108536e4a57d717 Mon Sep 17 00:00:00 2001 From: samlyme Date: Sun, 28 Sep 2025 13:25:50 -0700 Subject: [PATCH 011/279] revert auth page --- frontend/src/pages/Auth.tsx | 159 ++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 69 deletions(-) diff --git a/frontend/src/pages/Auth.tsx b/frontend/src/pages/Auth.tsx index ae4423b..9fd1b2b 100644 --- a/frontend/src/pages/Auth.tsx +++ b/frontend/src/pages/Auth.tsx @@ -1,11 +1,8 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useNavigate } from "react-router"; import useAuth from "../hooks/useAuth"; -import { Field, Form, Tabs } from "@base-ui-components/react"; -import styles from "../index.module.css"; - -export default function Auth() { +function Auth() { const { token } = useAuth(); const navigate = useNavigate(); @@ -15,82 +12,106 @@ export default function Auth() { return (
-<<<<<<< HEAD - - - Login - Sign Up - - - - - - - - - - - -======= -

Login

+

Login

-

Signup

+

Signup

->>>>>>> parent of 76144dd (use balatro font)
) } function Login() { + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + + const { login } = useAuth(); + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + console.log('Attempting to log in with:'); + console.log('Username:', username); + console.log('Password:', password); + + login({ + username: username, + password: password, + }) + } + return ( -
- - Username - + +
+ + setUsername(e.target.value)} /> - - - - Password - +
+ + setPassword(e.target.value)} /> - - - - ) +
+ + +
+ ); } -function Signup() { +function SignUp() { + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + + const { signup } = useAuth(); + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + console.log('Attempting to signup with:'); + console.log('Username:', username); + console.log('Password:', password); + + signup({ + username: username, + password: password, + }) + } + return ( -
- - Username - + +
+ + setUsername(e.target.value)} /> - Password - +
+ + setPassword(e.target.value)} /> - - - - - ) -} \ No newline at end of file +
+ + +
+ ); + +} +export default Auth; \ No newline at end of file From 6dba36a4334c0a56832a2fb4bbc3d9b871214c84 Mon Sep 17 00:00:00 2001 From: samlyme Date: Sun, 28 Sep 2025 13:31:37 -0700 Subject: [PATCH 012/279] Home and Auth page no longer have header --- frontend/src/App.tsx | 56 ++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 77fe93c..f2c1b5e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -17,57 +17,51 @@ function App() {
- +
- ) + ); } -function MainContext({ children }: { children: ReactNode}) { - return ( - - {children} - - ) +function MainContext({ children }: { children: ReactNode }) { + return {children}; } function ServerUpdatesContext({ children }: { children: ReactNode }) { - const {lobbyId} = useParams() + const { lobbyId } = useParams(); return ( - - {children} - - ) + {children} + ); } function Content() { return ( -
- - - }> - }/> - }/> - }/> - - }/> +
+ + + } /> + } /> + } /> + }> + } /> - - }/> - - }/> + } + /> - - - -
+ } /> + +
+
+
); - } export default App; From 94f373b6f749c020aa350d59d91f09a2a3880d69 Mon Sep 17 00:00:00 2001 From: samlyme Date: Sun, 28 Sep 2025 13:32:07 -0700 Subject: [PATCH 013/279] flip position of opponent and player bid --- frontend/src/components/Menu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Menu.tsx b/frontend/src/components/Menu.tsx index 9e114d5..9aac780 100644 --- a/frontend/src/components/Menu.tsx +++ b/frontend/src/components/Menu.tsx @@ -135,8 +135,8 @@ function BiddingMenu() { className={`bidding-menu ${game.phase === "move" ? "lowlight" : ""}`} onSubmit={handleSubmit} > -

Your bid: ${userLastBidAmount}

Opponent bid: ${opponentLastBidAmount}

+

Your bid: ${userLastBidAmount}