Sync width directive
This commit is contained in:
parent
024f251a39
commit
d040961e25
@ -87,6 +87,7 @@ import { CustomTooltipModule } from './common/red-tooltip/custom-tooltip.module'
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
import { VirtualScrollComponent } from './utils/virtual-scroll/virtual-scroll.component';
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { SyncWidthDirective } from './utils/sync-width.directive';
|
||||
|
||||
export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
|
||||
@ -139,7 +140,8 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
CircleButtonComponent,
|
||||
ChevronButtonComponent,
|
||||
DictionaryListingScreenComponent,
|
||||
VirtualScrollComponent
|
||||
VirtualScrollComponent,
|
||||
SyncWidthDirective
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
border-bottom: 1px solid $separator;
|
||||
height: 30px;
|
||||
|
||||
> div {
|
||||
|
||||
@ -5,30 +5,29 @@
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="grid-container">
|
||||
<div class="header-item span-4">
|
||||
<div class="select-all-container">
|
||||
<div
|
||||
(click)="toggleSelectAll()"
|
||||
[class.active]="areAllDictsSelected"
|
||||
class="select-oval always-visible"
|
||||
*ngIf="!areAllDictsSelected && !areSomeDictsSelected"
|
||||
></div>
|
||||
<mat-icon *ngIf="areAllDictsSelected" (click)="toggleSelectAll()" class="selection-icon active" svgIcon="red:radio-selected"></mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="areSomeDictsSelected && !areAllDictsSelected"
|
||||
(click)="toggleSelectAll()"
|
||||
class="selection-icon"
|
||||
svgIcon="red:radio-indeterminate"
|
||||
></mat-icon>
|
||||
</div>
|
||||
|
||||
<span class="all-caps-label">
|
||||
{{ 'dictionary-listing.table-header.title' | translate: { length: dictionaries.length } }}
|
||||
</span>
|
||||
<div class="header-item span-4">
|
||||
<div class="select-all-container">
|
||||
<div
|
||||
(click)="toggleSelectAll()"
|
||||
[class.active]="areAllDictsSelected"
|
||||
class="select-oval always-visible"
|
||||
*ngIf="!areAllDictsSelected && !areSomeDictsSelected"
|
||||
></div>
|
||||
<mat-icon *ngIf="areAllDictsSelected" (click)="toggleSelectAll()" class="selection-icon active" svgIcon="red:radio-selected"></mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="areSomeDictsSelected && !areAllDictsSelected"
|
||||
(click)="toggleSelectAll()"
|
||||
class="selection-icon"
|
||||
svgIcon="red:radio-indeterminate"
|
||||
></mat-icon>
|
||||
</div>
|
||||
|
||||
<!-- Table column names-->
|
||||
<span class="all-caps-label">
|
||||
{{ 'dictionary-listing.table-header.title' | translate: { length: dictionaries.length } }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<div class="select-oval-placeholder placeholder-bottom-border"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
@ -40,8 +39,9 @@
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name label="dictionary-listing.table-col-names.hint-redaction" class="flex-center"></redaction-table-col-name>
|
||||
<div class="placeholder-bottom-border"></div>
|
||||
</div>
|
||||
|
||||
<!-- Table lines -->
|
||||
<div class="grid-container">
|
||||
<div class="table-item" *ngFor="let dict of dictionaries | sortBy: sortingOption.order:sortingOption.column">
|
||||
<div class="pr-0" (click)="toggleDictSelected($event, dict)">
|
||||
<div *ngIf="!isDictSelected(dict)" class="select-oval"></div>
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
@import '../../../../assets/styles/red-variables';
|
||||
@import '../../../../assets/styles/red-mixins';
|
||||
|
||||
.header-item {
|
||||
padding: 0 24px 0 10px;
|
||||
}
|
||||
|
||||
redaction-table-col-name::ng-deep {
|
||||
> div {
|
||||
padding-left: 10px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.left-container {
|
||||
.grid-container {
|
||||
grid-template-columns: auto 1fr 1fr 2fr;
|
||||
|
||||
.header-item {
|
||||
padding: 0 24px 0 10px;
|
||||
}
|
||||
|
||||
redaction-table-col-name::ng-deep {
|
||||
> div {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-item {
|
||||
> div {
|
||||
display: flex;
|
||||
@ -39,6 +39,7 @@
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
width: calc(100vw - 353px);
|
||||
}
|
||||
|
||||
.right-container {
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
}
|
||||
width: calc(100vw - 350px);
|
||||
}
|
||||
|
||||
.right-container {
|
||||
|
||||
@ -258,7 +258,6 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
|
||||
@HostListener('window:keyup', ['$event'])
|
||||
handleKeyEvent($event: KeyboardEvent) {
|
||||
console.log('handle', $event.key);
|
||||
if (!KEY_ARRAY.includes($event.key) || this._dialogRef?.getState() === MatDialogState.OPEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -39,13 +39,13 @@
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="grid-container">
|
||||
<div class="header-item span-4">
|
||||
<span class="all-caps-label">
|
||||
{{ 'project-listing.table-header.title' | translate: { length: displayedProjects.length || 0 } }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="all-caps-label">
|
||||
{{ 'project-listing.table-header.title' | translate: { length: displayedProjects.length || 0 } }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<redaction-table-col-name
|
||||
label="project-listing.table-col-names.name"
|
||||
column="project.projectName"
|
||||
@ -59,16 +59,18 @@
|
||||
<redaction-table-col-name label="project-listing.table-col-names.owner"></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name label="project-listing.table-col-names.status" class="flex-end"></redaction-table-col-name>
|
||||
</div>
|
||||
|
||||
<div *ngIf="displayedProjects?.length === 0" class="no-data heading-l" translate="project-listing.no-projects-match"></div>
|
||||
<div *ngIf="displayedProjects?.length === 0" class="no-data heading-l" translate="project-listing.no-projects-match"></div>
|
||||
|
||||
<div class="grid-container">
|
||||
<div
|
||||
*ngFor="let pw of displayedProjects | sortBy: sortingOption.order:sortingOption.column"
|
||||
[routerLink]="[canOpenProject(pw) ? '/ui/projects/' + pw.project.projectId : []]"
|
||||
class="table-item"
|
||||
[class.pointer]="canOpenProject(pw)"
|
||||
>
|
||||
<div>
|
||||
<div class="filename">
|
||||
<div class="table-item-title heading">
|
||||
{{ pw.project.projectName }}
|
||||
</div>
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
.status-container {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
width: calc(100vw - 466px);
|
||||
}
|
||||
|
||||
.right-container {
|
||||
|
||||
@ -90,31 +90,31 @@
|
||||
</div>
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container" [class.extended]="collapsedDetails">
|
||||
<div class="grid-container">
|
||||
<div class="header-item span-7">
|
||||
<div class="select-all-container">
|
||||
<div
|
||||
(click)="toggleSelectAll()"
|
||||
[class.active]="areAllFilesSelected"
|
||||
class="select-oval always-visible"
|
||||
*ngIf="!areAllFilesSelected && !areSomeFilesSelected"
|
||||
></div>
|
||||
<mat-icon *ngIf="areAllFilesSelected" (click)="toggleSelectAll()" class="selection-icon active" svgIcon="red:radio-selected"></mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="areSomeFilesSelected && !areAllFilesSelected"
|
||||
(click)="toggleSelectAll()"
|
||||
class="selection-icon"
|
||||
svgIcon="red:radio-indeterminate"
|
||||
></mat-icon>
|
||||
</div>
|
||||
|
||||
<span class="all-caps-label">
|
||||
{{ 'project-overview.table-header.title' | translate: { length: displayedFiles.length || 0 } }}
|
||||
</span>
|
||||
|
||||
<redaction-bulk-actions [selectedFileIds]="selectedFileIds" (reload)="bulkActionPerformed()"></redaction-bulk-actions>
|
||||
<div class="header-item">
|
||||
<div class="select-all-container">
|
||||
<div
|
||||
(click)="toggleSelectAll()"
|
||||
[class.active]="areAllFilesSelected"
|
||||
class="select-oval always-visible"
|
||||
*ngIf="!areAllFilesSelected && !areSomeFilesSelected"
|
||||
></div>
|
||||
<mat-icon *ngIf="areAllFilesSelected" (click)="toggleSelectAll()" class="selection-icon active" svgIcon="red:radio-selected"></mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="areSomeFilesSelected && !areAllFilesSelected"
|
||||
(click)="toggleSelectAll()"
|
||||
class="selection-icon"
|
||||
svgIcon="red:radio-indeterminate"
|
||||
></mat-icon>
|
||||
</div>
|
||||
|
||||
<span class="all-caps-label">
|
||||
{{ 'project-overview.table-header.title' | translate: { length: displayedFiles.length || 0 } }}
|
||||
</span>
|
||||
|
||||
<redaction-bulk-actions [selectedFileIds]="selectedFileIds" (reload)="bulkActionPerformed()"></redaction-bulk-actions>
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<!-- Table column names-->
|
||||
<div class="select-oval-placeholder placeholder-bottom-border"></div>
|
||||
|
||||
@ -160,9 +160,11 @@
|
||||
column="statusSort"
|
||||
label="project-overview.table-col-names.status"
|
||||
></redaction-table-col-name>
|
||||
</div>
|
||||
|
||||
<div *ngIf="displayedFiles?.length === 0" class="no-data heading-l" translate="project-overview.no-files-match"></div>
|
||||
<div *ngIf="displayedFiles?.length === 0" class="no-data heading-l" translate="project-overview.no-files-match"></div>
|
||||
|
||||
<div class="grid-container">
|
||||
<div
|
||||
*ngFor="let fileStatus of displayedFiles | sortBy: sortingOption.order:sortingOption.column"
|
||||
[class.pointer]="permissionsService.canOpenFile(fileStatus)"
|
||||
|
||||
@ -5,19 +5,19 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.header-item {
|
||||
padding: 0 24px 0 10px;
|
||||
}
|
||||
|
||||
redaction-table-col-name::ng-deep {
|
||||
> div {
|
||||
padding-left: 10px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
grid-template-columns: auto 3fr 2fr 1fr 1fr 2fr auto;
|
||||
|
||||
.header-item {
|
||||
padding: 0 24px 0 10px;
|
||||
}
|
||||
|
||||
redaction-table-col-name::ng-deep {
|
||||
> div {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-item {
|
||||
> div {
|
||||
padding-left: 10px;
|
||||
@ -63,7 +63,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.left-container {
|
||||
width: calc(100vw - 350px);
|
||||
}
|
||||
|
||||
.right-container {
|
||||
display: flex;
|
||||
width: 350px;
|
||||
min-width: 350px;
|
||||
padding: 16px 16px 16px 24px;
|
||||
|
||||
38
apps/red-ui/src/app/utils/sync-width.directive.ts
Normal file
38
apps/red-ui/src/app/utils/sync-width.directive.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { AfterViewChecked, Directive, ElementRef, HostListener, Input } from '@angular/core';
|
||||
import { debounce } from './debounce';
|
||||
|
||||
@Directive({
|
||||
selector: '[redactionSyncWidth]',
|
||||
exportAs: 'redactionSyncWidth'
|
||||
})
|
||||
export class SyncWidthDirective implements AfterViewChecked {
|
||||
@Input()
|
||||
redactionSyncWidth: string;
|
||||
|
||||
constructor(private el: ElementRef) {}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
this.matchWidth();
|
||||
}
|
||||
|
||||
@debounce(0)
|
||||
matchWidth() {
|
||||
const headerItems = this.el.nativeElement.children;
|
||||
const tableRows = document.getElementsByClassName(this.redactionSyncWidth);
|
||||
|
||||
if (!tableRows || !tableRows.length) return;
|
||||
|
||||
const tableRow = tableRows[0];
|
||||
if (tableRow.children.length !== headerItems.length) return;
|
||||
|
||||
for (let idx = 0; idx < headerItems.length; ++idx) {
|
||||
headerItems[idx].style.width = `${tableRow.children[idx].getBoundingClientRect().width}px`;
|
||||
headerItems[idx].style.minWidth = `${tableRow.children[idx].getBoundingClientRect().width}px`;
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:resize')
|
||||
onResize() {
|
||||
this.matchWidth();
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
@import 'red-variables';
|
||||
@import 'red-mixins';
|
||||
|
||||
.header-item {
|
||||
background-color: $grey-6;
|
||||
@ -7,8 +8,6 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
z-index: 1;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
gap: 10px;
|
||||
border-bottom: 1px solid $separator;
|
||||
box-sizing: border-box;
|
||||
|
||||
@ -66,7 +66,8 @@ body {
|
||||
}
|
||||
|
||||
.left-container {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
transition: width ease-in-out 0.2s, min-width ease-in-out 0.2s;
|
||||
|
||||
&.extended {
|
||||
width: calc(100vw - 60px) !important;
|
||||
@ -75,6 +76,7 @@ body {
|
||||
|
||||
.right-container {
|
||||
border-left: 1px solid $grey-4;
|
||||
box-sizing: border-box;
|
||||
background: $white;
|
||||
z-index: 1;
|
||||
overflow-y: scroll;
|
||||
|
||||
@ -1,29 +1,22 @@
|
||||
@import 'red-variables';
|
||||
@import 'red-mixins';
|
||||
|
||||
redaction-table-col-name,
|
||||
.select-oval-placeholder {
|
||||
background-color: $white;
|
||||
position: sticky;
|
||||
top: 50px;
|
||||
z-index: 1;
|
||||
.no-data {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
grid-column: 1/-1;
|
||||
padding: 12px;
|
||||
.table-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid $separator;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: grid;
|
||||
max-height: 100%;
|
||||
max-height: calc(100vh - 50px - 30px - 111px);
|
||||
overflow-y: scroll;
|
||||
@include no-scroll-bar();
|
||||
|
||||
.placeholder-bottom-border {
|
||||
border-bottom: 1px solid $separator;
|
||||
}
|
||||
|
||||
.table-item {
|
||||
display: contents;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user