tangled
alpha
login
or
join now
bwc9876.dev
/
manhunt-app
0
fork
atom
Live location tracking and playback for the game "manhunt"
0
fork
atom
overview
issues
pulls
1
pipelines
Add start game button, lobby screen cleanup
bwc9876.dev
2 weeks ago
79517e8d
aaa78e33
verified
This commit was signed with the committer's
known signature
.
bwc9876.dev
SSH Key Fingerprint:
SHA256:DanMEP/RNlSC7pAVbnXO6wzQV00rqyKj053tz4uH5gQ=
+137
-73
4 changed files
expand all
collapse all
unified
split
TODO.md
frontend
src
components
LobbyScreen.tsx
MenuScreen.tsx
style.css
+2
-1
TODO.md
···
1
1
# TODO
2
2
3
3
-
- [ ] Start on start game and game settings buttons
3
3
+
- [ ] Start on game settings form
4
4
+
- [ ] Setup screen
+48
-9
frontend/src/components/LobbyScreen.tsx
···
2
2
import { commands, LobbyState, PlayerProfile } from "@/bindings";
3
3
import { useTauriEvent } from "@/lib/hooks";
4
4
import ProfilePicture, { iconForDecor, ProfileDecor } from "./ProfilePicture";
5
5
-
import { tempSettings } from "./MenuScreen";
5
5
+
import { defaultSettings } from "./MenuScreen";
6
6
import { ask } from "@tauri-apps/plugin-dialog";
7
7
import {
8
8
IconArrowBigLeftLinesFilled,
9
9
IconCircleCheckFilled,
10
10
-
IconCircleDashedPlus
10
10
+
IconCircleDashedPlus,
11
11
+
IconFlagFilled
11
12
} from "@tabler/icons-react";
12
13
import LoadingCover from "./LoadingCover";
13
14
14
15
function ProfileList({
15
16
profiles,
16
16
-
decoration
17
17
+
decoration,
18
18
+
emptyText
17
19
}: {
18
20
profiles: [string, PlayerProfile][];
19
21
decoration: ProfileDecor;
22
22
+
emptyText: string;
20
23
}) {
21
24
return (
22
22
-
<div className="lobby-pfps">
25
25
+
<div className="pfp-list">
26
26
+
{profiles.length === 0 && <small>{emptyText}</small>}
23
27
{profiles.map(([k, p]) => (
24
28
<ProfilePicture
25
29
key={k}
···
60
64
teams: {},
61
65
self_id: "",
62
66
is_host: false,
63
63
-
settings: tempSettings
67
67
+
settings: defaultSettings()
64
68
};
65
69
66
70
export default function LobbyScreen() {
···
111
115
});
112
116
};
113
117
118
118
+
const canStart = lobbyState.is_host && seekers.length !== 0 && hiders.length !== 0;
119
119
+
120
120
+
const onStartGame = () => {
121
121
+
if (canStart) {
122
122
+
setLoadingCover(true);
123
123
+
ask(
124
124
+
"Are you ready to start the game? New players will be unable to join. The hiding timer will begin the moment you press start."
125
125
+
)
126
126
+
.then((choice) => {
127
127
+
if (choice) {
128
128
+
commands.hostStartGame().finally(() => {
129
129
+
setLoadingCover(false);
130
130
+
});
131
131
+
} else {
132
132
+
setLoadingCover(false);
133
133
+
}
134
134
+
})
135
135
+
.catch(() => {
136
136
+
setLoadingCover(false);
137
137
+
});
138
138
+
}
139
139
+
};
140
140
+
114
141
return (
115
142
<>
116
116
-
<LoadingCover text="Fetching Info" show={loadingCover} />
143
143
+
<LoadingCover show={loadingCover} />
117
144
<header>
118
145
<span className="grow">Lobby</span>
119
146
<span>Join: {lobbyState.join_code}</span>
120
147
</header>
121
148
<main className="lobby">
122
122
-
<ProfileList profiles={seekers} decoration="seeker" />
149
149
+
<ProfileList profiles={seekers} decoration="seeker" emptyText="No Seekers" />
123
150
<TeamButton
124
151
onClick={() => commands.switchTeams(true)}
125
152
active={isSeeker}
···
128
155
/>
129
156
<div className="frame">
130
157
<button onClick={onLeaveLobby} aria-label="Leave Lobby" className="fab left">
131
131
-
<IconArrowBigLeftLinesFilled size="2em" />
158
158
+
<IconArrowBigLeftLinesFilled size="1.5em" />
159
159
+
Leave
132
160
</button>
161
161
+
{lobbyState.is_host && (
162
162
+
<button
163
163
+
disabled={!canStart}
164
164
+
onClick={onStartGame}
165
165
+
aria-label="Start Game"
166
166
+
className="fab right"
167
167
+
>
168
168
+
<IconFlagFilled size="1.5em" />
169
169
+
Start
170
170
+
</button>
171
171
+
)}
133
172
</div>
134
173
<TeamButton
135
174
onClick={() => commands.switchTeams(false)}
···
137
176
text="Hiders"
138
177
deco="hider"
139
178
/>
140
140
-
<ProfileList profiles={hiders} decoration="hider" />
179
179
+
<ProfileList profiles={hiders} decoration="hider" emptyText="No Hiders" />
141
180
</main>
142
181
</>
143
182
);
+7
-14
frontend/src/components/MenuScreen.tsx
···
10
10
import LoadingCover from "./LoadingCover";
11
11
import { message } from "@tauri-apps/plugin-dialog";
12
12
13
13
-
// Temp settings for now.
14
14
-
export const tempSettings: GameSettings = {
15
15
-
random_seed: 21341234,
16
16
-
hiding_time_seconds: 10,
13
13
+
export const defaultSettings: () => GameSettings = () => ({
14
14
+
random_seed: Math.floor(Math.random() * 2 ** 32),
15
15
+
hiding_time_seconds: 60 * 5,
17
16
ping_start: "Instant",
18
17
ping_minutes_interval: 1,
19
18
powerup_start: "Instant",
20
19
powerup_chance: 60,
21
20
powerup_minutes_cooldown: 1,
22
22
-
powerup_locations: [
23
23
-
{
24
24
-
lat: 0,
25
25
-
long: 0,
26
26
-
heading: null
27
27
-
}
28
28
-
]
29
29
-
};
21
21
+
powerup_locations: []
22
22
+
});
30
23
31
24
const defaultProfile: PlayerProfile = {
32
25
display_name: "",
···
50
43
}, [setProfile]);
51
44
52
45
const startLobby = useCallback(() => {
53
53
-
commands.startLobby(null, tempSettings);
46
46
+
commands.startLobby(null, defaultSettings());
54
47
}, []);
55
48
56
49
const joinLobby = useCallback(() => {
···
65
58
.checkRoomCode(cleanedCode)
66
59
.then((valid) => {
67
60
if (valid) {
68
68
-
commands.startLobby(cleanedCode, tempSettings).finally(() => {
61
61
+
commands.startLobby(cleanedCode, defaultSettings()).finally(() => {
69
62
setLoadingCover(false);
70
63
});
71
64
} else {
+80
-49
frontend/src/style.css
···
66
66
67
67
.map {
68
68
flex-grow: 1;
69
69
-
background-color: #111;
69
69
+
background-color: #211; /* TEMP: Until I set up and actual map */
70
70
}
71
71
72
72
-
.lobby-pfps {
73
73
-
z-index: 2;
74
74
-
overflow-x: auto;
75
75
-
box-shadow: 0 0 10px #0004;
76
76
-
display: flex;
77
77
-
flex-direction: row;
78
78
-
gap: var(--2);
79
79
-
width: 100%;
80
80
-
font-size: 20pt;
81
81
-
min-height: calc(20pt + var(--2));
82
82
-
padding: var(--small);
83
83
-
}
72
72
+
&.lobby {
73
73
+
.frame {
74
74
+
flex-grow: 1;
75
75
+
background-color: #aaa;
76
76
+
position: relative;
77
77
+
overflow-y: scroll;
78
78
+
width: 100%;
79
79
+
}
80
80
+
81
81
+
.pfp-list {
82
82
+
z-index: 4;
83
83
+
overflow-x: auto;
84
84
+
box-shadow: 0 0 10px #0004;
85
85
+
display: flex;
86
86
+
flex-direction: row;
87
87
+
align-items: center;
88
88
+
justify-content: center;
89
89
+
gap: var(--2);
90
90
+
width: 100%;
91
91
+
font-size: 20pt;
92
92
+
height: 5vh;
93
93
+
padding: var(--small) 0;
84
94
85
85
-
.team-button {
86
86
-
display: flex;
87
87
-
flex-direction: row;
88
88
-
align-items: center;
89
89
-
justify-content: center;
90
90
-
font-size: 16pt;
91
91
-
gap: var(--small);
92
92
-
padding: var(--1);
93
93
-
border: none;
95
95
+
small {
96
96
+
font-size: 0.7em;
97
97
+
font-style: italic;
98
98
+
color: #383838ff;
99
99
+
}
94
100
95
95
-
&.hider {
96
96
-
background-color: #67c;
97
97
-
}
101
101
+
.pfp {
102
102
+
transition: transform 175ms linear;
98
103
99
99
-
&.seeker {
100
100
-
background-color: #c67;
104
104
+
@starting-style {
105
105
+
transform: scale(0);
106
106
+
}
107
107
+
}
101
108
}
102
102
-
}
103
109
104
104
-
&.lobby > div.frame {
105
105
-
flex-grow: 1;
106
106
-
background-color: #aaa;
107
107
-
position: relative;
108
108
-
overflow-y: scroll;
109
109
-
width: 100%;
110
110
-
111
111
-
button.fab {
112
112
-
background-color: black;
113
113
-
color: white;
114
114
-
border-radius: 50%;
115
115
-
box-shadow: 0 0 5px black;
116
116
-
border: none;
110
110
+
.team-button {
117
111
display: flex;
112
112
+
--deco: black;
113
113
+
z-index: 3;
114
114
+
flex-direction: row;
118
115
align-items: center;
119
116
justify-content: center;
120
120
-
font-size: 12pt;
121
121
-
padding: var(--2);
122
122
-
position: absolute;
123
123
-
bottom: var(--small);
117
117
+
box-shadow: 0 0 5px var(--deco);
118
118
+
background-color: var(--deco);
119
119
+
font-size: 16pt;
120
120
+
gap: var(--small);
121
121
+
padding: var(--1) 0;
122
122
+
border: none;
124
123
125
125
-
&.left {
126
126
-
left: var(--small);
124
124
+
&.hider {
125
125
+
--deco: #67c;
127
126
}
128
127
129
129
-
&.right {
130
130
-
right: var(--small);
128
128
+
&.seeker {
129
129
+
--deco: #c67;
131
130
}
132
131
}
133
132
}
···
267
266
--deco-color: #67c;
268
267
}
269
268
}
269
269
+
270
270
+
button.fab {
271
271
+
transition: 100ms linear;
272
272
+
transition-property: color, background-color, box-shadow;
273
273
+
background-color: #151515ff;
274
274
+
color: #eee;
275
275
+
border-radius: 100px;
276
276
+
box-shadow: 0 0 6px #222;
277
277
+
border: none;
278
278
+
display: flex;
279
279
+
align-items: center;
280
280
+
justify-content: center;
281
281
+
gap: 0.3em;
282
282
+
font-size: 14pt;
283
283
+
padding: var(--2);
284
284
+
position: absolute;
285
285
+
bottom: var(--small);
286
286
+
287
287
+
&:disabled {
288
288
+
background-color: #999;
289
289
+
color: #555;
290
290
+
box-shadow: 0 0 5px #4445 inset;
291
291
+
}
292
292
+
293
293
+
&.left {
294
294
+
left: var(--small);
295
295
+
}
296
296
+
297
297
+
&.right {
298
298
+
right: var(--small);
299
299
+
}
300
300
+
}