Skip to content

Commit

Permalink
Merge branch 'main' into resizable-panels
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack-Papel authored Dec 1, 2024
2 parents 09a72dc + 9321c2b commit a336782
Show file tree
Hide file tree
Showing 250 changed files with 5,334 additions and 3,554 deletions.
10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,30 @@
"Chronokaiser",
"Consig",
"Deodat",
"Disguiser",
"Doesnt",
"dompurify",
"entriy",
"Informant",
"Informants",
"inno",
"killable",
"Kira",
"Kiras",
"Mafiosos",
"Necro",
"necronomicon",
"Ojos",
"Parris",
"Playerlist",
"Poli",
"Pyrolisk",
"Pyrolisks",
"Rabblerouser",
"rbed",
"reeducator",
"repr",
"retrainer",
"Retri",
"Retributionist",
"Retributionists",
Expand All @@ -39,6 +47,8 @@
"tungstenite",
"unclicked",
"Unswappable",
"Uzumaki",
"Uzumakis",
"vigi",
"votee",
"whisperee",
Expand Down
24 changes: 3 additions & 21 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"@types/react-dom": "^18.0.11",
"dompurify": "^3.0.3",
"marked": "^5.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"react-resizable-panels": "^2.1.6",
Expand All @@ -25,8 +24,7 @@
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
"@types/react-helmet": "^6.1.11",
"@types/react-window": "^1.8.8"
"@types/react-helmet": "^6.1.11"
},
"scripts": {
"start": "react-scripts start",
Expand Down
Binary file modified client/public/images/icon/circle/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/circle/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/circle/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/circle/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/circle/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/circle/favicon.ico
Binary file not shown.
Binary file modified client/public/images/icon/old/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/old/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/old/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/old/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/old/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/old/favicon.ico
Binary file not shown.
Binary file modified client/public/images/icon/square/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/square/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/square/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/square/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/square/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified client/public/images/icon/square/favicon.ico
Binary file not shown.
32 changes: 32 additions & 0 deletions client/src/ListMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export type ListMapData<K, V> = [K, V][]

export default class ListMap<K, V> {
list: ListMapData<K, V>;
constructor(list: ListMapData<K, V> = []) {
this.list = list
}
get(key: K): V | null {
for (const [k, v] of this.list) {
if (k === key) {
return v
}
}
return null
}
set(key: K, value: V) {
this.list = this.list.filter(([k, v]) => k !== key);
this.list.push([key, value])
}
delete(key: K) {
this.list = this.list.filter(([k, v]) => k !== key)
}
entries(): ListMapData<K, V> {
return this.list
}
keys(): K[] {
return this.list.map(([k, v]) => k)
}
values(): V[] {
return this.list.map(([k, v]) => v)
}
}
23 changes: 19 additions & 4 deletions client/src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useMemo, useRef } from "react";
import { ReactElement, useState } from "react";
import React, { useEffect, useMemo, useRef, ReactElement, useState, forwardRef } from "react";
import "./button.css";
import ReactDOM from "react-dom/client";
import { THEME_CSS_ATTRIBUTES } from "..";

export type ButtonProps<R> = Omit<JSX.IntrinsicElements['button'], 'onClick' | 'ref'> & {
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => (R | void | Promise<R | void>)
Expand All @@ -23,8 +23,21 @@ function reconcileProps<R>(props: ButtonProps<R>): JSX.IntrinsicElements['button
const POPUP_TIMEOUT_MS = 1000;

export function Button<R>(props: ButtonProps<R>): ReactElement {
return <RawButton {...props} />
}

const RawButton = forwardRef<HTMLButtonElement, ButtonProps<any>>(function RawButton<R>(props: ButtonProps<R>, passedRef: React.ForwardedRef<HTMLButtonElement>): ReactElement {
const [success, setSuccess] = useState<R | "unclicked">("unclicked");
const ref = useRef<HTMLButtonElement>(null);

useEffect(() => {
if (typeof passedRef === "function") {
passedRef(ref.current);
} else if (passedRef) {
passedRef.current = ref.current
}
}, [props, ref, passedRef]);

const popupContainer = useRef<HTMLDivElement>(document.createElement('div'));

let lastTimeout: NodeJS.Timeout | null = null;
Expand Down Expand Up @@ -67,7 +80,9 @@ export function Button<R>(props: ButtonProps<R>): ReactElement {
}
}}
>{children}</button>
}
})

export { RawButton };

