Browse Source

UI: continue new-menu rollout — home-links page, dashboard view toolbar, breadcrumb/user-menu polish

pull/15888/head
Igor Kulikov 3 months ago
parent
commit
f587052369
  1. 6
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html
  2. 2
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.scss
  3. 9
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-toolbar.component.scss
  4. 6
      ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.html
  5. 14
      ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.scss
  6. 6
      ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.ts
  7. 7
      ui-ngx/src/app/modules/home/components/dashboard-page/states/entity-state-controller.component.html
  8. 3
      ui-ngx/src/app/modules/home/components/dashboard-page/states/entity-state-controller.component.scss
  9. 2
      ui-ngx/src/app/modules/home/components/dashboard-view/dashboard-view.component.html
  10. 26
      ui-ngx/src/app/modules/home/components/dashboard-view/dashboard-view.component.ts
  11. 1
      ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts
  12. 2
      ui-ngx/src/app/modules/home/pages/home-links/home-links.component.html
  13. 44
      ui-ngx/src/app/modules/home/pages/home-links/home-links.component.ts
  14. 65
      ui-ngx/src/app/shared/components/breadcrumb.component.html
  15. 11
      ui-ngx/src/app/shared/components/user-menu.component.html
  16. 13
      ui-ngx/src/app/shared/components/user-menu.component.scss
  17. 1
      ui-ngx/src/app/shared/models/dashboard.models.ts

6
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html

