Skip to content

Commit

Permalink
feat: timeline view
Browse files Browse the repository at this point in the history
  • Loading branch information
cpvalente committed Jul 20, 2024
1 parent 90751b4 commit 3010366
Show file tree
Hide file tree
Showing 16 changed files with 120 additions and 21 deletions.
9 changes: 9 additions & 0 deletions apps/client/src/common/hooks/useSocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,12 @@ export const useRuntimePlaybackOverview = () => {

return useRuntimeStore(featureSelector);
};

export const useTimelineStatus = () => {
const featureSelector = (state: RuntimeStore) => ({
clock: state.clock,
offset: state.runtime.offset,
});

return useRuntimeStore(featureSelector);
};
19 changes: 9 additions & 10 deletions apps/client/src/features/viewers/timeline/Timeline.module.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@use '../../../theme/viewerDefs' as *;

$timeline-entry-height: 20px;

.timeline {
Expand All @@ -11,23 +13,16 @@ $timeline-entry-height: 20px;

.entryColumn {
position: absolute;
background-color: var(--lighter, $gray-500);
background-color: var(--lighter, $viewer-card-bg-color);
border-bottom: 0.25rem solid var(--color, $ui-white);
border-right: 1px solid $ui-black;
min-height: 80px;

&.fullHeight {
height: calc(100% - 4rem);
}
min-height: 100px;
}

.entryContent {
padding-top: var(--top, 0);

&.lastElement {
text-align: right;
transform: translateX(-100%);
}
padding-bottom: 0.5rem;
}

.entryText {
Expand All @@ -41,6 +36,10 @@ $timeline-entry-height: 20px;
&.textBg {
background-color: var(--bg, $black-10);
}

&.lastElement {
white-space: normal;
}
}

.start,
Expand Down
40 changes: 34 additions & 6 deletions apps/client/src/features/viewers/timeline/TimelineEntry.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { useClock } from '../../../common/hooks/useSocket';
import { useLayoutEffect, useRef, useState } from 'react';

import { useTimelineStatus } from '../../../common/hooks/useSocket';
import { alpha, cx } from '../../../common/utils/styleUtils';
import { formatDuration, formatTime } from '../../../common/utils/time';
import { useTranslation } from '../../../translation/TranslationProvider';

import { getStatusLabel } from './timeline.utils';

Expand Down Expand Up @@ -32,14 +35,28 @@ const formatOptions = {
export function TimelineEntry(props: TimelineEntry) {
const { colour, duration, isLast, lane, left, status, start, title, width, mayGrow, fullHeight } = props;

const elementRef = useRef<HTMLDivElement>(null);
const [rightOffset, setRightOffset] = useState(0);

useLayoutEffect(() => {
if (!isLast || !elementRef.current) {
return;
}
const screenWidth = window.innerWidth;
const b = elementRef.current.getBoundingClientRect();
const right = b.x + b.width;
const offset = right > screenWidth ? right - screenWidth : 0;
setRightOffset(offset);
}, [isLast, title]);

const formattedStartTime = formatTime(start, formatOptions);
const formattedDuration = formatDuration(duration);

const lighterColour = alpha(colour, 0.7);
const alphaColour = alpha(colour, 0.6);
const columnClasses = cx([style.entryColumn, fullHeight && style.fullHeight]);
const contentClasses = cx([style.entryContent, isLast && style.lastElement]);
const textBgClasses = cx([style.entryText, mayGrow && style.textBg]);
const contentClasses = cx([style.entryContent]);
const textBgClasses = cx([style.entryText, mayGrow && style.textBg, isLast && style.lastElement]);

return (
<div
Expand All @@ -61,8 +78,11 @@ export function TimelineEntry(props: TimelineEntry) {
>
<div
className={textBgClasses}
ref={isLast ? elementRef : null}
style={{
'--bg': alphaColour ?? '',
right: `${rightOffset}px`,
width: isLast ? `${Math.max(width, 100)}px` : 'fit-content',
}}
>
<div className={style.start}>{formattedStartTime}</div>
Expand All @@ -82,9 +102,17 @@ interface TimelineEntryStatusProps {
// we isolate this component to avoid re-rendering too many elements
function TimelineEntryStatus(props: TimelineEntryStatusProps) {
const { status, start } = props;
// TODO: account for offset instead of just using the clock
const { clock } = useClock();
const statusText = getStatusLabel(start - clock, status);
const { clock, offset } = useTimelineStatus();
const { getLocalizedString } = useTranslation();

let statusText = getStatusLabel(start - clock + offset, status);
if (statusText === 'live') {
statusText = getLocalizedString('timeline.live').toUpperCase();
} else if (statusText === 'pending') {
statusText = getLocalizedString('timeline.pending').toUpperCase();
} else if (statusText === 'finished') {
statusText = getLocalizedString('timeline.finished').toUpperCase();
}

return <div className={style.status}>{statusText}</div>;
}
25 changes: 25 additions & 0 deletions apps/client/src/features/viewers/timeline/TimelinePage.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,28 @@
row-gap: 1rem;
column-gap: 3rem;
}

.sectionTitle {
line-height: 1.2em;
font-size: 1.5rem;
text-transform: uppercase;
}

.sectionContent {
line-height: 1em;
font-size: 3rem;
text-transform: uppercase;
font-weight: 600;

&.now {
color: $active-red;
}

&.next {
color: $green-500;
}

&.subdue {
opacity: $opacity-disabled;
}
}
8 changes: 5 additions & 3 deletions apps/client/src/features/viewers/timeline/TimelinePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { MaybeString, OntimeEvent, ProjectData, Settings } from 'ontime-types';
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
import { formatTime, getDefaultFormat } from '../../../common/utils/time';
import { useTranslation } from '../../../translation/TranslationProvider';

import Section from './timeline-section/TimelineSection';
import Timeline from './Timeline';
Expand All @@ -23,6 +24,7 @@ interface TimelinePageProps {
export default function TimelinePage(props: TimelinePageProps) {
const { backstageEvents, general, selectedId, settings, time } = props;

const { getLocalizedString } = useTranslation();
const clock = formatTime(time.clock);
const { now, next, followedBy } = getUpcomingEvents(backstageEvents, selectedId);

Expand All @@ -35,9 +37,9 @@ export default function TimelinePage(props: TimelinePageProps) {
<ViewParamsEditor viewOptions={progressOptions} />
<div className={style.title}>{general.title}</div>
<div className={style.sections}>
<Section title='Time now' content={clock} category='now' />
<Section title='Next' content={next} category='next' />
<Section title='Current' content={now} category='now' />
<Section title={getLocalizedString('common.time_now')} content={clock} category='now' />
<Section title={getLocalizedString('common.next')} content={next} category='next' />
<Section title={getLocalizedString('timeline.live')} content={now} category='now' />
<Section title='Followed by' content={followedBy} category='next' />
</div>
<Timeline selectedEventId={selectedId} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

& > span {
flex-grow: 1;
border-left: 1px solid $ui-black;
border-left: 1px solid $white-7;
height: 100vh;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export function getStatusLabel(timeToStart: number, status: ProgressStatus): str
}

if (timeToStart < 0) {
return 'T - 0';
return 'pending';
}

return `T - ${formatDuration(timeToStart)}`;
Expand Down
4 changes: 4 additions & 0 deletions apps/client/src/translation/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ export const langDe: TranslationObject = {
'countdown.to_start': 'Zeit bis zum Start',
'countdown.waiting': 'Warten auf den Veranstaltungsbeginn',
'countdown.overtime': 'überfällig',
'timeline.live': 'live',
'timeline.finished': 'Beendet',
'timeline.pending': 'Ausstehend',
'timeline.followedby': 'Gefolgt von',
};
4 changes: 4 additions & 0 deletions apps/client/src/translation/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export const langEn = {
'countdown.to_start': 'Time to start',
'countdown.waiting': 'Waiting for event start',
'countdown.overtime': 'in overtime',
'timeline.live': 'live',
'timeline.finished': 'finished',
'timeline.pending': 'pending',
'timeline.followedby': 'Followed by',
};

export type TranslationObject = Record<keyof typeof langEn, string>;
4 changes: 4 additions & 0 deletions apps/client/src/translation/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ export const langEs: TranslationObject = {
'countdown.to_start': 'Tiempo para comenzar',
'countdown.waiting': 'Esperando el inicio del evento',
'countdown.overtime': 'en tiempo extra',
'timeline.live': 'live',
'timeline.finished': 'Terminado',
'timeline.pending': 'pendiente',
'timeline.followedby': 'Seguido por',
};
4 changes: 4 additions & 0 deletions apps/client/src/translation/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ export const langFr: TranslationObject = {
'countdown.to_start': 'Évènement commence dans',
'countdown.waiting': 'En attente du début de l’évènement',
'countdown.overtime': 'en dépassement',
'timeline.live': 'live',
'timeline.finished': 'Terminé',
'timeline.pending': 'En attente',
'timeline.followedby': 'Suivi de',
};
4 changes: 4 additions & 0 deletions apps/client/src/translation/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ export const langIt: TranslationObject = {
'countdown.to_start': 'Tempo alla partenza',
'countdown.waiting': "In attesa dell'inizio dell'evento",
'countdown.overtime': 'in ritardo',
'timeline.live': 'live',
'timeline.finished': 'Terminato',
'timeline.pending': 'In sospeso',
'timeline.followedby': 'Seguito da',
};
4 changes: 4 additions & 0 deletions apps/client/src/translation/languages/no.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ export const langNo: TranslationObject = {
'countdown.to_start': 'Tid til start',
'countdown.waiting': 'Venter på start',
'countdown.overtime': 'i overtiden',
'timeline.live': 'live',
'timeline.finished': 'Ferdig',
'timeline.pending': 'Venter',
'timeline.followedby': 'Etterfulgt av',
};
4 changes: 4 additions & 0 deletions apps/client/src/translation/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ export const langPl: TranslationObject = {
'countdown.to_start': 'Do rozpoczęcia',
'countdown.waiting': 'Oczekiwanie na start',
'countdown.overtime': 'ponad czasem',
'timeline.live': 'live',
'timeline.finished': 'Zakończony',
'timeline.pending': 'Oczekujący',
'timeline.followedby': 'Następnie',
};
4 changes: 4 additions & 0 deletions apps/client/src/translation/languages/pt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ export const langPt: TranslationObject = {
'countdown.to_start': 'Tempo para iniciar',
'countdown.waiting': 'Aguardando o início do evento',
'countdown.overtime': 'em tempo extra',
'timeline.live': 'live',
'timeline.finished': 'Concluído',
'timeline.pending': 'Pendente',
'timeline.followedby': 'Seguido por',
};
4 changes: 4 additions & 0 deletions apps/client/src/translation/languages/sv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ export const langSv: TranslationObject = {
'countdown.to_start': 'Tid till start',
'countdown.waiting': 'Väntar på att evenemanget ska starta',
'countdown.overtime': 'i övertid',
'timeline.live': 'live',
'timeline.finished': 'Avslutad',
'timeline.pending': 'Väntande',
'timeline.followedby': 'Följt av',
};

0 comments on commit 3010366

Please sign in to comment.