Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions apps/client/src/common/components/schedule-time/ScheduleTime.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@use '@/theme/viewerDefs' as *;

.schedule__ {
padding-top: 0.5rem;

display: flex;
gap: 0.25em;
font-size: $timer-label-size;
color: var(--label-color-override, $timer-color);
}

.schedule__delayed {
color: $ontime-delay-text;
}

.schedule__strike {
text-decoration: line-through;
color: var(--label-color-override, $viewer-label-color);
}

.schedule__over {
color: $playback-over;
}

.schedule__under {
color: $playback-under;
}
79 changes: 79 additions & 0 deletions apps/client/src/common/components/schedule-time/ScheduleTime.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { dayInMs, MILLIS_PER_MINUTE } from 'ontime-utils';

import ClockTime from '../../../views/common/clock-time/ClockTime';
import { getOffsetState } from '../../utils/offset';
import { ExpectedEvent } from '../../utils/rundownMetadata';
import { cx } from '../../utils/styleUtils';

import './ScheduleTime.scss';

type ScheduleTimeProps = {
event: ExpectedEvent;
showExpected: boolean;
className?: string;
preferredFormat12?: string;
preferredFormat24?: string;
};

//TODO: consider relative mode
export default function ScheduleTime(props: ScheduleTimeProps) {
const { event, showExpected, className, preferredFormat12 = 'h:mm a', preferredFormat24 = 'HH:mm' } = props;
const { timeStart, duration, delay, expectedStart, countToEnd } = event;

const plannedStart = timeStart + delay + event.dayOffset * dayInMs;

// only show new expected value if outside range of the planned value
const isExpectedValueShow = showExpected && isOutsideRange(plannedStart, expectedStart);

const plannedStateClass = isExpectedValueShow ? 'schedule__strike' : delay !== 0 ? 'schedule__delayed' : '';

const expectedOffsetState = getOffsetState(expectedStart - plannedStart);
const expectedStateClass = expectedOffsetState ? `schedule__${expectedOffsetState}` : '';
const plannedEnd = plannedStart + duration + delay;
const expectedEnd = countToEnd ? Math.max(expectedStart + duration, plannedEnd) : expectedStart + duration;
const expectedEndOffsetState = getOffsetState(expectedEnd - plannedEnd);
const expectedEndClass = expectedEndOffsetState ? `schedule__${expectedEndOffsetState}` : '';

return (
<div className={cx(['schedule__', className])}>
<ClockTime
value={plannedStart}
preferredFormat12={preferredFormat12}
preferredFormat24={preferredFormat24}
className={plannedStateClass}
/>
{!isExpectedValueShow && (
<>
<ClockTime
value={plannedEnd}
preferredFormat12={preferredFormat12}
preferredFormat24={preferredFormat24}
className={plannedStateClass}
/>
</>
)}
{isExpectedValueShow && (
<>
<ClockTime
value={expectedStart}
className={expectedStateClass}
preferredFormat12={preferredFormat12}
preferredFormat24={preferredFormat24}
/>
<ClockTime
value={expectedEnd}
className={expectedEndClass}
preferredFormat12={preferredFormat12}
preferredFormat24={preferredFormat24}
/>
</>
)}
</div>
);
}

function isOutsideRange(a: number, b: number): boolean {
return Math.abs(a - b) > MILLIS_PER_MINUTE;
}
78 changes: 49 additions & 29 deletions apps/client/src/common/components/title-card/TitleCard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,60 @@
position: relative;
display: flex;
flex-direction: column;
}

.title-card__title,
.title-card__placeholder {
font-weight: 600;
font-size: $title-font-size;
line-height: 1.2em;
}
background-color: var(--card-background-color-override, $viewer-card-bg-color);
padding: $view-card-padding;
border-radius: $element-border-radius;

.title-card__title {
color: var(--color-override, $viewer-color);
padding-right: 1em;
min-height: 1.2em;
}
border-left: 1vw solid;

