Clean projector detail interface
Alters the projector detail interface to provide better usability. Alters the dragging slightly to have a nice preview and smoother transitions.
This commit is contained in:
parent
d77abf5934
commit
587a0fe443
@ -1,3 +1,5 @@
|
|||||||
|
@import '../../../../assets/styles/drag.scss';
|
||||||
|
|
||||||
.box {
|
.box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: solid 1px #ccc;
|
border-bottom: solid 1px #ccc;
|
||||||
@ -5,21 +7,6 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cdk-drag-preview {
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14),
|
|
||||||
0 3px 14px 2px rgba(0, 0, 0, 0.12);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cdk-drag-placeholder {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cdk-drag-animating {
|
|
||||||
transition: transform 125ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box:last-child {
|
.box:last-child {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
@ -12,56 +12,65 @@
|
|||||||
<os-projector [projector]="projector"></os-projector>
|
<os-projector [projector]="projector"></os-projector>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
<!-- Controls under the projector preview -->
|
||||||
<div class="column-right" *osPerms="'core.can_manage_projector'">
|
<div class="control-group projector-controls">
|
||||||
<div class="control-group">
|
<!-- scaling indicator -->
|
||||||
<div class="button-size">{{ projector.scroll }}</div>
|
<div class="button-size">{{ projector.scale }}</div>
|
||||||
<button type="button" mat-icon-button (click)="scroll(scrollScaleDirection.Up)">
|
|
||||||
<mat-icon>arrow_upward</mat-icon>
|
<!-- scale up -->
|
||||||
|
<button type="button" mat-icon-button (click)="scale(scrollScaleDirection.Up)">
|
||||||
|
<mat-icon>zoom_in</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- scale down -->
|
||||||
|
<button type="button" mat-icon-button (click)="scale(scrollScaleDirection.Down)">
|
||||||
|
<mat-icon>zoom_out</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- scroll indicator -->
|
||||||
|
<div class="button-size">{{ projector.scroll }}</div>
|
||||||
|
|
||||||
|
<!-- scroll down -->
|
||||||
<button type="button" mat-icon-button (click)="scroll(scrollScaleDirection.Down)">
|
<button type="button" mat-icon-button (click)="scroll(scrollScaleDirection.Down)">
|
||||||
<mat-icon>arrow_downward</mat-icon>
|
<mat-icon>arrow_downward</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- scroll up -->
|
||||||
|
<button type="button" mat-icon-button (click)="scroll(scrollScaleDirection.Up)">
|
||||||
|
<mat-icon>arrow_upward</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- refresh button -->
|
||||||
<button type="button" mat-icon-button (click)="scroll(scrollScaleDirection.Reset)">
|
<button type="button" mat-icon-button (click)="scroll(scrollScaleDirection.Reset)">
|
||||||
<mat-icon>refresh</mat-icon>
|
<mat-icon>refresh</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="control-group">
|
|
||||||
<div class="button-size">{{ projector.scale }}</div>
|
|
||||||
<button type="button" mat-icon-button (click)="scale(scrollScaleDirection.Up)">
|
|
||||||
<mat-icon>zoom_in</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button type="button" mat-icon-button (click)="scale(scrollScaleDirection.Down)">
|
|
||||||
<mat-icon>zoom_out</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button type="button" mat-icon-button (click)="scale(scrollScaleDirection.Reset)">
|
|
||||||
<mat-icon>refresh</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<div class="column-right" *osPerms="'core.can_manage_projector'">
|
||||||
<div class="control-group">
|
<div class="control-group slide-controls">
|
||||||
<button type="button" mat-button (click)="projectPreviousSlide()" [disabled]="projector?.elements_history.length === 0">
|
<button
|
||||||
|
type="button"
|
||||||
|
mat-button
|
||||||
|
(click)="projectPreviousSlide()"
|
||||||
|
[disabled]="projector?.elements_history.length === 0"
|
||||||
|
>
|
||||||
<mat-icon>arrow_back</mat-icon>
|
<mat-icon>arrow_back</mat-icon>
|
||||||
<span translate>Previous</span>
|
<span translate>Previous</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" mat-button (click)="projectNextSlide()" [disabled]="projector?.elements_preview.length === 0">
|
<button
|
||||||
|
type="button"
|
||||||
|
mat-button
|
||||||
|
(click)="projectNextSlide()"
|
||||||
|
[disabled]="projector?.elements_preview.length === 0"
|
||||||
|
>
|
||||||
<span translate>Next</span>
|
<span translate>Next</span>
|
||||||
<mat-icon>arrow_forward</mat-icon>
|
<mat-icon>arrow_forward</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
<hr />
|
||||||
|
|
||||||
<div class="queue" *ngIf="projector.elements_history.length">
|
|
||||||
<h5 translate>History</h5>
|
|
||||||
<p *ngFor="let elements of projector.elements_history">
|
|
||||||
{{ getSlideTitle(elements[0]) }}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h5 translate>Current</h5>
|
|
||||||
|
|
||||||
<div *ngIf="projector.non_stable_elements.length">
|
<div *ngIf="projector.non_stable_elements.length">
|
||||||
<h4 translate>Slides</h4>
|
|
||||||
<mat-list>
|
<mat-list>
|
||||||
<mat-list-item *ngFor="let element of projector.non_stable_elements" class="projected">
|
<mat-list-item *ngFor="let element of projector.non_stable_elements" class="projected">
|
||||||
<button type="button" mat-icon-button (click)="unprojectCurrent(element)">
|
<button type="button" mat-icon-button (click)="unprojectCurrent(element)">
|
||||||
@ -72,92 +81,38 @@
|
|||||||
</mat-list>
|
</mat-list>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="countdowns.length">
|
<!-- Expandable elements -->
|
||||||
<h4>
|
<mat-accordion multi="true">
|
||||||
<span translate>Countdowns</span>
|
<!-- Queue -->
|
||||||
<button type="button" mat-icon-button disableRipple routerLink="/projectors/countdowns">
|
<mat-expansion-panel *ngIf="projector.elements_preview.length" [expanded]="true">
|
||||||
<mat-icon>edit</mat-icon>
|
<mat-expansion-panel-header>
|
||||||
</button>
|
<span translate>Queue</span>
|
||||||
</h4>
|
</mat-expansion-panel-header>
|
||||||
<mat-list>
|
|
||||||
<mat-list-item *ngFor="let countdown of countdowns" [ngClass]="{'projected': isProjected(countdown)}">
|
|
||||||
<button type="button" mat-icon-button (click)="project(countdown)">
|
|
||||||
<mat-icon>videocam</mat-icon>
|
|
||||||
</button>
|
|
||||||
{{ countdown.description }}
|
|
||||||
</mat-list-item>
|
|
||||||
</mat-list>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngIf="messages.length">
|
<div
|
||||||
<h4>
|
cdkDropList
|
||||||
<span translate>Messages</span>
|
class="drop-list"
|
||||||
<button type="button" mat-icon-button disableRipple routerLink="/projectors/messages">
|
[cdkDropListDisabled]="!editQueue"
|
||||||
<mat-icon>edit</mat-icon>
|
(cdkDropListDropped)="onSortingChange($event)"
|
||||||
</button>
|
>
|
||||||
</h4>
|
<div
|
||||||
<mat-list>
|
class="drop-list-entry"
|
||||||
<mat-list-item *ngFor="let message of messages" [ngClass]="{'projected': isProjected(message)}">
|
*ngFor="let element of projector.elements_preview; let i = index"
|
||||||
<button type="button" mat-icon-button (click)="project(message)">
|
cdkDrag
|
||||||
<mat-icon>videocam</mat-icon>
|
>
|
||||||
</button>
|
<div class="drag-handle" cdkDragHandle *ngIf="editQueue">
|
||||||
<span>{{ message.getPreview(40) }}</span>
|
|
||||||
</mat-list-item>
|
|
||||||
</mat-list>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h4>Current list of speakers overlay</h4>
|
|
||||||
<mat-list>
|
|
||||||
<mat-list-item [ngClass]="{'projected': isClosProjected(true)}">
|
|
||||||
<button type="button" mat-icon-button (click)="toggleClos(true)">
|
|
||||||
<mat-icon>videocam</mat-icon>
|
|
||||||
</button>
|
|
||||||
<span translate>Current list of speakers overlay</span>
|
|
||||||
</mat-list-item>
|
|
||||||
</mat-list>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngIf="!isClosProjected(false)">
|
|
||||||
<h4>Current list of speakers slide</h4>
|
|
||||||
<mat-list>
|
|
||||||
<mat-list-item>
|
|
||||||
<button type="button" mat-icon-button (click)="toggleClos(false)">
|
|
||||||
<mat-icon>videocam</mat-icon>
|
|
||||||
</button>
|
|
||||||
<span translate>Current list of speakers slide</span>
|
|
||||||
</mat-list-item>
|
|
||||||
</mat-list>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h4>Current speaker chyron</h4>
|
|
||||||
<mat-list>
|
|
||||||
<mat-list-item [ngClass]="{'projected': isChyronProjected()}">
|
|
||||||
<button type="button" mat-icon-button (click)="toggleChyron()">
|
|
||||||
<mat-icon>videocam</mat-icon>
|
|
||||||
</button>
|
|
||||||
<span translate>Current speaker chyron</span>
|
|
||||||
</mat-list-item>
|
|
||||||
</mat-list>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="queue" *ngIf="projector.elements_preview.length">
|
|
||||||
<h5 translate>Queue</h5>
|
|
||||||
<div cdkDropList class="drop-list" (cdkDropListDropped)="onSortingChange($event)">
|
|
||||||
<div class="list-entry" *ngFor="let element of projector.elements_preview; let i = index" cdkDrag>
|
|
||||||
<div class="drag-handle" cdkDragHandle>
|
|
||||||
<mat-icon>drag_indicator</mat-icon>
|
<mat-icon>drag_indicator</mat-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="drag-handle" *ngIf="!editQueue">
|
||||||
|
<button type="button" mat-mini-fab (click)="projectNow(i)">
|
||||||
|
<mat-icon>videocam</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
{{ i + 1 }}. <span>{{ getSlideTitle(element) }}</span>
|
{{ i + 1 }}. <span>{{ getSlideTitle(element) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-right">
|
<div class="button-right" *ngIf="editQueue">
|
||||||
<div>
|
<div>
|
||||||
<button type="button" mat-button (click)="projectNow(i)">
|
|
||||||
<span translate>Project now</span>
|
|
||||||
</button>
|
|
||||||
<button type="button" mat-icon-button (click)="removePreviewElement(i)">
|
<button type="button" mat-icon-button (click)="removePreviewElement(i)">
|
||||||
<mat-icon>close</mat-icon>
|
<mat-icon>close</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
@ -165,6 +120,103 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<mat-action-row>
|
||||||
|
<button type="button" mat-icon-button (click)="editQueue = !editQueue">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-action-row>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
|
||||||
|
<!-- Previous Slides -->
|
||||||
|
<mat-expansion-panel *ngIf="projector.elements_history.length">
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<span translate>History</span>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<p *ngFor="let elements of projector.elements_history; let i = index">
|
||||||
|
{{ i + 1 }}. {{ getSlideTitle(elements[0]) }}
|
||||||
|
</p>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
|
||||||
|
<!-- countdowns -->
|
||||||
|
<mat-expansion-panel *ngIf="countdowns.length">
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<span translate>Countdowns</span>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<mat-list>
|
||||||
|
<mat-list-item
|
||||||
|
*ngFor="let countdown of countdowns"
|
||||||
|
[ngClass]="{ projected: isProjected(countdown) }"
|
||||||
|
>
|
||||||
|
<button type="button" mat-icon-button (click)="project(countdown)">
|
||||||
|
<mat-icon>videocam</mat-icon>
|
||||||
|
</button>
|
||||||
|
{{ countdown.description }}
|
||||||
|
</mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
<mat-action-row>
|
||||||
|
<button type="button" mat-icon-button routerLink="/projectors/countdowns">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-action-row>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
|
||||||
|
<!-- messages -->
|
||||||
|
<mat-expansion-panel *ngIf="messages.length">
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<span translate>Messages</span>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<mat-list>
|
||||||
|
<mat-list-item *ngFor="let message of messages" [ngClass]="{ projected: isProjected(message) }">
|
||||||
|
<button type="button" mat-icon-button (click)="project(message)">
|
||||||
|
<mat-icon>videocam</mat-icon>
|
||||||
|
</button>
|
||||||
|
<span>{{ message.getPreview(40) }}</span>
|
||||||
|
</mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
<mat-action-row>
|
||||||
|
<button type="button" mat-icon-button routerLink="/projectors/messages">
|
||||||
|
<mat-icon>edit</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-action-row>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
|
||||||
|
<!-- Current List of Speakers -->
|
||||||
|
<mat-expansion-panel>
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<span translate>Current list of speakers</span>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
|
||||||
|
<!-- Overlay -->
|
||||||
|
<mat-list>
|
||||||
|
<mat-list-item [ngClass]="{ projected: isClosProjected(true) }">
|
||||||
|
<button type="button" mat-icon-button (click)="toggleClos(true)">
|
||||||
|
<mat-icon>videocam</mat-icon>
|
||||||
|
</button>
|
||||||
|
<span translate>Current list of speakers overlay</span>
|
||||||
|
</mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
|
||||||
|
<!-- Current Speaker -->
|
||||||
|
<mat-list *ngIf="!isClosProjected(false)">
|
||||||
|
<mat-list-item>
|
||||||
|
<button type="button" mat-icon-button (click)="toggleClos(false)">
|
||||||
|
<mat-icon>videocam</mat-icon>
|
||||||
|
</button>
|
||||||
|
<span translate>Current list of speakers slide</span>
|
||||||
|
</mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
|
||||||
|
<!-- Chyron -->
|
||||||
|
<mat-list>
|
||||||
|
<mat-list-item [ngClass]="{ projected: isChyronProjected() }">
|
||||||
|
<button type="button" mat-icon-button (click)="toggleChyron()">
|
||||||
|
<mat-icon>videocam</mat-icon>
|
||||||
|
</button>
|
||||||
|
<span translate>Current speaker chyron</span>
|
||||||
|
</mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
@import '../../../../../assets/styles/drag.scss';
|
||||||
|
|
||||||
#projector {
|
#projector {
|
||||||
width: 100%; /*1000px;*/
|
width: 100%; /*1000px;*/
|
||||||
border: 1px solid lightgrey;
|
border: 1px solid lightgrey;
|
||||||
@ -25,8 +27,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.control-group {
|
.control-group {
|
||||||
text-align: center;
|
color: rgba(0, 0, 0, 0.5);
|
||||||
color: rgba(0, 0, 0, 0.54);
|
|
||||||
|
|
||||||
.button-size {
|
.button-size {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
@ -34,28 +35,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
.slide-controls {
|
||||||
margin-top: 5px;
|
text-align: center;
|
||||||
|
|
||||||
button {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
.projector-controls {
|
||||||
margin-bottom: 0;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.queue {
|
|
||||||
margin-top: 15px;
|
|
||||||
|
|
||||||
.drop-list {
|
.drop-list {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.list-entry {
|
.drop-list-entry {
|
||||||
display: table;
|
display: table;
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -90,8 +84,11 @@ h5 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-entry:last-child {
|
.drop-list-entry:last-child {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// move away from preview.
|
||||||
|
.drop-list.cdk-drop-list-dragging .drop-list-entry:not(.cdk-drag-placeholder) {
|
||||||
|
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,11 @@ export class ProjectorDetailComponent extends BaseViewComponent implements OnIni
|
|||||||
|
|
||||||
public messages: ViewProjectorMessage[] = [];
|
public messages: ViewProjectorMessage[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true if the queue might be altered
|
||||||
|
*/
|
||||||
|
public editQueue = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param titleService
|
* @param titleService
|
||||||
* @param translate
|
* @param translate
|
||||||
|
29
client/src/assets/styles/drag.scss
Normal file
29
client/src/assets/styles/drag.scss
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
//shared CSS rules that are required for all components that implement drag and drop
|
||||||
|
/**
|
||||||
|
* Moving list entries away from preview cannot be stored in this scss file, cause the naming
|
||||||
|
* of the css classes is relevant. Use it like the following.
|
||||||
|
*
|
||||||
|
* transform can somehow not be stored as css variable
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```css
|
||||||
|
* .drop-list.cdk-drop-list-dragging .list-entry:not(.cdk-drag-placeholder) {
|
||||||
|
* transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
.cdk-drag-preview {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14),
|
||||||
|
0 3px 14px 2px rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cdk-drag-placeholder {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cdk-drag-animating {
|
||||||
|
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user