From a27bae710e4acb078a1adff09362a264d324a887 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 9 Apr 2026 16:13:19 +0300 Subject: [PATCH] Responsive installed items, detail dialog, search, remove DEVICE from compact Installed items: - Sticky actions column with more_vert dropdown menu on lt-lg - Scrollable table wrapper, column sizing with nowrap - ResizeObserver hidePageSize at <640px - Filter chips/clear on separate row below toolbar on lt-lg - Responsive padding (24px lt-md, 16px xs), column header on xs Item detail dialog: - Responsive widths: 1200px default, 900px lt-xxl, 768px lt-lg, 100% lt-md - Column layout for dlg-row-1 on lt-md, header on xs - Custom carousel controls: arrows + dots on same row - Carousel aspect-ratio 1.5 for solution templates - isCompactLayout method (CF/RC only, no DEVICE) Search page: - Responsive padding (24px lt-lg, 16px lt-sm) - Sort button color="primary", wraps on lt-sm - Pagination column layout on lt-sm - Results count below pagination on lt-lg DEVICE removed from compact layout across all components: - Item card, browse, detail dialog, home, search - DEVICE now uses big card layout (same as widgets/dashboards) --- .../iot-hub/iot-hub-browse.component.html | 2 +- .../iot-hub/iot-hub-browse.component.scss | 1 - .../iot-hub/iot-hub-browse.component.ts | 2 +- .../iot-hub/iot-hub-item-card.component.ts | 2 +- .../iot-hub-item-detail-dialog.component.html | 39 +++--- .../iot-hub-item-detail-dialog.component.scss | 99 ++++++++++--- .../iot-hub-item-detail-dialog.component.ts | 12 ++ .../pages/iot-hub/iot-hub-home.component.ts | 2 +- .../iot-hub-installed-items.component.html | 93 ++++++++----- .../iot-hub-installed-items.component.scss | 131 ++++++++++++++++-- .../iot-hub-installed-items.component.ts | 29 +++- .../iot-hub/iot-hub-search.component.html | 2 +- .../iot-hub/iot-hub-search.component.scss | 49 ++++++- .../pages/iot-hub/iot-hub-search.component.ts | 6 +- 14 files changed, 375 insertions(+), 94 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html index 349e04f275..c20acedecb 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html @@ -213,7 +213,7 @@ } - diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss index c031c1bd62..955233e880 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss @@ -304,7 +304,6 @@ // Sort button — Design: 14px Medium, primary color, with filter_list icon .tb-iot-hub-sort-btn { - color: $tb-primary-color; flex-shrink: 0; font-size: 14px; font-weight: 500; diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts index d9e17ed99d..e0d94228b3 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts @@ -74,7 +74,7 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { } get isCompactType(): boolean { - return this._activeType === ItemType.CALCULATED_FIELD || this._activeType === ItemType.RULE_CHAIN || this._activeType === ItemType.DEVICE; + return this._activeType === ItemType.CALCULATED_FIELD || this._activeType === ItemType.RULE_CHAIN; } items: MpItemVersionView[] = []; diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.ts b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.ts index c1236aa8c5..dca2813a63 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.ts +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.ts @@ -93,7 +93,7 @@ export class TbIotHubItemCardComponent { } getCustomIconColor(): string | null { - if ((this.item.type === ItemType.CALCULATED_FIELD || this.item.type === ItemType.RULE_CHAIN) && this.item.color) { + if (this.isCompactLayout() && this.item.color) { return this.item.color; } return null; diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html index 18a1da0554..22f282109e 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html @@ -18,7 +18,7 @@
- @if (item.type === ItemType.CALCULATED_FIELD || item.type === ItemType.RULE_CHAIN) { + @if (isCompactLayout()) {
{{ getCompactIcon() }}
@@ -52,7 +52,7 @@
- @if (item.type === ItemType.CALCULATED_FIELD || item.type === ItemType.RULE_CHAIN || item.type === ItemType.DEVICE) { + @if (isCompactLayout()) {
@@ -107,7 +107,7 @@ } @else {
-
+
@if (item.type === ItemType.SOLUTION_TEMPLATE && carouselImages.length > 1) { } @else { @if (getPreviewUrl(); as url) { diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.scss b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.scss index 652ef05dc1..104ef48a6c 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.scss @@ -24,7 +24,24 @@ border-radius: 8px; overflow: hidden; max-height: 80vh; - width: 900px; + width: 1200px; + + @media #{$mat-lt-xxl} { + width: 900px; + } + + @media #{$mat-lt-lg} { + width: 768px; + } + + @media #{$mat-lt-md} { + width: 100%; + } + + @media #{$mat-xs} { + max-height: 100%; + height: 100%; + } } // Header — Design: pl-24, pr-12, py-16, gap between icon+content=16, content+close=8 @@ -135,6 +152,10 @@ align-items: center; justify-content: center; padding: 16px; + + &.dlg-preview-carousel { + aspect-ratio: 1.5; + } } .dlg-preview-img { @@ -399,6 +420,8 @@ .dlg-hero-carousel { width: 100%; height: 100%; + display: flex; + flex-direction: column; animation: dlg-carousel-fade-in 0s 0.3s forwards; visibility: hidden; } @@ -413,17 +436,12 @@ ::ng-deep .carousel { display: flex !important; flex-direction: column !important; + flex: 1; > section { flex: 1; min-height: 0; } - ul.indicators { - position: relative !important; - bottom: auto !important; - flex-shrink: 0; - padding: 8px 0; - } - - .direction { height: calc(100% - 40px) !important; } + ul.indicators { display: none !important; } + .direction { display: none !important; } } .dlg-carousel-container { @@ -440,28 +458,50 @@ width: 100%; height: 100%; object-fit: contain; - padding: 8px; } } } } +.dlg-carousel-hidden-nav { + display: none; +} + +.dlg-carousel-controls { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding-top: 16px; +} + +.dlg-carousel-dots { + display: flex; + align-items: center; + justify-content: center; + flex: 1; +} + .dlg-carousel-nav { - color: rgba(0, 0, 0, 0.6); - background: rgba(255, 255, 255, 0.8); + width: 40px; + height: 40px; + background: white; + color: rgba(0, 0, 0, 0.76); + flex-shrink: 0; - &:hover { background: rgba(255, 255, 255, 0.95); } + &:hover { background: rgba(245, 245, 245, 1); } } .dlg-carousel-dot { - width: 8px; - height: 8px; - border-radius: 50%; - background: rgba(0, 0, 0, 0.2); - margin: 0 3px; + width: 6px; + height: 6px; + border-radius: 999px; + background: rgba(0, 0, 0, 0.38); + margin: 9px 12px; + cursor: pointer; transition: background 0.2s; - &.active { background: rgba(0, 0, 0, 0.6); } + &.active { background: rgba(0, 0, 0, 0.76); } } // Info panel — Design: flex-col, space-between, py-16, gap-32 @@ -576,3 +616,24 @@ .dlg-footer-spacer { flex: 1; } + +// Responsive +@media #{$mat-lt-md} { + .dlg-row-1 { + flex-direction: column; + } +} + +@media #{$mat-xs} { + .dlg-header { + flex-direction: column; + position: relative; + padding-right: 48px; + } + + .dlg-close { + position: absolute; + top: 12px; + right: 12px; + } +} diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.ts b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.ts index f26bfdb21f..0d50a1b596 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.ts @@ -90,6 +90,10 @@ export class TbIotHubItemDetailDialogComponent extends DialogComponent
-
- - - @for (type of allItemTypes; track type; let last = $last) { -
- - {{ getItemTypeLabel(type) }} - -
- @if (!last) { - - } + + + @for (type of allItemTypes; track type; let last = $last) { +
+ + {{ getItemTypeLabel(type) }} + +
+ @if (!last) { + } -
- @if (hasActiveFilters()) { - - @for (type of activeTypeFilters; track type) { - - {{ getItemTypeLabel(type) }} - close - - } - - } -
+ + @if (hasActiveFilters()) { + + @for (type of activeTypeFilters; track type) { + + {{ getItemTypeLabel(type) }} + close + + } + + + } +