From 3d6164fcf57c0013dc54af35d124e64c169a3d3c Mon Sep 17 00:00:00 2001 From: Jack Papel Date: Fri, 27 Dec 2024 02:16:05 -0800 Subject: [PATCH 01/15] UI changes to benefit mobile --- client/src/components/DetailsSummary.tsx | 4 +- client/src/components/TextAreaDropdown.tsx | 35 +++++---- client/src/components/detailsSummary.css | 19 +++-- client/src/components/dragAndDrop.css | 3 +- .../EnabledModifiersDisplay.tsx | 77 ------------------ .../EnabledModifiersSelector.tsx | 78 +++++++++++++++++++ .../gameModeSettings/EnabledRoleSelector.tsx | 10 +-- .../gameModeSettings/GameModeSelector.tsx | 2 +- .../gameModeSettings/GameModesEditor.tsx | 4 +- .../gameModeSettings/OutlineSelector.tsx | 29 ++++--- .../gameModeSettings/PhaseTimeSelector.tsx | 41 +++++----- .../gameModeSettings/disabledRoleSelector.css | 4 +- .../gameModeSettings/outlineSelector.css | 1 + .../gameModeSettings/phaseTimeSelector.css | 10 +-- client/src/components/textAreaDropdown.css | 19 ++--- client/src/index.css | 4 +- client/src/menu/anchor.css | 4 +- client/src/menu/game/GameScreen.tsx | 9 ++- client/src/menu/game/HeaderMenu.tsx | 4 +- client/src/menu/game/gameScreen.css | 6 ++ .../AbilityMenu/AbilityMenu.tsx | 4 +- .../AbilityMenu/abilityMenu.css | 4 + .../AbilityMenu/genericAbilityMenu.css | 5 -- .../game/gameScreenContent/GraveyardMenu.tsx | 11 ++- .../menu/game/gameScreenContent/WillMenu.tsx | 2 +- .../game/gameScreenContent/graveyardMenu.css | 9 +-- .../menu/game/gameScreenContent/willMenu.css | 35 --------- client/src/menu/game/headerMenu.css | 18 +++-- client/src/menu/globalMenu.css | 4 +- client/src/menu/lobby/LobbyMenu.tsx | 48 ++++++------ client/src/menu/lobby/lobbyMenu.css | 61 +++++++-------- client/src/resources/lang/en_us.json | 2 +- server/src/lobby/on_client_message.rs | 2 +- 33 files changed, 277 insertions(+), 291 deletions(-) delete mode 100644 client/src/components/gameModeSettings/EnabledModifiersDisplay.tsx create mode 100644 client/src/components/gameModeSettings/EnabledModifiersSelector.tsx diff --git a/client/src/components/DetailsSummary.tsx b/client/src/components/DetailsSummary.tsx index 92202cf28..2fa242b86 100644 --- a/client/src/components/DetailsSummary.tsx +++ b/client/src/components/DetailsSummary.tsx @@ -24,7 +24,7 @@ export default function DetailsSummary(props: Readonly<{ }, [props.open, openState, props.disabled]); return
-
{ if(props.disabled) return; setOpen(!open); @@ -33,7 +33,7 @@ export default function DetailsSummary(props: Readonly<{ > {(props.dropdownArrow === undefined || props.dropdownArrow === true) ? ((props.disabled === undefined || props.disabled===false) ? - {open ? "expand_more" : "expand_less"} + {open ? "keyboard_arrow_down" : "keyboard_arrow_right"} : close ) : diff --git a/client/src/components/TextAreaDropdown.tsx b/client/src/components/TextAreaDropdown.tsx index 84d425acb..7d5297c8b 100644 --- a/client/src/components/TextAreaDropdown.tsx +++ b/client/src/components/TextAreaDropdown.tsx @@ -7,11 +7,13 @@ import { Button } from "./Button"; import Icon from "./Icon"; import translate from "../game/lang"; import "./textAreaDropdown.css"; +import DetailsSummary from "./DetailsSummary"; export function TextDropdownArea(props: Readonly<{ titleString: string, savedText: string, open?: boolean, + dropdownArrow?: boolean, onAdd?: () => void, onSubtract?: () => void, onSave: (text: string) => void, @@ -37,18 +39,20 @@ export function TextDropdownArea(props: Readonly<{ } return ( -
- - - + } + > {unsaved ? "Unsaved" : ""} -
+ ) } @@ -144,11 +148,12 @@ function PrettyTextArea(props: Readonly<{ const [writing, setWriting] = useState(false); const [hover, setHover] = useState(false); - return
setHover(true)} onMouseLeave={() => setHover(false)} + onTouchEnd={() => setWriting(true)} onFocus={() => setWriting(true)} - onBlur={() => setWriting(false)} + onBlur={() => {setWriting(false); setHover(false)}} > {(!writing && !hover) ?
diff --git a/client/src/components/detailsSummary.css b/client/src/components/detailsSummary.css index 6d5152ba1..c42d88b41 100644 --- a/client/src/components/detailsSummary.css +++ b/client/src/components/detailsSummary.css @@ -5,19 +5,24 @@ align-items: center; background-color: var(--primary-color); - border: .13rem solid var(--primary-border-color); - border-bottom-color: var(--primary-border-shadow-color); - border-right-color: var(--primary-border-shadow-color); - margin: .13rem; - padding: .13rem; border-radius: .5rem; + padding: .13rem; +} +.details-summary-summary-container.open { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom: .13rem solid var(--primary-border-shadow-color); } .details-summary-container{ display: flex; flex-direction: column; - width: 100%; - margin: 0; + margin: .13rem; padding: 0; + background-color: var(--secondary-color); + border: .13rem solid var(--primary-border-color); + border-bottom-color: var(--primary-border-shadow-color); + border-right-color: var(--primary-border-shadow-color); + border-radius: 0.5rem; /* justify-content: left; align-items: center; */ } \ No newline at end of file diff --git a/client/src/components/dragAndDrop.css b/client/src/components/dragAndDrop.css index 595212c2e..d95c16212 100644 --- a/client/src/components/dragAndDrop.css +++ b/client/src/components/dragAndDrop.css @@ -1,5 +1,6 @@ div.draggable { - cursor: grab + cursor: grab; + touch-action: none; } div.draggable.dragged { diff --git a/client/src/components/gameModeSettings/EnabledModifiersDisplay.tsx b/client/src/components/gameModeSettings/EnabledModifiersDisplay.tsx deleted file mode 100644 index 11f65ee49..000000000 --- a/client/src/components/gameModeSettings/EnabledModifiersDisplay.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { ReactElement, useContext } from "react"; -import { MODIFIERS, ModifierType } from "../../game/gameState.d"; -import React from "react"; -import translate from "../../game/lang"; -import StyledText from "../StyledText"; -import { GameModeContext } from "./GameModesEditor"; -import Select, { SelectOptionsSearch } from "../Select"; - -export function EnabledModifiersDisplay(props: { - disabled: boolean, - enabledModifiers?: ModifierType[], - onChange?: (modifiers: ModifierType[]) => void, -}): ReactElement { - let {enabledModifiers} = useContext(GameModeContext); - - enabledModifiers = props.enabledModifiers ?? (enabledModifiers as ModifierType[]); - - const dropdownsSelected = props.disabled === true ? enabledModifiers : (enabledModifiers as (ModifierType | null)[]).concat([null]) - - return
-

{translate("modifiers")}

- {dropdownsSelected.map((currentModifier, index) => { - return !enabledModifiers.includes(m)||m===currentModifier) - } - onChange={newModifier => { - if (props.onChange === undefined) - return; - - let currentModifiers: (ModifierType | null)[] = [...enabledModifiers]; - currentModifiers.splice(index, 1, newModifier); - - //make sure to remove duplicates & null - const out = currentModifiers - .filter((value, index, self) => self.indexOf(value) === index) - .filter(modifier => modifier !== null) as ModifierType[]; - - props.onChange(out); - }} - /> - - })} -
-} - -function EnabledModifierDisplay(props: { - modifier: ModifierType | null, - choosableModifiers?: ModifierType[], - disabled: boolean, - onChange: (modifier: ModifierType | null) => void, -}): ReactElement { - - const optionMap: SelectOptionsSearch = new Map(); - optionMap.set("none", [ - {translate("none")}, - translate("none") - ]); - for (let modifier of (props.choosableModifiers ?? MODIFIERS)) { - optionMap.set(modifier, [ - {translate(modifier)}, - translate(modifier) - ]); - } - - return { - const value = Number(e.target.value); + {props.disabled + ? props.time + : { + const value = Number(e.target.value); - if (!isValidPhaseTime(value)) return - - props.onChange(props.phase, value); - - }} - onKeyUp={(e)=>{ - if(e.key !== 'Enter') return; - - props.onChange(props.phase, props.time); - }} - /> + if (!isValidPhaseTime(value)) return + + props.onChange(props.phase, value); + + }} + onKeyUp={(e)=>{ + if(e.key !== 'Enter') return; + + props.onChange(props.phase, props.time); + }} + /> + }
} \ No newline at end of file diff --git a/client/src/components/gameModeSettings/disabledRoleSelector.css b/client/src/components/gameModeSettings/disabledRoleSelector.css index 4d1c79417..e8b81c953 100644 --- a/client/src/components/gameModeSettings/disabledRoleSelector.css +++ b/client/src/components/gameModeSettings/disabledRoleSelector.css @@ -12,7 +12,7 @@ flex-grow: 1; width: 5rem; } -.disabled-role-element { +.placard { display: inline-block; background-color: var(--primary-color); border: .13rem solid var(--primary-border-color); @@ -21,6 +21,6 @@ border-radius: .25rem; white-space: pre; } -.disabled-role-element.disabled { +.placard.disabled { background-color: var(--secondary-color); } \ No newline at end of file diff --git a/client/src/components/gameModeSettings/outlineSelector.css b/client/src/components/gameModeSettings/outlineSelector.css index 3d8134c37..d20db8d87 100644 --- a/client/src/components/gameModeSettings/outlineSelector.css +++ b/client/src/components/gameModeSettings/outlineSelector.css @@ -40,6 +40,7 @@ align-items:center; gap: .25rem; display: flex; + overflow-x: auto; } .role-list-setter-add-button-div { justify-content: center; diff --git a/client/src/components/gameModeSettings/phaseTimeSelector.css b/client/src/components/gameModeSettings/phaseTimeSelector.css index 5196e056f..d772649e2 100644 --- a/client/src/components/gameModeSettings/phaseTimeSelector.css +++ b/client/src/components/gameModeSettings/phaseTimeSelector.css @@ -2,7 +2,6 @@ max-height: 50vh; overflow-y: auto; display: flex; - gap: .25rem; flex-direction: row; flex-wrap: wrap; margin-bottom: 0.25rem; @@ -12,20 +11,15 @@ display: flex; flex-basis: 11rem; flex-grow: 1; - border: .13rem solid var(--primary-border-color); background-color: var(--secondary-color); - border-radius: 0.5rem; align-items: center; justify-content: space-between; } .phase-times-selector > .phase-times > div > span { - margin: 0 .25rem; white-space: pre; } .phase-times-selector > .phase-times > div > input { - border-top-color: var(--primary-border-shadow-color); - border-left-color: var(--primary-border-shadow-color); - border-bottom-color: var(--primary-border-color); - border-right-color: var(--primary-border-color); width: 3rem; + margin: 0; + padding: 0; } \ No newline at end of file diff --git a/client/src/components/textAreaDropdown.css b/client/src/components/textAreaDropdown.css index 094d925ef..e42eeb9ee 100644 --- a/client/src/components/textAreaDropdown.css +++ b/client/src/components/textAreaDropdown.css @@ -1,28 +1,29 @@ -.text-area-dropdown details > div { - padding: .13rem; +.pretty-text-area { + display: flex; + flex-direction: column; + align-items: stretch; } .text-area-dropdown .textarea, .text-area-dropdown textarea { text-align: left; height: 20rem; - width: 100%; - margin: 0; + margin: .13rem; text-wrap: wrap; + resize: none; } .text-area-dropdown .textarea > * { text-wrap: pretty; } -.text-area-dropdown summary > div { - display: inline-flex; +.text-area-dropdown .details-summary-summary-container > div { + display: flex; width: 100%; flex-direction: row; flex-wrap: wrap; + padding-left: .25rem; justify-content: space-between; text-align: left; align-items: baseline; - /* This is a little hacky. This whole thing is a little hacky.*/ - padding-right: .75rem; } -.text-area-dropdown summary > div > div { +.text-area-dropdown .details-summary-summary-container > div > div { display:flex; flex-wrap: wrap; gap: 0.25rem; diff --git a/client/src/index.css b/client/src/index.css index 0abeda3aa..070ea4c46 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -177,8 +177,8 @@ button, select, summary { user-select: none; } input, option, textarea, .textarea { - border-top-color: var(--background-border-shadow-color); - border-left-color: var(--background-border-shadow-color); + border-top-color: var(--primary-border-shadow-color); + border-left-color: var(--primary-border-shadow-color); } :has(input):focus-within > button.clear { diff --git a/client/src/menu/anchor.css b/client/src/menu/anchor.css index ea3c3eb8e..039650f04 100644 --- a/client/src/menu/anchor.css +++ b/client/src/menu/anchor.css @@ -67,8 +67,8 @@ .anchor .global-menu-button { z-index: 101; position: fixed; - right: .2rem; - top: .2rem; + right: .25rem; + top: .25rem; height: fit-content; width: fit-content; font-size: 1.5rem; diff --git a/client/src/menu/game/GameScreen.tsx b/client/src/menu/game/GameScreen.tsx index 16f236527..5f3dcea59 100644 --- a/client/src/menu/game/GameScreen.tsx +++ b/client/src/menu/game/GameScreen.tsx @@ -1,5 +1,5 @@ import React, { createContext, ReactElement, useCallback, useContext, useEffect, useState } from "react"; -import HeaderMenu from "./HeaderMenu"; +import HeaderMenu, { MenuButtons } from "./HeaderMenu"; import GraveyardMenu from "./gameScreenContent/GraveyardMenu"; import ChatMenu from "./gameScreenContent/ChatMenu"; import PlayerListMenu from "./gameScreenContent/PlayerListMenu"; @@ -198,6 +198,7 @@ export default function GameScreen(): ReactElement {
+ {mobile && }
} @@ -225,11 +226,11 @@ export function GameScreenMenus(): ReactElement { className="panel" minSize={minSize} defaultSize={mobile===false?defaultSizes[menu]:undefined} - key={index} - > + key={menu} + > - {menusOpen.some((_, i) => i > index) && } + {!mobile && menusOpen.some((_, i) => i > index) && } })} {menuController.menusOpen().length === 0 &&
diff --git a/client/src/menu/game/HeaderMenu.tsx b/client/src/menu/game/HeaderMenu.tsx index d1e747684..d94a56cf1 100644 --- a/client/src/menu/game/HeaderMenu.tsx +++ b/client/src/menu/game/HeaderMenu.tsx @@ -30,7 +30,7 @@ export default function HeaderMenu(props: Readonly<{ return
{!(GAME_MANAGER.getMySpectator() && !GAME_MANAGER.getMyHost()) && } - {!(GAME_MANAGER.getMySpectator() && !mobile) && } + {!GAME_MANAGER.getMySpectator() && !mobile && }
} @@ -189,7 +189,7 @@ function VerdictButton(props: Readonly<{ verdict: Verdict }>) { } -function MenuButtons(props: Readonly<{ chatMenuNotification: boolean }>): ReactElement | null { +export function MenuButtons(props: Readonly<{ chatMenuNotification: boolean }>): ReactElement | null { const menuController = useContext(MenuControllerContext)!; return
diff --git a/client/src/menu/game/gameScreen.css b/client/src/menu/game/gameScreen.css index 65a651147..a2ed20c9f 100644 --- a/client/src/menu/game/gameScreen.css +++ b/client/src/menu/game/gameScreen.css @@ -4,6 +4,12 @@ flex-direction: column; } +.game-screen > .menu-buttons > button { + padding: 0.5rem; + font-size: 1.5em; + aspect-ratio: 1/1; +} + .game-screen > .leave-button { position: absolute; margin: 0; diff --git a/client/src/menu/game/gameScreenContent/AbilityMenu/AbilityMenu.tsx b/client/src/menu/game/gameScreenContent/AbilityMenu/AbilityMenu.tsx index acabe89c1..ff07d8fa7 100644 --- a/client/src/menu/game/gameScreenContent/AbilityMenu/AbilityMenu.tsx +++ b/client/src/menu/game/gameScreenContent/AbilityMenu/AbilityMenu.tsx @@ -17,10 +17,10 @@ export default function AbilityMenu(): ReactElement { {translate("menu.ability.title")} {!mySpectator && - <> +
- +
}
diff --git a/client/src/menu/game/gameScreenContent/AbilityMenu/abilityMenu.css b/client/src/menu/game/gameScreenContent/AbilityMenu/abilityMenu.css index e92cf4d71..a151b4aaa 100644 --- a/client/src/menu/game/gameScreenContent/AbilityMenu/abilityMenu.css +++ b/client/src/menu/game/gameScreenContent/AbilityMenu/abilityMenu.css @@ -1,6 +1,10 @@ .ability-menu { overflow-y: auto; } +.ability-menu .abilities { + display: flex; + flex-direction: column; +} .game-screen .content > .ability-menu { width: 10%; } diff --git a/client/src/menu/game/gameScreenContent/AbilityMenu/genericAbilityMenu.css b/client/src/menu/game/gameScreenContent/AbilityMenu/genericAbilityMenu.css index 2dd331ef2..244ac85d8 100644 --- a/client/src/menu/game/gameScreenContent/AbilityMenu/genericAbilityMenu.css +++ b/client/src/menu/game/gameScreenContent/AbilityMenu/genericAbilityMenu.css @@ -1,8 +1,3 @@ -.generic-ability-menu { - margin-top: .4rem; -} - - .generic-ability-menu-tab-summary { display: flex; flex-direction: row; diff --git a/client/src/menu/game/gameScreenContent/GraveyardMenu.tsx b/client/src/menu/game/gameScreenContent/GraveyardMenu.tsx index 88da450a8..e555cda6a 100644 --- a/client/src/menu/game/gameScreenContent/GraveyardMenu.tsx +++ b/client/src/menu/game/gameScreenContent/GraveyardMenu.tsx @@ -7,17 +7,20 @@ import StyledText from "../../../components/StyledText"; import { EnabledRolesDisplay } from "../../../components/gameModeSettings/EnabledRoleSelector"; import { useGameState, usePlayerState } from "../../../components/useHooks"; import { translateRoleOutline } from "../../../game/roleListState.d"; -import { EnabledModifiersDisplay } from "../../../components/gameModeSettings/EnabledModifiersDisplay"; import { Button } from "../../../components/Button"; import DetailsSummary from "../../../components/DetailsSummary"; +import { EnabledModifiersDisplay } from "../../../components/gameModeSettings/EnabledModifiersSelector"; export default function GraveyardMenu(): ReactElement { return
{translate("menu.gameMode.title")} -
+ -
+
@@ -38,7 +41,7 @@ function RoleListDisplay(): ReactElement { const roleOutlineName = translateRoleOutline(entry); return + }
+ {mobile && }
); diff --git a/server/src/lobby/lobby_client.rs b/server/src/lobby/lobby_client.rs index 15432082e..b2697aceb 100644 --- a/server/src/lobby/lobby_client.rs +++ b/server/src/lobby/lobby_client.rs @@ -24,6 +24,7 @@ pub struct LobbyClient{ } #[derive(Clone, Debug, Serialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] pub enum Ready { Host, Ready, From 29dcdab403b364548c0fc0b2686b314ab9771cc7 Mon Sep 17 00:00:00 2001 From: Jack Papel Date: Sat, 28 Dec 2024 01:42:39 -0800 Subject: [PATCH 09/15] Settings for menu order, menu number --- client/src/components/ChatMessage.tsx | 4 +- client/src/components/chatMessage.css | 3 + .../gameModeSettings/gameMode/dataFixer/v3.ts | 9 +- client/src/components/grave.css | 6 +- client/src/game/localStorage.tsx | 39 ++-- client/src/index.tsx | 2 +- client/src/menu/Anchor.tsx | 2 - client/src/menu/Settings.tsx | 168 +++++++++--------- client/src/menu/game/GameScreen.tsx | 61 +++++-- client/src/menu/game/HeaderMenu.tsx | 61 ++----- client/src/menu/lobby/LobbyMenu.tsx | 7 + client/src/menu/settings.css | 68 +++---- .../menu/spectator/SpectatorGameScreen.tsx | 31 ++-- client/src/resources/lang/en_us.json | 8 +- 14 files changed, 242 insertions(+), 227 deletions(-) diff --git a/client/src/components/ChatMessage.tsx b/client/src/components/ChatMessage.tsx index 72655b548..fabbfe3e4 100644 --- a/client/src/components/ChatMessage.tsx +++ b/client/src/components/ChatMessage.tsx @@ -156,9 +156,7 @@ const ChatElement = React.memo(( } defaultOpen={GAME_MANAGER.getMySpectator()} > -
- -
+ ; } diff --git a/client/src/components/chatMessage.css b/client/src/components/chatMessage.css index e7d7f7947..24ad54a00 100644 --- a/client/src/components/chatMessage.css +++ b/client/src/components/chatMessage.css @@ -134,4 +134,7 @@ } .kira-guess-result.notInGame{ border-color: red; +} +.chat-message-div .details-summary-container { + width: 100%; } \ No newline at end of file diff --git a/client/src/components/gameModeSettings/gameMode/dataFixer/v3.ts b/client/src/components/gameModeSettings/gameMode/dataFixer/v3.ts index 75391a400..1ff195bfd 100644 --- a/client/src/components/gameModeSettings/gameMode/dataFixer/v3.ts +++ b/client/src/components/gameModeSettings/gameMode/dataFixer/v3.ts @@ -1,6 +1,6 @@ import { VersionConverter } from "."; import { GameMode, GameModeData, GameModeStorage, ShareableGameMode } from ".."; -import { Settings } from "../../../../game/localStorage"; +import { getDefaultSettings, Settings } from "../../../../game/localStorage"; import { RoleOutline, RoleOutlineOption } from "../../../../game/roleListState.d"; import { Role } from "../../../../game/roleState.d"; import { Failure, ParseResult, ParseSuccess, Success, isFailure } from "../parse"; @@ -27,6 +27,13 @@ function parseSettings(json: NonNullable): ParseResult { } } + for(const key of ['maxMenus', 'menuOrder']) { + if (!Object.keys(json).includes(key)) { + json.maxMenus = getDefaultSettings().maxMenus + json.menuOrder = getDefaultSettings().menuOrder + } + } + if (json.format !== "v3") { return Failure("settingsFormatNotV3", json); } diff --git a/client/src/components/grave.css b/client/src/components/grave.css index 438e890b9..ebb468b39 100644 --- a/client/src/components/grave.css +++ b/client/src/components/grave.css @@ -1,9 +1,11 @@ .grave { white-space: normal; - width: 100%; background-color: var(--primary-color); - border: 1px solid var(--primary-border-color); + margin: .25rem; + padding: .25rem; + border-radius: .5rem; + border: .13rem solid var(--primary-border-color); } .grave .note-area { background-color: var(--secondary-color); diff --git a/client/src/game/localStorage.tsx b/client/src/game/localStorage.tsx index b216017e4..31fc50bd3 100644 --- a/client/src/game/localStorage.tsx +++ b/client/src/game/localStorage.tsx @@ -3,6 +3,7 @@ import { CurrentFormat, GameModeStorage } from "../components/gameModeSettings/g import { Language } from "./lang"; import { Role } from "./roleState.d"; import parseFromJson from "../components/gameModeSettings/gameMode/dataFixer"; +import { ContentMenu } from "../menu/game/GameScreen"; export function saveReconnectData(roomCode: number, playerId: number) { localStorage.setItem( @@ -49,6 +50,8 @@ export type Settings = { accessibilityFont: boolean; defaultName: string | null; language: Language; + maxMenus: number; + menuOrder: ContentMenu[] roleSpecificMenus: Role[] // RoleSpecificMenuType=standalone for all listed roles, otherwise it should be playerlist }; @@ -59,7 +62,7 @@ export type RoleSpecificMenuType = "playerList" | "standalone"; export function loadSettingsParsed(): Settings { const result = parseFromJson("Settings", loadSettings()); if(result.type === "failure") { - return DEFAULT_SETTINGS; + return getDefaultSettings(); }else{ return result.value; } @@ -74,7 +77,7 @@ export function loadSettings(): unknown { return null; } } - return DEFAULT_SETTINGS; + return getDefaultSettings(); } export function saveSettings(newSettings: Partial) { const currentSettings = parseFromJson("Settings", loadSettings()); @@ -82,7 +85,7 @@ export function saveSettings(newSettings: Partial) { if(currentSettings.type === "failure") { localStorage.setItem("settings", JSON.stringify({ - ...DEFAULT_SETTINGS, + ...getDefaultSettings(), ...newSettings, })); }else{ @@ -117,13 +120,23 @@ export function deleteGameModes() { localStorage.removeItem("savedGameModes"); } - -export const DEFAULT_SETTINGS: Readonly = { - format: "v3", - volume: 0.5, - fontSize: 1, - accessibilityFont: false, - language: "en_us", - defaultName: null, - roleSpecificMenus: [] -}; \ No newline at end of file +export function getDefaultSettings(): Readonly { + return { + format: "v3", + volume: 0.5, + fontSize: 1, + accessibilityFont: false, + language: "en_us", + defaultName: null, + maxMenus: window.innerWidth < 600 ? 1 : 6, + menuOrder: [ + ContentMenu.WikiMenu, + ContentMenu.GraveyardMenu, + ContentMenu.PlayerListMenu, + ContentMenu.ChatMenu, + ContentMenu.WillMenu, + ContentMenu.RoleSpecificMenu + ], + roleSpecificMenus: [] + } +} \ No newline at end of file diff --git a/client/src/index.tsx b/client/src/index.tsx index db5236e2b..49a33b168 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -6,7 +6,7 @@ import { GameManager, createGameManager } from './game/gameManager'; import LoadingScreen from './menu/LoadingScreen'; import route from './routing'; -export type Theme = "player-list-menu-colors" | "will-menu-colors" | "role-specific-colors" | "graveyard-menu-colors" | "wiki-menu-colors" +export type Theme = "chat-menu-colors" | "player-list-menu-colors" | "will-menu-colors" | "role-specific-colors" | "graveyard-menu-colors" | "wiki-menu-colors" const THEME_CSS_ATTRIBUTES = [ 'background-color', 'fade-color', 'primary-color', 'secondary-color', diff --git a/client/src/menu/Anchor.tsx b/client/src/menu/Anchor.tsx index 7aefd54d9..3688fbfed 100644 --- a/client/src/menu/Anchor.tsx +++ b/client/src/menu/Anchor.tsx @@ -159,8 +159,6 @@ export default function Anchor(props: Readonly<{ let coverCardTheme: Theme | null = null; if (coverCard.type === WikiCoverCard || coverCard.type === WikiArticle) { coverCardTheme = "wiki-menu-colors" - } else if (coverCard.type === SettingsMenu) { - coverCardTheme = "graveyard-menu-colors" } if (callback) { diff --git a/client/src/menu/Settings.tsx b/client/src/menu/Settings.tsx index a0be87de8..1b07552d8 100644 --- a/client/src/menu/Settings.tsx +++ b/client/src/menu/Settings.tsx @@ -9,14 +9,16 @@ import { Role, roleJsonData } from "../game/roleState.d"; import AudioController from "./AudioController"; import { getAllRoles } from "../game/roleListState.d"; import CheckBox from "../components/CheckBox"; +import { DragAndDrop } from "../components/DragAndDrop"; +import { MENU_ELEMENTS, MENU_THEMES, MENU_TRANSLATION_KEYS } from "./game/GameScreen"; export default function SettingsMenu(): ReactElement { const [volume, setVolume] = useState(loadSettingsParsed().volume); const [fontSizeState, setFontSize] = useState(loadSettingsParsed().fontSize); const [defaultName, setDefaultName] = useState(loadSettingsParsed().defaultName); - const [roleSpecificMenuSettings, setRoleSpecificMenuSettings] = useState(loadSettingsParsed().roleSpecificMenus); const [accessibilityFontEnabled, setAccessibilityFontEnabled] = useState(loadSettingsParsed().accessibilityFont); - const mobile = useContext(MobileContext)!; + const [menuOrder, setMenuOrder] = useState(loadSettingsParsed().menuOrder); + const [maxMenus, setMaxMenus] = useState(loadSettingsParsed().maxMenus); const anchorController = useContext(AnchorControllerContext)!; useEffect(() => { @@ -31,21 +33,23 @@ export default function SettingsMenu(): ReactElement {
-
-
-
-

volume_up {translate("menu.settings.volume")}

- { - const volume = parseFloat(e.target.value); - saveSettings({volume}); - setVolume(volume); - } - }/> -
-
-

{translate("menu.settings.fontSize")}

+
+

{translate("menu.settings.general")}

+
+

volume_up {translate("menu.settings.volume")}

+ { + const volume = parseFloat(e.target.value); + saveSettings({volume}); + setVolume(volume); + } + }/> +
+
+

{translate("menu.settings.font")}

+
-
-

language {translate("menu.settings.language")}

- -
+ +
-

{translate("menu.settings.dangerZone")}

- +

language {translate("menu.settings.language")}

+
-
-
+
+

{translate("menu.settings.gameplay")}

+
+

{translate("menu.settings.menus")}

+ +
+ {translate("menu.settings.menuOrder")} +
+
+ {translate(MENU_TRANSLATION_KEYS[menu] + ".icon")} +
} + onDragEnd={newItems => { + saveSettings({menuOrder: [...newItems]}) + setMenuOrder([...newItems]) + }} + /> +
+
+
+

{translate("menu.settings.defaultName")}

-
-

{translate("menu.settings.accessibility")}

- -
- {mobile &&

{translate("menu.settings.advanced")}

} -
- - {translate("menu.settings.roleSpecificMenus")} - - { - Object.entries(roleJsonData()).map(([role, roleJsonData]) => { - // const roleSpecificMenuExists = type.roleSpecificMenu; - const menuType: RoleSpecificMenuType = roleSpecificMenuSettings.includes(role as Role) ? "standalone" : "playerList"; - - - return
- {translate(`role.${role}.name`)} - -
- }) - } -
+

{translate("menu.settings.dangerZone")}

+
diff --git a/client/src/menu/game/GameScreen.tsx b/client/src/menu/game/GameScreen.tsx index e5db3d517..3f0783340 100644 --- a/client/src/menu/game/GameScreen.tsx +++ b/client/src/menu/game/GameScreen.tsx @@ -4,7 +4,7 @@ import GraveyardMenu from "./gameScreenContent/GraveyardMenu"; import ChatMenu from "./gameScreenContent/ChatMenu"; import PlayerListMenu from "./gameScreenContent/PlayerListMenu"; import WillMenu from "./gameScreenContent/WillMenu"; -import GAME_MANAGER, { modulus } from "../.."; +import GAME_MANAGER, { modulus, Theme } from "../.."; import WikiMenu from "./gameScreenContent/WikiMenu"; import "../../index.css"; import "./gameScreen.css"; @@ -17,6 +17,7 @@ import { Button } from "../../components/Button"; import translate from "../../game/lang"; import { useGameState } from "../../components/useHooks"; import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; +import { loadSettingsParsed } from "../../game/localStorage"; export enum ContentMenu { ChatMenu = "ChatMenu", @@ -36,6 +37,24 @@ export const MENU_ELEMENTS = { [ContentMenu.WikiMenu]: WikiMenu } +export const MENU_THEMES: Record = { + [ContentMenu.ChatMenu]: "chat-menu-colors", + [ContentMenu.PlayerListMenu]: "player-list-menu-colors", + [ContentMenu.RoleSpecificMenu]: "role-specific-colors", + [ContentMenu.WillMenu]: "will-menu-colors", + [ContentMenu.GraveyardMenu]: "graveyard-menu-colors", + [ContentMenu.WikiMenu]: "wiki-menu-colors" +} + +export const MENU_TRANSLATION_KEYS: Record = { + [ContentMenu.ChatMenu]: "menu.chat", + [ContentMenu.PlayerListMenu]: "menu.playerList", + [ContentMenu.RoleSpecificMenu]: "menu.ability", + [ContentMenu.WillMenu]: "menu.will", + [ContentMenu.GraveyardMenu]: "menu.gameMode", + [ContentMenu.WikiMenu]: "menu.wiki" +} + const ALL_CONTENT_MENUS = Object.values(ContentMenu); export interface MenuController { @@ -45,6 +64,8 @@ export interface MenuController { menusOpen(): ContentMenu[]; menuOpen(menu: ContentMenu): boolean; canOpen(menu: ContentMenu): boolean; + menus(): ContentMenu[] + maxMenus: number } export function useMenuController>>( @@ -121,7 +142,11 @@ export function useMenuController }, canOpen(menu): boolean { return contentMenus[menu] !== undefined - } + }, + menus(): ContentMenu[] { + return Object.keys(contentMenus).filter(menu => contentMenus[menu as ContentMenu] !== undefined) as ContentMenu[]; + }, + maxMenus: maxContent }) }, [contentMenus, getMenuController, maxContent, setMenuController]); @@ -144,17 +169,22 @@ export { MenuControllerContext } export default function GameScreen(): ReactElement { const mobile = useContext(MobileContext)!; + const { maxMenus, menuOrder } = loadSettingsParsed(); + + const menusOpen: [ContentMenu, boolean | undefined][] = [ + [ContentMenu.WikiMenu, mobile ? undefined : false ], + [ContentMenu.GraveyardMenu, maxMenus > 4 ], + [ContentMenu.PlayerListMenu, maxMenus > 1 ], + [ContentMenu.ChatMenu, true ], + [ContentMenu.WillMenu, maxMenus > 3 ], + [ContentMenu.RoleSpecificMenu, maxMenus > 2 ], + ]; + + menusOpen.sort((a, b) => menuOrder.indexOf(a[0]) - menuOrder.indexOf(b[0])) const menuController = useMenuController( - mobile ? 2 : Infinity, - { - WikiMenu: mobile ? undefined : false, - GraveyardMenu: !mobile, - PlayerListMenu: true, - ChatMenu: true, - WillMenu: !mobile, - RoleSpecificMenu: !mobile, - }, + maxMenus, + Object.fromEntries(menusOpen), () => MENU_CONTROLLER_HOLDER.controller!, menuController => MENU_CONTROLLER_HOLDER.controller = menuController ); @@ -164,6 +194,13 @@ export default function GameScreen(): ReactElement { ["addChatMessages"] )!; + useEffect(() => { + const onBeforeUnload = (e: BeforeUnloadEvent) => e.preventDefault(); + + window.addEventListener("beforeunload", onBeforeUnload); + return () => window.removeEventListener("beforeunload", onBeforeUnload); + }, []) + useEffect(() => { const swipeEventListener = (right: boolean) => { // Close the furthest right menu, open the next one to the left or right @@ -174,7 +211,7 @@ export default function GameScreen(): ReactElement { } const allowedMenus = ALL_CONTENT_MENUS.filter(menu => { - return !menusOpen.includes(menu) + return !menusOpen.includes(menu) && menuController.menus().includes(menu) }); const rightMostMenu = menusOpen[menusOpen.length - 1]; diff --git a/client/src/menu/game/HeaderMenu.tsx b/client/src/menu/game/HeaderMenu.tsx index 401fc3fff..0e0d69242 100644 --- a/client/src/menu/game/HeaderMenu.tsx +++ b/client/src/menu/game/HeaderMenu.tsx @@ -2,7 +2,7 @@ import React, { ReactElement, useContext, useMemo } from "react"; import translate from "../../game/lang"; import GAME_MANAGER from "../../index"; import { PhaseState, Player, Verdict } from "../../game/gameState.d"; -import { MenuControllerContext, ContentMenu } from "./GameScreen"; +import { MenuControllerContext, ContentMenu, MENU_THEMES, MENU_TRANSLATION_KEYS } from "./GameScreen"; import "./headerMenu.css"; import StyledText from "../../components/StyledText"; import Icon from "../../components/Icon"; @@ -15,6 +15,7 @@ export default function HeaderMenu(props: Readonly<{ chatMenuNotification: boolean }>): ReactElement { const mobile = useContext(MobileContext)!; + const menuController = useContext(MenuControllerContext)!; const phaseState = useGameState( gameState => gameState.phaseState, @@ -30,7 +31,7 @@ export default function HeaderMenu(props: Readonly<{ return
{!(GAME_MANAGER.getMySpectator() && !GAME_MANAGER.getMyHost()) && } - {!GAME_MANAGER.getMySpectator() && !mobile && } + {!mobile && }
} @@ -191,55 +192,21 @@ function VerdictButton(props: Readonly<{ verdict: Verdict }>) { export function MenuButtons(props: Readonly<{ chatMenuNotification: boolean }>): ReactElement | null { const menuController = useContext(MenuControllerContext)!; - const mobile = useContext(MobileContext); return
- {!mobile && } - - - - {GAME_MANAGER.getMySpectator() || } - {!GAME_MANAGER.getMySpectator() && - } + })}
} diff --git a/client/src/menu/lobby/LobbyMenu.tsx b/client/src/menu/lobby/LobbyMenu.tsx index a2d700f93..859d5d9da 100644 --- a/client/src/menu/lobby/LobbyMenu.tsx +++ b/client/src/menu/lobby/LobbyMenu.tsx @@ -41,6 +41,13 @@ export default function LobbyMenu(): ReactElement { setAdvancedView(isHost || mobile) }, [mobile, isHost]) + useEffect(() => { + const onBeforeUnload = (e: BeforeUnloadEvent) => e.preventDefault(); + + window.addEventListener("beforeunload", onBeforeUnload); + return () => window.removeEventListener("beforeunload", onBeforeUnload); + }, []) + return
diff --git a/client/src/menu/settings.css b/client/src/menu/settings.css index 3c3a17951..5a2a995e9 100644 --- a/client/src/menu/settings.css +++ b/client/src/menu/settings.css @@ -14,71 +14,49 @@ gap: 0.5rem; } -.settings-menu { +.settings-menu-card input { + min-width: 3rem; +} + +.settings-menu-card > main { display: flex; flex-direction: row; flex-wrap: wrap; gap: 1rem; overflow-y: scroll; scrollbar-width: none; + align-items: start; } -.settings-menu > div { +.settings-menu-card > main > div { display: flex; flex-direction: column; - flex-basis: 47%; + flex-basis: 30%; flex-grow: 1; - gap: 1rem; + gap: .5rem; max-width: 100%; + padding: 1rem; + background-color: var(--background-color); + border: .13rem solid var(--primary-border-color); + border-bottom-color: var(--primary-border-shadow-color); + border-right-color: var(--primary-border-shadow-color); + border-radius: 1rem; } .settings-menu > div > section { display: flex; flex-direction: column; -} - -.settings-menu > div .horizontal { - display: flex; - flex-direction: row; - flex-wrap: wrap; - gap: 1rem; -} - -.settings-menu > div .horizontal > * { - flex-grow: 1; -} - -.role-specific-menu-settings { - display: flex; - flex-direction: column; - max-height: 20rem; - overflow-y: scroll; - gap: 0.25rem; -} - -.role-specific-menu-settings-selector { - display: flex; - border: .13rem solid var(--primary-border-color); - background-color: var(--secondary-color); - border-radius: 0.5rem; - align-items: center; - justify-content: space-between; - margin-top: 0.25rem; -} -.role-specific-menu-settings-selector > span { - margin: 0 .25rem; - white-space: pre; -} - -.settings-menu > div .standout { border: solid .13rem var(--primary-border-color); border-top-color: var(--primary-border-shadow-color); border-left-color: var(--primary-border-shadow-color); - border-radius: .5rem; - padding: 0.25rem; + border-radius: 0.5rem; + padding: 0.5rem; background-color: var(--secondary-color); + align-items: center; } -.settings-menu div .settings-volume { - border: 0; - padding: 0; +.settings-menu .menu-list { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; } \ No newline at end of file diff --git a/client/src/menu/spectator/SpectatorGameScreen.tsx b/client/src/menu/spectator/SpectatorGameScreen.tsx index 6a334a0f7..334c5ce48 100644 --- a/client/src/menu/spectator/SpectatorGameScreen.tsx +++ b/client/src/menu/spectator/SpectatorGameScreen.tsx @@ -1,8 +1,9 @@ import React, { ReactElement, useContext } from "react"; import "../game/gameScreen.css" import HeaderMenu, { MenuButtons } from "../game/HeaderMenu"; -import { MenuController, useMenuController, MenuControllerContext, GameScreenMenus } from "../game/GameScreen"; +import { MenuController, useMenuController, MenuControllerContext, GameScreenMenus, ContentMenu } from "../game/GameScreen"; import { MobileContext } from "../Anchor"; +import { loadSettingsParsed } from "../../game/localStorage"; let CONTENT_CONTROLLER: MenuController | undefined; @@ -10,22 +11,24 @@ export function getSpectatorScreenContentController(): MenuController | undefine return CONTENT_CONTROLLER; } -type SpectatorContentMenus = { - ChatMenu: boolean, - PlayerListMenu: boolean, - GraveyardMenu: boolean -} - export default function SpectatorGameScreen(): ReactElement { const mobile = useContext(MobileContext)!; + const { maxMenus, menuOrder } = loadSettingsParsed(); + + const menusOpen: [ContentMenu, boolean | undefined][] = [ + [ContentMenu.WikiMenu, undefined ], + [ContentMenu.GraveyardMenu, maxMenus > 2 ], + [ContentMenu.PlayerListMenu, maxMenus > 1 ], + [ContentMenu.ChatMenu, true ], + [ContentMenu.WillMenu, undefined ], + [ContentMenu.RoleSpecificMenu, undefined ], + ]; + + menusOpen.sort((a, b) => menuOrder.indexOf(a[0]) - menuOrder.indexOf(b[0])) - const contentController = useMenuController( - mobile ? 2 : Infinity, - { - GraveyardMenu: !mobile, - PlayerListMenu: true, - ChatMenu: true - }, + const contentController = useMenuController( + maxMenus, + Object.fromEntries(menusOpen), () => CONTENT_CONTROLLER!, contentController => CONTENT_CONTROLLER = contentController ); diff --git a/client/src/resources/lang/en_us.json b/client/src/resources/lang/en_us.json index cfe3a474a..369f894f3 100644 --- a/client/src/resources/lang/en_us.json +++ b/client/src/resources/lang/en_us.json @@ -43,12 +43,16 @@ "menu.globalMenu.gameSettingsEditor": "Game Mode Editor", "menu.settings.title": "Settings", - "menu.settings.advanced": "Advanced Settings", + "menu.settings.general": "General", + "menu.settings.gameplay": "Gameplay", + "menu.settings.menus": "Menus", + "menu.settings.maxMenus": "Max Menus Open", + "menu.settings.menuOrder": "Menu Order", "menu.settings.dangerZone": "Danger zone", "menu.settings.volume": "Volume", "menu.settings.font": "Font", "menu.settings.fontSize": "Font Size", - "menu.settings.accessibility": "Accessibility", + "menu.settings.accessibilityFont": "Accessibility Font", "menu.settings.language": "Language", "menu.settings.defaultName": "Default Name", "menu.settings.eraseSaveData": "Erase Save Data", From 5726839a3cbbb9cf0367ad4b54f90e1cd051886f Mon Sep 17 00:00:00 2001 From: Jack Papel Date: Sat, 28 Dec 2024 01:48:21 -0800 Subject: [PATCH 10/15] Fix build --- client/src/menu/Anchor.tsx | 1 - client/src/menu/Settings.tsx | 8 +++----- client/src/menu/game/HeaderMenu.tsx | 1 - client/src/menu/settings.css | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/client/src/menu/Anchor.tsx b/client/src/menu/Anchor.tsx index 3688fbfed..53b365415 100644 --- a/client/src/menu/Anchor.tsx +++ b/client/src/menu/Anchor.tsx @@ -3,7 +3,6 @@ import "../index.css"; import "./anchor.css"; import translate, { switchLanguage } from "../game/lang"; import GlobalMenu from "./GlobalMenu"; -import SettingsMenu from './Settings'; import { loadSettingsParsed } from "../game/localStorage"; import LoadingScreen from "./LoadingScreen"; import { Theme } from ".."; diff --git a/client/src/menu/Settings.tsx b/client/src/menu/Settings.tsx index 1b07552d8..fbd075353 100644 --- a/client/src/menu/Settings.tsx +++ b/client/src/menu/Settings.tsx @@ -3,14 +3,12 @@ import "./settings.css"; import translate, { Language, languageName, LANGUAGES, switchLanguage } from "../game/lang"; import StyledText, { computeKeywordData } from "../components/StyledText"; import Icon from "../components/Icon"; -import { loadSettingsParsed, RoleSpecificMenuType, saveSettings } from "../game/localStorage"; -import { MobileContext, AnchorControllerContext, ANCHOR_CONTROLLER } from "./Anchor"; -import { Role, roleJsonData } from "../game/roleState.d"; +import { loadSettingsParsed, saveSettings } from "../game/localStorage"; +import { AnchorControllerContext, ANCHOR_CONTROLLER } from "./Anchor"; import AudioController from "./AudioController"; -import { getAllRoles } from "../game/roleListState.d"; import CheckBox from "../components/CheckBox"; import { DragAndDrop } from "../components/DragAndDrop"; -import { MENU_ELEMENTS, MENU_THEMES, MENU_TRANSLATION_KEYS } from "./game/GameScreen"; +import { MENU_THEMES, MENU_TRANSLATION_KEYS } from "./game/GameScreen"; export default function SettingsMenu(): ReactElement { const [volume, setVolume] = useState(loadSettingsParsed().volume); diff --git a/client/src/menu/game/HeaderMenu.tsx b/client/src/menu/game/HeaderMenu.tsx index 0e0d69242..b6c6a8824 100644 --- a/client/src/menu/game/HeaderMenu.tsx +++ b/client/src/menu/game/HeaderMenu.tsx @@ -15,7 +15,6 @@ export default function HeaderMenu(props: Readonly<{ chatMenuNotification: boolean }>): ReactElement { const mobile = useContext(MobileContext)!; - const menuController = useContext(MenuControllerContext)!; const phaseState = useGameState( gameState => gameState.phaseState, diff --git a/client/src/menu/settings.css b/client/src/menu/settings.css index 5a2a995e9..c1c6d97ac 100644 --- a/client/src/menu/settings.css +++ b/client/src/menu/settings.css @@ -25,7 +25,7 @@ gap: 1rem; overflow-y: scroll; scrollbar-width: none; - align-items: start; + align-items: flex-start; } .settings-menu-card > main > div { From 6d4f4bbe7de06cb542400ee221f9a703e8c66838 Mon Sep 17 00:00:00 2001 From: Jack Papel Date: Sat, 28 Dec 2024 02:12:56 -0800 Subject: [PATCH 11/15] Make dev testing less annoying --- client/src/index.tsx | 2 ++ client/src/menu/game/GameScreen.tsx | 6 ++++-- client/src/menu/lobby/LobbyMenu.tsx | 6 ++++-- client/src/resources/config.json | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/client/src/index.tsx b/client/src/index.tsx index 49a33b168..5d1a14c7e 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -6,6 +6,8 @@ import { GameManager, createGameManager } from './game/gameManager'; import LoadingScreen from './menu/LoadingScreen'; import route from './routing'; +export const DEV_ENV = process.env.NODE_ENV !== 'production'; + export type Theme = "chat-menu-colors" | "player-list-menu-colors" | "will-menu-colors" | "role-specific-colors" | "graveyard-menu-colors" | "wiki-menu-colors" const THEME_CSS_ATTRIBUTES = [ diff --git a/client/src/menu/game/GameScreen.tsx b/client/src/menu/game/GameScreen.tsx index 3f0783340..833c2c719 100644 --- a/client/src/menu/game/GameScreen.tsx +++ b/client/src/menu/game/GameScreen.tsx @@ -4,7 +4,7 @@ import GraveyardMenu from "./gameScreenContent/GraveyardMenu"; import ChatMenu from "./gameScreenContent/ChatMenu"; import PlayerListMenu from "./gameScreenContent/PlayerListMenu"; import WillMenu from "./gameScreenContent/WillMenu"; -import GAME_MANAGER, { modulus, Theme } from "../.."; +import GAME_MANAGER, { DEV_ENV, modulus, Theme } from "../.."; import WikiMenu from "./gameScreenContent/WikiMenu"; import "../../index.css"; import "./gameScreen.css"; @@ -195,7 +195,9 @@ export default function GameScreen(): ReactElement { )!; useEffect(() => { - const onBeforeUnload = (e: BeforeUnloadEvent) => e.preventDefault(); + const onBeforeUnload = (e: BeforeUnloadEvent) => { + if (!DEV_ENV) e.preventDefault() + }; window.addEventListener("beforeunload", onBeforeUnload); return () => window.removeEventListener("beforeunload", onBeforeUnload); diff --git a/client/src/menu/lobby/LobbyMenu.tsx b/client/src/menu/lobby/LobbyMenu.tsx index 859d5d9da..9d6bc9259 100644 --- a/client/src/menu/lobby/LobbyMenu.tsx +++ b/client/src/menu/lobby/LobbyMenu.tsx @@ -1,5 +1,5 @@ import React, { ReactElement, useContext, useEffect, useMemo, useState } from "react"; -import GAME_MANAGER from "../../index"; +import GAME_MANAGER, { DEV_ENV } from "../../index"; import LobbyPlayerList from "./LobbyPlayerList"; import "./lobbyMenu.css"; import translate from "../../game/lang"; @@ -42,7 +42,9 @@ export default function LobbyMenu(): ReactElement { }, [mobile, isHost]) useEffect(() => { - const onBeforeUnload = (e: BeforeUnloadEvent) => e.preventDefault(); + const onBeforeUnload = (e: BeforeUnloadEvent) => { + if (!DEV_ENV) e.preventDefault() + }; window.addEventListener("beforeunload", onBeforeUnload); return () => window.removeEventListener("beforeunload", onBeforeUnload); diff --git a/client/src/resources/config.json b/client/src/resources/config.json index a1da17407..28daaac12 100644 --- a/client/src/resources/config.json +++ b/client/src/resources/config.json @@ -1,3 +1,3 @@ { - "address": "ws://localhost:8081" + "address": "ws://192.168.1.16:8081" } \ No newline at end of file From 48b64e9aa47a8cc808988ebbfe72c0f06aa9257c Mon Sep 17 00:00:00 2001 From: Jack Papel Date: Sat, 28 Dec 2024 18:05:16 -0800 Subject: [PATCH 12/15] Address comments + Fix server connection --- client/src/components/chatMessage.css | 8 -------- .../src/components/gameModeSettings/OutlineSelector.tsx | 5 +++-- client/src/components/useHooks.tsx | 2 +- client/src/menu/settings.css | 1 - client/src/menu/spectator/SpectatorGameScreen.tsx | 2 +- client/src/resources/config.json | 2 +- 6 files changed, 6 insertions(+), 14 deletions(-) diff --git a/client/src/components/chatMessage.css b/client/src/components/chatMessage.css index 24ad54a00..00e348b1f 100644 --- a/client/src/components/chatMessage.css +++ b/client/src/components/chatMessage.css @@ -101,14 +101,6 @@ .chat-message.warning { background-color: #660000; } -.grave-message { - border: .13rem solid var(--background-border-color); - border-bottom-color: var(--background-border-shadow-color); - border-right-color: var(--background-border-shadow-color); - border-radius: .5rem; - margin: .13rem; - padding: .25rem; -} .kira-guess-results { display: flex; diff --git a/client/src/components/gameModeSettings/OutlineSelector.tsx b/client/src/components/gameModeSettings/OutlineSelector.tsx index a9a71f435..588632232 100644 --- a/client/src/components/gameModeSettings/OutlineSelector.tsx +++ b/client/src/components/gameModeSettings/OutlineSelector.tsx @@ -8,6 +8,7 @@ import { DragAndDrop } from "../DragAndDrop"; import { GameModeContext } from "./GameModesEditor"; import Select, { SelectOptionsSearch } from "../Select"; import StyledText from "../StyledText"; +import { Button } from "../Button"; type RoleOutlineSelectorProps = { roleOutline: RoleOutline, @@ -199,9 +200,9 @@ export function OutlineListSelector(props: { return

{translate("menu.lobby.roleList")}: {roleList.length}

- {!props.disabled && } + }
(a: T, b: T): boolean { const bothAreObjects = a && b && typeof a === "object" && typeof b === "object"; - return Boolean( + return ( bothAreObjects && Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([k, v]) => deepEqual(v, b[k as keyof T])) diff --git a/client/src/menu/settings.css b/client/src/menu/settings.css index c1c6d97ac..b31a6aa71 100644 --- a/client/src/menu/settings.css +++ b/client/src/menu/settings.css @@ -57,6 +57,5 @@ .settings-menu .menu-list { display: flex; flex-direction: row; - flex-wrap: wrap; justify-content: center; } \ No newline at end of file diff --git a/client/src/menu/spectator/SpectatorGameScreen.tsx b/client/src/menu/spectator/SpectatorGameScreen.tsx index 334c5ce48..6ece70522 100644 --- a/client/src/menu/spectator/SpectatorGameScreen.tsx +++ b/client/src/menu/spectator/SpectatorGameScreen.tsx @@ -41,7 +41,7 @@ export default function SpectatorGameScreen(): ReactElement {
- {mobile && } + {mobile === true && }
); diff --git a/client/src/resources/config.json b/client/src/resources/config.json index 28daaac12..a1da17407 100644 --- a/client/src/resources/config.json +++ b/client/src/resources/config.json @@ -1,3 +1,3 @@ { - "address": "ws://192.168.1.16:8081" + "address": "ws://localhost:8081" } \ No newline at end of file From 0810958fbd50ad63cc7c40b05236685812d6e35c Mon Sep 17 00:00:00 2001 From: Jack Papel Date: Sat, 28 Dec 2024 18:52:23 -0800 Subject: [PATCH 13/15] Make alibi closeable --- client/src/components/TextAreaDropdown.tsx | 5 +++-- client/src/menu/game/gameScreenContent/WillMenu.tsx | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/components/TextAreaDropdown.tsx b/client/src/components/TextAreaDropdown.tsx index 7d5297c8b..1913b7f07 100644 --- a/client/src/components/TextAreaDropdown.tsx +++ b/client/src/components/TextAreaDropdown.tsx @@ -1,8 +1,7 @@ -import { ReactElement, useEffect, useMemo, useState } from "react"; +import React, { ReactElement, useEffect, useMemo, useState } from "react"; import StyledText from "./StyledText"; import { sanitizePlayerMessage } from "./ChatMessage"; import GAME_MANAGER, { replaceMentions } from ".."; -import React from "react"; import { Button } from "./Button"; import Icon from "./Icon"; import translate from "../game/lang"; @@ -12,6 +11,7 @@ import DetailsSummary from "./DetailsSummary"; export function TextDropdownArea(props: Readonly<{ titleString: string, savedText: string, + defaultOpen?: boolean, open?: boolean, dropdownArrow?: boolean, onAdd?: () => void, @@ -42,6 +42,7 @@ export function TextDropdownArea(props: Readonly<{ { From 316ea26f1596334ddecd37d2d99bf9c0a95d5c52 Mon Sep 17 00:00:00 2001 From: Jack Papel Date: Sat, 28 Dec 2024 18:57:19 -0800 Subject: [PATCH 14/15] Fix build --- client/src/components/gameModeSettings/OutlineSelector.tsx | 2 +- client/src/menu/Settings.tsx | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/client/src/components/gameModeSettings/OutlineSelector.tsx b/client/src/components/gameModeSettings/OutlineSelector.tsx index 4b0c14bf9..2403fe33e 100644 --- a/client/src/components/gameModeSettings/OutlineSelector.tsx +++ b/client/src/components/gameModeSettings/OutlineSelector.tsx @@ -2,7 +2,7 @@ import React, { ReactElement, useCallback, useContext } from "react"; import "./outlineSelector.css"; import translate from "../../game/lang"; import { getAllRoles, getRolesFromRoleSet, ROLE_SETS, RoleList, RoleOutline, RoleOutlineOption, simplifyRoleOutline, translateRoleOutline, translateRoleOutlineOption} from "../../game/roleListState.d"; -import { Role, roleJsonData } from "../../game/roleState.d"; +import { Role } from "../../game/roleState.d"; import Icon from "../Icon"; import { DragAndDrop } from "../DragAndDrop"; import { GameModeContext } from "./GameModesEditor"; diff --git a/client/src/menu/Settings.tsx b/client/src/menu/Settings.tsx index 4ebe32438..fbd075353 100644 --- a/client/src/menu/Settings.tsx +++ b/client/src/menu/Settings.tsx @@ -3,9 +3,8 @@ import "./settings.css"; import translate, { Language, languageName, LANGUAGES, switchLanguage } from "../game/lang"; import StyledText, { computeKeywordData } from "../components/StyledText"; import Icon from "../components/Icon"; -import { loadSettingsParsed, RoleSpecificMenuType, saveSettings } from "../game/localStorage"; -import { MobileContext, AnchorControllerContext, ANCHOR_CONTROLLER } from "./Anchor"; -import { Role } from "../game/roleState.d"; +import { loadSettingsParsed, saveSettings } from "../game/localStorage"; +import { AnchorControllerContext, ANCHOR_CONTROLLER } from "./Anchor"; import AudioController from "./AudioController"; import CheckBox from "../components/CheckBox"; import { DragAndDrop } from "../components/DragAndDrop"; From e01cc2b8618ec5b3e60d01a2f743766d87c82eea Mon Sep 17 00:00:00 2001 From: Jack Papel Date: Sat, 28 Dec 2024 19:37:59 -0800 Subject: [PATCH 15/15] Fix role list issues --- client/src/components/gameModeSettings/OutlineSelector.tsx | 2 +- client/src/game/messageListener.tsx | 1 + client/src/menu/lobby/LobbyMenu.tsx | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/components/gameModeSettings/OutlineSelector.tsx b/client/src/components/gameModeSettings/OutlineSelector.tsx index 2403fe33e..eae302b8f 100644 --- a/client/src/components/gameModeSettings/OutlineSelector.tsx +++ b/client/src/components/gameModeSettings/OutlineSelector.tsx @@ -213,7 +213,7 @@ export function OutlineListSelector(props: { }
{ diff --git a/client/src/game/messageListener.tsx b/client/src/game/messageListener.tsx index 61b2346ec..03a5de720 100644 --- a/client/src/game/messageListener.tsx +++ b/client/src/game/messageListener.tsx @@ -279,6 +279,7 @@ export default function messageListener(packet: ToClientPacket){ case "roleOutline": //role list entriy if(GAME_MANAGER.state.stateType === "lobby" || GAME_MANAGER.state.stateType === "game") { + GAME_MANAGER.state.roleList = structuredClone(GAME_MANAGER.state.roleList); GAME_MANAGER.state.roleList[packet.index] = packet.roleOutline; GAME_MANAGER.state.roleList = [...GAME_MANAGER.state.roleList]; } diff --git a/client/src/menu/lobby/LobbyMenu.tsx b/client/src/menu/lobby/LobbyMenu.tsx index 9d6bc9259..4ed1d7b05 100644 --- a/client/src/menu/lobby/LobbyMenu.tsx +++ b/client/src/menu/lobby/LobbyMenu.tsx @@ -114,7 +114,7 @@ function LobbyMenuSettings(props: Readonly<{ }, [setAnchorContent]); const sendRoleList = (newRoleList: RoleList) => { - const combinedRoleList = [...roleList]; + const combinedRoleList = structuredClone(roleList); newRoleList.forEach((role, index) => { combinedRoleList[index] = role })