Skip to content

Commit b3ebcf3

Browse files
committed
SOFIE-284 | improve UX in properties editor
1 parent 3304737 commit b3ebcf3

File tree

8 files changed

+147
-123
lines changed

8 files changed

+147
-123
lines changed

packages/meteor-lib/src/triggers/RundownViewEventBus.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export enum RundownViewEvents {
4949

5050
TOGGLE_SHELF_DROPZONE = 'toggleShelfDropzone',
5151
ITEM_DROPPED = 'itemDropped',
52+
CLOSE_NOTIFICATIONS = 'closeNotifications',
5253
}
5354

5455
export interface IEventContext {
@@ -162,6 +163,7 @@ export interface RundownViewEventBusEvents {
162163
[RundownViewEvents.CREATE_SNAPSHOT_FOR_DEBUG]: [e: BaseEvent]
163164
[RundownViewEvents.TOGGLE_SHELF_DROPZONE]: [e: ToggleShelfDropzoneEvent]
164165
[RundownViewEvents.ITEM_DROPPED]: [e: ItemDroppedEvent]
166+
[RundownViewEvents.CLOSE_NOTIFICATIONS]: []
165167
}
166168

167169
class RundownViewEventBus0 extends EventEmitter<RundownViewEventBusEvents> {}

packages/webui/src/client/styles/propertiesPanel.scss

Lines changed: 14 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
background: linear-gradient(to right, transparent 0%, rgba(0, 0, 0, 0.15) 100%);
3333
}
3434

35+
.propertiespanel-pop-up__label-with-icon {
36+
margin-left: 0.5em;
37+
}
38+
3539
.propertiespanel-pop-up {
3640
background: #2e2e2e;
3741
border-radius: 1px;
@@ -64,8 +68,6 @@
6468
letter-spacing: 0.5px;
6569

6670
> .svg {
67-
width: 1em;
68-
height: 1.2em;
6971
flex-shrink: 0;
7072
}
7173
> .title {
@@ -87,13 +89,16 @@
8789
flex-shrink: 0;
8890
}
8991
> .propertiespanel-pop-up_close {
90-
height: 1em;
91-
margin-left: 1em;
9292
background-color: unset;
9393
border: none;
9494
}
9595
}
9696

97+
.propertiespanel-pop-up__buttons-container {
98+
display: flex;
99+
gap: 0.5em;
100+
}
101+
97102
> .propertiespanel-pop-up__footer {
98103
flex: 1;
99104
flex: 0 0 0;
@@ -109,7 +114,9 @@
109114

110115
> .propertiespanel-pop-up__button,
111116
.propertiespanel-pop-up__button-group .propertiespanel-pop-up__button {
112-
display: block;
117+
display: flex;
118+
gap: 0.5em;
119+
align-items: center;
113120

114121
border-radius: 5px;
115122
border: 1px solid #7f7f7f;
@@ -227,14 +234,14 @@
227234
}
228235

229236
.propertiespanel-pop-up__button {
230-
// margin-top: 10px;
231237
background: #636363;
232238
padding: 10px;
233-
gap: 10px;
234239
border-radius: 5px;
235240
border: 1px solid #7f7f7f;
236241
color: #dfdfdf;
237242

243+
gap: 0.5em;
244+
238245
font-size: 0.875em;
239246
font-weight: 500;
240247

@@ -266,63 +273,6 @@
266273
width: 100%;
267274
}
268275

269-
// // Force the base input-l class
270-
// .input-l {
271-
// width: 100% !important;
272-
// max-width: none !important;
273-
// margin-left: 0px;
274-
// border: none;
275-
// }
276-
277-
// // Force the select/text-input defaults
278-
// .select,
279-
// .inline-select,
280-
// .text-input {
281-
// display: block !important;
282-
// position: relative;
283-
// width: 100% !important;
284-
// }
285-
286-
// .input {
287-
// border: 1px solid #e5e7eb;
288-
// border-radius: 0.375rem;
289-
// padding: 0.5rem 0.75rem;
290-
// width: 100%;
291-
292-
// &:focus {
293-
// outline: none;
294-
// border-color: #3b82f6;
295-
// box-shadow: 0 0 0 1px #3b82f6;
296-
// background-color: unset !important; // origo >.>
297-
// }
298-
// }
299-
300-
// .label-text {
301-
// &:before {
302-
// content: none !important;
303-
// }
304-
// }
305-
306-
// .dropdown {
307-
// background: white;
308-
// border: 1px solid #e5e7eb;
309-
// border-radius: 0.375rem;
310-
// width: 100%;
311-
// max-width: 100%;
312-
313-
// .input,
314-
// .input-l {
315-
// border: none;
316-
// outline: none;
317-
// box-shadow: none;
318-
// }
319-
320-
// &:focus-within {
321-
// border-color: #3b82f6;
322-
// box-shadow: 0 0 0 1px #3b82f6;
323-
// }
324-
// }
325-
326276
.form-switch {
327277
margin: 0.5rem 0;
328278

@@ -337,13 +287,6 @@
337287
margin-bottom: 0.5rem; // Increased spacing between label and selector
338288
margin-top: 0.5rem; // Clearance from the previous
339289
}
340-
341-
// .label {
342-
// font-size: 0.875rem;
343-
// font-weight: 500;
344-
// color: #374151;
345-
// display: block;
346-
// }
347290
}
348291
}
349292
}