.title-card__placeholder {
color: var(--label-color-override, $viewer-label-color);
}
.title-card__title:empty::before {
color: var(--label-color-override, $viewer-label-color);
content: attr(data-placeholder);
}

.title-card__secondary {
font-size: $base-font-size;
color: var(--secondary-color-override, $viewer-secondary-color);
line-height: 1.2em;
}
.title-card__title {
font-weight: 600;
line-height: 1.4em;
padding-right: 1em;
color: var(--color-override, $viewer-color);
}

.title-card__secondary {
color: var(--secondary-color-override, $viewer-secondary-color);
line-height: 1.2em;
}

&.md {
.title-card__title {
font-size: $title-font-size;
}
.title-card__secondary {
font-size: $base-font-size;
}
}
&.lg {
.title-card__title {
font-size: $large-font-size;
}
.title-card__secondary {
font-size: $title-font-size;
}
.schedule__ {
font-size: $base-font-size;
}
}

.title-card__label {
position: absolute;
right: 1rem;
top: 0.5rem;
font-size: $timer-label-size;
color: var(--secondary-color-override, $viewer-secondary-color);
text-transform: uppercase;
.title-card__label {
position: absolute;
right: 1rem;
top: 0.5rem;
font-size: $timer-label-size;
color: var(--secondary-color-override, $viewer-secondary-color);
text-transform: uppercase;

&--accent {
color: var(--accent-color-override, $accent-color);
&--accent {
color: var(--accent-color-override, $accent-color);
}
}
}
30 changes: 26 additions & 4 deletions apps/client/src/common/components/title-card/TitleCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { ForwardedRef, forwardRef } from 'react';

import { useTranslation } from '../../../translation/TranslationProvider';
import { cx } from '../../utils/styleUtils';
import { ExpectedEvent } from '../../utils/rundownMetadata';
import { cx, enDash } from '../../utils/styleUtils';
import ScheduleTime from '../schedule-time/ScheduleTime';

import './TitleCard.scss';

Expand All @@ -10,17 +12,37 @@ interface TitleCardProps {
label?: 'now' | 'next';
secondary?: string;
className?: string;
colour?: string;
textAlign?: 'left' | 'right' | 'center';
size?: 'md' | 'lg';
event?: ExpectedEvent;
showExpected?: boolean;
placeholder?: string;
}

const TitleCard = forwardRef((props: TitleCardProps, ref: ForwardedRef<HTMLDivElement>) => {
const { label, title, secondary, className = '' } = props;
const {
label,
title,
secondary,
className = '',
colour = 'transparent',
textAlign = 'left',
size = 'md',
event,
showExpected = false,
placeholder = enDash,
} = props;
const { getLocalizedString } = useTranslation();

const accent = label === 'now';

return (
<div className={cx(['title-card', className])} ref={ref}>
<span className='title-card__title'>{title}</span>
<div className={cx(['title-card', className, size])} style={{ borderColor: colour }} ref={ref}>
{event && <ScheduleTime event={event} showExpected={showExpected} />}
<span className='title-card__title' style={{ textAlign }} data-placeholder={placeholder}>
{title}
</span>
<span className={cx(['title-card__label', accent && 'title-card__label--accent'])}>
{label && getLocalizedString(`common.${label}`)}
</span>
Expand Down
29 changes: 28 additions & 1 deletion apps/client/src/common/utils/rundownMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import {
MaybeNumber,
MaybeString,
OffsetMode,
OntimeDelay,
OntimeEntry,
OntimeEvent,
OntimeMilestone,
OntimeReport,
PlayableEvent,
Rundown,
isOntimeEvent,
isOntimeGroup,
isPlayableEvent,
} from 'ontime-types';
import { checkIsNextDay, isNewLatest } from 'ontime-utils';
import { checkIsNextDay, getExpectedStart, isNewLatest } from 'ontime-utils';

export type RundownMetadata = {
previousEvent: PlayableEvent | null; // The playableEvent from the previous iteration, used by indicators
Expand All @@ -30,6 +33,7 @@ export type RundownMetadata = {
};

export type ExtendedEntry<T extends OntimeEntry = OntimeEntry> = T & RundownMetadata;
export type ExpectedEvent = ExtendedEntry<OntimeEvent> & { expectedStart: number; endedAt: MaybeNumber };

export const lastMetadataKey = 'LAST';

Expand Down Expand Up @@ -173,3 +177,26 @@ function processEntry(

return processedData;
}

export function expectedEventData(
event: ExtendedEntry<OntimeEvent>,
currentDay: number,
actualStart: MaybeNumber,
plannedStart: MaybeNumber,
offset: number,
mode: OffsetMode,
reportData: OntimeReport,
): ExpectedEvent {
const { totalGap, isLinkedToLoaded } = event;
const expectedStart = getExpectedStart(event, {
currentDay,
totalGap,
actualStart,
plannedStart,
isLinkedToLoaded,
offset,
mode,
});
const { endedAt } = reportData[event.id] ?? { endedAt: null };
return { ...event, expectedStart, endedAt };
}
1 change: 1 addition & 0 deletions apps/client/src/theme/_viewerDefs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ $viewer-opacity-disabled: 0.6;
$timer-label-size: clamp(12px, 1.25vw, 20px);
$base-font-size: clamp(15px, 1.5vw, 28px);
$title-font-size: clamp(18px, 2.25vw, 42px);
$large-font-size: clamp(40px, 4.5vw, 80px);
$timer-value-size: clamp(24px, 2.5vw, 48px);
$header-font-size: clamp(24px, 2.5vw, 48px);

Expand Down
5 changes: 5 additions & 0 deletions apps/client/src/views/backstage/Backstage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
color: var(--label-color-override, $viewer-label-color);
}

.title-card {
// overwrite the title-card bg color so they don't stack as it is transparent
background-color: transparent;
}

/* =================== HEADER + EXTRAS ===================*/

.project-header {
Expand Down
5 changes: 2 additions & 3 deletions apps/client/src/views/backstage/backstage.utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { MaybeNumber, OntimeEvent, Playback, TimerPhase } from 'ontime-types';

import { enDash } from '../../common/utils/styleUtils';
import { getPropertyValue } from '../common/viewUtils';

/**
Expand Down Expand Up @@ -46,9 +45,9 @@ export function getCardData(
}

// if we are loaded, we show the upcoming event as next
const nowMain = getPropertyValue(eventNow, mainSource ?? 'title') || enDash;
const nowMain = getPropertyValue(eventNow, mainSource ?? 'title');
const nowSecondary = getPropertyValue(eventNow, secondarySource);
const nextMain = getPropertyValue(eventNext, mainSource ?? 'title') || enDash;
const nextMain = getPropertyValue(eventNext, mainSource ?? 'title');
const nextSecondary = getPropertyValue(eventNext, secondarySource);

return {
Expand Down
24 changes: 7 additions & 17 deletions apps/client/src/views/countdown/Countdown.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@use '@/theme/viewerDefs' as *;
@use 'sass:color';

$item-height: 3.5rem;

Expand Down Expand Up @@ -118,7 +119,8 @@ $item-height: 3.5rem;
}

.sub--live {
background-color: $active-green;
// we need to dim this if the schedule times are ahead of schedule they will be green and diaper in a full green background
background-color: color.adjust($active-green, $lightness: -10%);
}

.sub--armed {
Expand All @@ -132,6 +134,10 @@ $item-height: 3.5rem;

.sub__schedule {
grid-area: schedule;
}

.sub__schedule-inline {
grid-area: schedule;
padding-top: 0.5rem;

display: flex;
Expand All @@ -140,22 +146,6 @@ $item-height: 3.5rem;
color: var(--label-color-override, $viewer-label-color);
}

.sub__schedule--delayed {
color: $ontime-delay-text;
}

.sub__schedule--strike {
text-decoration: line-through;
}

.sub__schedule--over {
color: $playback-over;
}

.sub__schedule--under {
color: $playback-under;
}

.sub__title {
grid-area: title;
padding-bottom: 0.5rem;
Expand Down
Loading
Loading