mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-09 17:33:55 +00:00
feat: implement logo in all views
This commit is contained in:
committed by
Carlos Valente
parent
9a2cfb59e7
commit
9bfa3e9f8e
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user