Add prettier list of speakers

Also cleans up some CSS and unifies some Drag-N-Drop Component
styles.
This commit is contained in:
Sean Engelhardt 2019-03-21 18:40:41 +01:00 committed by Emanuel Schütze
parent 63a2c6b05b
commit ab19d66022
6 changed files with 222 additions and 130 deletions

View File

@ -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 }}.&nbsp;</span> <span *ngIf="count">{{ i + 1 }}.&nbsp;</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>

View File

@ -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 {

View File

@ -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">
&nbsp;&nbsp; {{ 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>

View File

@ -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;
}

View File

@ -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;
} }
} }

View File

@ -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;
} }