feat: implement logo in all views

This commit is contained in:
Carlos Valente
2024-11-18 13:40:37 +01:00
committed by Carlos Valente
parent 9a2cfb59e7
commit 9bfa3e9f8e
16 changed files with 124 additions and 36 deletions
@@ -0,0 +1,11 @@
import { projectLogoPath } from '../../api/constants';
interface ViewLogoProps {
name: string;
className: string;
}
export default function ViewLogo(props: ViewLogoProps) {
const { name, className } = props;
return <img src={`${projectLogoPath}/${name}`} className={className} />;
}
@@ -29,6 +29,12 @@
font-size: clamp(32px, 4.5vw, 64px);
font-weight: 600;
display: flex;
gap: 1rem;
}
.logo {
max-width: min(200px, 20vw);
max-height: min(100px, 20vh);
}
.clock-container {
@@ -10,6 +10,7 @@ import Schedule from '../../../common/components/schedule/Schedule';
import { ScheduleProvider } from '../../../common/components/schedule/ScheduleContext';
import ScheduleNav from '../../../common/components/schedule/ScheduleNav';
import TitleCard from '../../../common/components/title-card/TitleCard';
import ViewLogo from '../../../common/components/view-logo/ViewLogo';
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
import { useWindowTitle } from '../../../common/hooks/useWindowTitle';
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
@@ -27,19 +28,19 @@ import './Backstage.scss';
export const MotionTitleCard = motion(TitleCard);
interface BackstageProps {
customFields: CustomFields;
isMirrored: boolean;
eventNow: OntimeEvent | null;
eventNext: OntimeEvent | null;
time: ViewExtendedTimer;
backstageEvents: OntimeEvent[];
selectedId: string | null;
customFields: CustomFields;
eventNext: OntimeEvent | null;
eventNow: OntimeEvent | null;
general: ProjectData;
isMirrored: boolean;
time: ViewExtendedTimer;
selectedId: string | null;
settings: Settings | undefined;
}
export default function Backstage(props: BackstageProps) {
const { customFields, isMirrored, eventNow, eventNext, time, backstageEvents, selectedId, general, settings } = props;
const { backstageEvents, customFields, eventNext, eventNow, general, time, isMirrored, selectedId, settings } = props;
const { getLocalizedString } = useTranslation();
const [blinkClass, setBlinkClass] = useState(false);
@@ -81,6 +82,7 @@ export default function Backstage(props: BackstageProps) {
<div className={`backstage ${isMirrored ? 'mirror' : ''}`} data-testid='backstage-view'>
<ViewParamsEditor viewOptions={backstageOptions} />
<div className='project-header'>
{general?.projectLogo && <ViewLogo name={general.projectLogo} className='logo' />}
{general.title}
<div className='clock-container'>
<div className='label'>{getLocalizedString('common.time_now')}</div>
@@ -13,10 +13,18 @@
place-content: center;
.clock {
font-family: var(--font-family-bold-override, $timer-bold-font-family) ;
font-family: var(--font-family-bold-override, $timer-bold-font-family);
font-size: 20vw;
position: relative;
color: var(--timer-color-override, $timer-color);
letter-spacing: 0.05em;
}
.logo {
position: absolute;
top: 2vw;
left: 2vw;
max-width: min(200px, 20vw);
max-height: min(100px, 20vh);
}
}
@@ -1,6 +1,7 @@
import { useSearchParams } from 'react-router-dom';
import { Settings } from 'ontime-types';
import { ProjectData, Settings } from 'ontime-types';
import ViewLogo from '../../../common/components/view-logo/ViewLogo';
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
import { useWindowTitle } from '../../../common/hooks/useWindowTitle';
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
@@ -13,13 +14,14 @@ import { getClockOptions } from './clock.options';
import './Clock.scss';
interface ClockProps {
general: ProjectData;
isMirrored: boolean;
time: ViewExtendedTimer;
settings: Settings | undefined;
}
export default function Clock(props: ClockProps) {
const { isMirrored, time, settings } = props;
const { general, isMirrored, time, settings } = props;
const [searchParams] = useSearchParams();
useWindowTitle('Clock');
@@ -122,6 +124,7 @@ export default function Clock(props: ClockProps) {
}}
data-testid='clock-view'
>
{general?.projectLogo && <ViewLogo name={general.projectLogo} className='logo' />}
<ViewParamsEditor viewOptions={clockOptions} />
<SuperscriptTime
time={clock}
@@ -33,6 +33,14 @@
}
}
.logo {
position: absolute;
top: 2vw;
left: 2vw;
max-width: min(200px, 20vw);
max-height: min(100px, 20vh);
}
/* =================== MAIN - EVENT CONTAINER ===================*/
.countdown-container {
@@ -75,7 +83,7 @@
.status {
grid-area: status;
color: var(--label-color-override, $viewer-label-color);
font-size: clamp(2rem, 3.5vw, 3.5rem);
font-size: clamp(2rem, 3.5vw, 3.5rem);
font-weight: 600;
}
@@ -127,7 +135,7 @@
justify-items: center;
text-align: center;
row-gap: clamp(1rem, 5vh, 4rem);
align-self: flex-end;
height: fit-content;
@@ -1,7 +1,17 @@
import { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { OntimeEvent, OntimeRundownEntry, Playback, Runtime, Settings, SupportedEvent, TimerPhase } from 'ontime-types';
import {
OntimeEvent,
OntimeRundownEntry,
Playback,
ProjectData,
Runtime,
Settings,
SupportedEvent,
TimerPhase,
} from 'ontime-types';
import ViewLogo from '../../../common/components/view-logo/ViewLogo';
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
import { useWindowTitle } from '../../../common/hooks/useWindowTitle';
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
@@ -17,8 +27,9 @@ import CountdownSelect from './CountdownSelect';
import './Countdown.scss';
interface CountdownProps {
isMirrored: boolean;
backstageEvents: OntimeEvent[];
general: ProjectData;
isMirrored: boolean;
runtime: Runtime;
selectedId: string | null;
settings: Settings | undefined;
@@ -26,7 +37,7 @@ interface CountdownProps {
}
export default function Countdown(props: CountdownProps) {
const { isMirrored, backstageEvents, runtime, selectedId, settings, time } = props;
const { backstageEvents, general, isMirrored, runtime, selectedId, settings, time } = props;
const [searchParams] = useSearchParams();
const { getLocalizedString } = useTranslation();
@@ -105,6 +116,7 @@ export default function Countdown(props: CountdownProps) {
return (
<div className={`countdown ${isMirrored ? 'mirror' : ''}`} data-testid='countdown-view'>
{general?.projectLogo && <ViewLogo name={general.projectLogo} className='logo' />}
<ViewParamsEditor viewOptions={viewOptions} />
{follow === null ? (
<CountdownSelect events={backstageEvents} />
@@ -21,7 +21,7 @@
.timer {
opacity: 1;
font-family: var(--font-family-bold-override, $timer-bold-font-family) ;
font-family: var(--font-family-bold-override, $timer-bold-font-family);
font-size: 20vw;
position: relative;
color: var(--timer-color-override, var(--phase-color));
@@ -43,11 +43,19 @@
/* =================== OVERLAY ===================*/
.end-message {
text-align: center;
font-size: 12vw;
line-height: 0.9em;
font-weight: 600;
color: $timer-finished-color;
padding: 0;
}
text-align: center;
font-size: 12vw;
line-height: 0.9em;
font-weight: 600;
color: $timer-finished-color;
padding: 0;
}
.logo {
position: absolute;
top: 2vw;
left: 2vw;
max-width: min(200px, 20vw);
max-height: min(100px, 20vh);
}
}
@@ -1,6 +1,7 @@
import { useSearchParams } from 'react-router-dom';
import { Playback, TimerPhase, TimerType, ViewSettings } from 'ontime-types';
import { Playback, ProjectData, TimerPhase, TimerType, ViewSettings } from 'ontime-types';
import ViewLogo from '../../../common/components/view-logo/ViewLogo';
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
import { useWindowTitle } from '../../../common/hooks/useWindowTitle';
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
@@ -13,13 +14,14 @@ import { MINIMAL_TIMER_OPTIONS } from './minimalTimer.options';
import './MinimalTimer.scss';
interface MinimalTimerProps {
general: ProjectData;
isMirrored: boolean;
time: ViewExtendedTimer;
viewSettings: ViewSettings;
}
export default function MinimalTimer(props: MinimalTimerProps) {
const { isMirrored, time, viewSettings } = props;
const { general, isMirrored, time, viewSettings } = props;
const { getLocalizedString } = useTranslation();
const [searchParams] = useSearchParams();
@@ -158,6 +160,7 @@ export default function MinimalTimer(props: MinimalTimerProps) {
}}
data-testid='minimal-timer'
>
{general?.projectLogo && <ViewLogo name={general.projectLogo} className='logo' />}
<ViewParamsEditor viewOptions={MINIMAL_TIMER_OPTIONS} />
{showEndMessage ? (
<div className='end-message'>{viewSettings.endMessage}</div>
@@ -29,6 +29,12 @@
font-size: clamp(32px, 4.5vw, 64px);
font-weight: 600;
display: flex;
gap: 1rem;
}
.logo {
max-width: min(200px, 20vw);
max-height: min(100px, 20vh);
}
.clock-container {
@@ -70,7 +76,7 @@
grid-area: schedule;
overflow: hidden;
height: 100%;
margin-left: clamp(16px, 5vw, 64px);;
margin-left: clamp(16px, 5vw, 64px);
}
.schedule-nav-container {
@@ -7,6 +7,7 @@ import Schedule from '../../../common/components/schedule/Schedule';
import { ScheduleProvider } from '../../../common/components/schedule/ScheduleContext';
import ScheduleNav from '../../../common/components/schedule/ScheduleNav';
import TitleCard from '../../../common/components/title-card/TitleCard';
import ViewLogo from '../../../common/components/view-logo/ViewLogo';
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
import { useWindowTitle } from '../../../common/hooks/useWindowTitle';
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
@@ -24,26 +25,26 @@ export const MotionTitleCard = motion(TitleCard);
interface BackstageProps {
customFields: CustomFields;
general: ProjectData;
isMirrored: boolean;
publicEventNow: OntimeEvent | null;
publicEventNext: OntimeEvent | null;
time: ViewExtendedTimer;
events: OntimeEvent[];
publicSelectedId: string | null;
general: ProjectData;
settings: Settings | undefined;
}
export default function Public(props: BackstageProps) {
const {
customFields,
general,
isMirrored,
publicEventNow,
publicEventNext,
time,
events,
publicSelectedId,
general,
settings,
} = props;
@@ -66,6 +67,7 @@ export default function Public(props: BackstageProps) {
<div className={`public-screen ${isMirrored ? 'mirror' : ''}`} data-testid='public-view'>
<ViewParamsEditor viewOptions={publicOptions} />
<div className='project-header'>
{general?.projectLogo && <ViewLogo name={general.projectLogo} className='logo' />}
{general.title}
<div className='clock-container'>
<div className='label'>{getLocalizedString('common.time_now')}</div>
@@ -204,6 +204,13 @@ $orange-active: #f60;
background-color: var(--studio-idle, $red-idle);
}
}
.logo {
position: absolute;
top: 2vw;
right: 2vw;
max-width: min(200px, 20vw);
max-height: min(100px, 20vh);
}
}
@media only screen and (max-width: 1200px) {
@@ -1,9 +1,10 @@
import { useSearchParams } from 'react-router-dom';
import type { MaybeString, OntimeEvent, OntimeRundown, Settings } from 'ontime-types';
import type { MaybeString, OntimeEvent, OntimeRundown, ProjectData, Settings } from 'ontime-types';
import { Playback } from 'ontime-types';
import { millisToString, removeSeconds, secondsInMillis } from 'ontime-utils';
import { FitText } from '../../../common/components/fit-text/FitText';
import ViewLogo from '../../../common/components/view-logo/ViewLogo';
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
import { useWindowTitle } from '../../../common/hooks/useWindowTitle';
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
@@ -16,10 +17,11 @@ import StudioClockSchedule from './StudioClockSchedule';
import './StudioClock.scss';
interface StudioClockProps {
isMirrored: boolean;
eventNext: OntimeEvent | null;
time: ViewExtendedTimer;
backstageEvents: OntimeRundown;
eventNext: OntimeEvent | null;
general: ProjectData;
isMirrored: boolean;
time: ViewExtendedTimer;
selectedId: MaybeString;
nextId: MaybeString;
onAir: boolean;
@@ -27,7 +29,7 @@ interface StudioClockProps {
}
export default function StudioClock(props: StudioClockProps) {
const { isMirrored, eventNext, time, backstageEvents, selectedId, nextId, onAir, settings } = props;
const { backstageEvents, eventNext, general, isMirrored, time, selectedId, nextId, onAir, settings } = props;
const [searchParams] = useSearchParams();
@@ -65,6 +67,7 @@ export default function StudioClock(props: StudioClockProps) {
className={`studio-clock ${isMirrored ? 'mirror' : ''} ${hideRight ? 'hide-right' : ''}`}
data-testid='studio-view'
>
{general?.projectLogo && <ViewLogo name={general.projectLogo} className='logo' />}
<ViewParamsEditor viewOptions={studioClockOptions} />
<div className='clock-container'>
{hasAmPm && <div className='clock__ampm'>{hasAmPm}</div>}
@@ -13,10 +13,10 @@ import {
ViewSettings,
} from 'ontime-types';
import { projectLogoPath } from '../../../common/api/constants';
import { FitText } from '../../../common/components/fit-text/FitText';
import MultiPartProgressBar from '../../../common/components/multi-part-progress-bar/MultiPartProgressBar';
import TitleCard from '../../../common/components/title-card/TitleCard';
import ViewLogo from '../../../common/components/view-logo/ViewLogo';
import ViewParamsEditor from '../../../common/components/view-params-editor/ViewParamsEditor';
import { useWindowTitle } from '../../../common/hooks/useWindowTitle';
import { ViewExtendedTimer } from '../../../common/models/TimeManager.type';
@@ -172,7 +172,7 @@ export default function Timer(props: TimerProps) {
return (
<div className={showFinished ? `${baseClasses} stage-timer--finished` : baseClasses} data-testid='timer-view'>
{general?.projectLogo && <img src={`${projectLogoPath}/${general.projectLogo}`} className='logo' />}
{general?.projectLogo && <ViewLogo name={general.projectLogo} className='logo' />}
<ViewParamsEditor viewOptions={timerOptions} />
<div className={message.timer.blackout ? 'blackout blackout--active' : 'blackout'} />
@@ -18,10 +18,17 @@
font-size: clamp(32px, 4.5vw, 64px);
font-weight: 600;
display: flex;
justify-content: space-between;
gap: 1rem;
}
.logo {
max-width: min(200px, 20vw);
max-height: min(100px, 20vh);
}
.clock-container {
margin-left: auto;
.label {
font-size: clamp(16px, 1.5vw, 24px);
font-weight: 600;
@@ -1,6 +1,7 @@
import { useMemo } from 'react';
import { MaybeString, OntimeEvent, ProjectData, Runtime, Settings } from 'ontime-types';
import ViewLogo from '../../common/components/view-logo/ViewLogo';
import ViewParamsEditor from '../../common/components/view-params-editor/ViewParamsEditor';
import { useWindowTitle } from '../../common/hooks/useWindowTitle';
import { ViewExtendedTimer } from '../../common/models/TimeManager.type';
@@ -74,6 +75,7 @@ export default function TimelinePage(props: TimelinePageProps) {
<div className='timeline'>
<ViewParamsEditor viewOptions={progressOptions} />
<div className='project-header'>
{general?.projectLogo && <ViewLogo name={general.projectLogo} className='logo' />}
{general.title}
<div className='clock-container'>
<div className='label'>{getLocalizedString('common.time_now')}</div>