mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-10 08:39:34 +00:00
@@ -16,5 +16,5 @@ export default function useProjectData() {
|
|||||||
networkMode: 'always',
|
networkMode: 'always',
|
||||||
});
|
});
|
||||||
|
|
||||||
return { data, status, isFetching, isError, refetch };
|
return { data: data ?? projectDataPlaceholder, status, isFetching, isError, refetch };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,3 +120,14 @@ export const useTimer = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const setClientName = (newName: string) => socketSendJson('set-client-name', newName);
|
export const setClientName = (newName: string) => socketSendJson('set-client-name', newName);
|
||||||
|
|
||||||
|
export const useRuntimeOverview = () => {
|
||||||
|
const featureSelector = (state: RuntimeStore) => ({
|
||||||
|
playback: state.playback,
|
||||||
|
clock: state.timer.clock,
|
||||||
|
numEvents: state.loaded.numEvents,
|
||||||
|
selectedEventIndex: state.loaded.selectedEventIndex,
|
||||||
|
});
|
||||||
|
|
||||||
|
return useRuntimeStore(featureSelector, deepCompare);
|
||||||
|
};
|
||||||
|
|||||||
@@ -34,18 +34,13 @@ $playback-width: 26rem;
|
|||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: $menu-width auto;
|
grid-template-columns: $menu-width auto;
|
||||||
grid-template-rows: 2rem 1fr;
|
grid-template-rows: 3rem 1fr;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
'menu overview'
|
'menu overview'
|
||||||
'menu main';
|
'menu main';
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.overview {
|
|
||||||
grid-area: overview;
|
|
||||||
background-color: $white-10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panelContainer {
|
.panelContainer {
|
||||||
grid-area: main;
|
grid-area: main;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import MenuBar from '../menu/MenuBar';
|
|||||||
import AboutModal from '../modals/about-modal/AboutModal';
|
import AboutModal from '../modals/about-modal/AboutModal';
|
||||||
import QuickStart from '../modals/quick-start/QuickStart';
|
import QuickStart from '../modals/quick-start/QuickStart';
|
||||||
import UploadModal from '../modals/upload-modal/UploadModal';
|
import UploadModal from '../modals/upload-modal/UploadModal';
|
||||||
|
import Overview from '../overview/Overview';
|
||||||
|
|
||||||
import styles from './Editor.module.scss';
|
import styles from './Editor.module.scss';
|
||||||
|
|
||||||
@@ -98,12 +99,7 @@ export default function Editor() {
|
|||||||
<Info />
|
<Info />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={styles.overview}>
|
<Overview />
|
||||||
<ErrorBoundary></ErrorBoundary>
|
|
||||||
{
|
|
||||||
// TODO: the information about the event
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<EventEditor />
|
<EventEditor />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useInfoPanel } from '../../common/hooks/useSocket';
|
import { useInfoPanel } from '../../common/hooks/useSocket';
|
||||||
import { useEditorSettings } from '../../common/stores/editorSettings';
|
import { useEditorSettings } from '../../common/stores/editorSettings';
|
||||||
|
|
||||||
import InfoHeader from './info-header/InfoHeader';
|
|
||||||
import CollapsableInfo from './CollapsableInfo';
|
import CollapsableInfo from './CollapsableInfo';
|
||||||
import InfoLogger from './InfoLogger';
|
import InfoLogger from './InfoLogger';
|
||||||
import InfoNif from './InfoNif';
|
import InfoNif from './InfoNif';
|
||||||
@@ -25,15 +24,8 @@ export default function Info() {
|
|||||||
note: data.eventNext?.note || '',
|
note: data.eventNext?.note || '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const selected = !data.numEvents
|
|
||||||
? 'No events'
|
|
||||||
: `Event ${data.selectedEventIndex !== null ? data.selectedEventIndex + 1 : '-'} / ${
|
|
||||||
data.numEvents ? data.numEvents : '-'
|
|
||||||
}`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<InfoHeader selected={selected} />
|
|
||||||
{showNif && (
|
{showNif && (
|
||||||
<CollapsableInfo title='Network Info'>
|
<CollapsableInfo title='Network Info'>
|
||||||
<InfoNif />
|
<InfoNif />
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import useProjectData from '../../../common/hooks-query/useProjectData';
|
|
||||||
|
|
||||||
import style from '../Info.module.scss';
|
|
||||||
|
|
||||||
export default function InfoHeader({ selected }: { selected: string }) {
|
|
||||||
const { data } = useProjectData();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={style.panelHeader}>
|
|
||||||
<span className={style.title}>{data?.title || ''}</span>
|
|
||||||
<span className={style.selected}>{selected}</span>
|
|
||||||
</div>
|
|
||||||
<div className={style.description}>{data?.description || ''}</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
@use '../../theme/ontimeColours' as *;
|
||||||
|
@use '../../theme/v2Styles' as *;
|
||||||
|
|
||||||
|
.overview {
|
||||||
|
grid-area: overview;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: start;
|
||||||
|
font-size: $inner-section-text-size;
|
||||||
|
gap: 2rem;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titles {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
font-size: 1rem;
|
||||||
|
color: $label-gray;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin indicator($bg-color) {
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
background-color: $bg-color;
|
||||||
|
display: inline-flex;
|
||||||
|
height: 0.75em;
|
||||||
|
width: 0.75em;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.start {
|
||||||
|
@include indicator($green-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.end {
|
||||||
|
@include indicator($red-500);
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { Tooltip } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
import ErrorBoundary from '../../common/components/error-boundary/ErrorBoundary';
|
||||||
|
import PlaybackIcon from '../../common/components/playback-icon/PlaybackIcon';
|
||||||
|
import { useRuntimeOverview } from '../../common/hooks/useSocket';
|
||||||
|
import useProjectData from '../../common/hooks-query/useProjectData';
|
||||||
|
import { formatTime } from '../../common/utils/time';
|
||||||
|
|
||||||
|
import styles from './Overview.module.scss';
|
||||||
|
|
||||||
|
export default function Overview() {
|
||||||
|
return (
|
||||||
|
<div className={styles.overview}>
|
||||||
|
<ErrorBoundary>
|
||||||
|
<TitlesOverview />
|
||||||
|
<div className={styles.clocks}>
|
||||||
|
<Tooltip label='Planned start'>
|
||||||
|
<div className={styles.start}>Planned start</div>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip label='Actual start'>
|
||||||
|
<div className={styles.start}>Actual start</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<RuntimeOverview />
|
||||||
|
<div className={styles.clocks}>
|
||||||
|
<Tooltip label='Planned end'>
|
||||||
|
<div className={styles.end}>Planned end</div>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip label='Expected end'>
|
||||||
|
<div className={styles.end}>Expected end</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</ErrorBoundary>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TitlesOverview() {
|
||||||
|
const { data } = useProjectData();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.titles}>
|
||||||
|
<div className={styles.title}>{data.title}</div>
|
||||||
|
<div className={styles.description}>{data.description}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function RuntimeOverview() {
|
||||||
|
const { playback, clock, numEvents, selectedEventIndex } = useRuntimeOverview();
|
||||||
|
|
||||||
|
const current = selectedEventIndex !== null ? selectedEventIndex + 1 : '-';
|
||||||
|
const ofTotal = numEvents || '-';
|
||||||
|
|
||||||
|
const display = formatTime(clock, {
|
||||||
|
showSeconds: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.clocks}>
|
||||||
|
<div className={styles.inline}>
|
||||||
|
<PlaybackIcon state={playback} skipTooltip />
|
||||||
|
{display}
|
||||||
|
</div>
|
||||||
|
<div className={styles.inline}>
|
||||||
|
<span>{`(${current} / ${ofTotal})`}</span>
|
||||||
|
Over / Under
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user