Skip to content

Commit de67a78

Browse files
committed
lobby popup stack
1 parent 0237f13 commit de67a78

File tree

3 files changed

+97
-50
lines changed

3 files changed

+97
-50
lines changed

src/main/client/src/feature/lobby/Lobby.jsx

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
} from "./ActiveGames.jsx"
3131
import {
3232
useAuthStore,
33+
useLobbyStore,
3334
} from "src/store.js"
3435
import {
3536
CgClose,
@@ -44,25 +45,15 @@ const detailData = [
4445
]
4546

4647
export function Lobby() {
47-
let [isNewGameOpen, setNewGameOpen] = useState(false)
48+
let isNewGameOpen = useLobbyStore(state => state.isNewGameOpen())
49+
let setNewGameOpen = useLobbyStore(state => state.setNewGameOpen)
50+
let handleLobbyClick = useLobbyStore(state => state.handleLobbyClick)
51+
let closeLobbyPopup = useLobbyStore(state => state.closeLobbyPopup)
4852
let [detail, setDetail] = useState("open")
4953
let stompClient = useContext(StompContext)
5054
let navigate = useNavigate()
5155
let auth = useAuthStore(state => state.auth)
5256
let newGameRef = useRef()
53-
let onClickOutside = useCallback((event) => {
54-
if (!isNewGameOpen) {
55-
return
56-
}
57-
let el = newGameRef.current
58-
if (!el) {
59-
return
60-
}
61-
let rect = el.getBoundingClientRect()
62-
if (event.clientX > rect.right || event.clientX < rect.left || event.clientY > rect.bottom || event.clientY < rect.top) {
63-
setNewGameOpen(false)
64-
}
65-
}, [isNewGameOpen] )
6657
let onNewGame = useCallback((d) => doTry(async () => {
6758
let response = await tfetch("/api/create", {
6859
method: "POST",
@@ -77,7 +68,7 @@ export function Lobby() {
7768
navigate(base + "/game/" + game.id)
7869
sub.unsubscribe()
7970
})
80-
setNewGameOpen(false)
71+
closeLobbyPopup()
8172
}), [auth.token, navigate, stompClient])
8273
let onStartEdit = useCallback((d) => doTry(async () => {
8374
let response = await tfetch("/api/start_edit", {
@@ -91,27 +82,29 @@ export function Lobby() {
9182
navigate(base + "/game/" + response.id)
9283
}), [auth, navigate])
9384
return (
94-
<div onClick={onClickOutside} className="h-full">
85+
<div onClick={handleLobbyClick} className="h-full">
9586
<div className={twJoin(
9687
"mt-2 py-2 pr-4 gap-x-1",
9788
isNewGameOpen && "",
9889
!isNewGameOpen && "border-transparent",
9990
)}>
100-
{isNewGameOpen ? (
101-
<NewGameDialog
102-
newGameRef={newGameRef}
103-
onNewGame={onNewGame}
104-
onStartEdit={onStartEdit}
105-
setNewGameOpen={setNewGameOpen} />
106-
) : "" }
107-
<button disabled={isNewGameOpen} className={!isNewGameOpen ? twJoin(
91+
<NewGameDialog
92+
newGameRef={newGameRef}
93+
onNewGame={onNewGame}
94+
onStartEdit={onStartEdit} />
95+
<button disabled={isNewGameOpen} className={isNewGameOpen ? twJoin(
96+
"ml-2 border-2 bg-gray-400 border-transparent px-4 py-2 rounded-lg",
97+
) : twJoin(
10898
"ml-2 border-2 border-transparent px-4 py-2 rounded-lg",
10999
"hover:border-sky-700",
110-
) : twJoin(
111-
"ml-2 border-2 bg-gray-400 border-transparent px-4 py-2 rounded-lg",
112100
)}
113-
onClick={() => {
114-
setNewGameOpen(true)
101+
onClick={(event) => {
102+
setNewGameOpen(newGameRef.current)
103+
if (event.stopPropagation) {
104+
event.stopPropagation()
105+
} else {
106+
event.cancelBubble = true
107+
}
115108
}}>
116109
New Game
117110
</button>
@@ -131,12 +124,14 @@ export function Lobby() {
131124
)
132125
}
133126

134-
function NewGameDialog({onNewGame, onStartEdit, setNewGameOpen, newGameRef}) {
127+
function NewGameDialog({onNewGame, onStartEdit, newGameRef}) {
135128
let dimRef = useRef(9)
136129
let timeRef = useRef(10)
137130
let [edit, setEdit] = useState(false)
131+
let closeLobbyPopup = useLobbyStore(state => state.closeLobbyPopup)
132+
let isNewGameOpen = useLobbyStore(state => state.isNewGameOpen())
138133
return (
139-
<form className="contents" onSubmit={(e) => {
134+
<form onSubmit={(e) => {
140135
e.preventDefault()
141136
let game = {dim: dimRef.current, timesetting: timeRef.current}
142137
if (edit) {
@@ -145,9 +140,13 @@ function NewGameDialog({onNewGame, onStartEdit, setNewGameOpen, newGameRef}) {
145140
onNewGame(game)
146141
}
147142
}}>
148-
<div ref={newGameRef} className="absolute ml-40 bg-slate-800 border-2 border-slate-600 rounded-lg z-10 px-3 py-2">
143+
<div ref={newGameRef}
144+
className={twJoin(
145+
!isNewGameOpen && "hidden",
146+
"absolute ml-40 bg-slate-800 border-2 border-slate-600 rounded-lg z-10 px-3 py-2",
147+
)}>
149148
<div className="absolute top-1 right-1">
150-
<button onClick={() => setNewGameOpen(false)} className="text-stone-100 hover:text-stone-300">
149+
<button onClick={closeLobbyPopup} className="text-stone-100 hover:text-stone-300">
151150
<IconContext.Provider value={{ size: "1.25em" }}>
152151
<CgClose />
153152
</IconContext.Provider>

src/main/client/src/feature/lobby/OpenGames.jsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
} from "src/util.js"
3636
import {
3737
useAuthStore,
38+
useLobbyStore,
3839
} from "src/store.js"
3940

4041
export function OpenGames() {
@@ -87,13 +88,11 @@ export function OpenGames() {
8788
key={game.id} />
8889
))}
8990
</div>
90-
{acceptableGame && (
91-
<AcceptDialog
92-
acceptableGame={acceptableGame}
93-
setAcceptableGame={setAcceptableGame}
94-
onAccept={onAccept}
91+
<AcceptDialog
92+
acceptableGame={acceptableGame}
93+
setAcceptableGame={setAcceptableGame}
94+
onAccept={onAccept}
9595
/>
96-
)}
9796
</div>
9897
)
9998
}
@@ -139,7 +138,7 @@ function OpenGame({game, acceptableGame, setAcceptableGame}) {
139138
}
140139

141140
function AcceptDialog({acceptableGame, onAccept}) {
142-
let { top, right } = acceptableGame.rect
141+
let { top, right } = acceptableGame?.rect || {top: 0, right: 0}
143142
let [isFlip, setFlip] = useState(false)
144143
let [handi, setHandi] = useState(1)
145144
let auth = useAuthStore(state => state.auth)
@@ -151,15 +150,17 @@ function AcceptDialog({acceptableGame, onAccept}) {
151150
handicap: handi === 1 ? 0 : handi,
152151
})}
153152
style={{
154-
position: "absolute",
155153
top: top,
156154
left: Math.trunc(right) + 16,
157155
}}
158-
className="absolute bg-sky-200 px-4 py-3 rounded-lg z-10 flex flex-col">
156+
className={twJoin(
157+
!acceptableGame && "hidden",
158+
"absolute bg-sky-200 px-4 py-3 rounded-lg z-8 flex flex-col",
159+
)}>
159160
<div className="text-black">
160161
<button type="button" className="inline-flex" onClick={() => setFlip(!isFlip)}>
161162
<BabyStone color={isFlip ? "white": "black"} className="pr-2" />
162-
{acceptableGame.game.user}
163+
{acceptableGame?.game.user}
163164
</button>
164165
</div>
165166
<div className="text-black">

src/main/client/src/store.js

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,58 @@ export const useMuteStore = create(
4646
)
4747
)
4848

49-
export const useTimeoutStore = create(set => (
50-
{
51-
timeout: 10,
52-
setTimeout: timeout => set(produce(draft => {
53-
draft.timeout = timeout
54-
}), true)
55-
}
56-
))
49+
export const useTimeoutStore = create(set => ({
50+
timeout: 10,
51+
setTimeout: timeout => set(produce(draft => {
52+
draft.timeout = timeout
53+
}), true),
54+
}))
55+
56+
export const useLobbyStore = create((set, get) => ({
57+
stack: [],
58+
isNewGameOpen: () => {
59+
return get().stack.some(obj => obj.kind === "newgame")
60+
},
61+
setOpen: (el, kind) => set(produce(draft => {
62+
if (!el) {
63+
return
64+
}
65+
if (get().stack.some(obj => obj.kind === kind)) {
66+
return
67+
}
68+
let rect = el.getBoundingClientRect()
69+
draft.stack = [...get().stack, {
70+
kind: kind,
71+
left: rect.left,
72+
right: rect.right,
73+
bottom: rect.bottom,
74+
top: rect.top,
75+
}]
76+
}), true),
77+
setNewGameOpen: (el) => get().setOpen(el, "newgame"),
78+
isAcceptOpen: () => {
79+
return get().stack.some(obj => obj.kind === "accept")
80+
},
81+
setAcceptOpen: (el) => get().setOpen(el, "accept"),
82+
closeLobbyPopup: () => set(produce(draft => {
83+
if (!get().stack.length) {
84+
return
85+
}
86+
let newStack = [...get().stack]
87+
newStack.pop()
88+
draft.stack = newStack
89+
}), true),
90+
handleLobbyClick: (event) => set(produce(draft => {
91+
if (!get().stack.length) {
92+
return
93+
}
94+
let {clientX, clientY} = event
95+
let {left, right, top, bottom} = get().stack[get().stack.length - 1]
96+
if (clientX <= right && clientX >= left && clientY <= bottom && clientY >= top) {
97+
return
98+
}
99+
let newStack = [...get().stack]
100+
newStack.pop()
101+
draft.stack = newStack
102+
}), true),
103+
}))

0 commit comments

Comments
 (0)