UI: Improve widgets/widget bundles select panel.
This commit is contained in:
parent
039e563622
commit
c5605eefff
@ -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>
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -28,5 +28,6 @@
|
|||||||
}
|
}
|
||||||
.tb-scroll-grid-item-container {
|
.tb-scroll-grid-item-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user