packages/webui/src/client/styles/rundownView.scss

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ $break-width: 35rem;
161161
}
162162

163163
&.properties-panel-open {
164-
padding-right: $properties-panel-width;
164+
padding-right: calc(#{$properties-panel-width} - 3.5em);
165165
transition: 0s padding-right 1s;
166166

167167
> .rundown-header .rundown-overview {
@@ -209,8 +209,13 @@ body.no-overflow {
209209
bottom: 0;
210210
right: 0;
211211

212-
background:
213-
linear-gradient(-45deg, $color-status-fatal 33%, transparent 33%, transparent 66%, $color-status-fatal 66%),
212+
background: linear-gradient(
213+
-45deg,
214+
$color-status-fatal 33%,
215+
transparent 33%,
216+
transparent 66%,
217+
$color-status-fatal 66%
218+
),
214219
linear-gradient(-45deg, $color-status-fatal 33%, transparent 33%, transparent 66%, $color-status-fatal 66%),
215220
linear-gradient(-45deg, $color-status-fatal 33%, transparent 33%, transparent 66%, $color-status-fatal 66%),
216221
linear-gradient(-45deg, $color-status-fatal 33%, transparent 33%, transparent 66%, $color-status-fatal 66%);
@@ -1100,8 +1105,7 @@ svg.icon {
11001105
}
11011106
.segment-timeline__part {
11021107
.segment-timeline__part__invalid-cover {
1103-
background-image:
1104-
repeating-linear-gradient(
1108+
background-image: repeating-linear-gradient(
11051109
45deg,
11061110
var(--invalid-reason-color-transparent) 0%,
11071111
var(--invalid-reason-color-transparent) 4px,
@@ -1383,8 +1387,7 @@ svg.icon {
13831387
left: 2px;
13841388
right: 2px;
13851389
z-index: 3;
1386-
background:
1387-
repeating-linear-gradient(
1390+
background: repeating-linear-gradient(
13881391
45deg,
13891392
var(--invalid-reason-color-opaque) 0,
13901393
var(--invalid-reason-color-opaque) 5px,
@@ -1566,8 +1569,7 @@ svg.icon {
15661569
right: 1px;
15671570
z-index: 10;
15681571
pointer-events: all;
1569-
background-image:
1570-
repeating-linear-gradient(
1572+
background-image: repeating-linear-gradient(
15711573
45deg,
15721574
var(--invalid-reason-color-transparent) 0%,
15731575
var(--invalid-reason-color-transparent) 5px,

packages/webui/src/client/ui/RundownView.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ const RundownViewContent = translateWithTracker<IPropsWithReady & ITrackedProps,
379379

380380
RundownViewEventBus.on(RundownViewEvents.GO_TO_LIVE_SEGMENT, this.onGoToLiveSegment)
381381
RundownViewEventBus.on(RundownViewEvents.GO_TO_TOP, this.onGoToTop)
382+
RundownViewEventBus.on(RundownViewEvents.CLOSE_NOTIFICATIONS, this.onCloseNotifications)
382383

383384
if (this.props.playlist) {
384385
documentTitle.set(this.props.playlist.name)
@@ -622,6 +623,7 @@ const RundownViewContent = translateWithTracker<IPropsWithReady & ITrackedProps,
622623

623624
RundownViewEventBus.off(RundownViewEvents.GO_TO_LIVE_SEGMENT, this.onGoToLiveSegment)
624625
RundownViewEventBus.off(RundownViewEvents.GO_TO_TOP, this.onGoToTop)
626+
RundownViewEventBus.off(RundownViewEvents.CLOSE_NOTIFICATIONS, this.onCloseNotifications)
625627
}
626628

627629
private onBeforeUnload = (e: any) => {
@@ -905,6 +907,12 @@ const RundownViewContent = translateWithTracker<IPropsWithReady & ITrackedProps,
905907
)
906908
}
907909

910+
private onCloseNotifications = () => {
911+
this.setState({
912+
isNotificationsCenterOpen: undefined,
913+
})
914+
}
915+
908916
private onToggleSupportPanel = () => {
909917
this.setState({
910918
isSupportPanelOpen: !this.state.isSupportPanelOpen,
@@ -1371,6 +1379,8 @@ const RundownViewContent = translateWithTracker<IPropsWithReady & ITrackedProps,
13711379
<DragContextProvider t={t}>
13721380
<SelectedElementsContext.Consumer>
13731381
{(selectionContext) => {
1382+
const isPropertiesPanelOpen = selectionContext.listSelectedElements().length > 0
1383+
13741384
return (
13751385
<div
13761386
className={classNames('rundown-view', {
@@ -1463,13 +1473,14 @@ const RundownViewContent = translateWithTracker<IPropsWithReady & ITrackedProps,
14631473
</ErrorBoundary>
14641474
<ErrorBoundary>
14651475
<AnimatePresence>
1466-
{this.state.isNotificationsCenterOpen && (
1476+
{!isPropertiesPanelOpen && this.state.isNotificationsCenterOpen && (
14671477
<NotificationCenterPanel
14681478
filter={this.state.isNotificationsCenterOpen}
14691479
hideRundownHeader={this.props.hideRundownHeader}
14701480
/>
14711481
)}
1472-
{!this.state.isNotificationsCenterOpen &&
1482+
{isPropertiesPanelOpen &&
1483+
!this.state.isNotificationsCenterOpen &&
14731484
selectionContext.listSelectedElements().length > 0 && (
14741485
<div>
14751486
<PropertiesPanel />
@@ -1521,7 +1532,10 @@ const RundownViewContent = translateWithTracker<IPropsWithReady & ITrackedProps,
15211532
onQueueNextSegment={this.onQueueNextSegment}
15221533
onSetQuickLoopStart={this.onSetQuickLoopStart}
15231534
onSetQuickLoopEnd={this.onSetQuickLoopEnd}
1524-
onEditProps={(selection) => selectionContext.clearAndSetSelection(selection)}
1535+
onEditProps={(selection) => {
1536+
this.setState({ isNotificationsCenterOpen: undefined })
1537+
selectionContext.clearAndSetSelection(selection)
1538+
}}
15251539
studioMode={this.props.userPermissions.studio}
15261540
enablePlayFromAnywhere={!!studio.settings.enablePlayFromAnywhere}
15271541
enableQuickLoop={!!studio.settings.enableQuickLoop}

packages/webui/src/client/ui/SegmentTimeline/SegmentContextMenu.tsx

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ export const SegmentContextMenu = withTranslation()(
6969
part?.instance._id !== this.props.playlist.nextPartInfo?.partInstanceId &&
7070
part?.instance._id !== this.props.playlist.previousPartInfo?.partInstanceId
7171

72+
const segmentHasEditableContent = !!(
73+
segment?.userEditOperations?.length ||
74+
segment?.userEditProperties?.pieceTypeProperties ||
75+
segment?.userEditProperties?.globalProperties ||
76+
segment?.userEditProperties?.operations?.length
77+
)
78+
const partHasEditableContent = !!(
79+
part?.instance.part.userEditOperations?.length ||
80+
part?.instance.part.userEditProperties?.pieceTypeProperties ||
81+
part?.instance.part.userEditProperties?.globalProperties ||
82+
part?.instance.part.userEditProperties?.operations?.length
83+
)
84+
const pieceHasEditableContent = !!(
85+
piece?.instance.piece.userEditOperations?.length ||
86+
piece?.instance.piece.userEditProperties?.pieceTypeProperties ||
87+
piece?.instance.piece.userEditProperties?.globalProperties ||
88+
piece?.instance.piece.userEditProperties?.operations?.length
89+
)
90+
7291
const canSetAsNext = !!this.props.playlist?.activationId
7392

7493
return segment?.orphaned !== SegmentOrphanedReason.ADLIB_TESTING ? (
@@ -108,7 +127,7 @@ export const SegmentContextMenu = withTranslation()(
108127
/>
109128
)}
110129
<hr />
111-
{this.props.enableUserEdits && (
130+
{this.props.enableUserEdits && segmentHasEditableContent && (
112131
<>
113132
<hr />
114133
<MenuItem
@@ -199,28 +218,35 @@ export const SegmentContextMenu = withTranslation()(
199218
isFormEditable={isPartEditAble}
200219
/>
201220

202-
{this.props.enableUserEdits && (
203-
<>
204-
<hr />
205-
<MenuItem
206-
onClick={() => this.props.onEditProps({ type: 'segment', elementId: part.instance.segmentId })}
207-
>
208-
<span>{t('Edit Segment Properties')}</span>
209-
</MenuItem>
210-
<MenuItem
211-
onClick={() => this.props.onEditProps({ type: 'part', elementId: part.instance.part._id })}
212-
>
213-
<span>{t('Edit Part Properties')}</span>
214-
</MenuItem>
215-
{piece && piece.instance.piece.userEditProperties && (
216-
<MenuItem
217-
onClick={() => this.props.onEditProps({ type: 'piece', elementId: piece.instance.piece._id })}
218-
>
219-
<span>{t('Edit Piece Properties')}</span>
220-
</MenuItem>
221-
)}
222-
</>
223-
)}
221+
{this.props.enableUserEdits &&
222+
(segmentHasEditableContent || partHasEditableContent || pieceHasEditableContent) && (
223+
<>
224+
<hr />
225+
{segmentHasEditableContent && (
226+
<MenuItem
227+
onClick={() =>
228+
this.props.onEditProps({ type: 'segment', elementId: part.instance.segmentId })
229+
}
230+
>
231+
<span>{t('Edit Segment Properties')}</span>
232+
</MenuItem>
233+
)}
234+
{partHasEditableContent && (
235+
<MenuItem
236+
onClick={() => this.props.onEditProps({ type: 'part', elementId: part.instance.part._id })}
237+
>
238+
<span>{t('Edit Part Properties')}</span>
239+
</MenuItem>
240+
)}
241+
{pieceHasEditableContent && (
242+
<MenuItem
243+
onClick={() => this.props.onEditProps({ type: 'piece', elementId: piece.instance.piece._id })}
244+
>
245+
<span>{t('Edit Piece Properties')}</span>
246+
</MenuItem>
247+
)}
248+
</>
249+
)}
224250
</>
225251
)}
226252
</ContextMenu>

packages/webui/src/client/ui/SegmentTimeline/SegmentTimeline.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,8 +1057,18 @@ export class SegmentTimelineClass extends React.Component<Translated<WithTiming<
10571057
<div
10581058
onDoubleClick={() => {
10591059
if (this.props.studio.settings.enableUserEdits) {
1060-
if (!selectElementContext.isSelected(this.props.segment._id)) {
1061-
selectElementContext.clearAndSetSelection({ type: 'segment', elementId: this.props.segment._id })
1060+
const segment = this.props.segment
1061+
1062+
const hasEditableContent = !!(
1063+
segment.userEditOperations?.length ||
1064+
segment.userEditProperties?.pieceTypeProperties ||
1065+
segment.userEditProperties?.globalProperties ||
1066+
segment.userEditProperties?.operations?.length
1067+
)
1068+
if (!hasEditableContent) return
1069+
1070+
if (!selectElementContext.isSelected(segment._id)) {
1071+
selectElementContext.clearAndSetSelection({ type: 'segment', elementId: segment._id })
10621072
} else {
10631073
selectElementContext.clearSelections()
10641074
}

0 commit comments

Comments
 (0)