Merge pull request #4527 from tsiegleauq/list-of-speakers-template
Add prettier list of speakers
This commit is contained in:
commit
faa0a6077e
@ -1,17 +1,17 @@
|
|||||||
<div cdkDropList class="os-card" [cdkDropListDisabled]="!enable" (cdkDropListDropped)="drop($event)">
|
<div cdkDropList [cdkDropListDisabled]="!enable" (cdkDropListDropped)="drop($event)">
|
||||||
<div class="box line" *ngIf="!array.length">
|
<div class="line" *ngIf="!array.length">
|
||||||
<span translate>No data</span>
|
<span translate>No data</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="box line" *ngFor="let item of array; let i = index" cdkDrag>
|
<div class="line" *ngFor="let item of array; let i = index" cdkDrag>
|
||||||
<div class="section-one" cdkDragHandle *ngIf="enable">
|
<div class="section-one backgroundColorLight" cdkDragHandle *ngIf="enable">
|
||||||
<mat-icon>drag_indicator</mat-icon>
|
<mat-icon>drag_indicator</mat-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="section-two">
|
<div class="section-two backgroundColorLight">
|
||||||
<!-- {number}. {item.getTitle()} -->
|
<!-- {number}. {item.getTitle()} -->
|
||||||
<span *ngIf="count">{{ i + 1 }}. </span>
|
<span *ngIf="count">{{ i + 1 }}. </span>
|
||||||
<span>{{ item.getTitle() }}</span>
|
<span>{{ item.getTitle() }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="section-three">
|
<div class="section-three backgroundColorLight">
|
||||||
<!-- Extra controls slot using implicit template references -->
|
<!-- Extra controls slot using implicit template references -->
|
||||||
<ng-template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ $implicit: item }"></ng-template>
|
<ng-template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{ $implicit: item }"></ng-template>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,19 +1,11 @@
|
|||||||
@import '~assets/styles/drag.scss';
|
@import '~assets/styles/drag.scss';
|
||||||
|
|
||||||
.box {
|
|
||||||
width: 100%;
|
|
||||||
border-bottom: solid 1px #ccc;
|
|
||||||
color: rgba(0, 0, 0, 0.87);
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box:last-child {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.line {
|
.line {
|
||||||
display: table;
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
.section-one {
|
.section-one {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
@ -28,7 +20,12 @@
|
|||||||
.section-two {
|
.section-two {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
width: 80%;
|
width: 100%;
|
||||||
|
padding-left: 20px;
|
||||||
|
|
||||||
|
span + span {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-three {
|
.section-three {
|
||||||
|
@ -11,85 +11,100 @@
|
|||||||
</div>
|
</div>
|
||||||
</os-head-bar>
|
</os-head-bar>
|
||||||
|
|
||||||
<h1 class="title on-transition-fade" *ngIf="viewItem">{{ viewItem.getTitle() }}</h1>
|
<mat-card class="os-card speaker-card" *ngIf="viewItem">
|
||||||
|
<!-- Title -->
|
||||||
|
<h1 class="title on-transition-fade" *ngIf="viewItem">{{ viewItem.getTitle() }}</h1>
|
||||||
|
|
||||||
<mat-card class="speaker-card" *ngIf="viewItem">
|
|
||||||
<!-- List of finished speakers -->
|
<!-- List of finished speakers -->
|
||||||
<mat-expansion-panel *ngIf="finishedSpeakers && finishedSpeakers.length > 0" class="finished-list">
|
<mat-expansion-panel *ngIf="finishedSpeakers && finishedSpeakers.length > 0" class="finished-list">
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
<mat-panel-title translate> Last speakers </mat-panel-title>
|
<mat-panel-title translate> Last speakers </mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<mat-list>
|
<mat-list>
|
||||||
<!-- {Number}. {full_name} {time} minutes (Start time: {begin_time}) [close button] -->
|
|
||||||
<mat-list-item *ngFor="let speaker of finishedSpeakers; let number = index">
|
<mat-list-item *ngFor="let speaker of finishedSpeakers; let number = index">
|
||||||
<div class="finished-prefix">
|
<div class="finished-speaker-grid">
|
||||||
<span>{{ number + 1 }}. {{ speaker }}</span>
|
<div class="number">{{ number + 1 }}.</div>
|
||||||
|
<div class="name">{{ speaker }}</div>
|
||||||
|
<div class="time">
|
||||||
|
{{ durationString(speaker) }} ({{ 'Start time' | translate }}: {{ startTimeToString(speaker) }})
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
matTooltip="{{ 'Remove' | translate }}"
|
||||||
|
*osPerms="'agenda.can_manage_list_of_speakers'"
|
||||||
|
(click)="onDeleteButton(speaker)"
|
||||||
|
>
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="finished-suffix">
|
|
||||||
{{ durationString(speaker) }} ({{ 'Start time' | translate }}:
|
|
||||||
{{ startTimeToString(speaker) }})
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
mat-stroked-button
|
|
||||||
matTooltip="{{ 'Remove' | translate }}"
|
|
||||||
*osPerms="'agenda.can_manage_list_of_speakers'"
|
|
||||||
(click)="onDeleteButton(speaker)"
|
|
||||||
>
|
|
||||||
<mat-icon>close</mat-icon>
|
|
||||||
</button>
|
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
</mat-list>
|
</mat-list>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
|
|
||||||
|
<!-- horizontal separation line -->
|
||||||
|
<mat-divider *ngIf="finishedSpeakers && finishedSpeakers.length"></mat-divider>
|
||||||
|
<div *ngIf="finishedSpeakers && finishedSpeakers.length" class="spacer-bottom-40"></div>
|
||||||
|
|
||||||
<!-- Current Speaker -->
|
<!-- Current Speaker -->
|
||||||
<div class="current-speaker" *ngIf="activeSpeaker">
|
<div class="current-speaker" *ngIf="activeSpeaker">
|
||||||
<mat-icon class="speaking-icon">play_arrow</mat-icon>
|
<span class="prefix">
|
||||||
<span class="speaking-name">{{ activeSpeaker }}</span>
|
<mat-icon>mic</mat-icon>
|
||||||
|
</span>
|
||||||
|
|
||||||
<button
|
<span class="name">{{ activeSpeaker }}</span>
|
||||||
mat-stroked-button
|
|
||||||
matTooltip="{{ 'End speech' | translate }}"
|
<span class="suffix">
|
||||||
*osPerms="'agenda.can_manage_list_of_speakers'"
|
<!-- Stop speaker button -->
|
||||||
(click)="onStopButton()"
|
<button
|
||||||
>
|
mat-icon-button
|
||||||
<mat-icon>mic_off</mat-icon>
|
matTooltip="{{ 'End speech' | translate }}"
|
||||||
<span translate>Stop</span>
|
*osPerms="'agenda.can_manage_list_of_speakers'"
|
||||||
</button>
|
(click)="onStopButton()"
|
||||||
|
>
|
||||||
|
<mat-icon>stop</mat-icon>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Waiting speakers -->
|
<!-- Waiting speakers -->
|
||||||
<div>
|
<div class="waiting-list" *ngIf="speakers && speakers.length > 0">
|
||||||
<div class="waiting-list" *ngIf="speakers && speakers.length > 0">
|
<os-sorting-list
|
||||||
<os-sorting-list
|
[input]="speakers"
|
||||||
[input]="speakers"
|
[live]="true"
|
||||||
[live]="true"
|
[count]="true"
|
||||||
[count]="true"
|
[enable]="opCanManage()"
|
||||||
[enable]="opCanManage()"
|
(sortEvent)="onSortingChange($event)"
|
||||||
(sortEvent)="onSortingChange($event)"
|
>
|
||||||
>
|
<!-- implicit item references into the component using ng-template slot -->
|
||||||
<!-- implicit item references into the component using ng-template slot -->
|
<ng-template let-item>
|
||||||
<ng-template let-item>
|
<span *osPerms="'agenda.can_manage_list_of_speakers'">
|
||||||
<span *osPerms="'agenda.can_manage_list_of_speakers'">
|
<span *ngIf="hasSpokenCount(item)" class="red-warning-text speaker-warning">
|
||||||
<span *ngIf="hasSpokenCount(item)" class="red-warning-text speaker-warning">
|
{{ hasSpokenCount(item) + 1 }}. <span translate>contribution</span>
|
||||||
{{ hasSpokenCount(item) + 1 }}. <span translate>contribution</span>
|
|
||||||
</span>
|
|
||||||
<span *ngIf="item.gender">({{ item.gender | translate }})</span>
|
|
||||||
</span>
|
</span>
|
||||||
<mat-button-toggle-group *osPerms="'agenda.can_manage_list_of_speakers'">
|
<span *ngIf="item.gender">({{ item.gender | translate }})</span>
|
||||||
<mat-button-toggle matTooltip="{{ 'Begin speech' | translate }}" (click)="onStartButton(item)">
|
</span>
|
||||||
<mat-icon>mic</mat-icon>
|
|
||||||
<span translate>Start</span>
|
<!-- Start, start and delete buttons -->
|
||||||
</mat-button-toggle>
|
<span *osPerms="'agenda.can_manage_list_of_speakers'">
|
||||||
<mat-button-toggle matTooltip="{{ 'Mark speaker' | translate }}" (click)="onMarkButton(item)">
|
<!-- start button -->
|
||||||
<mat-icon>{{ item.marked ? 'star' : 'star_border' }}</mat-icon>
|
<button mat-icon-button matTooltip="{{ 'Begin speech' | translate }}" (click)="onStartButton(item)">
|
||||||
</mat-button-toggle>
|
<mat-icon>play_arrow</mat-icon>
|
||||||
<mat-button-toggle matTooltip="{{ 'Remove' | translate }}" (click)="onDeleteButton(item)">
|
</button>
|
||||||
<mat-icon>close</mat-icon>
|
|
||||||
</mat-button-toggle>
|
<!-- star button -->
|
||||||
</mat-button-toggle-group>
|
<button mat-icon-button matTooltip="{{ 'Mark speaker' | translate }}" (click)="onMarkButton(item)">
|
||||||
</ng-template>
|
<mat-icon>{{ item.marked ? 'star' : 'star_border' }}</mat-icon>
|
||||||
</os-sorting-list>
|
</button>
|
||||||
</div>
|
|
||||||
|
<!-- delete button -->
|
||||||
|
<button mat-icon-button matTooltip="{{ 'Remove' | translate }}" (click)="onDeleteButton(item)">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</ng-template>
|
||||||
|
</os-sorting-list>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Search for speakers -->
|
<!-- Search for speakers -->
|
||||||
@ -110,11 +125,11 @@
|
|||||||
<!-- Add me and remove me if OP has correct permission -->
|
<!-- Add me and remove me if OP has correct permission -->
|
||||||
<div *osPerms="'agenda.can_be_speaker'" class="add-self-buttons">
|
<div *osPerms="'agenda.can_be_speaker'" class="add-self-buttons">
|
||||||
<div *ngIf="speakers && !closedList">
|
<div *ngIf="speakers && !closedList">
|
||||||
<button mat-raised-button (click)="addNewSpeaker()" *ngIf="!isOpInList()">
|
<button mat-stroked-button (click)="addNewSpeaker()" *ngIf="!isOpInList()">
|
||||||
<mat-icon>add</mat-icon>
|
<mat-icon>add</mat-icon>
|
||||||
<span translate>Add me</span>
|
<span translate>Add me</span>
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button (click)="onDeleteButton()" *ngIf="isOpInList()">
|
<button mat-stroked-button (click)="onDeleteButton()" *ngIf="isOpInList()">
|
||||||
<mat-icon>remove</mat-icon>
|
<mat-icon>remove</mat-icon>
|
||||||
<span translate>Remove me</span>
|
<span translate>Remove me</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,72 +1,147 @@
|
|||||||
|
@import '~@angular/material/theming';
|
||||||
|
|
||||||
|
@mixin os-list-of-speakers-style($theme) {
|
||||||
|
$primary: map-get($theme, primary);
|
||||||
|
$accent: map-get($theme, accent);
|
||||||
|
$warn: map-get($theme, warn);
|
||||||
|
$contrast: map-get($primary, contrast);
|
||||||
|
$foreground: map-get($theme, foreground);
|
||||||
|
|
||||||
|
.current-speaker {
|
||||||
|
background-color: mat-color($accent) !important;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
color: mat-color($accent, default-contrast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.finished-speaker-grid {
|
||||||
|
> .number .name .controls {
|
||||||
|
color: mat-color($foreground, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .time {
|
||||||
|
color: mat-color($foreground, secondary-text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
margin-left: 25px;
|
margin-left: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.speaker-card {
|
.finished-list {
|
||||||
margin: 0 20px 0 20px;
|
box-shadow: none !important;
|
||||||
padding: 0;
|
margin-bottom: 15px;
|
||||||
|
|
||||||
.finished-list {
|
.mat-list-item {
|
||||||
margin-bottom: 15px;
|
height: auto;
|
||||||
.finished-suffix {
|
margin-bottom: 10px;
|
||||||
color: slategray;
|
}
|
||||||
font-size: 80%;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-list-item {
|
.finished-speaker-grid {
|
||||||
height: auto;
|
display: grid;
|
||||||
}
|
width: 100%;
|
||||||
|
grid-template-areas: 'number name time controls';
|
||||||
|
grid-gap: 5px;
|
||||||
|
grid-template-columns: 30px 1fr min-content min-content;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
@media only screen and (max-width: 960px) {
|
||||||
margin-left: 10px;
|
.finished-speaker-grid {
|
||||||
|
grid-template-areas:
|
||||||
|
'number name controls'
|
||||||
|
'number time controls';
|
||||||
|
grid-template-columns: 30px 1fr min-content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-speaker {
|
.number {
|
||||||
padding: 10px 25px 15px 25px;
|
grid-area: number;
|
||||||
display: table;
|
margin: 0;
|
||||||
.speaking-icon {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.speaking-name {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
font-weight: bold;
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.waiting-list {
|
.name {
|
||||||
padding: 10px 25px 0 25px;
|
grid-area: name;
|
||||||
width: 75%;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
form {
|
.time {
|
||||||
padding: 15px 25px 10px 25px;
|
grid-area: time;
|
||||||
width: auto;
|
margin: 0;
|
||||||
|
//allows pushing this grid area as small as possible and aligns the end to the same level
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
.search-users {
|
.controls {
|
||||||
display: grid;
|
grid-area: controls;
|
||||||
.mat-form-field {
|
margin: 0;
|
||||||
width: 100%;
|
opacity: 0.7;
|
||||||
|
|
||||||
|
.mat-icon-button {
|
||||||
|
height: 20px;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
.mat-icon {
|
||||||
|
line-height: 19px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.add-self-buttons {
|
.current-speaker {
|
||||||
padding: 20px 0 20px 25px;
|
display: table;
|
||||||
|
width: -webkit-fill-available;
|
||||||
|
height: 50px;
|
||||||
|
margin: 50px 25px 20px 25px;
|
||||||
|
box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.25);
|
||||||
|
|
||||||
|
.prefix {
|
||||||
|
display: table-cell;
|
||||||
|
padding: 0 15px;
|
||||||
|
vertical-align: middle;
|
||||||
|
.mat-icon {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.speaker-warning {
|
.name {
|
||||||
margin-right: 5px;
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-left: 10px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.suffix {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.waiting-list {
|
||||||
|
padding: 10px 25px 0 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
padding: 15px 25px 10px 25px;
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
.search-users {
|
||||||
|
display: grid;
|
||||||
|
.mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-self-buttons {
|
||||||
|
padding: 15px 0 20px 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.speaker-warning {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
@ -81,7 +81,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.backgroundColorLight {
|
.backgroundColorLight {
|
||||||
background-color: mat-color($background, status-bar);
|
background-color: mat-color($background, hover);
|
||||||
color: mat-color($foreground, text) !important;
|
color: mat-color($foreground, text) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,11 @@
|
|||||||
@import './assets/styles/openslides-dark-theme.scss';
|
@import './assets/styles/openslides-dark-theme.scss';
|
||||||
@import './assets/styles/openslides-green-theme.scss';
|
@import './assets/styles/openslides-green-theme.scss';
|
||||||
|
|
||||||
/** Import the component-related stylesheets here */
|
/** Import the component-related style sheets here */
|
||||||
@import './app/site/site.component.scss-theme.scss';
|
@import './app/site/site.component.scss-theme.scss';
|
||||||
@import './assets/styles/global-components-style.scss';
|
@import './assets/styles/global-components-style.scss';
|
||||||
@import './app/shared/components/projector-button/projector-button.component.scss';
|
@import './app/shared/components/projector-button/projector-button.component.scss';
|
||||||
|
@import './app/site/agenda/components/list-of-speakers/list-of-speakers.component.scss';
|
||||||
|
|
||||||
/** fonts */
|
/** fonts */
|
||||||
@import './assets/styles/fonts.scss';
|
@import './assets/styles/fonts.scss';
|
||||||
@ -21,6 +22,7 @@
|
|||||||
@include os-site-theme($theme);
|
@include os-site-theme($theme);
|
||||||
@include os-components-style($theme);
|
@include os-components-style($theme);
|
||||||
@include os-projector-button-style($theme);
|
@include os-projector-button-style($theme);
|
||||||
|
@include os-list-of-speakers-style($theme);
|
||||||
/** More components are added here */
|
/** More components are added here */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,6 +410,9 @@ button.mat-menu-item.selected {
|
|||||||
.spacer-bottom-20 {
|
.spacer-bottom-20 {
|
||||||
margin-bottom: 20px !important;
|
margin-bottom: 20px !important;
|
||||||
}
|
}
|
||||||
|
.spacer-bottom-40 {
|
||||||
|
margin-bottom: 40px !important;
|
||||||
|
}
|
||||||
.spacer-left-10 {
|
.spacer-left-10 {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user