@@ -17,6 +17,8 @@ import {
1717 ResetFiltersButton ,
1818} from "./filters"
1919import { formatBlockTime } from "./format-block-time"
20+ import { useCurrentTimeMarker } from "./use-current-time-marker"
21+ import { Button } from "@/app/conf/_design-system/button"
2022
2123export interface FiltersConfig
2224 extends Partial <
@@ -138,21 +140,32 @@ export function ScheduleList({
138140 const firstDayIsDayZero = Object . keys ( firstDay ) . length < 3
139141 const startIndex = firstDayIsDayZero ? 0 : 1
140142
143+ const { getTimeMarker } = useCurrentTimeMarker ( )
144+
141145 return (
142146 < >
143147 < div className = "flex justify-between gap-1 max-lg:flex-col" >
144148 < BookmarkOnSched year = { year } />
145- < ResetFiltersButton
146- filters = { filtersState }
147- onReset = { ( ) =>
148- setFiltersState (
149- FilterStates . initial (
150- Object . keys ( filterFields ) as ( keyof ScheduleSession ) [ ] ,
151- ) ,
152- )
153- }
154- className = "max-lg:mb-4 max-lg:w-fit max-lg:self-end"
155- />
149+ < div className = "flex gap-2" >
150+ < Button
151+ href = "#current-time-marker"
152+ variant = "tertiary"
153+ className = "hidden h-fit items-center gap-x-2 bg-neu-100 !p-2 text-neu-700 transition-opacity hover:bg-neu-200/80 hover:text-neu-900 disabled:opacity-0 [body:has(#current-time-marker)_&]:flex"
154+ >
155+ Scroll to current block
156+ </ Button >
157+ < ResetFiltersButton
158+ filters = { filtersState }
159+ onReset = { ( ) =>
160+ setFiltersState (
161+ FilterStates . initial (
162+ Object . keys ( filterFields ) as ( keyof ScheduleSession ) [ ] ,
163+ ) ,
164+ )
165+ }
166+ className = "max-lg:mb-4 max-lg:w-fit max-lg:self-end"
167+ />
168+ </ div >
156169 </ div >
157170 { showFilter && (
158171 < Filters
@@ -229,6 +242,16 @@ export function ScheduleList({
229242 blockEnd . getTime ( ) ,
230243 )
231244
245+ let timeMarker = getTimeMarker ( sessionDate , blockEnd )
246+ // if end times differ and blockEnd is far from start, we treat this as a long event, like "solutions showcase"
247+ if (
248+ endTimesDiffer &&
249+ blockEnd . getTime ( ) - new Date ( sessionDate ) . getTime ( ) >
250+ 1000 * 60 * 60 * 2
251+ ) {
252+ timeMarker = null
253+ }
254+
232255 return (
233256 < div
234257 key = { `concurrent sessions on ${ sessionDate } ` }
@@ -256,6 +279,18 @@ export function ScheduleList({
256279 ) ) }
257280 </ div >
258281 </ div >
282+ { timeMarker && (
283+ < div
284+ id = "current-time-marker"
285+ 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"
286+ style = { {
287+ top : `${ timeMarker . positionPercentage } %` ,
288+ } }
289+ >
290+ < span className = "max-2xl:hidden" > now: </ span >
291+ { timeMarker . currentTime }
292+ </ div >
293+ ) }
259294 { hasDashedBorder && (
260295 < svg
261296 className = "absolute -bottom-px left-0 h-px w-full text-neu-50"
0 commit comments