Skip to content

Commit 8b27102

Browse files
committed
feat: mobile improvements
1 parent b7d9ad6 commit 8b27102

File tree

5 files changed

+158
-72
lines changed

5 files changed

+158
-72
lines changed

src/Schedule.tsx

Lines changed: 113 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react'
2-
import { useState } from 'react'
2+
import { useState, useRef } from 'react'
33
import { Table } from './style/Table'
44
import {
55
Button,
@@ -51,6 +51,12 @@ const Countdown = ({
5151

5252
const userTimeZone = new Intl.DateTimeFormat().resolvedOptions().timeZone
5353

54+
type AddSession = {
55+
name: string
56+
hour: number
57+
minute: number
58+
}
59+
5460
export const Schedule = ({
5561
conferenceName,
5662
conferenceDate,
@@ -67,7 +73,24 @@ export const Schedule = ({
6773
const [updatedDay, updateDay] = useState(conferenceDate)
6874
const [updatedTimeZone, updateTimeZone] = useState(eventTimezoneName)
6975
const [updatedSessions, updateSessions] = useState(sessions)
70-
const [add, updateAdd] = useState({ name: '', hour: 0, minute: 0 })
76+
const [add, updateAdd] = useState<AddSession>({
77+
name: '',
78+
hour: 0,
79+
minute: 0,
80+
})
81+
const inputRef = useRef<HTMLInputElement>(null)
82+
const isInputValid = () =>
83+
add.name.length > 0 &&
84+
add.hour >= 0 &&
85+
add.hour <= 23 &&
86+
add.minute >= 0 &&
87+
add.minute <= 59
88+
89+
const addSession = (add: AddSession) =>
90+
updateSessions((sessions) => ({
91+
...sessions,
92+
[parseInt(`${add.hour}${add.minute}`, 10)]: add.name,
93+
}))
7194

7295
const toUserTime = (time: number) => {
7396
const minutes = time % 100
@@ -100,7 +123,7 @@ export const Schedule = ({
100123
<Table>
101124
<thead>
102125
<tr>
103-
<th colSpan={4}>
126+
<th colSpan={editing ? 3 : 4}>
104127
{!editing && `${updatedName}: ${updatedDay}`}
105128
{editing && (
106129
<>
@@ -141,7 +164,7 @@ export const Schedule = ({
141164
</th>
142165
</tr>
143166
<tr>
144-
<th>
167+
<th colSpan={editing ? 2 : 1}>
145168
Conf Time
146169
<br />
147170
{editing && (
@@ -152,99 +175,126 @@ export const Schedule = ({
152175
)}
153176
{!editing && <small>{updatedTimeZone}</small>}
154177
</th>
155-
<th>
156-
Your Time
157-
<br />
158-
<small>{userTimeZone}</small>
159-
</th>
160-
<th>Starts in</th>
178+
{!editing && (
179+
<>
180+
<th>
181+
Your Time
182+
<br />
183+
<small>{userTimeZone}</small>
184+
</th>
185+
<th>Starts in</th>
186+
</>
187+
)}
161188
<th>Session</th>
162189
</tr>
163190
</thead>
164191
<tbody>
165-
{Object.entries(updatedSessions).map(([time, name]) => (
166-
<tr key={time}>
167-
<td className={'time'}>
168-
{formatEventTime(toEventTime((time as unknown) as number))}
169-
</td>
170-
<td className={'time'}>
171-
{formatUserTime(toUserTime((time as unknown) as number))}
172-
</td>
173-
<Countdown
174-
key={updatedDay}
175-
startTime={toUserTime((time as unknown) as number)}
176-
/>
177-
<td>
178-
{name}
179-
{editing && (
180-
<DeleteButton>
181-
<DeleteIcon
182-
onClick={() => {
183-
updateSessions((sessions) => {
184-
const s = { ...sessions }
185-
delete s[(time as unknown) as number]
186-
return s
187-
})
188-
}}
189-
/>
190-
</DeleteButton>
191-
)}
192-
</td>
193-
</tr>
194-
))}
195192
{editing && (
196193
<tr>
194+
<td>
195+
<AddButton
196+
disabled={!isInputValid()}
197+
onClick={() => {
198+
addSession(add)
199+
}}
200+
>
201+
<AddIcon />
202+
</AddButton>
203+
</td>
197204
<td className="time">
198205
<NumberInput
206+
ref={inputRef}
199207
type="number"
200208
min={0}
201209
max={23}
202210
value={add.hour}
203-
onChange={({ target: { value } }) =>
204-
updateAdd({
205-
...add,
206-
hour: parseInt(value, 10),
207-
})
208-
}
211+
onChange={({ target: { value } }) => {
212+
try {
213+
const hour = parseInt(value, 10)
214+
updateAdd({
215+
...add,
216+
hour,
217+
})
218+
} catch {}
219+
}}
209220
/>
221+
{':'}
210222
<NumberInput
211223
type="number"
212224
min={0}
213225
max={59}
214226
value={add.minute}
215-
onChange={({ target: { value } }) =>
216-
updateAdd({
217-
...add,
218-
minute: parseInt(value, 10),
219-
})
220-
}
227+
onChange={({ target: { value } }) => {
228+
try {
229+
const minute = parseInt(value, 10)
230+
updateAdd({
231+
...add,
232+
minute,
233+
})
234+
} catch {}
235+
}}
221236
/>
222237
</td>
223-
<td colSpan={2}></td>
224238
<td>
225239
<Input
226240
type="text"
227241
value={add.name}
242+
onKeyUp={({ key }) => {
243+
if (key === 'Enter') {
244+
if (isInputValid()) {
245+
addSession(add)
246+
updateAdd({
247+
...add,
248+
name: '',
249+
})
250+
inputRef.current?.focus()
251+
}
252+
}
253+
}}
228254
onChange={({ target: { value } }) =>
229255
updateAdd({
230256
...add,
231257
name: value,
232258
})
233259
}
234260
/>
235-
<AddButton>
236-
<AddIcon
237-
onClick={() => {
238-
updateSessions((sessions) => ({
239-
...sessions,
240-
[parseInt(`${add.hour}${add.minute}`, 10)]: add.name,
241-
}))
242-
}}
243-
/>
244-
</AddButton>
245261
</td>
246262
</tr>
247263
)}
264+
{Object.entries(updatedSessions).map(([time, name]) => (
265+
<tr key={time}>
266+
{editing && (
267+
<td>
268+
<DeleteButton>
269+
<DeleteIcon
270+
onClick={() => {
271+
updateSessions((sessions) => {
272+
const s = { ...sessions }
273+
delete s[(time as unknown) as number]
274+
return s
275+
})
276+
}}
277+
/>
278+
</DeleteButton>
279+
</td>
280+
)}
281+
<td className={'time'}>
282+
{formatEventTime(toEventTime((time as unknown) as number))}
283+
</td>
284+
{!editing && (
285+
<>
286+
<td className={'time'}>
287+
{formatUserTime(toUserTime((time as unknown) as number))}
288+
</td>
289+
<Countdown
290+
key={updatedDay}
291+
startTime={toUserTime((time as unknown) as number)}
292+
/>
293+
</>
294+
)}
295+
<td>{name}</td>
296+
</tr>
297+
))}
248298
</tbody>
249299
</Table>
250300
)

src/style/Footer.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import * as React from 'react'
22
import styled from 'styled-components'
3-
import { mobileBreakpoint, wideBreakpoint } from './settings'
3+
import { wideBreakpoint } from './settings'
44

55
import GithubIcon from 'feather-icons/dist/icons/github.svg'
66

77
const StyledFooter = styled.footer`
88
padding: 1rem 2rem;
9-
@media (min-width: ${mobileBreakpoint}) {
9+
@media (min-width: ${wideBreakpoint}) {
1010
padding: 4rem;
1111
}
1212
@@ -27,7 +27,10 @@ const Copyright = styled(Section)`
2727
font-size: 80%;
2828
opacity: 0.8;
2929
text-align: center;
30-
margin-top: 4rem;
30+
margin-top: 2rem;
31+
@media (min-width: ${wideBreakpoint}) {
32+
margin-top: 4rem;
33+
}
3134
`
3235

3336
const Nav = styled.nav`

src/style/Form.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,25 @@ export const DeleteButton = styled(Button)`
1515

1616
export const AddButton = styled(Button)`
1717
color: #0fa;
18+
&:disabled {
19+
color: #aaa;
20+
}
1821
`
1922

2023
export const Input = styled.input`
2124
background-color: transparent;
2225
border: 1px solid #fff;
23-
padding: 0.5rem;
26+
padding: 0.25rem 0.5rem;
2427
height: 30px;
2528
color: #fff;
2629
`
2730

2831
export const DateInput = styled(Input)`
2932
margin: 0;
33+
${Input} + & {
34+
margin-left: 0.5rem;
35+
}
3036
`
3137
export const NumberInput = styled(Input)`
3238
width: 50px;
33-
& + & {
34-
margin-left: 0.5rem;
35-
}
3639
`

src/style/Main.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ export const Main = styled.main``
44

55
export const Info = styled.p`
66
text-align: center;
7+
font-size: 14px;
8+
margin: 1rem;
79
`

src/style/Table.tsx

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import styled from 'styled-components'
2+
import { wideBreakpoint } from './settings'
23

34
export const Table = styled.table`
45
border-collapse: collapse;
@@ -8,11 +9,38 @@ export const Table = styled.table`
89
th {
910
border: 1px solid #7d7d7d;
1011
padding: 0.25rem;
11-
font-size: 12px;
12-
@media (min-width: 600px) {
12+
@media (min-width: ${wideBreakpoint}) {
1313
padding: 1rem;
1414
font-size: 16px;
1515
}
16+
vertical-align: middle;
17+
&:first-child {
18+
border-left: 0;
19+
}
20+
&:last-child {
21+
border-right: 0;
22+
}
23+
}
24+
td {
25+
font-size: 14px;
26+
@media (min-width: ${wideBreakpoint}) {
27+
font-size: 16px;
28+
}
29+
}
30+
th {
31+
font-size: 12px;
32+
@media (min-width: ${wideBreakpoint}) {
33+
font-size: 14px;
34+
}
35+
}
36+
thead {
37+
tr:first-child {
38+
th {
39+
font-size: 16px;
40+
border-top: 0;
41+
padding: 1rem;
42+
}
43+
}
1644
}
1745
td.time {
1846
text-align: right;

0 commit comments

Comments
 (0)