Skip to content

Commit e5340b9

Browse files
committed
Add current time marker
1 parent e21d8cf commit e5340b9

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

src/app/conf/2025/schedule/_components/schedule-list.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
ResetFiltersButton,
1818
} from "./filters"
1919
import { formatBlockTime } from "./format-block-time"
20+
import { useCurrentTimeMarker } from "./use-current-time-marker"
2021

2122
export interface FiltersConfig
2223
extends Partial<
@@ -138,6 +139,8 @@ export function ScheduleList({
138139
const firstDayIsDayZero = Object.keys(firstDay).length < 3
139140
const startIndex = firstDayIsDayZero ? 0 : 1
140141

142+
const getTimeMarker = useCurrentTimeMarker()
143+
141144
return (
142145
<>
143146
<div className="flex justify-between gap-1 max-lg:flex-col">
@@ -229,6 +232,16 @@ export function ScheduleList({
229232
blockEnd.getTime(),
230233
)
231234

235+
let timeMarker = getTimeMarker(sessionDate, blockEnd)
236+
// if end times differ and blockEnd is far from start, we treat this as a long event, like "solutions showcase"
237+
if (
238+
endTimesDiffer &&
239+
blockEnd.getTime() - new Date(sessionDate).getTime() >
240+
1000 * 60 * 60 * 2
241+
) {
242+
timeMarker = null
243+
}
244+
232245
return (
233246
<div
234247
key={`concurrent sessions on ${sessionDate}`}
@@ -256,6 +269,18 @@ export function ScheduleList({
256269
))}
257270
</div>
258271
</div>
272+
{timeMarker && (
273+
<div
274+
id="current-time-marker"
275+
className="typography-body-xs pointer-events-none absolute -right-1 z-10 -translate-y-full font-mono tabular-nums text-pri-base before:absolute before:inset-x-0 before:bottom-0 before:border-b before:border-pri-base before:opacity-80 after:absolute after:bottom-0 after:left-[-100vw] after:w-screen after:border-t after:border-pri-base after:opacity-20 dark:text-pri-light dark:before:border-pri-light dark:after:border-pri-light max-xl:bg-neu-0 xl:translate-x-full"
276+
style={{
277+
top: `${timeMarker.positionPercentage}%`,
278+
}}
279+
>
280+
<span className="max-2xl:hidden">now: </span>
281+
{timeMarker.currentTime}
282+
</div>
283+
)}
259284
{hasDashedBorder && (
260285
<svg
261286
className="absolute -bottom-px left-0 h-px w-full text-neu-50"
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { useEffect, useState } from "react"
2+
import { format } from "date-fns"
3+
4+
const CONFERENCE_START = new Date("2025-09-08T00:00:00")
5+
const CONFERENCE_END = new Date("2025-09-10T23:59:59")
6+
7+
export function useCurrentTimeMarker() {
8+
const [now, setNow] = useState<Date>(new Date())
9+
10+
useEffect(() => {
11+
const id = setInterval(() => setNow(new Date()), 60 * 1000)
12+
return () => clearInterval(id)
13+
}, [])
14+
15+
const showNowMarkers =
16+
now.getTime() >= CONFERENCE_START.getTime() &&
17+
now.getTime() <= CONFERENCE_END.getTime()
18+
19+
const getTimeMarker = (sessionDate: string, blockEnd: Date) => {
20+
const blockStart = new Date(sessionDate)
21+
const isCurrentBlock =
22+
showNowMarkers &&
23+
now.getTime() >= blockStart.getTime() &&
24+
now.getTime() < blockEnd.getTime()
25+
26+
if (!isCurrentBlock) {
27+
return null
28+
}
29+
30+
const blockDuration = blockEnd.getTime() - blockStart.getTime()
31+
const timePassed = now.getTime() - blockStart.getTime()
32+
const positionPercentage = Math.min(
33+
100,
34+
Math.max(0, (timePassed / blockDuration) * 100),
35+
)
36+
const currentTimeFormatted = format(now, "HH:mm")
37+
38+
return {
39+
positionPercentage,
40+
currentTime: currentTimeFormatted,
41+
}
42+
}
43+
44+
return getTimeMarker
45+
}

0 commit comments

Comments
 (0)