style: clock period (#601)

* style: tweaks to studio override

* style: improvements to 12 hour format
This commit is contained in:
Carlos Valente
2023-11-20 09:53:35 +01:00
committed by GitHub
parent 2316bbebac
commit 1b55dbc170
16 changed files with 108 additions and 39 deletions
@@ -1,7 +1,12 @@
import SuperscriptTime from '../../../features/viewers/common/superscript-time/SuperscriptTime';
import { formatTime } from '../../utils/time'; import { formatTime } from '../../utils/time';
import './Schedule.scss'; import './Schedule.scss';
const formatOptions = {
format: 'hh:mm a',
};
interface ScheduleItemProps { interface ScheduleItemProps {
selected: 'past' | 'now' | 'future'; selected: 'past' | 'now' | 'future';
timeStart: number; timeStart: number;
@@ -16,8 +21,8 @@ interface ScheduleItemProps {
export default function ScheduleItem(props: ScheduleItemProps) { export default function ScheduleItem(props: ScheduleItemProps) {
const { selected, timeStart, timeEnd, title, presenter, backstageEvent, colour, skip } = props; const { selected, timeStart, timeEnd, title, presenter, backstageEvent, colour, skip } = props;
const start = formatTime(timeStart, { format: 'hh:mm' }); const start = formatTime(timeStart, formatOptions);
const end = formatTime(timeEnd, { format: 'hh:mm' }); const end = formatTime(timeEnd, formatOptions);
const userColour = colour !== '' ? colour : ''; const userColour = colour !== '' ? colour : '';
const selectStyle = `entry--${selected}`; const selectStyle = `entry--${selected}`;
@@ -25,7 +30,12 @@ export default function ScheduleItem(props: ScheduleItemProps) {
<li className={`entry ${selectStyle} ${skip ? 'skip' : ''}`}> <li className={`entry ${selectStyle} ${skip ? 'skip' : ''}`}>
<div className='entry-times'> <div className='entry-times'>
<span className='entry-colour' style={{ backgroundColor: userColour }} /> <span className='entry-colour' style={{ backgroundColor: userColour }} />
{`${start}${end} ${backstageEvent ? '*' : ''}`} <div style={{ display: 'flex' }}>
<SuperscriptTime time={start} />
{' → '}
<SuperscriptTime time={end} />
{backstageEvent ? '*' : ''}
</div>
</div> </div>
<div className='entry-title'>{title}</div> <div className='entry-title'>{title}</div>
{presenter && <div className='entry-presenter'>{presenter}</div>} {presenter && <div className='entry-presenter'>{presenter}</div>}
@@ -26,4 +26,14 @@ describe('formatTime()', () => {
const time = formatTime(ms); const time = formatTime(ms);
expect(time).toStrictEqual('...'); expect(time).toStrictEqual('...');
}); });
it('shows 12h format without times', () => {
const ms = 13 * 60 * 60 * 1000;
const options = {
showSeconds: false,
format: 'hh:mm a',
};
const time = formatTime(ms, options, () => '12');
expect(time).toStrictEqual('01:00 PM');
});
}); });
@@ -60,6 +60,7 @@
font-weight: 600; font-weight: 600;
color: var(--secondary-color-override, $viewer-secondary-color); color: var(--secondary-color-override, $viewer-secondary-color);
letter-spacing: 0.05em; letter-spacing: 0.05em;
line-height: 0.95em;
} }
.message { .message {
@@ -18,6 +18,7 @@ import { TimeManagerType } from '../../../common/models/TimeManager.type';
import { formatTime } from '../../../common/utils/time'; import { formatTime } from '../../../common/utils/time';
import { useTranslation } from '../../../translation/TranslationProvider'; import { useTranslation } from '../../../translation/TranslationProvider';
import { titleVariants } from '../common/animation'; import { titleVariants } from '../common/animation';
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
import './Backstage.scss'; import './Backstage.scss';
@@ -97,7 +98,7 @@ export default function Backstage(props: BackstageProps) {
{general.title} {general.title}
<div className='clock-container'> <div className='clock-container'>
<div className='label'>{getLocalizedString('common.time_now')}</div> <div className='label'>{getLocalizedString('common.time_now')}</div>
<div className='time'>{clock}</div> <SuperscriptTime time={clock} className='time' />
</div> </div>
</div> </div>
@@ -128,12 +129,16 @@ export default function Backstage(props: BackstageProps) {
<div className='timer-group'> <div className='timer-group'>
<div className='aux-timers'> <div className='aux-timers'>
<div className='aux-timers__label'>{getLocalizedString('common.started_at')}</div> <div className='aux-timers__label'>{getLocalizedString('common.started_at')}</div>
<div className='aux-timers__value'>{startedAt}</div> <SuperscriptTime time={startedAt} className='aux-timers__value' />
</div> </div>
<div className='timer-gap' /> <div className='timer-gap' />
<div className='aux-timers'> <div className='aux-timers'>
<div className='aux-timers__label'>{getLocalizedString('common.expected_finish')}</div> <div className='aux-timers__label'>{getLocalizedString('common.expected_finish')}</div>
<div className='aux-timers__value'>{expectedFinish}</div> {isNegative ? (
<div className='aux-timers__value'>{expectedFinish}</div>
) : (
<SuperscriptTime time={startedAt} className='aux-timers__value' />
)}
</div> </div>
<div className='timer-gap' /> <div className='timer-gap' />
<div className='aux-timers'> <div className='aux-timers'>
@@ -10,6 +10,7 @@ import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet
import { TimeManagerType } from '../../../common/models/TimeManager.type'; import { TimeManagerType } from '../../../common/models/TimeManager.type';
import { OverridableOptions } from '../../../common/models/View.types'; import { OverridableOptions } from '../../../common/models/View.types';
import { formatTime } from '../../../common/utils/time'; import { formatTime } from '../../../common/utils/time';
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
import './Clock.scss'; import './Clock.scss';
@@ -135,7 +136,8 @@ export default function Clock(props: ClockProps) {
> >
<NavigationMenu /> <NavigationMenu />
<ViewParamsEditor paramFields={CLOCK_OPTIONS} /> <ViewParamsEditor paramFields={CLOCK_OPTIONS} />
<div <SuperscriptTime
time={clock}
className='clock' className='clock'
style={{ style={{
color: userOptions.textColour, color: userOptions.textColour,
@@ -145,9 +147,7 @@ export default function Clock(props: ClockProps) {
left: userOptions.left, left: userOptions.left,
backgroundColor: userOptions.textBackground, backgroundColor: userOptions.textBackground,
}} }}
> />
{clock}
</div>
</div> </div>
); );
} }
@@ -0,0 +1,4 @@
sup.period {
top: -1em;
font-size: 0.4em;
}
@@ -0,0 +1,23 @@
import { CSSProperties } from 'react';
import './SuperscriptTime.scss';
interface SuperscriptTimeProps {
time: string;
className?: string;
style?: CSSProperties;
}
export default function SuperscriptTime(props: SuperscriptTimeProps) {
const { time, className, style } = props;
// we assume anything after space is a period tag
const [timeString, period] = time.split(' ');
return (
<div className={className} style={style}>
{timeString}
{period && <sup className='period'>{period}</sup>}
</div>
);
}
@@ -68,6 +68,7 @@
font-size: clamp(32px, 3.5vw, 50px); font-size: clamp(32px, 3.5vw, 50px);
color: var(--secondary-color-override, $viewer-secondary-color); color: var(--secondary-color-override, $viewer-secondary-color);
letter-spacing: 0.05em; letter-spacing: 0.05em;
line-height: 0.95em;
} }
} }
@@ -135,6 +136,7 @@
font-size: clamp(32px, 3.5vw, 50px); font-size: clamp(32px, 3.5vw, 50px);
color: var(--secondary-color-override, $viewer-secondary-color); color: var(--secondary-color-override, $viewer-secondary-color);
letter-spacing: 0.05em; letter-spacing: 0.05em;
line-height: 0.95em;
&--delayed { &--delayed {
color: $delay-color; color: $delay-color;
@@ -11,6 +11,7 @@ import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet
import { TimeManagerType } from '../../../common/models/TimeManager.type'; import { TimeManagerType } from '../../../common/models/TimeManager.type';
import { formatTime } from '../../../common/utils/time'; import { formatTime } from '../../../common/utils/time';
import { useTranslation } from '../../../translation/TranslationProvider'; import { useTranslation } from '../../../translation/TranslationProvider';
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
import { fetchTimerData, TimerMessage } from './countdown.helpers'; import { fetchTimerData, TimerMessage } from './countdown.helpers';
import CountdownSelect from './CountdownSelect'; import CountdownSelect from './CountdownSelect';
@@ -118,26 +119,27 @@ export default function Countdown(props: CountdownProps) {
<div className='countdown-container' data-testid='countdown-event'> <div className='countdown-container' data-testid='countdown-event'>
<div className='clock-container'> <div className='clock-container'>
<div className='label'>{getLocalizedString('common.time_now')}</div> <div className='label'>{getLocalizedString('common.time_now')}</div>
<div className='time'>{clock}</div> <SuperscriptTime time={clock} className='time' />
</div> </div>
{runningMessage !== TimerMessage.unhandled && ( {runningMessage !== TimerMessage.unhandled && (
<div className='status'>{getLocalizedString(`countdown.${runningMessage}`)}</div> <div className='status'>{getLocalizedString(`countdown.${runningMessage}`)}</div>
)} )}
<span className={`timer ${standby ? 'timer--paused' : ''} ${isRunningFinished ? 'timer--finished' : ''}`}> <SuperscriptTime
{formattedTimer} time={formattedTimer}
</span> className={`timer ${standby ? 'timer--paused' : ''} ${isRunningFinished ? 'timer--finished' : ''}`}
/>
<div className='title'>{follow?.title || 'Untitled Event'}</div> <div className='title'>{follow?.title || 'Untitled Event'}</div>
<div className='timer-group'> <div className='timer-group'>
<div className='aux-timers'> <div className='aux-timers'>
<div className='aux-timers__label'>{getLocalizedString('common.start_time')}</div> <div className='aux-timers__label'>{getLocalizedString('common.start_time')}</div>
<span className={`aux-timers__value ${delayedTimerStyles}`}>{startTime}</span> <SuperscriptTime time={startTime} className={`aux-timers__value ${delayedTimerStyles}`} />
</div> </div>
<div className='aux-timers'> <div className='aux-timers'>
<div className='aux-timers__label'>{getLocalizedString('common.end_time')}</div> <div className='aux-timers__label'>{getLocalizedString('common.end_time')}</div>
<span className={`aux-timers__value ${delayedTimerStyles}`}>{endTime}</span> <SuperscriptTime time={endTime} className={`aux-timers__value ${delayedTimerStyles}`} />
</div> </div>
</div> </div>
</div> </div>
@@ -9,6 +9,10 @@ import { sanitiseTitle } from './countdown.helpers';
import './Countdown.scss'; import './Countdown.scss';
const formatOptions = {
format: 'hh:mm a',
};
interface CountdownSelectProps { interface CountdownSelectProps {
events: OntimeRundownEntry[]; events: OntimeRundownEntry[];
} }
@@ -31,8 +35,8 @@ export default function CountdownSelect(props: CountdownSelectProps) {
filteredEvents.map((event: OntimeEvent, counter: number) => { filteredEvents.map((event: OntimeEvent, counter: number) => {
const index = counter + 1; const index = counter + 1;
const title = sanitiseTitle(event.title); const title = sanitiseTitle(event.title);
const start = formatTime(event.timeStart, { format: 'hh:mm' }); const start = formatTime(event.timeStart, formatOptions);
const end = formatTime(event.timeEnd, { format: 'hh:mm' }); const end = formatTime(event.timeEnd, formatOptions);
return ( return (
<li key={event.id}> <li key={event.id}>
@@ -58,6 +58,7 @@
font-size: clamp(32px, 3.5vw, 50px); font-size: clamp(32px, 3.5vw, 50px);
font-weight: 600; font-weight: 600;
letter-spacing: 0.05em; letter-spacing: 0.05em;
line-height: 0.95em;
} }
.message { .message {
@@ -16,6 +16,7 @@ import { TimeManagerType } from '../../../common/models/TimeManager.type';
import { formatTime } from '../../../common/utils/time'; import { formatTime } from '../../../common/utils/time';
import { useTranslation } from '../../../translation/TranslationProvider'; import { useTranslation } from '../../../translation/TranslationProvider';
import { titleVariants } from '../common/animation'; import { titleVariants } from '../common/animation';
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
import './Public.scss'; import './Public.scss';
@@ -63,7 +64,7 @@ export default function Public(props: BackstageProps) {
{general.title} {general.title}
<div className='clock-container'> <div className='clock-container'>
<div className='label'>{getLocalizedString('common.time_now')}</div> <div className='label'>{getLocalizedString('common.time_now')}</div>
<div className='time'>{clock}</div> <SuperscriptTime time={clock} className='time' />
</div> </div>
</div> </div>
@@ -13,7 +13,7 @@ $half-hours: min(1.5vh, 10px);
$size-min: min(2.5vh, 18px); $size-min: min(2.5vh, 18px);
$half-min: min(1.25vh, 9px); $half-min: min(1.25vh, 9px);
$red-active: #c53030; $red-active: #c53030;
$red-idle: #300000; $red-idle: #000000;
$cyan-active: #0ff; $cyan-active: #0ff;
$cyan-idle: #0aa; $cyan-idle: #0aa;
@@ -56,11 +56,10 @@ $cyan-idle: #0aa;
.hours { .hours {
border-radius: 50%; border-radius: 50%;
position: absolute; position: absolute;
background: $red-idle; background: var(--studio-idle, $red-idle);
&--active { &--active {
background: $red-active; background: var(--studio-active, $red-active);
box-shadow: 0 0 10px 2px rgba(255, 0, 0, 0.25);
} }
} }
@@ -80,7 +79,7 @@ $cyan-idle: #0aa;
} }
.studio-timer { .studio-timer {
color: $red-active; color: var(--studio-active, $red-active);
font-size: calc(#{$clock-size} / 3); font-size: calc(#{$clock-size} / 3);
margin-top: calc(50% - calc(#{$clock-size} / 7)); margin-top: calc(50% - calc(#{$clock-size} / 7));
line-height: 0.8em; line-height: 0.8em;
@@ -88,9 +87,8 @@ $cyan-idle: #0aa;
&--with-seconds { &--with-seconds {
font-size: calc(#{$clock-size} / 4.6); font-size: calc(#{$clock-size} / 4.6);
margin-top: calc(50% - calc(#{$clock-size} / 11)); margin-top: calc(50% - calc(#{$clock-size} / 11));
}
} }
}
.next-title:after, .next-title:after,
@@ -100,14 +98,15 @@ $cyan-idle: #0aa;
} }
.next-title { .next-title {
color: $cyan-idle; color: var(--studio-idle-label, $cyan-idle);
text-align: center; text-align: center;
} }
.next-countdown { .next-countdown {
color: var(--studio-active-label, $cyan-active);
font-size: 10vh; font-size: 10vh;
line-height: 1em; line-height: 1em;
color: $cyan-active;
&--overtime { &--overtime {
color: darken($red-active, 10%); color: darken($red-active, 10%);
@@ -131,16 +130,16 @@ $cyan-idle: #0aa;
padding-bottom: 2vh; padding-bottom: 2vh;
font-size: 15vh; font-size: 15vh;
line-height: 0.9em; line-height: 0.9em;
color: $red-active; color: var(--studio-active, $red-active);
&--idle { &--idle {
color: $red-idle; color: var(--studio-idle, $red-active);
} }
} }
.schedule { .schedule {
ul { ul {
color: $cyan-idle; color: var(--studio-idle-label, $cyan-idle);
font-size: 3.75vh; font-size: 3.75vh;
line-height: 1em; line-height: 1em;
list-style: none; list-style: none;
@@ -154,18 +153,18 @@ $cyan-idle: #0aa;
} }
.now { .now {
color: $cyan-active; color: var(--studio-active-label, $cyan-active);
} }
.next { .next {
color: $red-active; color: var(--studio-active, $red-active);
} }
.user-colour { .user-colour {
width: 0.35em; width: 0.35em;
height: 0.35em; height: 0.35em;
aspect-ratio: 1; aspect-ratio: 1;
background-color: $red-idle; background-color: var(--studio-idle, $red-idle);
margin-right: 0.35em; margin-right: 0.35em;
} }
} }
@@ -48,6 +48,7 @@
font-size: clamp(32px, 3.5vw, 50px); font-size: clamp(32px, 3.5vw, 50px);
color: var(--secondary-color-override, $viewer-secondary-color); color: var(--secondary-color-override, $viewer-secondary-color);
letter-spacing: 0.05em; letter-spacing: 0.05em;
line-height: 0.95em;
} }
&--hidden { &--hidden {
@@ -115,11 +116,11 @@
opacity: 1; opacity: 1;
transition: $viewer-transition-time; transition: $viewer-transition-time;
&--paused { &--paused {
opacity: $viewer-opacity-disabled; opacity: $viewer-opacity-disabled;
transition: $viewer-transition-time; transition: $viewer-transition-time;
}
} }
}
/* =================== OVERLAY ===================*/ /* =================== OVERLAY ===================*/
@@ -12,6 +12,7 @@ import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet
import { TimeManagerType } from '../../../common/models/TimeManager.type'; import { TimeManagerType } from '../../../common/models/TimeManager.type';
import { formatTime } from '../../../common/utils/time'; import { formatTime } from '../../../common/utils/time';
import { useTranslation } from '../../../translation/TranslationProvider'; import { useTranslation } from '../../../translation/TranslationProvider';
import SuperscriptTime from '../common/superscript-time/SuperscriptTime';
import { formatTimerDisplay, getTimerByType } from '../common/viewerUtils'; import { formatTimerDisplay, getTimerByType } from '../common/viewerUtils';
import './Timer.scss'; import './Timer.scss';
@@ -106,7 +107,7 @@ export default function Timer(props: TimerProps) {
<div className={`clock-container ${showClock ? '' : 'clock-container--hidden'}`}> <div className={`clock-container ${showClock ? '' : 'clock-container--hidden'}`}>
<div className='label'>{getLocalizedString('common.time_now')}</div> <div className='label'>{getLocalizedString('common.time_now')}</div>
<div className='clock'>{clock}</div> <SuperscriptTime time={clock} className='clock' />
</div> </div>
<div className={`timer-container ${showBlinking ? (showOverlay ? '' : 'blink') : ''}`}> <div className={`timer-container ${showBlinking ? (showOverlay ? '' : 'blink') : ''}`}>
+5
View File
@@ -16,6 +16,11 @@
--operator-running-bg-override: #D20300; --operator-running-bg-override: #D20300;
--operator-highlight-override: #FFAB33; --operator-highlight-override: #FFAB33;
--studio-active: #101010;
--studio-idle: #cfcfcf;
--studio-active-label: #101010;
--studio-idle-label: #595959;
} }
.timer { .timer {