@ -75,7 +75,9 @@
[states]="dashboardConfiguration.states"> [states]="dashboardConfiguration.states">
</tb-states-component> </tb-states-component>
} @else { } @else {
<tb-notification-bell class="gt-sm:!hidden"></tb-notification-bell> @if (!isPublicUser()) {
<tb-notification-bell class="gt-sm:!hidden"></tb-notification-bell>
}
<tb-breadcrumb class="lt-md:flex-1" <tb-breadcrumb class="lt-md:flex-1"
[componentBreadcrumbsTpl]="dashboardBreadcrumbsTpl"> [componentBreadcrumbsTpl]="dashboardBreadcrumbsTpl">
</tb-breadcrumb> </tb-breadcrumb>
@ -124,7 +126,7 @@
<mat-icon>{{isRightLayoutOpened ? 'arrow_back' : 'menu'}}</mat-icon> <mat-icon>{{isRightLayoutOpened ? 'arrow_back' : 'menu'}}</mat-icon>
</button> </button>
<div class="flex flex-row-reverse items-center lt-md:!hidden"> <div class="flex flex-row-reverse items-center lt-md:!hidden">
@if (!isEdit) { @if (!isEdit && !isPublicUser()) {
<tb-notification-bell></tb-notification-bell> <tb-notification-bell></tb-notification-bell>
} }
<button [class.!hidden]="hideFullscreenButton()" mat-icon-button <button [class.!hidden]="hideFullscreenButton()" mat-icon-button

2
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.scss

@ -18,7 +18,7 @@
$toolbar-height: 56px !default; $toolbar-height: 56px !default;
$fullscreen-toolbar-height: 56px !default; $fullscreen-toolbar-height: 56px !default;
$mobile-toolbar-height: 96px !default; $mobile-toolbar-height: 96px !default;
$mobile-app-toolbar-height: 40px !default; $mobile-app-toolbar-height: 48px !default;
tb-dashboard-page { tb-dashboard-page {
display: flex; display: flex;

9
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-toolbar.component.scss

@ -21,7 +21,7 @@ $mobile-toolbar-height: 96px !default;
$half-mobile-toolbar-height: 48px !default; $half-mobile-toolbar-height: 48px !default;
$mobile-toolbar-height-total: 96px !default; $mobile-toolbar-height-total: 96px !default;
$mobile-app-toolbar-height: 40px !default; $mobile-app-toolbar-height: 48px !default;
div.tb-dashboard-page.mobile-app { div.tb-dashboard-page.mobile-app {
tb-dashboard-toolbar { tb-dashboard-toolbar {
@ -95,9 +95,14 @@ tb-dashboard-toolbar {
} }
} }
&.mat-is-open {
.mat-fab-toolbar-wrapper {
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}
}
.mat-fab-toolbar-wrapper { .mat-fab-toolbar-wrapper {
height: $mobile-toolbar-height-total; height: $mobile-toolbar-height-total;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
@media #{$mat-gt-sm} { @media #{$mat-gt-sm} {
height: $toolbar-height; height: $toolbar-height;

6
ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.html

@ -15,8 +15,10 @@
limitations under the License. limitations under the License.
--> -->
<div class="flex flex-row items-center justify-start gap-2"> <div class="flex flex-row items-center justify-start gap-2" [class.tb-mobile]="isMobile">
<span class='state-divider'> > </span> @if ((breadcrumbs$ | async).length > 1) {
<span class='state-divider'> > </span>
}
<mat-select class="default-state-controller" [class.!hidden]="!displayStateSelection()" <mat-select class="default-state-controller" [class.!hidden]="!displayStateSelection()"
[(ngModel)]="stateObject[0].id" (ngModelChange)="selectedStateIdChanged()"> [(ngModel)]="stateObject[0].id" (ngModelChange)="selectedStateIdChanged()">
@for (stateKv of states | keyvalue; track stateKv) { @for (stateKv of states | keyvalue; track stateKv) {

14
ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.scss

@ -33,6 +33,11 @@
.state-divider { .state-divider {
display: block; display: block;
} }
.tb-mobile {
.state-divider {
display: none;
}
}
} }
} }
@ -44,6 +49,15 @@
--mat-select-enabled-trigger-text-color: rgba(0, 0, 0, 0.76); --mat-select-enabled-trigger-text-color: rgba(0, 0, 0, 0.76);
} }
} }
.tb-mobile {
::ng-deep {
.mat-mdc-select.default-state-controller {
--mat-select-trigger-text-size: 24px;
--mat-select-trigger-text-line-height: 32px;
--mat-select-trigger-text-weight: 400;
}
}
}
} }
:host ::ng-deep { :host ::ng-deep {

6
ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.ts

@ -27,6 +27,7 @@ import { base64toObj, objToBase64 } from '@app/core/utils';
import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
import { EntityService } from '@core/http/entity.service'; import { EntityService } from '@core/http/entity.service';
import { MobileService } from '@core/services/mobile.service'; import { MobileService } from '@core/services/mobile.service';
import { BreadcrumbService } from '@core/services/breadcrumb.service';
@Component({ @Component({
selector: 'tb-default-state-controller', selector: 'tb-default-state-controller',
@ -36,6 +37,8 @@ import { MobileService } from '@core/services/mobile.service';
}) })
export class DefaultStateControllerComponent extends StateControllerComponent implements OnInit, OnDestroy { export class DefaultStateControllerComponent extends StateControllerComponent implements OnInit, OnDestroy {
breadcrumbs$ = this.breadcrumbService.breadcrumbs$;
constructor(protected router: Router, constructor(protected router: Router,
protected route: ActivatedRoute, protected route: ActivatedRoute,
protected ngZone: NgZone, protected ngZone: NgZone,
@ -43,7 +46,8 @@ export class DefaultStateControllerComponent extends StateControllerComponent im
private utils: UtilsService, private utils: UtilsService,
private entityService: EntityService, private entityService: EntityService,
private mobileService: MobileService, private mobileService: MobileService,
private dashboardUtils: DashboardUtilsService) { private dashboardUtils: DashboardUtilsService,
private breadcrumbService: BreadcrumbService) {
super(router, route, ngZone, statesControllerService); super(router, route, ngZone, statesControllerService);
} }

7
ui-ngx/src/app/modules/home/components/dashboard-page/states/entity-state-controller.component.html

@ -18,7 +18,7 @@
<div class="entity-state-controller"> <div class="entity-state-controller">
@if (!isMobile) { @if (!isMobile) {
<div class="flex flex-row items-center justify-start gap-2"> <div class="flex flex-row items-center justify-start gap-2">
@for (state of stateObject; track state; let i = $index; let isLast = $last;) { @for (state of stateObject; track state.id; let i = $index; let isLast = $last;) {
@if ((breadcrumbs$ | async).length > 1 || i > 0) { @if ((breadcrumbs$ | async).length > 1 || i > 0) {
<span class='state-divider' [class.last-divider]="isLast"> > </span> <span class='state-divider' [class.last-divider]="isLast"> > </span>
} }
@ -29,12 +29,11 @@
</span> </span>
} }
</div> </div>
} } @else {
@if (isMobile) {
@if (stateObject.length > 1) { @if (stateObject.length > 1) {
<mat-select <mat-select
[(ngModel)]="selectedStateIndex" (ngModelChange)="selectedStateIndexChanged()"> [(ngModel)]="selectedStateIndex" (ngModelChange)="selectedStateIndexChanged()">
@for (state of stateObject; track state; let i = $index) { @for (state of stateObject; track state.id; let i = $index) {
<mat-option [value]="i"> <mat-option [value]="i">
{{getStateName(i)}} {{getStateName(i)}}
</mat-option> </mat-option>

3
ui-ngx/src/app/modules/home/components/dashboard-page/states/entity-state-controller.component.scss

@ -73,9 +73,6 @@
--mat-select-trigger-text-line-height: 32px; --mat-select-trigger-text-line-height: 32px;
--mat-select-trigger-text-weight: 400; --mat-select-trigger-text-weight: 400;
--mat-select-enabled-trigger-text-color: rgba(0,0,0,0.76); --mat-select-enabled-trigger-text-color: rgba(0,0,0,0.76);
.mat-mdc-select-value {
max-width: 200px;
}
.mat-mdc-select-arrow { .mat-mdc-select-arrow {
width: 24px; width: 24px;
} }

2
ui-ngx/src/app/modules/home/components/dashboard-view/dashboard-view.component.html

@ -15,4 +15,4 @@
limitations under the License. limitations under the License.
--> -->
<tb-dashboard-page [embedded]="true" [dashboard]="dashboard"></tb-dashboard-page> <tb-dashboard-page #dashboardPage [embedded]="true" [dashboard]="dashboard"></tb-dashboard-page>

26
ui-ngx/src/app/modules/home/components/dashboard-view/dashboard-view.component.ts

@ -14,12 +14,15 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, DestroyRef, effect, EventEmitter, viewChild } from '@angular/core';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { PageComponent } from '@shared/components/page.component'; import { PageComponent } from '@shared/components/page.component';
import { Dashboard } from '@shared/models/dashboard.models'; import { Dashboard } from '@shared/models/dashboard.models';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { MainToolbarComponent } from '@home/models/main-toolbar.models';
import { DashboardPageComponent } from '@home/components/dashboard-page/dashboard-page.component';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@Component({ @Component({
selector: 'tb-dashboard-view', selector: 'tb-dashboard-view',
@ -27,12 +30,29 @@ import { ActivatedRoute } from '@angular/router';
styleUrls: ['./dashboard-view.component.scss'], styleUrls: ['./dashboard-view.component.scss'],
standalone: false standalone: false
}) })
export class DashboardViewComponent extends PageComponent { export class DashboardViewComponent extends PageComponent implements MainToolbarComponent {
dashboard: Dashboard = this.route.snapshot.data.dashboard; dashboard: Dashboard = this.route.snapshot.data.dashboard;
hideMainToolbar = true;
toggleSideBar = new EventEmitter<void>();
private dashboardPage = viewChild<DashboardPageComponent>('dashboardPage');
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
private route: ActivatedRoute) { private route: ActivatedRoute,
private destroyRef: DestroyRef) {
super(store); super(store);
effect(() => {
const dashboardPage = this.dashboardPage();
if (dashboardPage) {
dashboardPage.toggleSideBar.pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe(() => {
this.toggleSideBar.emit();
});
}
});
} }
} }

1
ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts

@ -96,6 +96,7 @@ const applySystemParametersToHomeDashboard = (store: Store<AppState>,
} }
} }
dashboard.hideDashboardToolbar = true; dashboard.hideDashboardToolbar = true;
dashboard.isSystemDashboard = true;
return dashboard; return dashboard;
}) })
)) ))

