Skip to content

Commit 9eff487

Browse files
committed
wip: additional layer info on HoverPreviews
1 parent af14bcd commit 9eff487

File tree

8 files changed

+132
-52
lines changed

8 files changed

+132
-52
lines changed

meteor/server/publications/pieceContentStatusUI/checkPieceContentStatus.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ export async function checkPieceContentStatusAndDependencies(
240240
blacks: [],
241241
scenes: [],
242242

243-
thumbnailUrl: undefined,
243+
thumbnailUrl: '/dev/fakeThumbnail.png',
244244
previewUrl: '/dev/fakePreview.mp4',
245245

246246
packageName: null,

packages/blueprints-integration/src/content.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,54 @@ export type WithTimeline<T extends BaseContent> = T & {
88
timelineObjects: TimelineObjectCoreExt<TSR.TSRTimelineContent>[]
99
}
1010

11+
// The PreviewContent types are a partly replica of the types in PreviewPopUpContext.tsx
12+
export type PreviewContent =
13+
| {
14+
type: 'iframe'
15+
href: string
16+
postMessage?: any
17+
dimensions?: { width: number; height: number }
18+
}
19+
| {
20+
type: 'image'
21+
src: string
22+
}
23+
| {
24+
type: 'video'
25+
src: string
26+
}
27+
| {
28+
type: 'script'
29+
script?: string
30+
firstWords?: string
31+
lastWords?: string
32+
comment?: string
33+
lastModified?: number
34+
}
35+
| {
36+
type: 'title'
37+
content: string
38+
}
39+
| {
40+
type: 'inOutWords'
41+
in?: string
42+
out: string
43+
}
44+
| {
45+
type: 'layerInfo'
46+
layerType: SourceLayerType
47+
text: Array<string>
48+
inTime?: number | string
49+
outTime?: number | string
50+
}
51+
| {
52+
type: 'separationLine'
53+
}
54+
| {
55+
type: 'data'
56+
content: { key: string; value: string }[]
57+
}
58+
1159
export interface BaseContent {
1260
editable?: BaseEditableParameters
1361

@@ -25,6 +73,10 @@ export interface BaseContent {
2573
* Overwrite any default hover previews in Sofie
2674
*/
2775
popUpPreview?: PopupPreview
76+
/**
77+
* Add custom content preview content
78+
*/
79+
additionalPreviewContent?: Array<PreviewContent>
2880
}
2981

3082
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
1.13 MB
Loading

packages/webui/src/client/styles/shelf/dashboard-rundownView.scss

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
}
1212

1313
.dashboard-panel__panel__button {
14+
margin-top: 10px;
15+
height: 110px;
16+
max-width: 150px !important;
1417
> .dashboard-panel__panel__button__content {
1518
display: grid;
1619
grid-template-columns: 1fr min-content;
@@ -31,7 +34,7 @@
3134

3235
> .dashboard-panel__panel__button__thumbnail {
3336
position: relative;
34-
height: auto;
37+
height: 80px;
3538
z-index: 1;
3639
overflow: hidden;
3740
grid-column: auto / span 2;

packages/webui/src/client/ui/PreviewPopUp/PreviewPopUp.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@
5656
padding: 5px;
5757
}
5858

59+
.preview-popUp__element-with-time-info {
60+
width: 100%;
61+
62+
.preview-popUp__element-with-time-info__layer-color {
63+
width: 20px;
64+
font-size: 1.2em;
65+
@include item-type-colors();
66+
}
67+
}
68+
5969
.preview-popUp__warning {
6070
width: 100%;
6171

packages/webui/src/client/ui/PreviewPopUp/PreviewPopUpContent.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React from 'react'
2-
import { PreviewContent } from './PreviewPopUpContext.js'
32
import { WarningIconSmall } from '../../lib/ui/icons/notifications.js'
43
import { translateMessage } from '@sofie-automation/corelib/dist/TranslatableMessage'
54
import { TFunction, useTranslation } from 'react-i18next'
@@ -11,9 +10,11 @@ import { RundownUtils } from '../../lib/rundown.js'
1110
import { PieceInstancePiece } from '@sofie-automation/corelib/dist/dataModel/PieceInstance'
1211
import { ReadonlyObjectDeep } from 'type-fest/source/readonly-deep'
1312
import { PieceLifespan } from '@sofie-automation/blueprints-integration'
13+
import { LayerInfoPreview } from './Previews/LayerInfoPreview.js'
14+
import { PreviewContentUI } from './PreviewPopUpContext.js'
1415

1516
interface PreviewPopUpContentProps {
16-
content: PreviewContent
17+
content: PreviewContentUI
1718
time: number | null
1819
}
1920

@@ -59,6 +60,10 @@ export function PreviewPopUpContent({ content, time }: PreviewPopUpContentProps)
5960
</table>
6061
</div>
6162
)
63+
case 'layerInfo':
64+
return <LayerInfoPreview {...content} />
65+
case 'separationLine':
66+
return <hr className="separation-line" />
6267
case 'boxLayout':
6368
return <BoxLayoutPreview content={content} />
6469
case 'warning':

packages/webui/src/client/ui/PreviewPopUp/PreviewPopUpContext.tsx

Lines changed: 19 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
JSONBlobParse,
77
NoraPayload,
88
PieceLifespan,
9+
PreviewContent,
910
PreviewType,
1011
ScriptContent,
1112
SourceLayerType,
@@ -33,11 +34,11 @@ export function convertSourceLayerItemToPreview(
3334
item: ReadonlyObjectDeep<PieceInstancePiece> | IAdLibListItem,
3435
contentStatus?: ReadonlyObjectDeep<PieceContentStatusObj>,
3536
timeAsRendered?: { in?: number | null; dur?: number | null }
36-
): { contents: PreviewContent[]; options: Readonly<Partial<PreviewRequestOptions>> } {
37+
): { contents: PreviewContentUI[]; options: Readonly<Partial<PreviewRequestOptions>> } {
3738
// first try to read the popup preview
3839
if (item.content.popUpPreview) {
3940
const popupPreview = item.content.popUpPreview
40-
const contents: PreviewContent[] = []
41+
const contents: PreviewContentUI[] = []
4142
const options: Partial<PreviewRequestOptions> = {}
4243

4344
if (popupPreview.name) {
@@ -122,8 +123,12 @@ export function convertSourceLayerItemToPreview(
122123
}
123124
}
124125

126+
item.content.additionalPreviewContent?.forEach((content) => {
127+
contents.push(content as PreviewContentUI)
128+
})
129+
125130
if (popupPreview.warnings) {
126-
contents.push(...popupPreview.warnings.map((w): PreviewContent => ({ type: 'warning', content: w.reason })))
131+
contents.push(...popupPreview.warnings.map((w): PreviewContentUI => ({ type: 'warning', content: w.reason })))
127132
}
128133

129134
return { contents, options }
@@ -136,7 +141,7 @@ export function convertSourceLayerItemToPreview(
136141
const content = item.content as VTContent
137142

138143
return {
139-
contents: _.compact<(PreviewContent | undefined)[]>([
144+
contents: _.compact<(PreviewContentUI | undefined)[]>([
140145
{
141146
type: 'title',
142147
content: content.fileName,
@@ -159,11 +164,11 @@ export function convertSourceLayerItemToPreview(
159164
src: contentStatus.thumbnailUrl,
160165
}
161166
: undefined,
162-
...(contentStatus?.messages?.map<PreviewContent>((m) => ({
167+
...(contentStatus?.messages?.map<PreviewContentUI>((m) => ({
163168
type: 'warning',
164169
content: m as any,
165170
})) || []),
166-
]) as PreviewContent[],
171+
]) as PreviewContentUI[],
167172
options: {
168173
size: contentStatus?.previewUrl ? 'large' : undefined,
169174
},
@@ -220,7 +225,7 @@ export function convertSourceLayerItemToPreview(
220225
current: item.content.step.current,
221226
count: item.content.step.count,
222227
},
223-
]) as PreviewContent[],
228+
]) as PreviewContentUI[],
224229
options: { size: 'large' },
225230
}
226231
} catch (e) {
@@ -237,7 +242,7 @@ export function convertSourceLayerItemToPreview(
237242
current: item.content.step.current,
238243
count: item.content.step.count,
239244
},
240-
]) as PreviewContent[],
245+
]) as PreviewContentUI[],
241246
options: {},
242247
}
243248
}
@@ -287,43 +292,9 @@ export function convertSourceLayerItemToPreview(
287292

288293
return { contents: [], options: {} }
289294
}
290-
291-
export type PreviewContent =
292-
| {
293-
type: 'iframe'
294-
href: string
295-
postMessage?: any
296-
dimensions?: { width: number; height: number }
297-
}
298-
| {
299-
type: 'image'
300-
src: string
301-
}
302-
| {
303-
type: 'video'
304-
src: string
305-
}
306-
| {
307-
type: 'script'
308-
script?: string
309-
firstWords?: string
310-
lastWords?: string
311-
comment?: string
312-
lastModified?: number
313-
}
314-
| {
315-
type: 'title'
316-
content: string
317-
}
318-
| {
319-
type: 'inOutWords'
320-
in?: string
321-
out: string
322-
}
323-
| {
324-
type: 'data'
325-
content: { key: string; value: string }[]
326-
}
295+
// PreviewContentUI should be the same as PreviewContent, but we need to extend it with some more types:
296+
export type PreviewContentUI =
297+
| PreviewContent
327298
| {
328299
type: 'boxLayout'
329300
boxSourceConfiguration: ReadonlyDeep<(SplitsContentBoxContent & SplitsContentBoxProperties)[]>
@@ -351,7 +322,7 @@ export interface IPreviewPopUpSession {
351322
* Update the open preview with new content or modify the content already being previewed, such as change current showing
352323
* time in the video, etc.
353324
*/
354-
readonly update: (content?: PreviewContent[]) => void
325+
readonly update: (content?: PreviewContentUI[]) => void
355326
/**
356327
* Set the time that the current pointer position is representing in the scope of the preview contents
357328
*/
@@ -390,7 +361,7 @@ export interface IPreviewPopUpContext {
390361
*/
391362
requestPreview(
392363
anchor: HTMLElement | VirtualElement,
393-
content: PreviewContent[],
364+
content: PreviewContentUI[],
394365
opts?: PreviewRequestOptions
395366
): IPreviewPopUpSession
396367
}
@@ -415,7 +386,7 @@ export function PreviewPopUpContextProvider({ children }: React.PropsWithChildre
415386
const previewRef = useRef<PreviewPopUpHandle>(null)
416387

417388
const [previewSession, setPreviewSession] = useState<PreviewSession | null>(null)
418-
const [previewContent, setPreviewContent] = useState<PreviewContent[] | null>(null)
389+
const [previewContent, setPreviewContent] = useState<PreviewContentUI[] | null>(null)
419390
const [t, setTime] = useState<number | null>(null)
420391

421392
const context: IPreviewPopUpContext = {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { PreviewContent } from '@sofie-automation/blueprints-integration'
2+
import { RundownUtils } from '../../../lib/rundown'
3+
import { useTranslation } from 'react-i18next'
4+
import classNames from 'classnames'
5+
6+
type layerInfoContent = Extract<PreviewContent, { type: 'layerInfo' }>
7+
8+
export function LayerInfoPreview(content: layerInfoContent): React.ReactElement {
9+
const { t } = useTranslation()
10+
const sourceLayerClassName =
11+
content.layerType !== undefined ? RundownUtils.getSourceLayerClassName(content.layerType) : undefined
12+
13+
return (
14+
<div className="preview-popUp__element-with-time-info">
15+
<span className={classNames('preview-popUp__element-with-time-info__layer-color', sourceLayerClassName)}>
16+
{'◼️'}
17+
</span>
18+
{content.text.map((line, index) => (
19+
<div key={index} className="mini-inspector__full-text">
20+
{line}
21+
</div>
22+
))}
23+
<div className="preview-popUp__timing">
24+
{content.inTime && (
25+
<>
26+
<span className="label">IN: </span> {RundownUtils.formatTimeToShortTime((content.inTime as any as number) || 0)}
27+
</>
28+
)}
29+
&nbsp;{' '}
30+
{content.outTime && (
31+
<>
32+
<span className="label">{t('DURATION: ')}</span>
33+
{RundownUtils.formatTimeToShortTime((content.outTime as any as number) || 0)}
34+
</>
35+
)}
36+
</div>
37+
</div>
38+
)
39+
}

0 commit comments

Comments
 (0)