bump version to alpha release

This commit is contained in:
Carlos Valente
2024-06-22 20:17:37 +02:00
parent 8aeb4c7a01
commit 0e73f2ecb8
14 changed files with 113 additions and 63 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@getontime/cli", "name": "@getontime/cli",
"version": "3.3.2", "version": "3.4.0-alpha-timeline.2",
"author": "Carlos Valente", "author": "Carlos Valente",
"description": "Time keeping for live events", "description": "Time keeping for live events",
"repository": "https://github.com/cpvalente/ontime", "repository": "https://github.com/cpvalente/ontime",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ontime-ui", "name": "ontime-ui",
"version": "3.3.2", "version": "3.4.0-alpha-timeline.2",
"private": true, "private": true,
"type": "module", "type": "module",
"dependencies": { "dependencies": {
@@ -511,5 +511,14 @@ export const getOperatorOptions = (customFields: CustomFields, timeFormat: strin
export const getCountdownOptions = (timeFormat: string): ParamField[] => [getTimeOption(timeFormat), hideTimerSeconds]; export const getCountdownOptions = (timeFormat: string): ParamField[] => [getTimeOption(timeFormat), hideTimerSeconds];
export const getProgressOptions = (timeFormat: string): ParamField[] => { export const getProgressOptions = (timeFormat: string): ParamField[] => {
return [getTimeOption(timeFormat)]; return [
getTimeOption(timeFormat),
{
id: 'fullHeight',
title: 'Full height columns',
description: 'Whether the columns in the timeline should be the full height ',
type: 'boolean',
defaultValue: false,
},
];
}; };
@@ -24,6 +24,19 @@ export const getAccessibleColour = (bgColour?: string): ColourCombination => {
return { backgroundColor: '#1a1a1a', color: '#fffffa' }; return { backgroundColor: '#1a1a1a', color: '#fffffa' };
}; };
/**
* Adds opacity to a given colour, returns undefined if invalid
*/
export function alpha(colour: string, amount: number): string | undefined {
try {
const withAlpha = Color(colour).alpha(amount).hexa();
return withAlpha;
} catch (_error) {
/* we do not handle errors here */
}
return;
}
/** /**
* @description Creates a list of classnames from array of css module conditions * @description Creates a list of classnames from array of css module conditions
* @param classNames - css modules objects * @param classNames - css modules objects
@@ -6,40 +6,43 @@ $timeline-entry-height: 20px;
.timelineEvents { .timelineEvents {
position: relative; position: relative;
height: 100%;
} }
.entryIndicator { .entryColumn {
position: absolute; position: absolute;
background-color: var(--color, $ui-white); background-color: var(--lighter, $gray-500);
height: $timeline-entry-height; border-bottom: 0.25rem solid var(--color, $ui-white);
border-right: 1px solid $ui-black;
min-height: 80px;
&.fullHeight {
height: calc(100% - 4rem);
}
} }
.entryContent { .entryContent {
position: absolute;
margin-top: $timeline-entry-height;
padding-top: var(--top, 0); padding-top: var(--top, 0);
border-left: 2px solid var(--color, $ui-white);
color: $ui-white;
white-space: nowrap;
> div {
min-width: 100%;
padding-inline: 0.5em;
width: fit-content;
background-color: $ui-black;
}
&.lastElement { &.lastElement {
border-left: none;
border-right: 2px solid var(--color, $ui-black);
text-align: right; text-align: right;
transform: translateX(-100%); transform: translateX(-100%);
} }
} }
.entryText {
position: relative;
z-index: 2;
color: $ui-white;
padding-inline: 0.5em;
width: fit-content;
white-space: nowrap;
&.textBg {
background-color: var(--bg, $black-10);
}
}
.start, .start,
.title { .title {
font-weight: 600; font-weight: 600;
@@ -49,7 +52,7 @@ $timeline-entry-height: 20px;
[data-status='finished'] { [data-status='finished'] {
color: $gray-500; color: $gray-500;
.status { .status {
display: none display: none;
} }
} }
@@ -1,9 +1,11 @@
import { memo } from 'react'; import { memo } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useViewportSize } from '@mantine/hooks'; import { useViewportSize } from '@mantine/hooks';
import { isOntimeEvent, MaybeNumber } from 'ontime-types'; import { isOntimeEvent, MaybeNumber } from 'ontime-types';
import { dayInMs, getFirstEventNormal, getLastEventNormal, MILLIS_PER_HOUR } from 'ontime-utils'; import { dayInMs, getFirstEventNormal, getLastEventNormal, MILLIS_PER_HOUR } from 'ontime-utils';
import useRundown from '../../../common/hooks-query/useRundown'; import useRundown from '../../../common/hooks-query/useRundown';
import { isStringBoolean } from '../../viewers/common/viewUtils';
import { type ProgressStatus, TimelineEntry } from './TimelineEntry'; import { type ProgressStatus, TimelineEntry } from './TimelineEntry';
import { TimelineMarkers } from './TimelineMarkers'; import { TimelineMarkers } from './TimelineMarkers';
@@ -46,6 +48,8 @@ function Timeline(props: TimelineProps) {
const { selectedEventId } = props; const { selectedEventId } = props;
const { width: screenWidth } = useViewportSize(); const { width: screenWidth } = useViewportSize();
const timelineData = useTimeline(); const timelineData = useTimeline();
const [searchParams] = useSearchParams();
const fullHeight = isStringBoolean(searchParams.get('fullHeight'));
if (timelineData === null) { if (timelineData === null) {
return null; return null;
@@ -62,6 +66,7 @@ function Timeline(props: TimelineProps) {
return ( return (
<div className={style.timeline}> <div className={style.timeline}>
<TimelineMarkers /> <TimelineMarkers />
<ProgressBar startHour={startHour} endHour={endHour} />
<div className={style.timelineEvents}> <div className={style.timelineEvents}>
{order.map((eventId) => { {order.map((eventId) => {
// for now we dont render delays and blocks // for now we dont render delays and blocks
@@ -92,7 +97,8 @@ function Timeline(props: TimelineProps) {
event.duration, event.duration,
screenWidth, screenWidth,
); );
const estimatedRightPosition = elementLeftPosition + getEstimatedWidth(event.title); const estimatedWidth = getEstimatedWidth(event.title);
const estimatedRightPosition = elementLeftPosition + estimatedWidth;
const laneLevel = getLaneLevel(rightMostElements, elementLeftPosition); const laneLevel = getLaneLevel(rightMostElements, elementLeftPosition);
if (rightMostElements[laneLevel] === undefined || rightMostElements[laneLevel] < estimatedRightPosition) { if (rightMostElements[laneLevel] === undefined || rightMostElements[laneLevel] < estimatedRightPosition) {
@@ -111,11 +117,12 @@ function Timeline(props: TimelineProps) {
start={event.timeStart} start={event.timeStart}
title={event.title} title={event.title}
width={elementWidth} width={elementWidth}
mayGrow={elementWidth < estimatedWidth}
fullHeight={fullHeight}
/> />
); );
})} })}
</div> </div>
<ProgressBar startHour={startHour} endHour={endHour} />
</div> </div>
); );
} }
@@ -1,5 +1,5 @@
import { useClock } from '../../../common/hooks/useSocket'; import { useClock } from '../../../common/hooks/useSocket';
import { cx } from '../../../common/utils/styleUtils'; import { alpha, cx } from '../../../common/utils/styleUtils';
import { formatDuration, formatTime } from '../../../common/utils/time'; import { formatDuration, formatTime } from '../../../common/utils/time';
import { getStatusLabel } from './timelineUtils'; import { getStatusLabel } from './timelineUtils';
@@ -18,6 +18,9 @@ interface TimelineEntry {
start: number; start: number;
title: string; title: string;
width: number; width: number;
mayGrow: boolean;
fullHeight: boolean;
} }
const laneHeight = 120; const laneHeight = 120;
@@ -27,39 +30,48 @@ const formatOptions = {
}; };
export function TimelineEntry(props: TimelineEntry) { export function TimelineEntry(props: TimelineEntry) {
const { colour, duration, isLast, lane, left, status, start, title, width } = props; const { colour, duration, isLast, lane, left, status, start, title, width, mayGrow, fullHeight } = props;
const formattedStartTime = formatTime(start, formatOptions); const formattedStartTime = formatTime(start, formatOptions);
const formattedDuration = `Dur ${formatDuration(duration)}`; 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 contentClasses = cx([style.entryContent, isLast && style.lastElement]);
const textBgClasses = cx([style.entryText, mayGrow && style.textBg]);
return ( return (
<> <div
<div className={columnClasses}
className={style.entryIndicator} style={{
style={{ '--color': colour,
'--color': colour, '--lighter': lighterColour ?? '',
left: `${left}px`, left: `${left}px`,
width: `${width}px`, width: `${width}px`,
}} }}
/> >
<div <div
className={contentClasses} className={contentClasses}
data-status={status} data-status={status}
style={{ style={{
'--color': colour, '--color': colour,
'--top': `${lane * laneHeight}px`, '--top': `${lane * laneHeight}px`,
zIndex: 5 - lane,
left: `${left}px`,
}} }}
> >
<div className={style.start}>{formattedStartTime}</div> <div
<div className={style.title}>{title}</div> className={textBgClasses}
<div className={style.duration}>{formattedDuration}</div> style={{
<TimelineEntryStatus status={status} start={start} /> '--bg': alphaColour ?? '',
}}
>
<div className={style.start}>{formattedStartTime}</div>
<div className={style.title}>{title}</div>
<div className={style.duration}>{formattedDuration}</div>
<TimelineEntryStatus status={status} start={start} />
</div>
</div> </div>
</> </div>
); );
} }
@@ -1,19 +1,15 @@
.markers { .markers {
width: 100%; width: 100%;
color: $ui-white; color: $ui-white;
background-color: $white-10;
display: flex; display: flex;
height: 1rem; height: 1rem;
line-height: 1rem; line-height: 1rem;
font-size: calc(1rem - 2px); font-size: calc(1rem - 2px);
justify-content: space-evenly; justify-content: space-evenly;
text-align: center;
& > * { & > span {
flex-grow: 1; flex-grow: 1;
} border-left: 1px solid black;
height: 100vh;
:nth-child(odd) {
background-color: $white-20;
} }
} }
@@ -1,8 +1,13 @@
.progressBar { .progressBar {
position: relative; width: 100%;
height: 100%; height: 0.75rem;
border-right: 2px solid $active-red;
transition-duration: 0.3s; transition-duration: 0.3s;
transition-property: left; transition-property: left;
background-color: $gray-900;
.progress {
height: 100%;
background-color: $active-red;;
}
} }
@@ -13,7 +13,11 @@ export function ProgressBar(props: ProgressBarProps) {
const { startHour, endHour } = props; const { startHour, endHour } = props;
const { clock } = useClock(); const { clock } = useClock();
const left = getRelativePositionX(startHour, endHour, clock); const width = getRelativePositionX(startHour, endHour, clock);
return <div className={style.progressBar} style={{ width: `${left}%` }} />; return (
<div className={style.progressBar}>
<div className={style.progress} style={{ width: `${width}%` }} />
</div>
);
} }
@@ -4,7 +4,6 @@
background-color: $ui-black; background-color: $ui-black;
color: $ui-white; color: $ui-white;
text-transform: uppercase;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -38,11 +37,13 @@
font-weight: 600; font-weight: 600;
&.now { &.now {
color: $green-500; color: $red-500;
} }
&.next { &.next {
color: $red-500; color: $green-500;
} }
&.subdue { &.subdue {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ontime", "name": "ontime",
"version": "3.3.2", "version": "3.4.0-alpha-timeline.2",
"author": "Carlos Valente", "author": "Carlos Valente",
"description": "Time keeping for live events", "description": "Time keeping for live events",
"repository": "https://github.com/cpvalente/ontime", "repository": "https://github.com/cpvalente/ontime",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "ontime-server", "name": "ontime-server",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"version": "3.3.2", "version": "3.4.0-alpha-timeline.2",
"exports": "./src/index.js", "exports": "./src/index.js",
"dependencies": { "dependencies": {
"@googleapis/sheets": "^5.0.5", "@googleapis/sheets": "^5.0.5",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ontime", "name": "ontime",
"version": "3.3.2", "version": "3.4.0-alpha-timeline.2",
"description": "Time keeping for live events", "description": "Time keeping for live events",
"keywords": [ "keywords": [
"ontime", "ontime",