feat: autoscroll in leaderboard
continuous-integration/drone/push Build is passing Details

main
parent a02f32e024
commit aeeda341fc

@ -1,8 +1,9 @@
import { requestJSON } from '@/client/utils' import { requestJSON } from '@/client/utils'
import type { Room } from '@/db/model' import type { Room } from '@/db/model'
import { useEffect, useState } from 'preact/hooks' import { useEffect, useRef, useState } from 'preact/hooks'
import { Leaderboard } from './Leaderboard' import { Leaderboard } from './Leaderboard'
import { computeScoreboardState } from '@/ggwp' import { computeScoreboardState } from '@/ggwp'
import clsx from 'clsx'
type Props = { type Props = {
roomId: string roomId: string
@ -50,5 +51,48 @@ export const LiveLeaderboard = ({ roomId }: Props) => {
room.actions room.actions
) )
return <Leaderboard questions={room.questions} scoreboard={scoreboard} /> const [autoscroll, setAutoscroll] = useState<false | 'up' | 'down'>(false)
const timerRef = useRef<Timer | null>(null)
useEffect(() => {
if (autoscroll !== false) {
timerRef.current = setInterval(() => {
console.log('scrolling')
window.scrollBy({
top: autoscroll === 'down' ? 10 : -10,
behavior: 'smooth',
})
if (window.scrollY + window.innerHeight + 1 > document.body.scrollHeight) {
setAutoscroll('up')
}
if (window.scrollY === 0) {
setAutoscroll('down')
}
}, 100)
return () => {
if (timerRef.current) {
clearInterval(timerRef.current)
}
}
}
}, [autoscroll])
return (
<>
<Leaderboard questions={room.questions} scoreboard={scoreboard} />
<div class="position-fixed bottom right">
<button
class={clsx('square', autoscroll !== false && 'active')}
onClick={() => setAutoscroll(v => (v === false ? 'down' : false))}
>
<div class="icon">swap_vert</div>
</button>
</div>
</>
)
} }

@ -24,6 +24,8 @@ img {
:root { :root {
font-size: 18px; font-size: 18px;
--tint: oklch(from royalblue l 0 h);
--blue: oklch(from royalblue calc(l + 0.05) c h); --blue: oklch(from royalblue calc(l + 0.05) c h);
--red: oklch(63.11% 0.2387 32.0573); --red: oklch(63.11% 0.2387 32.0573);
--green: oklch(60.3% 0.3 134.48); --green: oklch(60.3% 0.3 134.48);
@ -42,7 +44,7 @@ body {
justify-items: center; justify-items: center;
align-content: start; align-content: start;
padding: 3rem 1rem 12rem; padding: 6rem 1rem 12rem;
gap: 3rem; gap: 3rem;
} }
@ -234,6 +236,23 @@ a {
height: 100%; height: 100%;
} }
.position-fixed {
position: fixed;
&.top {
top: 1rem;
}
&.bottom {
bottom: 1rem;
}
&.left {
left: 1rem;
}
&.right {
right: 1rem;
}
}
.icon { .icon {
font-family: 'Material Symbols Outlined Variable'; font-family: 'Material Symbols Outlined Variable';
font-weight: 400; font-weight: 400;
@ -343,6 +362,11 @@ button {
.icon { .icon {
font-size: 20px; font-size: 20px;
} }
&.active {
border-color: var(--blue);
color: var(--blue);
}
} }
.leaderboard { .leaderboard {

Loading…
Cancel
Save