added settings

This commit is contained in:
MasterGordon 2024-09-29 20:35:48 +02:00
parent 0b251c566c
commit 99e7325edb
13 changed files with 126 additions and 16 deletions

View File

@ -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) => {

BIN
bun.lockb

Binary file not shown.

View File

@ -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",

View File

@ -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<PropsWithChildren> = ({ children }) => {
</NavLink>
<NavLink href="/settings">
<Settings />
Settings
Settings <Tag size="sm">NEW</Tag>
</NavLink>
<Hr />
<div className="grow" />

View File

@ -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) => {

View File

@ -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) => {

View File

@ -239,7 +239,8 @@ const Tile = ({
: false;
const isFlagged = game.isFlagged[i][j];
const isQuestionMark = game.isQuestionMark[i][j];
const base = isRevealed ? (
const base =
isRevealed || isMine ? (
<Sprite key="b" texture={theme.revealed} />
) : (
<Sprite key="b" texture={theme.tile} />

28
src/components/Switch.tsx Normal file
View File

@ -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<typeof SwitchPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className,
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
)}
/>
</SwitchPrimitives.Root>
));
Switch.displayName = SwitchPrimitives.Root.displayName;
export { Switch };

View File

@ -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",
},
},

View File

@ -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%;

View File

@ -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(() => {
<h2 className="text-white/80 text-2xl">Comming Soon</h2>
)}
/>
<Route
path="/settings"
component={() => (
<h2 className="text-white/80 text-2xl">Comming Soon</h2>
)}
/>
<Route path="/settings" component={Settings} />
</Switch>
{/* <App /> */}
</Shell>

View File

@ -22,6 +22,7 @@ const Endless = () => {
setGameId(undefined);
};
}, [setGameId]);
console.log("set", setGameId);
return game ? (
<>

View File

@ -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<BoolSettingProps> = ({
label,
description,
value,
onChange,
}) => (
<div className="flex border-white/20 border-1 text-white/80 p-4 rounded-md justify-between items-end">
<div className="flex gap-4 flex-col">
<label className="text-white/90 text-lg">{label}</label>
<p className="text-white/70 text-sm">{description}</p>
</div>
<Switch checked={value} onCheckedChange={onChange} />
</div>
);
const Settings = () => {
const { data: settings, refetch } = useWSQuery("user.getSettings", null);
const updateSettings = useWSMutation("user.updateSettings");
return (
<div className="w-full">
<div className="max-w-[650px] mx-auto flex flex-col gap-8">
<h2 className="text-white/90 text-xl">Settings</h2>
<div className="flex flex-col gap-4 ">
<BoolSetting
label="Place Question Mark"
description={
<>
You can place a question mark on a tile after placing a flag.
<br />
Just right click again on the tile.
</>
}
value={settings?.placeQuestionMark ?? false}
onChange={async (value) => {
await updateSettings.mutateAsync({ placeQuestionMark: value });
refetch();
}}
/>
<BoolSetting
label="Long Press On Desktop"
description={
<>
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();
}}
/>
</div>
</div>
</div>
);
};
export default Settings;