function ButtonPopup(props: { children: React.ReactNode, button: HTMLButtonElement }): ReactElement {
const ref = useRef<HTMLDivElement>(null);
Expand All @@ -78,7 +93,7 @@ function ButtonPopup(props: { children: React.ReactNode, button: HTMLButtonEleme
const buttonBounds = props.button.getBoundingClientRect();
ref.current.style.top = `${buttonBounds.bottom}px`;
ref.current.style.left = `${(buttonBounds.left + buttonBounds.width / 2)}px`;
['background-color', 'primary-border-color', 'primary-color', 'secondary-color', 'tab-color'].forEach(prop => {
THEME_CSS_ATTRIBUTES.forEach(prop => {
if ((ref.current) === null) return;
ref.current.style.setProperty(`--${prop}`, getComputedStyle(props.button).getPropertyValue(`--${prop}`))
})
Expand Down
55 changes: 28 additions & 27 deletions client/src/components/ChatMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import { Grave } from "../game/graveState";
import DOMPurify from "dompurify";
import GraveComponent from "./grave";
import { RoleOutline, translateRoleOutline } from "../game/roleListState.d";
import { AuditorResult } from "../menu/game/gameScreenContent/RoleSpecificMenus/LargeAuditorMenu";
import { PuppeteerAction } from "../menu/game/gameScreenContent/RoleSpecificMenus/SmallPuppeteerMenu";
import { KiraGuess, KiraGuessResult, kiraGuessTranslate } from "../menu/game/gameScreenContent/RoleSpecificMenus/LargeKiraMenu";
import { CopyButton } from "./ClipboardButtons";
import { useLobbyOrGameState, usePlayerState } from "./useHooks";
import { RecruiterAction } from "../menu/game/gameScreenContent/RoleSpecificMenus/RecruiterMenu";
import { KiraGuess, KiraGuessResult, kiraGuessTranslate } from "../menu/game/gameScreenContent/AbilityMenu/RoleSpecificMenus/KiraMenu";
import { AuditorResult } from "../menu/game/gameScreenContent/AbilityMenu/RoleSpecificMenus/AuditorMenu";
import { PuppeteerAction } from "../menu/game/gameScreenContent/AbilityMenu/RoleSpecificMenus/SmallPuppeteerMenu";
import { RecruiterAction } from "../menu/game/gameScreenContent/AbilityMenu/RoleSpecificMenus/RecruiterMenu";
import DetailsSummary from "./DetailsSummary";

const ChatElement = React.memo((
props: {
Expand Down Expand Up @@ -146,20 +147,22 @@ const ChatElement = React.memo((
}

return <div className={"chat-message-div"}>
<details open={GAME_MANAGER.getMySpectator()}>
<summary>
<DetailsSummary
summary={
<StyledText className={"chat-message " + style}
playerKeywordData={props.playerKeywordData}
>
{(chatGroupIcon??"")} {translate("chatMessage.playerDied",
playerNames[message.variant.grave.player], graveRoleString
)}
</StyledText>
</summary>
}
defaultOpen={GAME_MANAGER.getMySpectator()}
>
<div className="grave-message">
<GraveComponent grave={message.variant.grave} playerNames={playerNames}/>
</div>
</details>
</DetailsSummary>
</div>;
}

Expand Down Expand Up @@ -530,12 +533,6 @@ export function translateChatMessage(message: ChatMessageVariant, playerNames?:
} else {
return translate("chatMessage.spyMafiaVisit", playerListToString(message.players, playerNames));
}
case "spyCultistCount":
if(message.count === 1){
return translate("chatMessage.spyCultistCount.one");
}else{
return translate("chatMessage.spyCultistCount", message.count);
}
case "spyBug":
return translate("chatMessage.spyBug."+message.bug);
case "trackerResult":
Expand Down Expand Up @@ -580,7 +577,7 @@ export function translateChatMessage(message: ChatMessageVariant, playerNames?:
const visitedByNobody = message.visitedBy.length === 0;

return translate("chatMessage.informantResult",
translate("chatMessage.informantResult.role", translate("role."+message.role+".name")),
translate("chatMessage.targetHasRole", translate("role."+message.role+".name")),
visitedNobody
? translate("chatMessage.informantResult.visited.nobody")
: translate("chatMessage.informantResult.visited", playerListToString(message.visited, playerNames)),
Expand Down Expand Up @@ -609,16 +606,14 @@ export function translateChatMessage(message: ChatMessageVariant, playerNames?:
);
case "roleChosen":
if(message.role === null){
return translate("chatMessage.rRoleChosen.none");
return translate("chatMessage.roleChosen.none");
}else{
return translate("chatMessage.roleChosen.role", translate("role."+message.role+".name"));
}
case "puppeteerActionChosen":
return translate("chatMessage.puppeteerActionChosen."+message.action);
case "recruiterActionChosen":
return translate("chatMessage.recruiterActionChosen."+message.action);
case "erosActionChosen":
return translate("chatMessage.erosActionChosen."+message.action);
case "marksmanChosenMarks":
if(message.marks.length === 0){
return translate("chatMessage.marksmanChosenMarks.none");
Expand All @@ -630,8 +625,8 @@ export function translateChatMessage(message: ChatMessageVariant, playerNames?:
return translate("chatMessage.mediumHauntStarted", playerNames[message.medium], playerNames[message.player]);
case "youWerePossessed":
return translate("chatMessage.youWerePossessed" + (message.immune ? ".immune" : ""));
case "possessionTargetsRole":
return translate("chatMessage.possessionTargetsRole", translate("role."+message.role+".name"));
case "targetHasRole":
return translate("chatMessage.targetHasRole", translate("role."+message.role+".name"));
case "werewolfTrackingResult":
if(message.players.length === 0){
return translate(
Expand All @@ -650,6 +645,11 @@ export function translateChatMessage(message: ChatMessageVariant, playerNames?:
return translate("chatMessage.youAreLoveLinked", playerNames[message.player]);
case "playerDiedOfABrokenHeart":
return translate("chatMessage.playerDiedOfBrokenHeart", playerNames[message.player], playerNames[message.lover]);
case "syndicateGunTarget":
return translate("chatMessage.syndicateGunTarget",
playerNames[message.shooter],
message.target===null?translate("nobody"):playerNames[message.target]
);
case "chronokaiserSpeedUp":
return translate("chatMessage.chronokaiserSpeedUp", message.percent);
case "deputyShotYou":
Expand Down Expand Up @@ -680,6 +680,7 @@ export function translateChatMessage(message: ChatMessageVariant, playerNames?:
case "psychicFailed":
case "phaseFastForwarded":
case "mayorCantWhisper":
case "politicianCountdownStarted":
case "youAttackedSomeone":
case "youWereAttacked":
case "armorsmithArmorBroke":
Expand Down Expand Up @@ -789,6 +790,8 @@ export type ChatMessageVariant = {
playerIndex: PlayerIndex
} | {
type: "mayorCantWhisper"
} | {
type: "politicianCountdownStarted"
} | {
type: "reporterReport",
report: string
Expand Down Expand Up @@ -865,9 +868,6 @@ export type ChatMessageVariant = {
} | {
type: "spyMafiaVisit",
players: PlayerIndex[]
} | {
type: "spyCultistCount",
count: number
} | {
type: "spyBug",
bug: "silenced" | "roleblocked" | "protected" | "transported" | "possessed"
Expand Down Expand Up @@ -919,6 +919,10 @@ export type ChatMessageVariant = {
type: "playerDiedOfABrokenHeart",
player: PlayerIndex
lover: PlayerIndex
} | {
type: "syndicateGunTarget",
shooter: PlayerIndex
target: PlayerIndex | null
} | {
type: "youWereProtected"
} | {
Expand Down Expand Up @@ -959,9 +963,6 @@ export type ChatMessageVariant = {
} | {
type: "recruiterActionChosen",
action: RecruiterAction,
} | {
type: "erosActionChosen",
action: "loveLink" | "kill",
} | {
type: "marksmanChosenMarks",
marks: PlayerIndex[],
Expand All @@ -971,7 +972,7 @@ export type ChatMessageVariant = {
type: "youWerePossessed",
immune: boolean
} | {
type: "possessionTargetsRole",
type: "targetHasRole",
role: Role
} | {
type: "targetsMessage",
Expand Down
17 changes: 17 additions & 0 deletions client/src/components/CheckBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react"
import Icon from "./Icon"
import "./checkBox.css"

export default function CheckBox(props: {
checked: boolean,
onChange: (checked: boolean) => void
}) {
return <label
className="checkbox"
onClick={()=>{
props.onChange(!props.checked)
}}
>
<Icon>{props.checked ? "check" : "close"}</Icon>
</label>
}
Loading

0 comments on commit a336782

Please sign in to comment.