UI: Improve widgets/widget bundles select panel.

This commit is contained in:
Igor Kulikov 2023-11-01 19:07:25 +02:00
parent 039e563622
commit c5605eefff
5 changed files with 136 additions and 75 deletions

View File

@ -27,6 +27,7 @@
<ng-template #widgets let-fetchFunction="fetchFunction" let-filter="filter"> <ng-template #widgets let-fetchFunction="fetchFunction" let-filter="filter">
<tb-scroll-grid <tb-scroll-grid
[columns]="columns" [columns]="columns"
[itemSize]="160"
[fetchFunction]="fetchFunction" [fetchFunction]="fetchFunction"
[filter]="filter" [filter]="filter"
[itemCard]="widgetCard" [itemCard]="widgetCard"
@ -35,16 +36,22 @@
[noData]="noWidgets"> [noData]="noWidgets">
</tb-scroll-grid> </tb-scroll-grid>
<ng-template #widgetCard let-item="item"> <ng-template #widgetCard let-item="item">
<mat-card class="tb-widget-preview-card" appearance="raised" fxFlexFill fxLayout="row" fxLayoutGap="16px" (click)="onWidgetClicked($event, item)"> <mat-card class="tb-widget-preview-card" appearance="raised" fxLayout="column" fxLayoutGap="8px" (click)="onWidgetClicked($event, item)">
<div class="preview-container" fxFlex="45"> <div class="title-container">
<img class="preview" [src]="getPreviewImage(item.image)" alt="{{ item.title }}"> <div title="{{item.name}}" class="widget-title">
{{item.name}}
</div>
<div class="title-items-container">
<div class="title-items">
<div class="widget-type">{{ 'widget.' + item.widgetType + '-short' | translate }}</div>
<div tb-popover [tbPopoverContent]="item.description" [tbPopoverOverlayStyle]="{maxWidth: '300px'}" tbPopoverShowCloseButton="false" class="info-banner tb-primary-fill"><span>i</span></div>
</div>
<div *ngIf="item.deprecated" class="widget-deprecated" translate>widget.deprecated</div>
</div>
</div> </div>
<div fxFlex fxLayout="column"> <div class="preview-container">
<mat-card-title>{{item.name}}<div *ngIf="item.deprecated" class="tb-deprecated" translate>widget.deprecated</div></mat-card-title> <div class="preview-spacer"></div>
<mat-card-subtitle>{{ 'widget.' + item.widgetType | translate }}</mat-card-subtitle> <img class="preview" [src]="getPreviewImage(item.image)" alt="{{ item.title }}">
<mat-card-content *ngIf="item.description">
{{ item.description }}
</mat-card-content>
</div> </div>
</mat-card> </mat-card>
</ng-template> </ng-template>
@ -67,6 +74,7 @@
<ng-template #bundles> <ng-template #bundles>
<tb-scroll-grid <tb-scroll-grid
[columns]="columns" [columns]="columns"
[itemSize]="160"
[fetchFunction]="widgetBundlesFetchFunction" [fetchFunction]="widgetBundlesFetchFunction"
[filter]="widgetsBundleFilter" [filter]="widgetsBundleFilter"
[itemCard]="widgetsBundleCard" [itemCard]="widgetsBundleCard"
@ -75,16 +83,19 @@
[noData]="noWidgetBundles"> [noData]="noWidgetBundles">
</tb-scroll-grid> </tb-scroll-grid>
<ng-template #widgetsBundleCard let-item="item"> <ng-template #widgetsBundleCard let-item="item">
<mat-card class="tb-widget-preview-card" appearance="raised" fxFlexFill fxLayout="row" fxLayoutGap="16px" (click)="selectBundle($event, item)"> <mat-card class="tb-widget-preview-card" appearance="raised" fxLayout="column" fxLayoutGap="8px" (click)="selectBundle($event, item)">
<div class="preview-container" fxFlex="45"> <div class="title-container">
<img class="preview" [src]=getPreviewImage(item.image) alt="{{ item.title }}"> <div title="{{item.name}}" class="widget-title">
{{item.title}}
</div>
<div class="title-items">
<div *ngIf="isSystem(item)" class="widget-type">sys</div>
<div tb-popover [tbPopoverContent]="item.description" [tbPopoverOverlayStyle]="{maxWidth: '300px'}" tbPopoverShowCloseButton="false" class="info-banner tb-primary-fill"><span>i</span></div>
</div>
</div> </div>
<div fxFlex fxLayout="column"> <div class="preview-container">
<mat-card-title>{{ item.title }}</mat-card-title> <div class="preview-spacer"></div>
<mat-card-subtitle *ngIf="isSystem(item)" translate>widgets-bundle.system</mat-card-subtitle> <img class="preview" [src]=getPreviewImage(item.image) alt="{{ item.title }}">
<mat-card-content *ngIf="item.description">
{{ item.description }}
</mat-card-content>
</div> </div>
</mat-card> </mat-card>
</ng-template> </ng-template>
@ -105,14 +116,11 @@
</ng-template> </ng-template>
</ng-template> </ng-template>
<ng-template #widgetLoadingCard> <ng-template #widgetLoadingCard>
<mat-card class="tb-widget-preview-card loading-cell" appearance="raised" fxLayout="row" fxLayoutGap="16px"> <mat-card class="tb-widget-preview-card loading-cell" appearance="raised" fxLayout="column" fxLayoutGap="8px">
<div class="preview-container" fxFlex="45"> <div class="title-container">
</div> </div>
<div fxFlex fxLayout="column"> <div class="preview-container">
<mat-card-title> <div class="preview-spacer"></div>
</mat-card-title>
<mat-card-content>
</mat-card-content>
</div> </div>
</mat-card> </mat-card>
</ng-template> </ng-template>

