From 23d3d603649e03d9dbb36001d1d725c424cd0061 Mon Sep 17 00:00:00 2001 From: HugoHMZ Date: Fri, 3 Jan 2025 19:04:23 +0900 Subject: [PATCH 1/4] [*] eslint: Fixed eslint weird indentation and sent all files from Popup handling --- src/app/GameBoard/page.tsx | 15 ++- .../ClientProviders/ClientProviders.tsx | 5 +- .../_subcomponents/PlayerTray/DeckDiscard.tsx | 35 ++++- .../_sharedcomponents/Popup/Popup.styles.ts | 120 ++++++++++++++++++ .../_sharedcomponents/Popup/Popup.tsx | 58 +++++++++ .../_sharedcomponents/Popup/Popup.types.ts | 41 ++++++ .../Popup/PopupVariant/DefaultPopup.tsx | 72 +++++++++++ .../Popup/PopupVariant/PilePopup.tsx | 89 +++++++++++++ .../Popup/PopupVariant/SelectCardsPopup.tsx | 93 ++++++++++++++ src/app/_contexts/Game.context.tsx | 20 +++ src/app/_contexts/Popup.context.tsx | 95 ++++++++++++++ 11 files changed, 630 insertions(+), 13 deletions(-) create mode 100644 src/app/_components/_sharedcomponents/Popup/Popup.styles.ts create mode 100644 src/app/_components/_sharedcomponents/Popup/Popup.tsx create mode 100644 src/app/_components/_sharedcomponents/Popup/Popup.types.ts create mode 100644 src/app/_components/_sharedcomponents/Popup/PopupVariant/DefaultPopup.tsx create mode 100644 src/app/_components/_sharedcomponents/Popup/PopupVariant/PilePopup.tsx create mode 100644 src/app/_components/_sharedcomponents/Popup/PopupVariant/SelectCardsPopup.tsx create mode 100644 src/app/_contexts/Popup.context.tsx diff --git a/src/app/GameBoard/page.tsx b/src/app/GameBoard/page.tsx index d4bb8c79..ce40eced 100644 --- a/src/app/GameBoard/page.tsx +++ b/src/app/GameBoard/page.tsx @@ -13,6 +13,7 @@ import { useGame } from '../_contexts/Game.context'; import { useSidebar } from '../_contexts/Sidebar.context'; import { transform } from 'next/dist/build/swc'; import { text } from 'stream/consumers'; +import PopupShell from '../_components/_sharedcomponents/Popup/Popup'; const GameBoard = () => { const { getOpponent, connectedPlayer, gameState } = useGame(); @@ -35,7 +36,7 @@ const GameBoard = () => { }; useEffect(() => { - // Update the drawer width when the drawer opens or closes + // Update the drawer width when the drawer opens or closes if (drawerRef.current) { setDrawerWidth(drawerRef.current.offsetWidth); } @@ -75,7 +76,8 @@ const GameBoard = () => { promptStyle: { textAlign: 'center', fontSize: '1.3em', - background: 'radial-gradient(ellipse, rgba(0,0,0, 0.9), rgba(0,0,0,0.7), rgba(0,0,0,0.0))', + background: + 'radial-gradient(ellipse, rgba(0,0,0, 0.9), rgba(0,0,0,0.7), rgba(0,0,0,0.0))', }, }; @@ -87,9 +89,7 @@ const GameBoard = () => { - + { /> )} - {gameState.players[connectedPlayer]?.promptState.menuTitle} + + {gameState.players[connectedPlayer]?.promptState.menuTitle} + { isBasicPromptOpen={isBasicPromptOpen} handleBasicPromptToggle={handleBasicPromptToggle} /> + ); }; diff --git a/src/app/_components/ClientProviders/ClientProviders.tsx b/src/app/_components/ClientProviders/ClientProviders.tsx index 111e76e9..7524c3c3 100644 --- a/src/app/_components/ClientProviders/ClientProviders.tsx +++ b/src/app/_components/ClientProviders/ClientProviders.tsx @@ -1,5 +1,6 @@ 'use client'; +import { PopupProvider } from '@/app/_contexts/Popup.context'; import { SidebarProvider } from '@/app/_contexts/Sidebar.context'; import { ThemeContextProvider } from '@/app/_contexts/Theme.context'; import { UserProvider } from '@/app/_contexts/User.context'; @@ -14,7 +15,9 @@ const ClientProviders: React.FC = ({ children }) => { - {children} + + {children} + diff --git a/src/app/_components/Gameboard/_subcomponents/PlayerTray/DeckDiscard.tsx b/src/app/_components/Gameboard/_subcomponents/PlayerTray/DeckDiscard.tsx index e1952e14..deb68ab3 100644 --- a/src/app/_components/Gameboard/_subcomponents/PlayerTray/DeckDiscard.tsx +++ b/src/app/_components/Gameboard/_subcomponents/PlayerTray/DeckDiscard.tsx @@ -1,13 +1,16 @@ import React from 'react'; -import { Card, CardContent, Box, Typography } from '@mui/material'; +import { Card, CardContent, Box, Typography, Button } from '@mui/material'; import GameCard from '../../../_sharedcomponents/Cards/GameCard/GameCard'; import { IDeckDiscardProps } from '@/app/_components/Gameboard/GameboardTypes'; import { useGame } from '@/app/_contexts/Game.context'; +import { usePopup } from '@/app/_contexts/Popup.context'; const DeckDiscard: React.FC = ( trayPlayer ) => { const { gameState } = useGame(); + const { openPopup } = usePopup(); + // ------------------------STYLES------------------------// const containerStyle = { display: 'flex', @@ -38,13 +41,33 @@ const DeckDiscard: React.FC = ( color: 'white', }; + const pileStyle = { + backgroundColor: 'transparent', + padding: '0', + borderRadius: '16px', + }; + return ( - - - Discard - - + Deck diff --git a/src/app/_components/_sharedcomponents/Popup/Popup.styles.ts b/src/app/_components/_sharedcomponents/Popup/Popup.styles.ts new file mode 100644 index 00000000..86ce3d4a --- /dev/null +++ b/src/app/_components/_sharedcomponents/Popup/Popup.styles.ts @@ -0,0 +1,120 @@ +export const buttonStyle = { + borderRadius: '15px', + backgroundColor: '#1E2D32', + padding: '1rem 1.5rem', + + border: '2px solid transparent', + background: + 'linear-gradient(#1E2D32, #1E2D32) padding-box, linear-gradient(to top, #038FC3, #595A5B) border-box', + '&:hover': { + background: 'hsl(195, 25%, 16%)', + }, + '&:disabled': { + color: '#666666', + }, +}; + +export const overlayStyle = { + position: 'absolute' as const, + width: '100%', + height: '100%', + pointerEvents: 'none', + + backgroundColor: 'rgba(0, 0, 0, 0.3)', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + zIndex: 10, +}; + +export const concedeButtonStyle = { + padding: '1rem 1.5rem', + borderRadius: '15px', + backgroundImage: 'linear-gradient(#1E2D32, #1E2D32)', + border: '2px solid transparent', + background: + 'linear-gradient(#380707, #380707) padding-box, linear-gradient(to top, #C30101, #7D0807) border-box', +}; + +export const contentStyle = (index: number) => ({ + padding: '2rem', + borderRadius: '15px', + position: 'absolute', + border: '2px solid transparent', + background: + 'linear-gradient(#0F1F27, #030C13) padding-box, linear-gradient(to top, #30434B, #50717D) border-box', + zIndex: 11 + index, + marginTop: index * 30, +}); + +export const containerStyle = { + alignItems: 'center', + justifyContent: 'center', + display: 'flex', + flexDirection: 'column', + textAlign: 'center', + + flex: 1, + maxHeight: '550px', + minHeigth: '260px', + height: '100%', + width: '100%', + minWidth: '560px', + maxWidth: '800px', +}; + +export const headerStyle = (isMinimized: boolean) => ({ + display: 'flex', + width: '100%', + justifyContent: 'space-between', + alignItems: 'center', + marginTop: '-10px', + marginBottom: isMinimized ? '-20px' : '0', +}); + +export const footerStyle = { + display: 'flex', + gap: '1rem', + marginTop: '2rem', + alignItems: 'center', + justifyContent: 'center', + width: '100%', +}; + +export const minimalButtonStyle = { + marginTop: '-15px', + color: 'white', + display: 'flex', +}; + +export const titleStyle = { + color: 'white', + fontSize: '1.25rem', + fontWeight: 'bold', + flex: 1, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', +}; + +export const textStyle = { + color: '#C7C7C7', +}; + +export const cardButtonStyle = { + backgroundColor: 'transparent', + padding: '0', + borderRadius: '8px', +}; + +export const selectedCardBorderStyle = (isSelected: boolean) => ({ + border: isSelected ? '2px solid #66E5FF' : '2px solid transparent', + borderRadius: '8px', +}); + +export const selectedIndicatorStyle = (isSelected: boolean) => ({ + backgroundColor: isSelected ? '#66E5FF' : '#666666', + height: '8px', + width: '8px', + borderRadius: '100%', +}); diff --git a/src/app/_components/_sharedcomponents/Popup/Popup.tsx b/src/app/_components/_sharedcomponents/Popup/Popup.tsx new file mode 100644 index 00000000..c8a34d22 --- /dev/null +++ b/src/app/_components/_sharedcomponents/Popup/Popup.tsx @@ -0,0 +1,58 @@ +'use client'; +import { PopupData, PopupType, usePopup } from '@/app/_contexts/Popup.context'; +import { Box, Button } from '@mui/material'; +import React from 'react'; +import { contentStyle, overlayStyle } from './Popup.styles'; +import { DefaultPopup, PilePopup, SelectCardsPopup } from './Popup.types'; +import { DefaultPopupModal } from './PopupVariant/DefaultPopup'; +import { PilePopupModal } from './PopupVariant/PilePopup'; +import { SelectCardsPopupModal } from './PopupVariant/SelectCardsPopup'; + +export const focusHandlerStyle = (index: number) => ({ + zIndex: 11 + index, + marginTop: index * 30, + padding: 0, + background: 'red', + minWidth: 'auto', + '&:hover': { + backgroundColor: 'transparent', + }, + pointerEvents: 'auto', +}); + +const PopupShell: React.FC = () => { + const { popups, focusPopup } = usePopup(); + + if (popups.length === 0) return null; // No popup to display + + const renderPopup = (type: PopupType, data: PopupData) => { + switch (type) { + case 'default': + return ; + case 'pile': + return ; + case 'select': + return ; + default: + return null; + } + }; + + return ( + + {popups.map((popup, index) => ( + + ))} + + ); +}; + +export default PopupShell; \ No newline at end of file diff --git a/src/app/_components/_sharedcomponents/Popup/Popup.types.ts b/src/app/_components/_sharedcomponents/Popup/Popup.types.ts new file mode 100644 index 00000000..738869dd --- /dev/null +++ b/src/app/_components/_sharedcomponents/Popup/Popup.types.ts @@ -0,0 +1,41 @@ +import { ICardData } from '../Cards/CardTypes'; + +export type PopupButton = { + text: string; + uuid: string; + command: string; + arg: string; +}; + +export type DefaultPopup = { + type: 'default'; + uuid: string; + title: string; + promptType?: string; + description?: string; + buttons: PopupButton[]; +}; + +export type SelectCardsPopup = { + type: 'select'; + uuid: string; + title: string; + maxNumber?: number; + cards: ICardData[]; + onConfirm: (cards: ICardData[]) => void; +}; + +// Necessary ? +export type SelectFromPilePopup = { + type: 'pile-select'; + uuid: string; + pile: ICardData[]; + onConfirm: (cards: ICardData[]) => void; +}; + +export type PilePopup = { + type: 'pile'; + uuid: string; + title: string; + cards: ICardData[]; +}; \ No newline at end of file diff --git a/src/app/_components/_sharedcomponents/Popup/PopupVariant/DefaultPopup.tsx b/src/app/_components/_sharedcomponents/Popup/PopupVariant/DefaultPopup.tsx new file mode 100644 index 00000000..5d56d45d --- /dev/null +++ b/src/app/_components/_sharedcomponents/Popup/PopupVariant/DefaultPopup.tsx @@ -0,0 +1,72 @@ +import { useGame } from '@/app/_contexts/Game.context'; +import { usePopup } from '@/app/_contexts/Popup.context'; +import { Box, Button, IconButton, Typography } from '@mui/material'; +import { MouseEvent, useState } from 'react'; +import { BiMinus, BiPlus } from 'react-icons/bi'; +import { + buttonStyle, + containerStyle, + footerStyle, + headerStyle, + minimalButtonStyle, + textStyle, + titleStyle, +} from '../Popup.styles'; +import { DefaultPopup, PopupButton } from '../Popup.types'; + +interface ButtonProps { + data: DefaultPopup; +} + +export const DefaultPopupModal = ({ data }: ButtonProps) => { + const { sendGameMessage } = useGame(); + const { closePopup } = usePopup(); + const [isMinimized, setIsMinimized] = useState(false); + + const renderPopupContent = () => { + if (isMinimized) return null; + return ( + <> + {data.description && ( + {data.description} + )} + + {data.buttons.map((button: PopupButton, index: number) => ( + + ))} + + + ); + }; + + const handleMinimize = (e: MouseEvent) => { + e.stopPropagation(); + setIsMinimized(!isMinimized); + }; + + return ( + + + {data.title} + + {isMinimized ? : } + + + {renderPopupContent()} + + ); +}; \ No newline at end of file diff --git a/src/app/_components/_sharedcomponents/Popup/PopupVariant/PilePopup.tsx b/src/app/_components/_sharedcomponents/Popup/PopupVariant/PilePopup.tsx new file mode 100644 index 00000000..14fd6793 --- /dev/null +++ b/src/app/_components/_sharedcomponents/Popup/PopupVariant/PilePopup.tsx @@ -0,0 +1,89 @@ +import { usePopup } from '@/app/_contexts/Popup.context'; +import { Box, Button, Grid2, IconButton, Typography } from '@mui/material'; +import { useState } from 'react'; +import { BiMinus, BiPlus } from 'react-icons/bi'; +import GameCard from '../../Cards/GameCard/GameCard'; +import { + buttonStyle, + containerStyle, + footerStyle, + headerStyle, + minimalButtonStyle, + titleStyle, +} from '../Popup.styles'; +import { PilePopup } from '../Popup.types'; + +interface ButtonProps { + data: PilePopup; +} + +export const gridContainerStyle = { + maxHeight: '60vh', + overflowY: 'auto', + marginTop: '1rem', + scrollbarColor: '#537079 transparent', + '&::-webkit-scrollbar-track': { + boxShadow: 'inset 0 0 6px rgba(0,0,0,0.00)', + webkitBoxShadow: 'inset 0 0 6px rgba(0,0,0,0.00)', + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: 'rgba(0,0,0,.1)', + outline: '1px solid slategrey', + }, + scrollbarGutter: 'stable', +}; + +export const PilePopupModal = ({ data }: ButtonProps) => { + const { closePopup } = usePopup(); + + const [isMinimized, setIsMinimized] = useState(false); + + const renderPopupContent = () => { + if (isMinimized) return null; + return ( + <> + + {data.cards.map((card, index) => ( + + + + ))} + + + + + + + ); + }; + + const handleMinimize = (e: React.MouseEvent) => { + e.stopPropagation(); + setIsMinimized(!isMinimized); + }; + + return ( + + + {data.title} + + {isMinimized ? : } + + + + {renderPopupContent()} + + ); +}; \ No newline at end of file diff --git a/src/app/_components/_sharedcomponents/Popup/PopupVariant/SelectCardsPopup.tsx b/src/app/_components/_sharedcomponents/Popup/PopupVariant/SelectCardsPopup.tsx new file mode 100644 index 00000000..3ca52195 --- /dev/null +++ b/src/app/_components/_sharedcomponents/Popup/PopupVariant/SelectCardsPopup.tsx @@ -0,0 +1,93 @@ +import { Box, Button, Typography } from '@mui/material'; +import { useState } from 'react'; +import { ICardData } from '../../Cards/CardTypes'; +import GameCard from '../../Cards/GameCard/GameCard'; +import { + buttonStyle, + cardButtonStyle, + containerStyle, + footerStyle, + selectedCardBorderStyle, + selectedIndicatorStyle, + titleStyle, +} from '../Popup.styles'; +import { SelectCardsPopup } from '../Popup.types'; + +const cardListContainerStyle = { + display: 'flex', + gap: '.25rem', + marginTop: '1rem', + overflowX: 'auto', +}; + +const cardSelectorStyle = { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + gap: '.5rem', +}; + +interface ButtonProps { + data: SelectCardsPopup; +} + +export const SelectCardsPopupModal = ({ data }: ButtonProps) => { + const [selectedCards, setSelectedCards] = useState< + Record + >([]); + + const handleCardClick = (index: number, card: ICardData) => { + if (!selectedCards[index]) { + setSelectedCards((prev) => ({ + ...prev, + [index]: [card], + })); + } else { + setSelectedCards((prev) => ({ + ...prev, + [index]: [...prev[index], card], + })); + } + }; + + const isSelectedCard = (index: number) => selectedCards[index] !== undefined; + const isButtonDisabled = () => + Object.keys(selectedCards).length === 0 || + (data.maxNumber !== undefined && data.maxNumber > Object.keys(selectedCards).length); + + // sort and not filter cards by selectable true first + const sortCards = (cards: ICardData[]) => + cards.sort((a, b) => Number(b.selectable) - Number(a.selectable)); + + return ( + + {data.title} + + {sortCards(data.cards).map((card, index) => ( + + + + + ))} + + + + + + ); +}; \ No newline at end of file diff --git a/src/app/_contexts/Game.context.tsx b/src/app/_contexts/Game.context.tsx index 86d5d3e9..daf39f30 100644 --- a/src/app/_contexts/Game.context.tsx +++ b/src/app/_contexts/Game.context.tsx @@ -10,6 +10,7 @@ import React, { } from 'react'; import io, { Socket } from 'socket.io-client'; import { useUser } from './User.context'; +import { usePopup } from './Popup.context'; interface IGameContextType { gameState: any; @@ -28,6 +29,7 @@ export const GameProvider = ({ children }: { children: ReactNode }) => { const [lobbyState, setLobbyState] = useState(null); const [socket, setSocket] = useState(undefined); const [connectedPlayer, setConnectedPlayer] = useState(''); + const { openPopup } = usePopup(); const { user } = useUser(); useEffect(() => { @@ -39,12 +41,30 @@ export const GameProvider = ({ children }: { children: ReactNode }) => { }, }); + const handleGameStatePopups = (gameState: any) => { + if (!user.id) return; + if (gameState.players?.[user.id].promptState) { + const promptState = gameState.players?.[user.id].promptState; + const { buttons, menuTitle, promptUuid, selectCard, promptType } = + promptState; + if (buttons.length > 0 && menuTitle && promptUuid && !selectCard) { + openPopup('default', { + uuid: promptUuid, + title: menuTitle, + promptType: promptType, + buttons, + }); + } + } + }; + newSocket.on('connect', () => { console.log(`Connected to server as ${user.username}`); }); newSocket.on('gamestate', (gameState: any) => { setGameState(gameState); console.log('Game state received:', gameState); + handleGameStatePopups(gameState); }); newSocket.on('lobbystate', (lobbyState: any) => { setLobbyState(lobbyState); diff --git a/src/app/_contexts/Popup.context.tsx b/src/app/_contexts/Popup.context.tsx new file mode 100644 index 00000000..b0819494 --- /dev/null +++ b/src/app/_contexts/Popup.context.tsx @@ -0,0 +1,95 @@ +'use client'; +import React, { createContext, useContext, useState } from 'react'; +import { + DefaultPopup, + PilePopup, + SelectCardsPopup, + SelectFromPilePopup, +} from '../_components/_sharedcomponents/Popup/Popup.types'; + +// TODO: SelectCardsPopup | LeaderAbilityPopup | DrawPopup | SelectCardsWithAspectPopup +export type PopupData = + | DefaultPopup + | SelectCardsPopup + | SelectFromPilePopup + | PilePopup; + +export type PopupType = PopupData['type']; + +export type PopupDataMap = { + default: Omit; + select: Omit; + pile: Omit; + 'pile-select': Omit; +}; + +interface PopupContextProps { + popups: PopupData[]; + openPopup: (type: T, data: PopupDataMap[T]) => void; + closePopup: (uuid: string) => void; + focusPopup: (uuid: string) => void; +} + +const PopupContext = createContext(undefined); + +export const PopupProvider: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + const [popups, setPopups] = useState([]); + + function isDefaultPopup(popup: PopupData): popup is DefaultPopup { + return (popup as DefaultPopup)?.promptType !== undefined; + } + + const openPopup = (type: T, data: PopupDataMap[T]) => { + if (popups.some((popup) => popup.uuid === data.uuid)) return; + if ( + popups.length > 0 && + popups.some((popup) => isDefaultPopup(popup)) && + isDefaultPopup({ type, ...data } as PopupData) + ) + return; + + console.log('Opening new popup with uuid', data.uuid); + setPopups((prev) => [...prev, { type, ...data } as PopupData]); + }; + + const closePopup = (uuid: string) => { + console.log('Closing popup with uuid', uuid); + + setPopups((prev) => prev.filter((popup) => popup.uuid !== uuid)); + }; + + const focusPopup = (uuid: string) => { + if (popups.length <= 1) return; + if (popups[popups.length - 1].uuid === uuid) return; + + setPopups((prev) => { + const index = prev.findIndex((popup) => popup.uuid === uuid); + if (index !== -1) { + const newPopups = [...prev]; + + const [popup] = newPopups.splice(index, 1); + newPopups.push(popup); + return newPopups; + } + return prev; + }); + }; + + return ( + + {children} + + ); +}; + +export const usePopup = () => { + const context = useContext(PopupContext); + if (!context) { + throw new Error('usePopup must be used within a PopupProvider'); + } + return context; +}; \ No newline at end of file From ea2ecf2f779fa775047263a122263cf434ad71ea Mon Sep 17 00:00:00 2001 From: HugoHMZ Date: Sat, 4 Jan 2025 18:09:22 +0900 Subject: [PATCH 2/4] [+] pile inspect: adding pile inspect locked position --- .../_sharedcomponents/Popup/Popup.styles.ts | 13 --- .../_sharedcomponents/Popup/Popup.tsx | 86 +++++++++++++++---- 2 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/app/_components/_sharedcomponents/Popup/Popup.styles.ts b/src/app/_components/_sharedcomponents/Popup/Popup.styles.ts index 86ce3d4a..8d7a790e 100644 --- a/src/app/_components/_sharedcomponents/Popup/Popup.styles.ts +++ b/src/app/_components/_sharedcomponents/Popup/Popup.styles.ts @@ -14,19 +14,6 @@ export const buttonStyle = { }, }; -export const overlayStyle = { - position: 'absolute' as const, - width: '100%', - height: '100%', - pointerEvents: 'none', - - backgroundColor: 'rgba(0, 0, 0, 0.3)', - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - zIndex: 10, -}; - export const concedeButtonStyle = { padding: '1rem 1.5rem', borderRadius: '15px', diff --git a/src/app/_components/_sharedcomponents/Popup/Popup.tsx b/src/app/_components/_sharedcomponents/Popup/Popup.tsx index c8a34d22..ce97b46d 100644 --- a/src/app/_components/_sharedcomponents/Popup/Popup.tsx +++ b/src/app/_components/_sharedcomponents/Popup/Popup.tsx @@ -1,31 +1,73 @@ 'use client'; import { PopupData, PopupType, usePopup } from '@/app/_contexts/Popup.context'; -import { Box, Button } from '@mui/material'; +import { Box, Button, SxProps, Theme } from '@mui/material'; import React from 'react'; -import { contentStyle, overlayStyle } from './Popup.styles'; import { DefaultPopup, PilePopup, SelectCardsPopup } from './Popup.types'; import { DefaultPopupModal } from './PopupVariant/DefaultPopup'; import { PilePopupModal } from './PopupVariant/PilePopup'; import { SelectCardsPopupModal } from './PopupVariant/SelectCardsPopup'; +import { contentStyle } from './Popup.styles'; +import { useGame } from '@/app/_contexts/Game.context'; -export const focusHandlerStyle = (index: number) => ({ +const overlayStyle = { + position: 'absolute', + width: '100%', + height: '100%', + pointerEvents: 'none', + backgroundColor: 'rgba(0, 0, 0, 0.3)', + display: 'flex', + zIndex: 10, +}; + +const focusHandlerStyle = (type: PopupType, data: PopupData, index: number, playerName:string): SxProps => ({ zIndex: 11 + index, - marginTop: index * 30, padding: 0, - background: 'red', minWidth: 'auto', '&:hover': { backgroundColor: 'transparent', }, pointerEvents: 'auto', + ...getPopupPosition(type, data, index, playerName) }); +export const getPopupPosition = (type: PopupType, data: PopupData, index: number, playerName:string) => { + const basePosition = { + position: 'absolute', + left: '50%', + transform: `translate(-50%, 0) translate(0px, ${index * 10}px)`, + }; + + const pilePosition = { + position: 'absolute', + left: '325px', + } + + if (type === 'pile') { + if (data.uuid === `${playerName}-discard`) { + return { + ...pilePosition, + bottom: '400px', + } as const; + } + return { + ...pilePosition, + top: '350px', + } as const; + } + + return { + ...basePosition, + top: '150px', + } as const; +} + const PopupShell: React.FC = () => { const { popups, focusPopup } = usePopup(); + const { connectedPlayer }= useGame(); if (popups.length === 0) return null; // No popup to display - const renderPopup = (type: PopupType, data: PopupData) => { + const renderPopupContent = (type: PopupType, data: PopupData) => { switch (type) { case 'default': return ; @@ -38,19 +80,29 @@ const PopupShell: React.FC = () => { } }; + const renderPopup= (popup: PopupData, index:number) => { + return ( + + ) + } + + const [nonDefaultPopups, defaultPopups] = [ + popups.filter((popup) => popup.type !== 'default'), + popups.filter((popup) => popup.type === 'default') + ]; + return ( - {popups.map((popup, index) => ( - - ))} + {defaultPopups.map((popup, index) => renderPopup(popup, index))} + {nonDefaultPopups.map((popup, index) => renderPopup(popup, index))} ); }; From 0fbd58f72c77fbf3f78084dc19fa870bf88ba13c Mon Sep 17 00:00:00 2001 From: HugoHMZ Date: Sun, 5 Jan 2025 03:49:14 +0900 Subject: [PATCH 3/4] [+] unwanted popups: preventing actionWindow popups to be created --- src/app/_contexts/Game.context.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/_contexts/Game.context.tsx b/src/app/_contexts/Game.context.tsx index daf39f30..8a8ee9f6 100644 --- a/src/app/_contexts/Game.context.tsx +++ b/src/app/_contexts/Game.context.tsx @@ -47,7 +47,8 @@ export const GameProvider = ({ children }: { children: ReactNode }) => { const promptState = gameState.players?.[user.id].promptState; const { buttons, menuTitle, promptUuid, selectCard, promptType } = promptState; - if (buttons.length > 0 && menuTitle && promptUuid && !selectCard) { + if (promptType === 'actionWindow') return; + else if (buttons.length > 0 && menuTitle && promptUuid && !selectCard) { openPopup('default', { uuid: promptUuid, title: menuTitle, From 90af06968d281b37614916b920769247bd29d7d0 Mon Sep 17 00:00:00 2001 From: Dan Bastin Date: Sun, 5 Jan 2025 17:27:36 -0500 Subject: [PATCH 4/4] temp fix for card border --- .../_sharedcomponents/Cards/GameCard/GameCard.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/_components/_sharedcomponents/Cards/GameCard/GameCard.tsx b/src/app/_components/_sharedcomponents/Cards/GameCard/GameCard.tsx index 2a4f028f..4bb4cf99 100644 --- a/src/app/_components/_sharedcomponents/Cards/GameCard/GameCard.tsx +++ b/src/app/_components/_sharedcomponents/Cards/GameCard/GameCard.tsx @@ -47,9 +47,9 @@ const GameCard: React.FC = ({ }*/ const handleClick = onClick ?? defaultClickFunction; const cardBorderColor = (card: ICardData) => { - if (card.selected) return 'yellow'; - if (card.selectable) return 'limegreen'; - if (card.exhausted) return 'gray'; + if (card?.selected) return 'yellow'; + if (card?.selectable) return 'limegreen'; + if (card?.exhausted) return 'gray'; return ''; } // helper function to get the correct aspects for the upgrade cards