diff --git a/backend/entities/game.ts b/backend/entities/game.ts index b5f4508..d0850f6 100644 --- a/backend/entities/game.ts +++ b/backend/entities/game.ts @@ -291,6 +291,7 @@ export const game = { if (finished) return; if (!isValid(serverGame, x, y)) return; if (isRevealed[x][y]) return; + serverGame.isFlagged[x][y] = false; serverGame.isQuestionMark[x][y] = true; }, clearTile: (serverGame: ServerGame, x: number, y: number) => { diff --git a/bun.lockb b/bun.lockb index 7959471..29a569c 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 8d19e37..a64205a 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-popover": "^1.1.1", + "@radix-ui/react-switch": "^1.1.0", "@tailwindcss/vite": "^4.0.0-alpha.24", "@tanstack/react-query": "^5.56.2", "@tanstack/react-query-devtools": "^5.0.0-alpha.91", diff --git a/src/Shell.tsx b/src/Shell.tsx index 54f79fa..1431f9a 100644 --- a/src/Shell.tsx +++ b/src/Shell.tsx @@ -6,6 +6,7 @@ import Hr from "./components/Hr"; import NavLink from "./components/NavLink"; import { useMediaQuery } from "@uidotdev/usehooks"; import Header from "./components/Header"; +import { Tag } from "./components/Tag"; const drawerWidth = 256; const drawerWidthWithPadding = drawerWidth; @@ -67,7 +68,7 @@ const Shell: React.FC = ({ children }) => { - Settings + Settings NEW
diff --git a/src/components/Auth/LoginButton.tsx b/src/components/Auth/LoginButton.tsx index 0be97c4..7acbee6 100644 --- a/src/components/Auth/LoginButton.tsx +++ b/src/components/Auth/LoginButton.tsx @@ -13,6 +13,7 @@ import { useWSMutation } from "../../hooks"; import { useAtom } from "jotai"; import { loginTokenAtom } from "../../atoms"; import PasswordInput from "./PasswordInput"; +import { wsClient } from "../../wsClient"; const LoginButton = () => { const [isOpen, setIsOpen] = useState(false); @@ -57,8 +58,11 @@ const LoginButton = () => { onClick={() => { login .mutateAsync({ username, password }) - .then((res) => { + .then(async (res) => { setToken(res.token); + await wsClient.dispatch("user.loginWithToken", { + token: JSON.parse(res.token), + }); queryClient.invalidateQueries(); }) .catch((e) => { diff --git a/src/components/Auth/RegisterButton.tsx b/src/components/Auth/RegisterButton.tsx index ceacb32..6936842 100644 --- a/src/components/Auth/RegisterButton.tsx +++ b/src/components/Auth/RegisterButton.tsx @@ -13,6 +13,7 @@ import { useAtom } from "jotai"; import { loginTokenAtom } from "../../atoms"; import { useQueryClient } from "@tanstack/react-query"; import PasswordInput from "./PasswordInput"; +import { wsClient } from "../../wsClient"; const RegisterButton = () => { const [isOpen, setIsOpen] = useState(false); @@ -57,8 +58,11 @@ const RegisterButton = () => { onClick={() => { register .mutateAsync({ username, password }) - .then((res) => { + .then(async (res) => { setToken(res.token); + await wsClient.dispatch("user.loginWithToken", { + token: JSON.parse(res.token), + }); queryClient.invalidateQueries(); }) .catch((e) => { diff --git a/src/components/Board.tsx b/src/components/Board.tsx index d0745e5..f4eeea0 100644 --- a/src/components/Board.tsx +++ b/src/components/Board.tsx @@ -239,11 +239,12 @@ const Tile = ({ : false; const isFlagged = game.isFlagged[i][j]; const isQuestionMark = game.isQuestionMark[i][j]; - const base = isRevealed ? ( - - ) : ( - - ); + const base = + isRevealed || isMine ? ( + + ) : ( + + ); const extra = isLastPos ? : null; const touchStart = useRef(0); const isMove = useRef(false); diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx new file mode 100644 index 0000000..e6e26cc --- /dev/null +++ b/src/components/Switch.tsx @@ -0,0 +1,28 @@ +"use client"; + +import * as React from "react"; +import * as SwitchPrimitives from "@radix-ui/react-switch"; +import { cn } from "../lib/utils"; + +const Switch = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +Switch.displayName = SwitchPrimitives.Root.displayName; + +export { Switch }; diff --git a/src/components/Tag.tsx b/src/components/Tag.tsx index d88c5ea..4d86321 100644 --- a/src/components/Tag.tsx +++ b/src/components/Tag.tsx @@ -16,7 +16,7 @@ const tagVariants = cva("font-semibold py-2 px-4 rounded-md flex gap-2", { }, size: { default: "h-10 py-2 px-4", - sm: "h-9 px-3 rounded-md", + sm: "h-7 py-2 px-2 rounded-md text-xs", lg: "h-11 px-8 rounded-md", }, }, diff --git a/src/index.css b/src/index.css index 413761b..8717290 100644 --- a/src/index.css +++ b/src/index.css @@ -1,7 +1,9 @@ @import "tailwindcss"; @theme { - --color-primary: rgb(251, 21, 242); + --color-primary: #D9AFD9; + --color-input: color-mix(in srgb, var(--color-white, #fff) 20%, transparent); + --color-background: black; --bg-brand: -webkit-linear-gradient(225deg, rgb(251, 175, 21), rgb(251, 21, 242), rgb(21, 198, 251)) 0% 0% / 100% 300%; --bg-secondary: linear-gradient(90deg, #D9AFD9 0%, #97D9E1 100%) 0% 0% / 100% 300%; diff --git a/src/main.tsx b/src/main.tsx index 3521dd5..72f83b4 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -11,6 +11,7 @@ import { Route, Switch } from "wouter"; import Endless from "./views/endless/Endless.tsx"; import { queryClient } from "./queryClient.ts"; import Home from "./views/home/Home.tsx"; +import Settings from "./views/settings/Settings.tsx"; connectWS(); @@ -43,12 +44,7 @@ setup().then(() => {

Comming Soon

)} /> - ( -

Comming Soon

- )} - /> + {/* */} diff --git a/src/views/endless/Endless.tsx b/src/views/endless/Endless.tsx index c43a1f4..2acb9a8 100644 --- a/src/views/endless/Endless.tsx +++ b/src/views/endless/Endless.tsx @@ -22,6 +22,7 @@ const Endless = () => { setGameId(undefined); }; }, [setGameId]); + console.log("set", setGameId); return game ? ( <> diff --git a/src/views/settings/Settings.tsx b/src/views/settings/Settings.tsx new file mode 100644 index 0000000..878073f --- /dev/null +++ b/src/views/settings/Settings.tsx @@ -0,0 +1,71 @@ +import { ReactNode } from "react"; +import { Switch } from "../../components/Switch"; +import { useWSMutation, useWSQuery } from "../../hooks"; + +interface BoolSettingProps { + label: string; + description: ReactNode; + value: boolean; + onChange: (value: boolean) => void; +} + +const BoolSetting: React.FC = ({ + label, + description, + value, + onChange, +}) => ( +
+
+ +

{description}

+
+ +
+); + +const Settings = () => { + const { data: settings, refetch } = useWSQuery("user.getSettings", null); + const updateSettings = useWSMutation("user.updateSettings"); + + return ( +
+
+

Settings

+
+ + You can place a question mark on a tile after placing a flag. +
+ Just right click again on the tile. + + } + value={settings?.placeQuestionMark ?? false} + onChange={async (value) => { + await updateSettings.mutateAsync({ placeQuestionMark: value }); + refetch(); + }} + /> + + You can long press on a tile to reveal it. This is useful for + touch devices. + + } + value={settings?.longPressOnDesktop ?? false} + onChange={async (value) => { + updateSettings.mutateAsync({ longPressOnDesktop: value }); + refetch(); + }} + /> +
+
+
+ ); +}; + +export default Settings;