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
Tweak layout for mobile, format
bwc9876.dev
3 weeks ago
a90bc069
0c840d95
verified
This commit was signed with the committer's
known signature
.
bwc9876.dev
SSH Key Fingerprint:
SHA256:DanMEP/RNlSC7pAVbnXO6wzQV00rqyKj053tz4uH5gQ=
+55
-46
9 changed files
expand all
collapse all
unified
split
TODO.md
frontend
src
components
LobbyScreen.tsx
game-settings
GameSettingsModal.tsx
SettingsAdmo.tsx
SettingsField.tsx
SettingsSection.tsx
SliderField.tsx
StartConditionField.tsx
style.css
-1
TODO.md
···
1
1
# TODO
2
2
3
3
-
- [ ] Start on game settings form
4
3
- [ ] Setup screen
+3
-3
frontend/src/components/LobbyScreen.tsx
···
179
179
deco="seeker"
180
180
/>
181
181
<div className="frame">
182
182
-
<button onClick={onLeaveLobby} className="fab left">
182
182
+
<button onClick={onLeaveLobby} className="fab tl">
183
183
<IconArrowBigLeftLinesFilled size="1.5em" />
184
184
Leave
185
185
</button>
186
186
{lobbyState.is_host && (
187
187
-
<button onClick={onOpenSettings} className="fab center">
187
187
+
<button onClick={onOpenSettings} className="fab bl">
188
188
<IconSettingsFilled size="1.5em" />
189
189
Rules
190
190
</button>
191
191
)}
192
192
{lobbyState.is_host && (
193
193
-
<button disabled={!canStart} onClick={onStartGame} className="fab right">
193
193
+
<button disabled={!canStart} onClick={onStartGame} className="fab br">
194
194
<IconFlagFilled size="1.5em" />
195
195
Start
196
196
</button>
+14
-7
frontend/src/components/game-settings/GameSettingsModal.tsx
···
19
19
const [pingInterval, setPingInterval] = useState(gameSettings.ping_minutes_interval);
20
20
21
21
const onSaveClick = () => {
22
22
-
const newSettings = {...gameSettings, hiding_time_seconds: hidingTime, ping_start: pingStart, ping_minutes_interval: pingInterval};
23
23
-
onSave(newSettings);
22
22
+
const newSettings = {
23
23
+
...gameSettings,
24
24
+
hiding_time_seconds: hidingTime,
25
25
+
ping_start: pingStart,
26
26
+
ping_minutes_interval: pingInterval
27
27
+
};
28
28
+
onSave(newSettings);
24
29
};
25
30
26
31
const HiderIcon = iconForDecor("hider");
···
28
33
return (
29
34
<div className="screen-cover">
30
35
<dialog className="settings-popup">
31
31
-
<h2><IconSettingsFilled/> Game Rules</h2>
36
36
+
<h2>
37
37
+
<IconSettingsFilled /> Game Rules
38
38
+
</h2>
32
39
<div>
33
33
-
<SettingsSection icon={<HiderIcon/>} title="Hiding">
40
40
+
<SettingsSection icon={<HiderIcon />} title="Hiding">
34
41
<SettingsAdmo>
35
42
Hiders will have a period of time to hide.
36
43
<br />
37
44
After this, seekers are allowed to begin searching.
38
45
</SettingsAdmo>
39
46
<SliderField
40
40
-
label="Hiding Time"
47
47
+
label="Hide For"
41
48
displayValue={`${hidingTime / 60} minutes`}
42
49
value={hidingTime / 60}
43
50
min={2}
···
47
54
}}
48
55
/>
49
56
</SettingsSection>
50
50
-
<SettingsSection icon={<IconMapPinFilled/>} title="Pings">
57
57
+
<SettingsSection icon={<IconMapPinFilled />} title="Pings">
51
58
<SettingsAdmo>
52
59
Pings are when hider locations are shared with everyone.
53
60
<br />
54
61
They start after seekers are released and continue at an interval.
55
62
</SettingsAdmo>
56
63
<StartConditionField
57
57
-
label="Pings Will Start"
64
64
+
label="Pings Start"
58
65
value={pingStart}
59
66
onChange={(val) => setPingStart(val)}
60
67
/>
+2
-5
frontend/src/components/game-settings/SettingsAdmo.tsx
···
1
1
import { IconInfoCircleFilled } from "@tabler/icons-react";
2
2
import React, { PropsWithChildren } from "react";
3
3
4
4
-
export default function SettingsAdmo({children}: PropsWithChildren<{}>) {
5
5
-
return <p>
6
6
-
{children}
7
7
-
</p>;
4
4
+
export default function SettingsAdmo({ children }: PropsWithChildren<{}>) {
5
5
+
return <p>{children}</p>;
8
6
}
9
9
-
+1
-5
frontend/src/components/game-settings/SettingsField.tsx
···
2
2
3
3
export type SettingsFieldProps = PropsWithChildren<{ label: string; displayValue: string }>;
4
4
5
5
-
export default function SettingsField({
6
6
-
label,
7
7
-
displayValue,
8
8
-
children
9
9
-
}: SettingsFieldProps) {
5
5
+
export default function SettingsField({ label, displayValue, children }: SettingsFieldProps) {
10
6
return (
11
7
<label>
12
8
<span>{label}</span>
+13
-7
frontend/src/components/game-settings/SettingsSection.tsx
···
1
1
import React, { PropsWithChildren, ReactNode } from "react";
2
2
3
3
-
4
4
-
export default function SettingsSection({title, children, icon}: PropsWithChildren<{title: string, icon: ReactNode}>) {
5
5
-
return <fieldset>
6
6
-
<h3>{icon} {title}</h3>
7
7
-
{children}
8
8
-
</fieldset>;
3
3
+
export default function SettingsSection({
4
4
+
title,
5
5
+
children,
6
6
+
icon
7
7
+
}: PropsWithChildren<{ title: string; icon: ReactNode }>) {
8
8
+
return (
9
9
+
<fieldset>
10
10
+
<h3>
11
11
+
{icon} {title}
12
12
+
</h3>
13
13
+
{children}
14
14
+
</fieldset>
15
15
+
);
9
16
}
10
10
-
+1
-1
frontend/src/components/game-settings/SliderField.tsx
···
1
1
import React, { HTMLProps } from "react";
2
2
import SettingsField, { SettingsFieldProps } from "./SettingsField";
3
3
4
4
-
type Props = Omit<Omit<HTMLProps<HTMLInputElement>,"type">, "label"> &
4
4
+
type Props = Omit<Omit<HTMLProps<HTMLInputElement>, "type">, "label"> &
5
5
Omit<SettingsFieldProps, "children">;
6
6
7
7
export default function SliderField({ label, displayValue, ...rest }: Props) {
+2
-2
frontend/src/components/game-settings/StartConditionField.tsx
···
11
11
const startConditionOptions = {
12
12
instant: "Instantly",
13
13
minutes: "After _ Minutes",
14
14
-
players: "After _ Players Caught"
14
14
+
players: "After _ Caught"
15
15
};
16
16
17
17
const startConditionDefaults: Record<keyof typeof startConditionOptions, PingStartCondition> = {
···
98
98
))}
99
99
</select>
100
100
</SettingsField>
101
101
-
{(sliderVal !== null) && (
101
101
+
{sliderVal !== null && (
102
102
<input
103
103
className="extra"
104
104
min={1}
+19
-15
frontend/src/style.css
···
225
225
font-family: "Bungee";
226
226
border-bottom: solid 2px #aaa;
227
227
display: flex;
228
228
-
gap: .2em;
228
228
+
gap: 0.2em;
229
229
align-items: center;
230
230
justify-content: center;
231
231
}
···
235
235
font-family: "Bungee";
236
236
margin: 0;
237
237
display: flex;
238
238
-
gap: .2em;
238
238
+
gap: 0.2em;
239
239
align-items: center;
240
240
}
241
241
···
273
273
border: none;
274
274
border-radius: 5px;
275
275
margin: 0;
276
276
-
padding: var(--1);
276
276
+
padding: 0 var(--1);
277
277
width: 100%;
278
278
height: 100%;
279
279
}
280
280
}
281
281
282
282
select {
283
283
-
padding: .5em 0;
283
283
+
padding: 0.5em 0;
284
284
}
285
285
286
286
input {
···
421
421
align-items: center;
422
422
justify-content: center;
423
423
gap: 0.3em;
424
424
-
font-size: 14pt;
424
424
+
font-size: 12pt;
425
425
padding: var(--2);
426
426
position: absolute;
427
427
-
bottom: var(--small);
428
427
429
428
&:disabled {
430
429
background-color: #999;
···
432
431
box-shadow: 0 0 5px #4445 inset;
433
432
}
434
433
435
435
-
&.left {
436
436
-
left: var(--small);
434
434
+
&.bl {
435
435
+
left: 0.5em;
436
436
+
bottom: var(--small);
437
437
}
438
438
439
439
-
&.right {
440
440
-
right: var(--small);
439
439
+
&.br {
440
440
+
right: 0.5em;
441
441
+
bottom: var(--small);
441
442
}
442
443
443
443
-
&.center {
444
444
-
max-width: min-content;
445
445
-
margin: auto;
446
446
-
left: 0;
447
447
-
right: 0;
444
444
+
&.tr {
445
445
+
right: 0.5em;
446
446
+
top: var(--small);
447
447
+
}
448
448
+
449
449
+
&.tl {
450
450
+
left: 0.5em;
451
451
+
top: var(--small);
448
452
}
449
453
}