UI fixes and report download in 3/4 cases

This commit is contained in:
Timo 2020-12-15 13:32:55 +02:00
parent 40455e24b6
commit 64ed8265be
25 changed files with 305 additions and 139 deletions

View File

@ -95,6 +95,8 @@ import { RulesScreenComponent } from './screens/admin/rules-screen/rules-screen.
import { WatermarkScreenComponent } from './screens/admin/watermark-screen/watermark-screen.component';
import { PdfViewerScreenComponent } from './screens/pdf-viewer-screen/pdf-viewer-screen.component';
import { HtmlDebugScreenComponent } from './screens/html-debug-screen/html-debug-screen.component';
import { ReportDownloadBtnComponent } from './components/buttons/report-download-btn/report-download-btn.component';
import { ProjectListingActionsComponent } from './screens/project-listing-screen/project-listing-actions/project-listing-actions.component';
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
@ -287,7 +289,9 @@ const matImports = [
RulesScreenComponent,
WatermarkScreenComponent,
PdfViewerScreenComponent,
HtmlDebugScreenComponent
HtmlDebugScreenComponent,
ReportDownloadBtnComponent,
ProjectListingActionsComponent
],
imports: [
BrowserModule,

View File

@ -1,4 +1,4 @@
<div class="file-actions">
<div class="file-actions" [class.active]="actionMenuOpen">
<!-- delete-->
<redaction-circle-button
(action)="openDeleteFileDialog($event, fileStatus)"
@ -22,17 +22,15 @@
</redaction-circle-button>
<!-- download report-->
<redaction-circle-button
(action)="downloadFileRedactionReport($event, fileStatus)"
*ngIf="permissionsService.canShowRedactionReportDownloadBtn(fileStatus)"
[disabled]="!fileStatus.isApproved"
<redaction-report-download-btn
(menuStateChanged)="actionMenuOpen = $event === 'OPEN'"
[tooltipClass]="'small'"
[tooltipPosition]="tooltipPosition"
[tooltip]="fileStatus.isApproved ? 'report.action' : 'report.unavailable-single'"
[file]="fileStatus"
[type]="buttonType"
icon="red:report"
[project]="appStateService.activeProject"
>
</redaction-circle-button>
</redaction-report-download-btn>
<!-- download redacted file-->
<redaction-circle-button

View File

@ -15,6 +15,7 @@ import { saveAs } from 'file-saver';
export class FileActionsComponent implements OnInit {
@Input() fileStatus: FileStatusWrapper;
@Output() actionPerformed = new EventEmitter<string>();
actionMenuOpen: boolean;
screen: 'file-preview' | 'project-overview';

View File

@ -1,5 +1,10 @@
@import '../../../../assets/styles/red-variables';
:host {
height: 34px;
width: 34px;
}
button {
height: 34px;
width: 34px;
@ -24,6 +29,7 @@ button {
&.warn {
background-color: $yellow-2;
&:hover {
background-color: $yellow-2;
}

View File

@ -0,0 +1,20 @@
<redaction-circle-button
*ngIf="project && permissionsService.isManagerAndOwner(project)"
[matMenuTriggerFor]="menu"
(click)="openReportMenu($event)"
[tooltipClass]="tooltipClass"
[tooltipPosition]="tooltipPosition"
[type]="type"
[tooltip]="isApproved ? 'report.action.label' : 'report.unavailable'"
[disabled]="!isApproved"
icon="red:report"
></redaction-circle-button>
<mat-menu #menu="matMenu" xPosition="before" (closed)="onMenuClosed()">
<div (click)="downloadRedactionReport($event, 'EFSA Template')" mat-menu-item>
<div [translate]="'report.action.efsa'"></div>
</div>
<div (click)="downloadRedactionReport($event, 'Syngenta Template')" mat-menu-item>
<div [translate]="'report.action.syngenta'"></div>
</div>
</mat-menu>

View File

@ -0,0 +1,52 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { PermissionsService } from '../../../common/service/permissions.service';
import { AppStateService } from '../../../state/app-state.service';
import { ProjectWrapper } from '../../../state/model/project.wrapper';
import { FileStatusWrapper } from '../../../screens/file/model/file-status.wrapper';
export type MenuState = 'OPEN' | 'CLOSED';
@Component({
selector: 'redaction-report-download-btn',
templateUrl: './report-download-btn.component.html',
styleUrls: ['./report-download-btn.component.scss']
})
export class ReportDownloadBtnComponent implements OnInit {
@Input() project: ProjectWrapper;
@Input() file: FileStatusWrapper;
@Input() tooltipPosition: 'above' | 'below' | 'before' | 'after' = 'above';
@Input() type: 'default' | 'primary' | 'warn' | 'dark-bg' = 'default';
@Input() tooltipClass: string;
@Output() menuStateChanged = new EventEmitter<MenuState>();
constructor(public readonly permissionsService: PermissionsService, private readonly _appStateService: AppStateService) {}
ngOnInit(): void {}
openReportMenu($event: MouseEvent) {
$event.stopPropagation();
this.menuStateChanged.emit('OPEN');
}
onMenuClosed() {
this.menuStateChanged.emit('CLOSED');
}
get isApproved() {
if (this.file) {
return this.file.isApproved;
} else {
return this.project.allFilesApproved;
}
}
downloadRedactionReport($event: MouseEvent, template: string) {
$event.preventDefault();
if (this.file) {
this._appStateService.downloadFileRedactionReport(this.file, template);
} else {
this._appStateService.downloadRedactionReport(this.project, template);
}
}
}

View File

@ -16,10 +16,10 @@
/>
</div>
<div class="red-input-group required" *ngIf="!project">
<div class="red-input-group required">
<mat-form-field floatLabel="always">
<mat-label>{{ 'project-listing.add-edit-dialog.form.template' | translate }}</mat-label>
<mat-select value="EFSA 1 (Vertebrate Authors)" style="width: 100%;">
<mat-select value="EFSA 1 (Vertebrate Authors)" style="width: 100%;" [disabled]="project?.hasFiles">
<mat-option *ngFor="let type of ['EFSA 1 (Vertebrate Authors)']" [value]="type">
{{ type }}
</mat-option>

View File

@ -18,7 +18,7 @@
<div class="red-input-group required" *ngIf="!isDictionaryRequest">
<label translate="manual-annotation.dialog.content.reason"></label>
<mat-select formControlName="reason" class="full-width">
<mat-select formControlName="reason" class="full-width" [placeholder]="'manual-annotation.dialog.content.reason-placeholder' | translate">
<mat-option *ngFor="let option of legalOptions" [value]="option">
{{ option.label }}
</mat-option>

View File

@ -59,6 +59,7 @@ export class IconsModule {
'sort-desc',
'status',
'trash',
'template',
'user',
'check-alt',
'page',

View File

@ -38,6 +38,10 @@ export class AnnotationWrapper {
return this.superType === 'ignore';
}
get isFalsePositive() {
return this.dictionary === 'false_positive';
}
get isManual() {
return this.superType === 'manual';
}

View File

@ -45,6 +45,10 @@ export class FileDataModel {
return;
}
if (annotation.isFalsePositive && !areDevFeaturesEnabled) {
return;
}
if (annotation.isReadyForAnalysis && annotation.isApproved) {
//
} else {

View File

@ -0,0 +1,48 @@
<redaction-status-bar [config]="getProjectStatusConfig(project)"></redaction-status-bar>
<div class="action-buttons" [class.active]="actionMenuOpen">
<redaction-circle-button
(action)="openDeleteProjectDialog($event, project)"
*ngIf="permissionsService.canDeleteProject(project)"
tooltip="project-listing.delete.action"
type="dark-bg"
icon="red:trash"
>
</redaction-circle-button>
<redaction-circle-button
(action)="openEditProjectDialog($event, project)"
*ngIf="permissionsService.isManager()"
tooltip="project-listing.edit.action"
type="dark-bg"
icon="red:edit"
>
</redaction-circle-button>
<redaction-report-download-btn (menuStateChanged)="actionMenuOpen = $event === 'OPEN'" [project]="project"> </redaction-report-download-btn>
<redaction-circle-button
(action)="openAssignProjectOwnerDialog($event, project)"
*ngIf="permissionsService.isManager()"
tooltip="project-listing.assign.action"
type="dark-bg"
icon="red:assign"
>
</redaction-circle-button>
<redaction-circle-button
*ngIf="permissionsService.displayReanalyseBtn(project)"
(action)="reanalyseProject($event, project)"
tooltip="project-listing.reanalyse.action"
type="dark-bg"
icon="red:refresh"
>
</redaction-circle-button>
<redaction-circle-button
(action)="downloadRedactedFiles($event, project)"
*ngIf="canDownloadRedactedFiles(project)"
tooltip="project-listing.download-files.action"
type="dark-bg"
icon="red:download"
></redaction-circle-button>
</div>

View File

@ -0,0 +1,82 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { PermissionsService } from '../../../common/service/permissions.service';
import { ProjectWrapper } from '../../../state/model/project.wrapper';
import { StatusSorter } from '../../../common/sorters/status-sorter';
import { download } from '../../../utils/file-download-utils';
import { computerize } from '../../../utils/functions';
import { FileManagementControllerService } from '@redaction/red-ui-http';
import { AppStateService } from '../../../state/app-state.service';
import { DialogService } from '../../../dialogs/dialog.service';
@Component({
selector: 'redaction-project-listing-actions',
templateUrl: './project-listing-actions.component.html',
styleUrls: ['./project-listing-actions.component.scss']
})
export class ProjectListingActionsComponent implements OnInit {
@Input() project: ProjectWrapper;
@Output() actionPerformed = new EventEmitter();
actionMenuOpen: boolean = false;
constructor(
public readonly permissionsService: PermissionsService,
public readonly appStateService: AppStateService,
private readonly _dialogService: DialogService,
private readonly _fileManagementControllerService: FileManagementControllerService
) {}
ngOnInit(): void {}
public openAssignProjectOwnerDialog($event: MouseEvent, project: ProjectWrapper) {
this._dialogService.openAssignProjectMembersAndOwnerDialog($event, project);
}
public openDeleteProjectDialog($event: MouseEvent, project: ProjectWrapper) {
this._dialogService.openDeleteProjectDialog($event, project, () => {
this.actionPerformed.emit();
});
}
openEditProjectDialog($event: MouseEvent, project: ProjectWrapper) {
this._dialogService.openEditProjectDialog($event, project, () => {
this.actionPerformed.emit();
});
}
async reanalyseProject($event: MouseEvent, project: ProjectWrapper) {
$event.stopPropagation();
await this.appStateService.reanalyzeProject(project);
await this.appStateService.loadAllProjects();
this.actionPerformed.emit();
}
// Download Files
public downloadRedactedFiles($event: MouseEvent, project: ProjectWrapper) {
$event.stopPropagation();
this._fileManagementControllerService
.downloadRedactedFiles({ fileIds: project.files.map((file) => file.fileId) }, project.projectId, false, 'response')
.subscribe((data) => {
download(data, 'redacted_files_' + computerize(project.name) + '.zip');
});
}
public canDownloadRedactedFiles(project: ProjectWrapper) {
return project.files.reduce((acc, file) => acc && this.permissionsService.canDownloadRedactedFile(file), true);
}
public getProjectStatusConfig(pw: ProjectWrapper) {
const obj = pw.files.reduce((acc, file) => {
const status = file.status;
if (!acc[status]) {
acc[status] = 1;
} else {
acc[status]++;
}
return acc;
}, {});
return Object.keys(obj)
.sort((a, b) => StatusSorter[a] - StatusSorter[b])
.map((status) => ({ length: obj[status], color: status }));
}
}

View File

@ -105,62 +105,7 @@
<redaction-initials-avatar [userId]="pw.project.ownerId" [withName]="true"></redaction-initials-avatar>
</div>
<div class="status-container">
<redaction-status-bar [config]="getProjectStatusConfig(pw)"></redaction-status-bar>
<div class="action-buttons">
<redaction-circle-button
(action)="openDeleteProjectDialog($event, pw)"
*ngIf="permissionsService.canDeleteProject(pw)"
tooltip="project-listing.delete.action"
type="dark-bg"
icon="red:trash"
>
</redaction-circle-button>
<redaction-circle-button
(action)="openEditProjectDialog($event, pw)"
*ngIf="permissionsService.isManager()"
tooltip="project-listing.edit.action"
type="dark-bg"
icon="red:edit"
>
</redaction-circle-button>
<redaction-circle-button
*ngIf="permissionsService.isManagerAndOwner(pw) && pw.hasFiles"
(action)="downloadRedactionReport($event, pw.project)"
[tooltip]="pw.allFilesApproved ? 'report.action' : 'report.unavailable'"
[disabled]="!pw.allFilesApproved"
type="dark-bg"
icon="red:report"
>
</redaction-circle-button>
<redaction-circle-button
(action)="openAssignProjectOwnerDialog($event, pw)"
*ngIf="permissionsService.isManager()"
tooltip="project-listing.assign.action"
type="dark-bg"
icon="red:assign"
>
</redaction-circle-button>
<redaction-circle-button
*ngIf="permissionsService.displayReanalyseBtn(pw)"
(action)="reanalyseProject($event, pw)"
tooltip="project-listing.reanalyse.action"
type="dark-bg"
icon="red:refresh"
>
</redaction-circle-button>
<redaction-circle-button
(action)="downloadRedactedFiles($event, pw)"
*ngIf="canDownloadRedactedFiles(pw)"
tooltip="project-listing.download-files.action"
type="dark-bg"
icon="red:download"
></redaction-circle-button>
</div>
<redaction-project-listing-actions [project]="pw" (actionPerformed)="actionPerformed(pw)"></redaction-project-listing-actions>
</div>
<div class="scrollbar-placeholder"></div>
</div>

View File

@ -3,7 +3,7 @@ import { FileManagementControllerService, Project } from '@redaction/red-ui-http
import { AppStateService } from '../../state/app-state.service';
import { UserService } from '../../user/user.service';
import { DoughnutChartConfig } from '../../components/simple-doughnut-chart/simple-doughnut-chart.component';
import { computerize, groupBy, humanize } from '../../utils/functions';
import { groupBy, humanize } from '../../utils/functions';
import { DialogService } from '../../dialogs/dialog.service';
import { FilterModel } from '../../common/filter/model/filter.model';
import {
@ -25,7 +25,6 @@ import { StatusSorter } from '../../common/sorters/status-sorter';
import { Router } from '@angular/router';
import { FormBuilder, FormGroup } from '@angular/forms';
import { debounce } from '../../utils/debounce';
import { download } from '../../utils/file-download-utils';
@Component({
selector: 'redaction-project-listing-screen',
@ -37,6 +36,7 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy {
public documentsChartData: DoughnutChartConfig[] = [];
public searchForm: FormGroup;
public actionMenuOpen: boolean;
public statusFilters: FilterModel[];
public peopleFilters: FilterModel[];
@ -153,44 +153,10 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy {
});
}
public openDeleteProjectDialog($event: MouseEvent, project: ProjectWrapper) {
this._dialogService.openDeleteProjectDialog($event, project, () => {
this._calculateData();
});
}
public downloadRedactionReport($event: MouseEvent, project: ProjectWrapper) {
$event.stopPropagation();
this.appStateService.downloadRedactionReport(project);
}
public openAssignProjectOwnerDialog($event: MouseEvent, project: ProjectWrapper) {
this._dialogService.openAssignProjectMembersAndOwnerDialog($event, project);
}
public getProjectStatusConfig(pw: ProjectWrapper) {
const obj = pw.files.reduce((acc, file) => {
const status = file.status;
if (!acc[status]) {
acc[status] = 1;
} else {
acc[status]++;
}
return acc;
}, {});
return Object.keys(obj)
.sort((a, b) => StatusSorter[a] - StatusSorter[b])
.map((status) => ({ length: obj[status], color: status }));
}
async reanalyseProject($event: MouseEvent, project: ProjectWrapper) {
$event.stopPropagation();
await this.appStateService.reanalyzeProject(project);
await this.appStateService.loadAllProjects();
this._calculateData();
}
private _computeAllFilters() {
const allDistinctFileStatus = new Set<string>();
const allDistinctPeople = new Set<string>();
@ -284,23 +250,7 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy {
this.displayedProjects = this._filteredProjects.filter((project) => project.name.toLowerCase().includes(value.query.toLowerCase()));
}
openEditProjectDialog($event: MouseEvent, project: ProjectWrapper) {
this._dialogService.openEditProjectDialog($event, project, () => {
this._calculateData();
});
}
// Download Files
public downloadRedactedFiles($event: MouseEvent, project: ProjectWrapper) {
$event.stopPropagation();
this._fileManagementControllerService
.downloadRedactedFiles({ fileIds: project.files.map((file) => file.fileId) }, project.projectId, false, 'response')
.subscribe((data) => {
download(data, 'redacted_files_' + computerize(project.name) + '.zip');
});
}
public canDownloadRedactedFiles(project: ProjectWrapper) {
return project.files.reduce((acc, file) => acc && this.permissionsService.canDownloadRedactedFile(file), true);
actionPerformed(pw: ProjectWrapper) {
this._calculateData();
}
}

View File

@ -80,6 +80,10 @@
'project-overview.project-details.stats.due-date' | translate: { date: appStateService.activeProject.project.dueDate | date: 'd MMM. yyyy' }
}}</span>
</div>
<div>
<mat-icon svgIcon="red:template"></mat-icon>
<span>{{ 'EFSA 1 (Vertebrate Authors)' }} </span>
</div>
</div>
<div class="mt-32" *ngIf="!!appStateService.activeProject.project.description">

View File

@ -57,14 +57,9 @@
tooltipPosition="below"
icon="red:assign"
></redaction-circle-button>
<redaction-circle-button
*ngIf="permissionsService.isManagerAndOwner()"
(action)="downloadRedactionReport($event)"
[tooltip]="appStateService.activeProject.allFilesApproved ? 'report.action' : 'report.unavailable'"
[disabled]="!appStateService.activeProject.allFilesApproved"
tooltipPosition="below"
icon="red:report"
></redaction-circle-button>
<redaction-report-download-btn [project]="appStateService.activeProject"> </redaction-report-download-btn>
<redaction-circle-button
(action)="downloadRedactedFiles()"
*ngIf="canDownloadRedactedFiles"

View File

@ -319,11 +319,6 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
});
}
public downloadRedactionReport($event: MouseEvent): void {
$event.stopPropagation();
this.appStateService.downloadRedactionReport();
}
public openAssignProjectMembersDialog(): void {
this._dialogService.openAssignProjectMembersAndOwnerDialog(null, this.appStateService.activeProject, () => {
this.reloadProjects();

View File

@ -267,7 +267,7 @@ export class AppStateService {
await this._reanalysisControllerService.reanalyzeProject(project.projectId).toPromise();
}
downloadRedactionReport(project?: ProjectWrapper) {
downloadRedactionReport(project?: ProjectWrapper, template?: string) {
if (!project) {
project = this.activeProject;
}
@ -339,7 +339,9 @@ export class AppStateService {
return foundProject.project;
} catch (error) {
this._notificationService.showToastNotification(
this._translateService.instant('projects.add-edit-dialog.errors.save'),
this._translateService.instant(
error.status === 409 ? 'projects.add-edit-dialog.errors.project-already-exists' : 'projects.add-edit-dialog.errors.generic'
),
null,
NotificationType.ERROR
);
@ -384,7 +386,7 @@ export class AppStateService {
}
}
downloadFileRedactionReport(file?: FileStatusWrapper) {
downloadFileRedactionReport(file?: FileStatusWrapper, template?: string) {
if (!file) {
file = this.activeFile;
}
@ -407,6 +409,7 @@ export class AppStateService {
tap((typesResponse) => {
for (const type of typesResponse.types) {
this._dictionaryData[type.type] = type;
this._dictionaryData[type.type].virtual = type.type === 'false_positive';
}
})
);

View File

@ -67,7 +67,11 @@
"report": {
"unavailable": "Redaction report is only available once all files have been approved.",
"unavailable-single": "Redaction report is only available once this file has been approved.",
"action": "Download Redaction Report"
"action": {
"label": "Download Redaction Report",
"efsa": "Download with EFSA Template",
"syngenta": "Download with Syngenta Template"
}
},
"project-listing": {
"search": "Project name...",
@ -114,6 +118,10 @@
"due-date": "Due Date",
"template": "Project Template"
},
"errors": {
"project-already-exists": "Project with this name already exists!",
"generic": "Failed to save project"
},
"actions": {
"save": "Save",
"save-and-add-members": "Save and Edit Team"
@ -469,6 +477,7 @@
"rectangle": "Custom Rectangle",
"dictionary": "Dictionary",
"reason": "Reason",
"reason-placeholder": "Select a reason ...",
"legalBasis": "Legal Basis",
"comment": "Comment"
}

View File

@ -0,0 +1,32 @@
<svg id="Capa_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="475.092px" height="475.092px" viewBox="0 0 475.092 475.092"
style="enable-background:new 0 0 475.092 475.092;"
xml:space="preserve">
<g fill="#283241">
<path d="M442.822,209.562c1.715-6.283,2.57-12.847,2.57-19.702c0-14.655-3.621-28.361-10.852-41.112
c0.567-3.995,0.855-8.088,0.855-12.275c0-19.223-5.716-36.162-17.132-50.819v-1.427c0.191-26.075-7.946-46.632-24.414-61.669
C377.387,7.521,355.831,0,329.186,0h-31.977c-19.985,0-39.02,2.093-57.102,6.28c-18.086,4.189-39.304,10.468-63.666,18.842
c-22.08,7.616-35.211,11.422-39.399,11.422H54.821c-10.088,0-18.702,3.567-25.84,10.704C21.845,54.387,18.276,63,18.276,73.085
v182.728c0,10.089,3.566,18.698,10.705,25.837c7.142,7.139,15.752,10.705,25.84,10.705h78.228
c6.849,4.572,19.889,19.324,39.113,44.255c11.231,14.661,21.416,26.741,30.551,36.265c3.612,3.997,6.564,10.089,8.848,18.271
c2.284,8.186,3.949,16.228,4.998,24.126c1.047,7.898,3.475,16.516,7.281,25.837c3.806,9.329,8.944,17.139,15.415,23.422
c7.423,7.043,15.985,10.561,25.697,10.561c15.988,0,30.361-3.087,43.112-9.274c12.754-6.184,22.463-15.845,29.126-28.981
c6.663-12.943,9.996-30.646,9.996-53.103c0-17.702-4.568-35.974-13.702-54.819h50.244c19.801,0,36.925-7.23,51.394-21.7
c14.469-14.462,21.693-31.497,21.693-51.103C456.809,239.165,452.15,223.652,442.822,209.562z M85.942,104.219
c-3.616,3.615-7.898,5.424-12.847,5.424c-4.95,0-9.233-1.805-12.85-5.424c-3.615-3.621-5.424-7.898-5.424-12.851
c0-4.948,1.809-9.231,5.424-12.847c3.621-3.617,7.9-5.424,12.85-5.424c4.949,0,9.231,1.807,12.847,5.424
c3.617,3.616,5.426,7.898,5.426,12.847C91.368,96.317,89.56,100.598,85.942,104.219z M409.135,281.377
c-7.42,7.33-15.886,10.992-25.413,10.992H283.227c0,11.04,4.564,26.217,13.698,45.535c9.138,19.321,13.71,34.598,13.71,45.829
c0,18.647-3.046,32.449-9.134,41.395c-6.092,8.949-18.274,13.422-36.546,13.422c-4.951-4.948-8.572-13.045-10.854-24.276
c-2.276-11.225-5.185-23.168-8.706-35.83c-3.519-12.655-9.18-23.079-16.984-31.266c-4.184-4.373-11.516-13.038-21.982-25.98
c-0.761-0.951-2.952-3.806-6.567-8.562c-3.614-4.757-6.613-8.658-8.992-11.703c-2.38-3.046-5.664-7.091-9.851-12.136
c-4.189-5.044-7.995-9.232-11.422-12.565c-3.427-3.327-7.089-6.708-10.992-10.137c-3.901-3.426-7.71-5.996-11.421-7.707
c-3.711-1.711-7.089-2.566-10.135-2.566h-9.136V73.092h9.136c2.474,0,5.47-0.282,8.993-0.854c3.518-0.571,6.658-1.192,9.419-1.858
c2.76-0.666,6.377-1.713,10.849-3.14c4.476-1.425,7.804-2.522,9.994-3.283c2.19-0.763,5.568-1.951,10.138-3.571
c4.57-1.615,7.33-2.613,8.28-2.996c40.159-13.894,72.708-20.839,97.648-20.839h36.542c16.563,0,29.506,3.899,38.828,11.704
c9.328,7.804,13.989,19.795,13.989,35.975c0,4.949-0.479,10.279-1.423,15.987c5.708,3.046,10.231,8.042,13.559,14.987
c3.333,6.945,4.996,13.944,4.996,20.985c0,7.039-1.711,13.61-5.141,19.701c10.089,9.517,15.126,20.839,15.126,33.974
c0,4.759-0.948,10.039-2.847,15.846c-1.899,5.808-4.285,10.327-7.139,13.562c6.091,0.192,11.184,4.665,15.276,13.422
c4.093,8.754,6.14,16.468,6.14,23.127C420.277,265.525,416.561,274.043,409.135,281.377z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,7 @@
<svg id="Capa_1" enable-background="new 0 0 508 508" height="512" viewBox="0 0 508 508" width="512"
xmlns="http://www.w3.org/2000/svg">
<g fill="currentColor">
<path
d="m264 459c0 5.52-4.49 10-10 10s-10-4.48-10-10c0-5.51 4.49-10 10-10s10 4.49 10 10zm-184.374-246c-5.523 0-10 4.477-10 10s4.477 10 10 10h20.374v100c0 5.523 4.477 10 10 10s10-4.477 10-10v-100h20.374c5.523 0 10-4.477 10-10s-4.477-10-10-10zm346.374-78c23.159 0 42 18.841 42 42s-18.841 42-42 42-42-18.841-42-42 18.841-42 42-42zm-22 42c0 12.131 9.869 22 22 22s22-9.869 22-22-9.869-22-22-22-22 9.869-22 22zm-6 292h-99c-5.731 0-10.359-4.847-9.978-10.669.348-5.315 5.003-9.331 10.329-9.331h88.649v-20h-74c-16.569 0-30-13.431-30-30v-26c0-16.569 13.431-30 30-30h74v-42h-138c-5.523 0-10-4.477-10-10v-186c0-5.523 4.477-10 10-10h138v-26c0-5.523-4.477-10-10-10h-248c-5.523 0-10 4.477-10 10v99h90c5.523 0 10 4.477 10 10v200c0 5.523-4.477 10-10 10h-90v61h88.649c5.326 0 9.981 4.016 10.329 9.331.381 5.822-4.247 10.669-9.978 10.669h-99c-5.523 0-10-4.477-10-10v-71h-90c-5.523 0-10-4.477-10-10v-200c0-5.523 4.477-10 10-10h90v-99c0-16.569 13.431-30 30-30h248c16.569 0 30 13.431 30 30v26h90c5.523 0 10 4.477 10 10v186c0 5.523-4.477 10-10 10h-90v42h26c16.569 0 30 13.431 30 30v26c0 16.569-13.431 30-30 30h-26v30c0 5.523-4.477 10-10 10zm-198-281h-180v180h180zm234 175h-120c-5.514 0-10 4.486-10 10v26c0 5.514 4.486 10 10 10h120c5.514 0 10-4.486 10-10v-26c0-5.514-4.486-10-10-10zm-174-82h154.895l-92.318-86.297c-11.488-10.738-29.486-10.74-40.973 0l-21.604 20.196zm228-166h-228v72.521l7.946-7.428c19.147-17.898 49.144-17.897 68.289 0l107.948 100.907h43.817z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -81,6 +81,12 @@
mat-icon {
width: 14px;
}
&.active {
display: flex;
// compensate for scroll
padding-right: 23px;
}
}
&:hover {