2
ui-ngx/src/app/modules/home/pages/home-links/home-links.component.html

@ -16,7 +16,7 @@
--> -->
@if (homeDashboard) { @if (homeDashboard) {
<tb-dashboard-page [embedded]="true" [dashboard]="homeDashboard" [hideToolbar]="homeDashboard.hideDashboardToolbar"></tb-dashboard-page> <tb-dashboard-page #dashboardPage [embedded]="true" [dashboard]="homeDashboard" [hideToolbar]="homeDashboard.hideDashboardToolbar"></tb-dashboard-page>
} @else { } @else {
<mat-grid-list class="tb-home-links" [cols]="cols" rowHeight="280px"> <mat-grid-list class="tb-home-links" [cols]="cols" rowHeight="280px">
@for (section of homeSections$| async; track section) { @for (section of homeSections$| async; track section) {

44
ui-ngx/src/app/modules/home/pages/home-links/home-links.component.ts

@ -14,22 +14,35 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component, DestroyRef,
effect,
EventEmitter,
OnInit,
viewChild
} from '@angular/core';
import { MenuService } from '@core/services/menu.service'; import { MenuService } from '@core/services/menu.service';
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
import { MediaBreakpoints } from '@shared/models/constants'; import { MediaBreakpoints } from '@shared/models/constants';
import { HomeSection } from '@core/services/menu.models'; import { HomeSection } from '@core/services/menu.models';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { HomeDashboard } from '@shared/models/dashboard.models'; import { HomeDashboard } from '@shared/models/dashboard.models';
import { MainToolbarComponent } from '@home/models/main-toolbar.models';
import { DashboardPageComponent } from '@home/components/dashboard-page/dashboard-page.component';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@Component({ @Component({
selector: 'tb-home-links', selector: 'tb-home-links',
templateUrl: './home-links.component.html', templateUrl: './home-links.component.html',
styleUrls: ['./home-links.component.scss'], styleUrls: ['./home-links.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false standalone: false
}) })
export class HomeLinksComponent implements OnInit { export class HomeLinksComponent implements MainToolbarComponent, OnInit {
private dashboardPage = viewChild<DashboardPageComponent>('dashboardPage');
homeSections$ = this.menuService.homeSections(); homeSections$ = this.menuService.homeSections();
@ -37,10 +50,25 @@ export class HomeLinksComponent implements OnInit {
homeDashboard: HomeDashboard = this.route.snapshot.data.homeDashboard; homeDashboard: HomeDashboard = this.route.snapshot.data.homeDashboard;
hideMainToolbar = false;
toggleSideBar = new EventEmitter<void>();
constructor(private menuService: MenuService, constructor(private menuService: MenuService,
public breakpointObserver: BreakpointObserver, public breakpointObserver: BreakpointObserver,
private cd: ChangeDetectorRef, private cd: ChangeDetectorRef,
private route: ActivatedRoute) { private route: ActivatedRoute,
private destroyRef: DestroyRef) {
effect(() => {
const dashboardPage = this.dashboardPage();
if (dashboardPage) {
dashboardPage.toggleSideBar.pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe(() => {
this.toggleSideBar.emit();
});
}
});
this.hideMainToolbar = (!!this.homeDashboard && !this.homeDashboard.isSystemDashboard);
} }
ngOnInit() { ngOnInit() {

65
ui-ngx/src/app/shared/components/breadcrumb.component.html

@ -16,28 +16,16 @@
--> -->
<div class="tb-breadcrumb flex flex-1 flex-row gap-2"> <div class="tb-breadcrumb flex flex-1 flex-row gap-2">
@if (componentBreadcrumbsTpl && (lastBreadcrumb$ | async) === null) { @if (lastBreadcrumb$ | async; as breadcrumb) {
<div class="min-w-0 flex-1"> @if (!componentBreadcrumbsTpl) {
<ng-container <h1 class="flex-1 gt-sm:!hidden">
*ngTemplateOutlet="componentBreadcrumbsTpl"> <ng-container
</ng-container> *ngTemplateOutlet="breadcrumbTpl;context:{breadcrumb: breadcrumb}">
</div> </ng-container>
} @else { </h1>
@if (lastBreadcrumb$ | async; as breadcrumb) {
@if (componentBreadcrumbsTpl) {
<div class="flex-1 gt-sm:!hidden">
<ng-container
*ngTemplateOutlet="componentBreadcrumbsTpl">
</ng-container>
</div>
} @else {
<h1 class="flex-1 gt-sm:!hidden">
<ng-container
*ngTemplateOutlet="breadcrumbTpl;context:{breadcrumb: breadcrumb}">
</ng-container>
</h1>
}
} }
}
@if (!componentBreadcrumbsTpl || (breadcrumbs$ | async).length > 1) {
<div class="flex flex-1 flex-row items-center gap-2 overflow-hidden lt-md:!hidden"> <div class="flex flex-1 flex-row items-center gap-2 overflow-hidden lt-md:!hidden">
@for (breadcrumb of breadcrumbs$ | async; track breadcrumb.id; let isLast = $last; let i = $index;) { @for (breadcrumb of breadcrumbs$ | async; track breadcrumb.id; let isLast = $last; let i = $index;) {
@switch (isLast) { @switch (isLast) {
@ -46,35 +34,36 @@
<span class="divider"> > </span> <span class="divider"> > </span>
} }
<span class="flex flex-row gap-2"> <span class="flex flex-row gap-2">
<a [routerLink]="breadcrumb.link" [queryParams]="breadcrumb.queryParams"> <a [routerLink]="breadcrumb.link" [queryParams]="breadcrumb.queryParams">
<ng-container <ng-container
*ngTemplateOutlet="breadcrumbTpl;context:{breadcrumb: breadcrumb}"> *ngTemplateOutlet="breadcrumbTpl;context:{breadcrumb: breadcrumb}">
</ng-container> </ng-container>
</a> </a>
</span> </span>
} }
@case (true) { @case (true) {
@if (componentBreadcrumbsTpl) { @if (!componentBreadcrumbsTpl) {
<span>
<ng-container
*ngTemplateOutlet="componentBreadcrumbsTpl">
</ng-container>
</span>
} @else {
@if (i > 0) { @if (i > 0) {
<span class="divider last-divider"> > </span> <span class="divider last-divider"> > </span>
} }
<span> <span>
<ng-container <ng-container
*ngTemplateOutlet="breadcrumbTpl;context:{breadcrumb: breadcrumb}"> *ngTemplateOutlet="breadcrumbTpl;context:{breadcrumb: breadcrumb}">
</ng-container> </ng-container>
</span> </span>
} }
} }
} }
} }
</div> </div>
} }
@if (componentBreadcrumbsTpl) {
<span>
<ng-container
*ngTemplateOutlet="componentBreadcrumbsTpl">
</ng-container>
</span>
}
</div> </div>
<ng-template #breadcrumbTpl let-breadcrumb="breadcrumb"> <ng-template #breadcrumbTpl let-breadcrumb="breadcrumb">
{{ breadcrumb.labelFunction ? breadcrumb.labelFunction() : (breadcrumb.customTranslate ? (breadcrumb.label | customTranslate) : (breadcrumb.label | translate)) }} {{ breadcrumb.labelFunction ? breadcrumb.labelFunction() : (breadcrumb.customTranslate ? (breadcrumb.label | customTranslate) : (breadcrumb.label | translate)) }}

11
ui-ngx/src/app/shared/components/user-menu.component.html

@ -33,9 +33,18 @@
} }
</div> </div>
</button> </button>
<button #menuPopover="tbPopover" mat-icon-button class="tb-user-menu-icon"
(click)="$event.stopPropagation();"
tb-popover
tbPopoverTrigger="click"
[tbPopoverMenu]="true"
[tbPopoverContent]="userMenuTpl"
[tbPopoverPlacement]="'bottomRight'">
<tb-icon class="material-icons tb-mini-avatar">mdi:account-circle-outline</tb-icon>
</button>
<ng-template #userMenuTpl> <ng-template #userMenuTpl>
@if (authority$ | async; as authority) { @if (authority$ | async; as authority) {
<div class="tb-menu-content tb-user-menu-items" [style.width.px]="!collapsed ? menuButton._elementRef.nativeElement.offsetWidth : ''"> <div class="tb-menu-content tb-user-menu-items" [style.width.px]="!collapsed ? menuButton?._elementRef?.nativeElement?.offsetWidth : ''">
<button mat-button (click)="menuPopover?.hide(); openAccount()"> <button mat-button (click)="menuPopover?.hide(); openAccount()">
<tb-icon matButtonIcon>mdi:account-circle-outline</tb-icon> <tb-icon matButtonIcon>mdi:account-circle-outline</tb-icon>
<span translate>account.account</span> <span translate>account.account</span>

13
ui-ngx/src/app/shared/components/user-menu.component.scss

@ -22,12 +22,22 @@
button.mat-mdc-button:not(.mat-mdc-icon-button).tb-user-menu { button.mat-mdc-button:not(.mat-mdc-icon-button).tb-user-menu {
padding: 12px 16px; padding: 12px 16px;
} }
@media #{$mat-lt-lg} {
button.mat-mdc-button:not(.mat-mdc-icon-button).tb-user-menu {
display: none;
}
.tb-user-menu-icon {
display: block;
}
}
} }
} }
tb-user-menu { tb-user-menu {
width: 100%; width: 100%;
.tb-user-menu-icon {
display: none;
}
button.mat-mdc-button:not(.mat-mdc-icon-button).tb-user-menu { button.mat-mdc-button:not(.mat-mdc-icon-button).tb-user-menu {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -81,7 +91,6 @@ tb-user-menu {
height: 20px; height: 20px;
font-size: 20px; font-size: 20px;
} }
.tb-user-info { .tb-user-info {
opacity: 0; opacity: 0;
} }

1
ui-ngx/src/app/shared/models/dashboard.models.ts

@ -199,6 +199,7 @@ export interface Dashboard extends DashboardInfo {
export interface HomeDashboard extends Dashboard { export interface HomeDashboard extends Dashboard {
hideDashboardToolbar: boolean; hideDashboardToolbar: boolean;
isSystemDashboard?: boolean;
} }
export interface HomeDashboardInfo { export interface HomeDashboardInfo {

Loading…
Cancel
Save