View File

@ -22,32 +22,99 @@
.mat-mdc-card.tb-widget-preview-card { .mat-mdc-card.tb-widget-preview-card {
cursor: pointer; cursor: pointer;
transition: box-shadow 0.2s; transition: box-shadow 0.2s;
padding: 16px; padding: 12px;
&:hover { &:hover {
box-shadow: 0 2px 6px 6px rgb(0 0 0 / 20%), 0 1px 4px 2px rgb(0 0 0 / 14%), 0 1px 6px 0 rgb(0 0 0 / 12%) box-shadow: 0 2px 6px 6px rgb(0 0 0 / 20%), 0 1px 4px 2px rgb(0 0 0 / 14%), 0 1px 6px 0 rgb(0 0 0 / 12%)
} }
.title-container {
height: 32px;
display: flex;
flex-direction: row;
gap: 4px;
.widget-title {
flex: 1;
color: rgba(0, 0, 0, 0.76);
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: 16px;
letter-spacing: 0.2px;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
}
.title-items-container {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 2px;
}
.widget-deprecated {
display: flex;
height: 12px;
padding: 0 2px;
justify-content: flex-end;
align-items: center;
align-self: stretch;
color: rgba(209, 39, 48, 0.72);
font-size: 11px;
font-style: normal;
font-weight: 400;
letter-spacing: 0.2px;
}
.title-items {
display: flex;
align-items: flex-start;
gap: 8px;
.widget-type {
padding: 1px 4px;
border-radius: 4px;
background: rgba(236, 236, 236, 0.64);
color: rgba(0, 0, 0, 0.54);
font-size: 11px;
font-style: normal;
font-weight: 500;
line-height: 16px;
letter-spacing: 0.017px;
}
.info-banner {
display: flex;
width: 18px;
padding: 1px 0;
justify-content: center;
align-items: center;
border-radius: 4px;
color: #fff;
font-size: 11px;
font-style: normal;
font-weight: 600;
line-height: 16px;
letter-spacing: 0.017px;
&:before {
opacity: 0.5;
}
& > span {
z-index: 1;
}
}
}
}
&.loading-cell { &.loading-cell {
height: 100%; height: 100%;
min-height: 200px; min-height: 200px;
.mat-mdc-card-title { .preview-container, .title-container {
height: 32px;
margin-bottom: 16px;
}
.preview-container {
height: 80%;
margin: auto 0;
}
.mat-mdc-card-content {
height: 100%;
margin: 0;
}
.preview-container, .mat-mdc-card-title, .mat-mdc-card-content {
background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%); background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%);
border-radius: 5px; border-radius: 5px;
background-size: 200% 100%; background-size: 200% 100%;
@ -56,40 +123,19 @@
} }
.preview-container { .preview-container {
text-align: center; position: relative;
margin: auto 0; }
.preview-spacer {
margin-top: 80%;
} }
.preview { .preview {
max-width: 100%; position: absolute;
max-height: 100%; inset: 0;
object-fit: contain; object-fit: contain;
} width: 100%;
height: 100%;
.mat-mdc-card-title {
font-size: 20px;
line-height: normal;
margin-bottom: 8px;
.tb-deprecated {
font-size: 14px;
color: rgba(209, 39, 48, 0.87);
}
}
.mat-mdc-card-subtitle {
margin-bottom: 16px;
margin-top: -4px;
line-height: normal;
font-weight: normal;
}
.mat-mdc-card-content {
font-size: 14px;
line-height: 18px;
color: #666;
margin-bottom: 16px;
padding: 0;
} }
} }
} }

View File

@ -139,10 +139,11 @@ export class DashboardWidgetSelectComponent implements OnInit {
widgetSelected: EventEmitter<WidgetInfo> = new EventEmitter<WidgetInfo>(); widgetSelected: EventEmitter<WidgetInfo> = new EventEmitter<WidgetInfo>();
columns: ScrollGridColumns = { columns: ScrollGridColumns = {
columns: 1, columns: 2,
breakpoints: { breakpoints: {
'screen and (min-width: 2000px)': 3, 'screen and (min-width: 2000px)': 5,
'screen and (min-width: 600px)': 2 'screen and (min-width: 1280px)': 4,
'screen and (min-width: 600px)': 3
} }
}; };

View File

@ -28,5 +28,6 @@
} }
.tb-scroll-grid-item-container { .tb-scroll-grid-item-container {
flex: 1; flex: 1;
min-width: 0;
} }
} }

View File

@ -4774,6 +4774,11 @@
"rpc": "Control widget", "rpc": "Control widget",
"alarm": "Alarm widget", "alarm": "Alarm widget",
"static": "Static widget", "static": "Static widget",
"timeseries-short": "series",
"latest-short": "latest",
"rpc-short": "control",
"alarm-short": "alarm",
"static-short": "static",
"select-widget-type": "Select widget type", "select-widget-type": "Select widget type",
"missing-widget-title-error": "Widget title must be specified!", "missing-widget-title-error": "Widget title must be specified!",
"widget-saved": "Widget saved", "widget-saved": "Widget saved",