-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Popup Manager #28
Popup Manager #28
Changes from 1 commit
7fb080e
4910437
3293a84
984fca0
1ea15d7
cd4f654
f02902c
2e05c96
c72b158
32de7d0
da51cff
30b88e6
ff1f392
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
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%)", | ||
}, | ||
}; | ||
|
||
export const overlayStyle = { | ||
position: "fixed" as const, | ||
inset: "0", | ||
backgroundColor: "rgba(0, 0, 0, 0.5)", | ||
display: "flex", | ||
justifyContent: "center", | ||
alignItems: "center", | ||
zIndex: 50, | ||
}; | ||
|
||
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 = { | ||
padding: "2rem", | ||
borderRadius: "15px", | ||
width: "90%", | ||
maxWidth: "500px", | ||
height: "260px", | ||
position: "relative" as const, | ||
|
||
border: "2px solid transparent", | ||
background: | ||
"linear-gradient(#0F1F27, #030C13) padding-box, linear-gradient(to top, #30434B, #50717D) border-box", | ||
}; | ||
|
||
export const containerStyle = { | ||
alignItems: "center", | ||
justifyContent: "center", | ||
display: "flex", | ||
flexDirection: "column", | ||
textAlign: "center", | ||
}; | ||
|
||
export const minimalButtonStyle = { | ||
position: "absolute", | ||
top: "0.5rem", | ||
right: "0.5rem", | ||
color: "white", | ||
}; | ||
|
||
export const titleStyle = { | ||
color: "white", | ||
fontSize: "1.25rem", | ||
fontWeight: "bold", | ||
}; | ||
|
||
export const textStyle = { | ||
color: "#C7C7C7", | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
"use client"; | ||
import { PopupData, PopupType, usePopup } from "@/app/_contexts/Popup.context"; | ||
import { Box, IconButton } from "@mui/material"; | ||
import React from "react"; | ||
import { BiMinus } from "react-icons/bi"; | ||
import { contentStyle, minimalButtonStyle, overlayStyle } from "./Popup.styles"; | ||
import { ConcedePopup, DefaultPopup, MulliganPopup } from "./Popup.types"; | ||
import { ConcededPopupModal } from "./PopupVariant/ConcedePopup"; | ||
import { DefaultPopupModal } from "./PopupVariant/DefaultPopup"; | ||
import { MulliganPopupModal } from "./PopupVariant/MulliganPopup"; | ||
|
||
const PopupShell: React.FC = () => { | ||
const { type, data, closePopup } = usePopup(); | ||
|
||
if (!type || !data) return null; // No popup to display | ||
|
||
const renderPopup = (type: PopupType, data: PopupData) => { | ||
switch (type) { | ||
case "default": | ||
return <DefaultPopupModal data={data as DefaultPopup} />; | ||
case "mulligan": | ||
return <MulliganPopupModal data={data as MulliganPopup} />; | ||
case "concede": | ||
return <ConcededPopupModal data={data as ConcedePopup} />; | ||
default: | ||
return null; | ||
} | ||
}; | ||
|
||
return ( | ||
<Box sx={overlayStyle}> | ||
<Box sx={contentStyle}> | ||
<IconButton | ||
sx={minimalButtonStyle} | ||
aria-label="minimize" | ||
onClick={closePopup} | ||
> | ||
<BiMinus /> | ||
</IconButton> | ||
{renderPopup(type, data)} | ||
</Box> | ||
</Box> | ||
); | ||
}; | ||
|
||
export default PopupShell; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
export type DefaultPopup = { | ||
type: "default"; | ||
title: string; | ||
description: string; | ||
onConfirm: () => void; | ||
onCancel: () => void; | ||
}; | ||
|
||
export type MulliganPopup = { | ||
type: "mulligan"; | ||
onDraw: () => void; | ||
onKeep: () => void; | ||
}; | ||
|
||
export type ConcedePopup = { | ||
type: "concede"; | ||
onConcede: () => void; | ||
onCancel: () => void; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Box, Button, Typography } from "@mui/material"; | ||
import { | ||
buttonStyle, | ||
concedeButtonStyle, | ||
containerStyle, | ||
textStyle, | ||
titleStyle, | ||
} from "../Popup.styles"; | ||
import { ConcedePopup } from "../Popup.types"; | ||
|
||
interface ButtonProps { | ||
data: ConcedePopup; | ||
} | ||
|
||
export const ConcededPopupModal = ({ data }: ButtonProps) => { | ||
return ( | ||
<Box sx={containerStyle}> | ||
<Typography sx={titleStyle}>Would you like to concede?</Typography> | ||
<Typography sx={textStyle}> | ||
Concede will end the game and declare you as the loser. | ||
</Typography> | ||
<Box sx={{ display: "flex", gap: "1rem", marginTop: "2rem" }}> | ||
<Button | ||
onClick={data.onConcede} | ||
sx={concedeButtonStyle} | ||
variant="contained" | ||
> | ||
Concede | ||
</Button> | ||
<Button onClick={data.onCancel} sx={buttonStyle}> | ||
Continue playing | ||
</Button> | ||
</Box> | ||
</Box> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Box, Button, Typography } from "@mui/material"; | ||
import { | ||
buttonStyle, | ||
containerStyle, | ||
textStyle, | ||
titleStyle, | ||
} from "../Popup.styles"; | ||
import { DefaultPopup } from "../Popup.types"; | ||
|
||
interface ButtonProps { | ||
data: DefaultPopup; | ||
} | ||
|
||
export const DefaultPopupModal = ({ data }: ButtonProps) => { | ||
return ( | ||
<Box sx={containerStyle}> | ||
<Typography sx={titleStyle}>{data.title}</Typography> | ||
<Typography sx={textStyle}>{data.description}</Typography> | ||
<Box sx={{ display: "flex", gap: "1rem", marginTop: "2rem" }}> | ||
<Button onClick={data.onConfirm} sx={buttonStyle} variant="contained"> | ||
Yes | ||
</Button> | ||
<Button onClick={data.onCancel} sx={buttonStyle}> | ||
No | ||
</Button> | ||
</Box> | ||
</Box> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { Box, Button, Typography } from "@mui/material"; | ||
import { | ||
buttonStyle, | ||
containerStyle, | ||
textStyle, | ||
titleStyle, | ||
} from "../Popup.styles"; | ||
import { MulliganPopup } from "../Popup.types"; | ||
|
||
interface ButtonProps { | ||
data: MulliganPopup; | ||
} | ||
|
||
export const MulliganPopupModal = ({ data }: ButtonProps) => { | ||
return ( | ||
<Box sx={containerStyle}> | ||
<Typography sx={titleStyle}>Would you like to mulligan?</Typography> | ||
<Typography sx={textStyle}> | ||
Mulligan will replace your initial 6 cards with another 6 new\nones. | ||
This action can only be done one time! | ||
</Typography> | ||
<Box sx={{ display: "flex", gap: "1rem", marginTop: "2rem" }}> | ||
<Button onClick={data.onDraw} sx={buttonStyle} variant="contained"> | ||
Draw another six | ||
</Button> | ||
<Button onClick={data.onKeep} sx={buttonStyle}> | ||
Keep this hand | ||
</Button> | ||
</Box> | ||
</Box> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
"use client"; | ||
import React, { createContext, useContext, useState } from "react"; | ||
import { | ||
ConcedePopup, | ||
DefaultPopup, | ||
MulliganPopup, | ||
} from "../_components/_sharedcomponents/Popup/Popup.types"; | ||
|
||
// TODO: SelectCardsPopup | LeaderAbilityPopup | DrawPopup | SelectCardsWithAspectPopup | ||
export type PopupData = DefaultPopup | MulliganPopup | ConcedePopup; | ||
|
||
export type PopupType = PopupData["type"]; | ||
|
||
export type PopupDataMap = { | ||
default: Omit<DefaultPopup, "type">; | ||
mulligan: Omit<MulliganPopup, "type">; | ||
concede: Omit<ConcedePopup, "type">; | ||
}; | ||
|
||
interface PopupContextProps { | ||
type?: PopupType; | ||
data?: PopupData; | ||
openPopup: <T extends PopupType>(type: T, data: PopupDataMap[T]) => void; | ||
closePopup: () => void; | ||
} | ||
|
||
const PopupContext = createContext<PopupContextProps | undefined>(undefined); | ||
|
||
export const PopupProvider: React.FC<{ children: React.ReactNode }> = ({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have support for multiple popups here or is that still WIP? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not yet. But refactoring the code to handle multiple popups will not be that struggling |
||
children, | ||
}) => { | ||
const [type, setType] = useState<PopupType | undefined>(undefined); | ||
const [data, setData] = useState<PopupData | undefined>(undefined); | ||
|
||
const openPopup = <T extends PopupType>(type: T, data: PopupDataMap[T]) => { | ||
setType(type); | ||
setData({ type, ...data } as PopupData); | ||
}; | ||
|
||
const closePopup = () => { | ||
console.log("Closing popup"); | ||
setType(undefined); | ||
setData(undefined); | ||
}; | ||
|
||
return ( | ||
<PopupContext.Provider value={{ type, data, openPopup, closePopup }}> | ||
{children} | ||
</PopupContext.Provider> | ||
); | ||
}; | ||
|
||
export const usePopup = () => { | ||
const context = useContext(PopupContext); | ||
if (!context) { | ||
throw new Error("usePopup must be used within a PopupProvider"); | ||
} | ||
return context; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,33 @@ | ||
// layout.tsx | ||
import type { Metadata } from "next"; | ||
import React from 'react'; | ||
import ClientLayout from './ClientLayout'; | ||
import { Barlow } from "next/font/google"; | ||
import React from "react"; | ||
import { PopupProvider } from "./_contexts/Popup.context"; | ||
import "./_utils/s3Utils"; | ||
import ClientLayout from "./ClientLayout"; | ||
|
||
const barlow = Barlow({ | ||
subsets: ["latin"], | ||
weight: ["400", "600", "800"], | ||
variable: "--font-barlow", | ||
subsets: ["latin"], | ||
weight: ["400", "600", "800"], | ||
variable: "--font-barlow", | ||
}); | ||
|
||
export const metadata: Metadata = { | ||
title: "Karabast", | ||
title: "Karabast", | ||
}; | ||
|
||
export default function RootLayout({ children }: { children: React.ReactNode }) { | ||
export default function RootLayout({ | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
}) { | ||
return ( | ||
<html lang="en" className={barlow.variable}> | ||
<body> | ||
<ClientLayout>{children}</ClientLayout> | ||
<PopupProvider> | ||
HugoHMZ marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<ClientLayout>{children}</ClientLayout> | ||
</PopupProvider> | ||
</body> | ||
</html> | ||
); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this a fine direction for this as far as giving us the ability to render different kinds of popups. However, I would think less about rendering specific popup and more about popup "forms" For instance, here, the concede and mulligan popups are essentially identical to the default popup. In fact both of these could be created using the default popup.
It may be that you only included these as a demonstration of selecting the popup type, but certainly the default popup is on the right track for what we want. I think it will be helpful for you to get into a game and start looking at some of the prompts we're receiving fromt he back end. I think even just this default prompt would handle a lot of cases if we change it to render the buttons provided by the prompts instead of just a yes no. I would take a look at the BasicPrompt already in the frontend code as a reference for how the default might work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see. About mulligan and concede, I saw a possible interest for a variant of design(red button because it's important action, or anything imaginable), but we can definitely make it part of the data object we pass to the openPopup method.
About the different prompts, I know that 80% of the prompts can be handled using the basic variant, it was mainly to show flexibility of coding. For the final versions, I see 4 variants: