player: use links to move between sessions

This commit is contained in:
Nikita Galaiko 2023-05-04 14:54:41 +02:00
parent d2e1f4f5fb
commit 71ed3e6bfb

View File

@ -36,6 +36,7 @@
import { format } from 'date-fns'; import { format } from 'date-fns';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import tinykeys from 'tinykeys'; import tinykeys from 'tinykeys';
import { goto } from '$app/navigation';
export let data: PageData; export let data: PageData;
@ -45,23 +46,27 @@
const unique = (value: any, index: number, self: any[]) => self.indexOf(value) === index; const unique = (value: any, index: number, self: any[]) => self.indexOf(value) === index;
const lexically = (a: string, b: string) => a.localeCompare(b); const lexically = (a: string, b: string) => a.localeCompare(b);
const { sessions, projectId } = data; const dateSessions = derived([data.sessions, page], ([sessions, page]) =>
sessions?.filter(
const dateSessions = derived([sessions, page], ([sessions, page]) =>
sessions.filter(
(session) => format(session.meta.startTimestampMs, 'yyyy-MM-dd') === page.params.date (session) => format(session.meta.startTimestampMs, 'yyyy-MM-dd') === page.params.date
) )
); );
const fileFilter = derived(page, (page) => page.url.searchParams.get('file')); const fileFilter = derived(page, (page) => page.url.searchParams.get('file'));
const projectId = derived(page, (page) => page.params.projectId);
const richSessions = asyncDerived([dateSessions, fileFilter], async ([sessions, fileFilter]) => { const richSessions = asyncDerived(
const paths = fileFilter ? [fileFilter] : undefined; [dateSessions, fileFilter, projectId],
const richSessions = await Promise.all(sessions.map((s) => enrichSession(projectId, s, paths))); async ([sessions, fileFilter, projectId]) => {
return richSessions const paths = fileFilter ? [fileFilter] : undefined;
.filter((s) => s.deltas.length > 0) const richSessions = await Promise.all(
.sort((a, b) => a.meta.startTimestampMs - b.meta.startTimestampMs); sessions.map((s) => enrichSession(projectId, s, paths))
}); );
return richSessions
.filter((s) => s.deltas.length > 0)
.sort((a, b) => a.meta.startTimestampMs - b.meta.startTimestampMs);
}
);
const currentDeltaIndex = writable(parseInt($page.url.searchParams.get('delta') || '0')); const currentDeltaIndex = writable(parseInt($page.url.searchParams.get('delta') || '0'));
const currentSessionId = writable($page.params.sessionId); const currentSessionId = writable($page.params.sessionId);
@ -94,20 +99,28 @@
currentDate.set(page.params.date); currentDate.set(page.params.date);
}); });
const currentSession = derived([currentSessionId, richSessions], ([currentSessionId, sessions]) => const currentSessionIndex = derived(
sessions?.find((session) => session.id === currentSessionId)
);
const hasNextSession = derived(
[currentSessionId, richSessions], [currentSessionId, richSessions],
([currentSessionId, sessions]) => ([currentSessionId, sessions]) =>
sessions?.findIndex((session) => session.id === currentSessionId) < sessions?.length - 1 sessions?.findIndex((session) => session.id === currentSessionId)
); );
const hasPrevSession = derived( const currentSession = derived(
[currentSessionId, richSessions], [currentSessionIndex, richSessions],
([currentSessionId, sessions]) => ([currentSessionIndex, sessions]) =>
sessions?.findIndex((session) => session.id === currentSessionId) > 0 currentSessionIndex > -1 ? sessions[currentSessionIndex] : null
);
const nextSession = derived(
[currentSessionIndex, richSessions],
([currentSessionIndex, sessions]) =>
currentSessionIndex < sessions?.length - 1 ? sessions[currentSessionIndex + 1] : null
);
const prevSession = derived(
[currentSessionIndex, richSessions],
([currentSessionIndex, sessions]) =>
currentSessionIndex > 0 ? sessions[currentSessionIndex - 1] : null
); );
const frame = derived([currentSession, currentDeltaIndex], ([session, currentDeltaIndex]) => { const frame = derived([currentSession, currentDeltaIndex], ([session, currentDeltaIndex]) => {
@ -160,28 +173,6 @@
} }
} }
const goToNextSession = () => {
if ($hasNextSession) {
const currentSessionIndex = $richSessions.findIndex(
(session) => session.id === $currentSessionId
);
const nextSession = $richSessions[currentSessionIndex + 1];
currentSessionId.set(nextSession.id);
currentDeltaIndex.set(0);
}
};
const goToPrevSession = () => {
if ($hasPrevSession) {
const currentSessionIndex = $richSessions.findIndex(
(session) => session.id === $currentSessionId
);
const prevSession = $richSessions[currentSessionIndex - 1];
currentSessionId.set(prevSession.id);
currentDeltaIndex.set(0);
}
};
inputValue.subscribe((value) => { inputValue.subscribe((value) => {
let i = 0; let i = 0;
for (const session of $richSessions || []) { for (const session of $richSessions || []) {
@ -242,12 +233,20 @@
start({ direction, speed }); start({ direction, speed });
}; };
const getSessionURI = (sessionId: string) =>
`/projects/${$page.params.projectId}/player/${$page.params.date}/${sessionId}?{removeFromSearchParams(
$page.url.searchParams,
'delta'
).toString()}`;
onMount(() => onMount(() =>
tinykeys(window, { tinykeys(window, {
ArrowRight: gotoNextDelta, ArrowRight: gotoNextDelta,
'Shift+ArrowRight': goToNextSession, 'Shift+ArrowRight': () =>
nextSession.load().then((session) => session && goto(getSessionURI(session.id))),
ArrowLeft: gotoPrevDelta, ArrowLeft: gotoPrevDelta,
'Shift+ArrowLeft': goToPrevSession, 'Shift+ArrowLeft': () =>
prevSession.load().then((session) => session && goto(getSessionURI(session.id))),
Space: () => { Space: () => {
if (isPlaying) { if (isPlaying) {
stop(); stop();
@ -292,10 +291,7 @@
class="session-card rounded border-[0.5px] border-gb-700 text-zinc-300 shadow-md" class="session-card rounded border-[0.5px] border-gb-700 text-zinc-300 shadow-md"
> >
<a <a
href="/projects/{projectId}/player/{$currentDate}/{session.id}?{removeFromSearchParams( href={getSessionURI(session.id)}
$page.url.searchParams,
'delta'
).toString()}"
class:pointer-events-none={isCurrent} class:pointer-events-none={isCurrent}
class="w-full" class="w-full"
> >
@ -356,24 +352,24 @@
{format($frame.session.meta.lastTimestampMs, 'HH:mm')} {format($frame.session.meta.lastTimestampMs, 'HH:mm')}
</span> </span>
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<button <a
on:click={goToPrevSession} href={$prevSession && getSessionURI($prevSession.id)}
class="rounded border border-zinc-500 bg-zinc-600 p-0.5" class="rounded border border-zinc-500 bg-zinc-600 p-0.5"
class:hover:bg-zinc-500={$hasPrevSession} class:hover:bg-zinc-500={!!$prevSession}
class:cursor-not-allowed={!$hasPrevSession} class:pointer-events-none={!$prevSession}
class:text-zinc-500={!$hasPrevSession} class:text-zinc-500={!$prevSession}
> >
<IconChevronLeft class="h-4 w-4" /> <IconChevronLeft class="h-4 w-4" />
</button> </a>
<button <a
on:click={goToNextSession} href={$nextSession && getSessionURI($nextSession.id)}
class="rounded border border-zinc-500 bg-zinc-600 p-0.5" class="rounded border border-zinc-500 bg-zinc-600 p-0.5"
class:hover:bg-zinc-500={$hasNextSession} class:hover:bg-zinc-500={!!$nextSession}
class:cursor-not-allowed={!$hasNextSession} class:pointer-events-none={!$nextSession}
class:text-zinc-500={!$hasNextSession} class:text-zinc-500={!$nextSession}
> >
<IconChevronRight class="h-4 w-4" /> <IconChevronRight class="h-4 w-4" />
</button> </a>
</div> </div>
</header> </header>
<div id="code" class="flex-auto overflow-auto bg-[#1E2021]"> <div id="code" class="flex-auto overflow-auto bg-[#1E2021]">