@sd-angular/core 19.0.0-beta.79 → 19.0.0-beta.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/sd-angular-core-components-table.mjs +2 -2
- package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules-authom.mjs +359 -0
- package/fesm2022/sd-angular-core-modules-authom.mjs.map +1 -0
- package/fesm2022/sd-angular-core-modules-layout.mjs +266 -13
- package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules.mjs +1 -0
- package/fesm2022/sd-angular-core-modules.mjs.map +1 -1
- package/modules/authom/authom.configuration.d.ts +17 -0
- package/modules/authom/authom.interceptor.d.ts +3 -0
- package/modules/authom/authom.module.d.ts +16 -0
- package/modules/authom/authom.service.d.ts +32 -0
- package/modules/authom/index.d.ts +35 -0
- package/modules/index.d.ts +1 -0
- package/modules/layout/components/index.d.ts +2 -0
- package/modules/layout/components/layout-main/layout-main.component.d.ts +1 -0
- package/modules/layout/components/sidebar-mobile-v1/components/sidebar/sidebar.component.d.ts +35 -0
- package/modules/layout/components/sidebar-mobile-v1/components/user/user.component.d.ts +24 -0
- package/modules/layout/components/sidebar-mobile-v1/main.component.d.ts +21 -0
- package/modules/layout/services/menu/menu.model.d.ts +1 -1
- package/package.json +47 -43
- package/sd-angular-core-19.0.0-beta.80.tgz +0 -0
- package/sd-angular-core-19.0.0-beta.79.tgz +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, ElementRef, input, booleanAttribute, effect, Component, Injectable, InjectionToken, signal, Pipe, output, DestroyRef, computed, untracked, viewChild, Inject, NgModule } from '@angular/core';
|
|
3
3
|
import * as i1$3 from '@angular/common';
|
|
4
|
-
import { CommonModule } from '@angular/common';
|
|
4
|
+
import { CommonModule, NgTemplateOutlet } from '@angular/common';
|
|
5
5
|
import * as i1$5 from '@angular/router';
|
|
6
6
|
import { Router, NavigationEnd, RouterModule, ActivatedRoute } from '@angular/router';
|
|
7
7
|
import { __decorate } from 'tslib';
|
|
@@ -296,7 +296,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
296
296
|
}]
|
|
297
297
|
}] });
|
|
298
298
|
|
|
299
|
-
class LayoutUserComponent {
|
|
299
|
+
let LayoutUserComponent$1 = class LayoutUserComponent {
|
|
300
300
|
// ==========================================
|
|
301
301
|
// INJECT SERVICES
|
|
302
302
|
// ==========================================
|
|
@@ -339,8 +339,8 @@ class LayoutUserComponent {
|
|
|
339
339
|
};
|
|
340
340
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LayoutUserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
341
341
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: LayoutUserComponent, isStandalone: true, selector: "lib-layout-user", inputs: { isMobileOrTablet: { classPropertyName: "isMobileOrTablet", publicName: "isMobileOrTablet", isSignal: true, isRequired: false, transformFunction: null }, isMenuLock: { classPropertyName: "isMenuLock", publicName: "isMenuLock", isSignal: true, isRequired: false, transformFunction: null }, isShowSidebar: { classPropertyName: "isShowSidebar", publicName: "isShowSidebar", isSignal: true, isRequired: false, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { menuClosed: "menuClosed", menuOpened: "menuOpened", toggleMenuLock: "toggleMenuLock" }, ngImport: i0, template: "@let _userInfo = userInfo();\r\n@let avatar = _userInfo?.avatar || _userInfo?.fullName || _userInfo?.username || _userInfo?.email;\r\n\r\n<div class=\"c-layout-user-wrapper\">\r\n <div class=\"c-layout-user-avatar\" [matMenuTriggerFor]=\"userMenu\" (menuClosed)=\"onMenuClosed()\" (menuOpened)=\"onMenuOpened()\">\r\n <sd-avatar [src]=\"avatar\" [size]=\"32\"></sd-avatar>\r\n </div>\r\n\r\n @if (!isMobileOrTablet()) {\r\n <div aria-hidden=\"true\" mat-mini-fab class=\"c-layout-icon-toggle\" (click)=\"onToggleMenuLock($event)\">\r\n <mat-icon style=\"color: #8c8c8c\">\r\n {{ isShowSidebar() ? 'keyboard_arrow_right' : 'keyboard_arrow_left' }}\r\n </mat-icon>\r\n </div>\r\n }\r\n</div>\r\n\r\n<mat-menu #userMenu=\"matMenu\" xPosition=\"before\" backdropClass=\"c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0\">\r\n <div aria-hidden=\"true\" class=\"c-user-menu-wrapper\" (click)=\"keepOpenWhenClickInsideMenu($event)\">\r\n <div class=\"c-user-info-wrapper\">\r\n <div class=\"c-user-avatar\">\r\n <sd-avatar [src]=\"avatar\" [size]=\"40\"></sd-avatar>\r\n </div>\r\n <span class=\"c-user-name\">{{ _userInfo.fullName || _userInfo.username }}</span>\r\n <span class=\"c-user-email\">{{ _userInfo.email }}</span>\r\n </div>\r\n\r\n @if (changePasswordLayoutConfig) {\r\n <div class=\"c-sign-button-wrapper\">\r\n <button class=\"c-account-options\" (click)=\"changePassword()\">\r\n <img alt=\"lock\" />\r\n <span>\u0110\u1ED5i m\u1EADt kh\u1EA9u</span>\r\n </button>\r\n </div>\r\n }\r\n\r\n <div class=\"c-sign-button-wrapper\">\r\n <button class=\"c-sign-button\" mat-flat-button (click)=\"logout()\">\u0110\u0103ng xu\u1EA5t</button>\r\n </div>\r\n </div>\r\n</mat-menu>", styles: ["::ng-deep .c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0+* .cdk-overlay-pane{transform:translate(277px,83px)}.c-layout-user-wrapper{display:flex;flex-direction:column;align-items:center;width:60px;height:80px}.c-layout-user-wrapper .c-layout-user-avatar{width:32px;height:32px;display:flex;align-items:center;justify-content:center;cursor:pointer}.c-layout-user-wrapper .c-layout-icon-toggle{background-color:transparent;border-top:1px solid #f0f0f0;box-shadow:none;margin-top:10px;width:32px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer}.c-user-menu-wrapper .c-user-info-wrapper{width:250px;padding:16px;display:flex;flex-direction:column;align-items:center;gap:8px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-avatar{width:40px;height:40px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-name{font-size:16px;font-weight:700;text-align:center}.c-user-menu-wrapper .c-user-info-wrapper .c-user-email{font-size:14px;color:#7a7a7a;text-align:center}.c-user-menu-wrapper .c-sign-button-wrapper{text-align:center;padding:16px 16px 8px;width:100%;border-top:1px solid #dee2e6}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options{all:unset;cursor:pointer;font-size:14px;display:flex;align-items:center;gap:8px}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options img{scale:.875;content:url('data:image/svg+xml,<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">%0D%0A <path%0D%0A d=\"M12 5.66667H11.3333V4.33333C11.3333 2.49333 9.83996 1 7.99996 1C6.15996 1 4.66663 2.49333 4.66663 4.33333V5.66667H3.99996C3.26663 5.66667 2.66663 6.26667 2.66663 7V13.6667C2.66663 14.4 3.26663 15 3.99996 15H12C12.7333 15 13.3333 14.4 13.3333 13.6667V7C13.3333 6.26667 12.7333 5.66667 12 5.66667ZM5.99996 4.33333C5.99996 3.22667 6.89329 2.33333 7.99996 2.33333C9.10663 2.33333 9.99996 3.22667 9.99996 4.33333V5.66667H5.99996V4.33333ZM12 13.6667H3.99996V7H12V13.6667ZM7.99996 11.6667C8.73329 11.6667 9.33329 11.0667 9.33329 10.3333C9.33329 9.6 8.73329 9 7.99996 9C7.26663 9 6.66663 9.6 6.66663 10.3333C6.66663 11.0667 7.26663 11.6667 7.99996 11.6667Z\"%0D%0A fill=\"%23757575\" />%0D%0A</svg>')}.c-user-menu-wrapper .c-sign-button-wrapper .c-sign-button{width:100%;color:#000;padding:16px;font-weight:700;background-color:#eef0f2}.c-avatar{max-width:100%;object-fit:cover}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: i1$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "component", type: SdAvatar, selector: "sd-avatar", inputs: ["src", "size"] }] });
|
|
342
|
-
}
|
|
343
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LayoutUserComponent, decorators: [{
|
|
342
|
+
};
|
|
343
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LayoutUserComponent$1, decorators: [{
|
|
344
344
|
type: Component,
|
|
345
345
|
args: [{ selector: 'lib-layout-user', imports: [MatMenuModule, MatButtonModule, MatIconModule, MatTooltipModule, SdAvatar], standalone: true, template: "@let _userInfo = userInfo();\r\n@let avatar = _userInfo?.avatar || _userInfo?.fullName || _userInfo?.username || _userInfo?.email;\r\n\r\n<div class=\"c-layout-user-wrapper\">\r\n <div class=\"c-layout-user-avatar\" [matMenuTriggerFor]=\"userMenu\" (menuClosed)=\"onMenuClosed()\" (menuOpened)=\"onMenuOpened()\">\r\n <sd-avatar [src]=\"avatar\" [size]=\"32\"></sd-avatar>\r\n </div>\r\n\r\n @if (!isMobileOrTablet()) {\r\n <div aria-hidden=\"true\" mat-mini-fab class=\"c-layout-icon-toggle\" (click)=\"onToggleMenuLock($event)\">\r\n <mat-icon style=\"color: #8c8c8c\">\r\n {{ isShowSidebar() ? 'keyboard_arrow_right' : 'keyboard_arrow_left' }}\r\n </mat-icon>\r\n </div>\r\n }\r\n</div>\r\n\r\n<mat-menu #userMenu=\"matMenu\" xPosition=\"before\" backdropClass=\"c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0\">\r\n <div aria-hidden=\"true\" class=\"c-user-menu-wrapper\" (click)=\"keepOpenWhenClickInsideMenu($event)\">\r\n <div class=\"c-user-info-wrapper\">\r\n <div class=\"c-user-avatar\">\r\n <sd-avatar [src]=\"avatar\" [size]=\"40\"></sd-avatar>\r\n </div>\r\n <span class=\"c-user-name\">{{ _userInfo.fullName || _userInfo.username }}</span>\r\n <span class=\"c-user-email\">{{ _userInfo.email }}</span>\r\n </div>\r\n\r\n @if (changePasswordLayoutConfig) {\r\n <div class=\"c-sign-button-wrapper\">\r\n <button class=\"c-account-options\" (click)=\"changePassword()\">\r\n <img alt=\"lock\" />\r\n <span>\u0110\u1ED5i m\u1EADt kh\u1EA9u</span>\r\n </button>\r\n </div>\r\n }\r\n\r\n <div class=\"c-sign-button-wrapper\">\r\n <button class=\"c-sign-button\" mat-flat-button (click)=\"logout()\">\u0110\u0103ng xu\u1EA5t</button>\r\n </div>\r\n </div>\r\n</mat-menu>", styles: ["::ng-deep .c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0+* .cdk-overlay-pane{transform:translate(277px,83px)}.c-layout-user-wrapper{display:flex;flex-direction:column;align-items:center;width:60px;height:80px}.c-layout-user-wrapper .c-layout-user-avatar{width:32px;height:32px;display:flex;align-items:center;justify-content:center;cursor:pointer}.c-layout-user-wrapper .c-layout-icon-toggle{background-color:transparent;border-top:1px solid #f0f0f0;box-shadow:none;margin-top:10px;width:32px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer}.c-user-menu-wrapper .c-user-info-wrapper{width:250px;padding:16px;display:flex;flex-direction:column;align-items:center;gap:8px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-avatar{width:40px;height:40px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-name{font-size:16px;font-weight:700;text-align:center}.c-user-menu-wrapper .c-user-info-wrapper .c-user-email{font-size:14px;color:#7a7a7a;text-align:center}.c-user-menu-wrapper .c-sign-button-wrapper{text-align:center;padding:16px 16px 8px;width:100%;border-top:1px solid #dee2e6}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options{all:unset;cursor:pointer;font-size:14px;display:flex;align-items:center;gap:8px}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options img{scale:.875;content:url('data:image/svg+xml,<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">%0D%0A <path%0D%0A d=\"M12 5.66667H11.3333V4.33333C11.3333 2.49333 9.83996 1 7.99996 1C6.15996 1 4.66663 2.49333 4.66663 4.33333V5.66667H3.99996C3.26663 5.66667 2.66663 6.26667 2.66663 7V13.6667C2.66663 14.4 3.26663 15 3.99996 15H12C12.7333 15 13.3333 14.4 13.3333 13.6667V7C13.3333 6.26667 12.7333 5.66667 12 5.66667ZM5.99996 4.33333C5.99996 3.22667 6.89329 2.33333 7.99996 2.33333C9.10663 2.33333 9.99996 3.22667 9.99996 4.33333V5.66667H5.99996V4.33333ZM12 13.6667H3.99996V7H12V13.6667ZM7.99996 11.6667C8.73329 11.6667 9.33329 11.0667 9.33329 10.3333C9.33329 9.6 8.73329 9 7.99996 9C7.26663 9 6.66663 9.6 6.66663 10.3333C6.66663 11.0667 7.26663 11.6667 7.99996 11.6667Z\"%0D%0A fill=\"%23757575\" />%0D%0A</svg>')}.c-user-menu-wrapper .c-sign-button-wrapper .c-sign-button{width:100%;color:#000;padding:16px;font-weight:700;background-color:#eef0f2}.c-avatar{max-width:100%;object-fit:cover}\n"] }]
|
|
346
346
|
}] });
|
|
@@ -725,7 +725,7 @@ class SidebarComponent {
|
|
|
725
725
|
return count;
|
|
726
726
|
};
|
|
727
727
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
728
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SidebarComponent, isStandalone: true, selector: "sidebar", inputs: { isShowSidebar: { classPropertyName: "isShowSidebar", publicName: "isShowSidebar", isSignal: true, isRequired: true, transformFunction: null }, menus: { classPropertyName: "menus", publicName: "menus", isSignal: true, isRequired: true, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { expandSideBar: "expandSideBar", popupUserMenuClosed: "popupUserMenuClosed", popupUserMenuOpened: "popupUserMenuOpened", showSideBar: "showSideBar" }, ngImport: i0, template: "@let _userInfo = userInfo();\r\n@let _sidebar = sidebar();\r\n\r\n@if (_userInfo && _sidebar) {\r\n <div class=\"wrapper\" [style.height]=\"isMobileOrTablet ? screenHeight + 'px' : '100%'\">\r\n <div class=\"c-header\">\r\n @if (_sidebar.logoUrl) {\r\n <div class=\"c-logo\">\r\n <a href=\"javascript:;\" (click)=\"openHomePage()\">\r\n <img alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\r\n </a>\r\n </div>\r\n }\r\n <div class=\"c-title-menu-group\">\r\n <span>{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\r\n </div>\r\n </div>\r\n <div class=\"c-body\">\r\n <div class=\"c-menu\">\r\n <div class=\"c-menu-group\">\r\n @for (nodeMenuGroup of menus(); track nodeMenuGroup.id) {\r\n <button\r\n (mouseenter)=\"onMouseOverMenuGroupNode($event, nodeMenuGroup)\"\r\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, nodeMenuGroup)\"\r\n (click)=\"expandMenuGroup(nodeMenuGroup)\"\r\n [matTooltip]=\"nodeMenuGroup.tooltipTitle || nodeMenuGroup.title\"\r\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\r\n [matTooltipPosition]=\"'right'\"\r\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\r\n @if (nodeMenuGroup.iconUrl) {\r\n <span\r\n class=\"c-menu-group-icon\"\r\n [ngStyle]=\"{\r\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n <img width=\"24px\" height=\"24px\" [src]=\"nodeMenuGroup.iconUrl\" [alt]=\"nodeMenuGroup.title\" />\r\n </span>\r\n } @else {\r\n <mat-icon\r\n class=\"c-menu-group-icon\"\r\n [ngStyle]=\"{\r\n color: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\r\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n {{ nodeMenuGroup.icon || 'widgets' }}\r\n </mat-icon>\r\n }\r\n </button>\r\n }\r\n </div>\r\n <div class=\"c-menu-tree\">\r\n @if (totalMenuInMenusByGroup() >= 10) {\r\n <div style=\"padding: 0px 4px\" class=\"c-menu-tree-search\">\r\n <sd-input size=\"sm\" placeholder=\"T\u00ECm ki\u1EBFm\" [model]=\"searchText()\" (sdChange)=\"onFilterSearchText($event)\">\r\n <ng-template sdSuffixDef>\r\n @if (searchText()) {\r\n <mat-icon class=\"c-search-prefix-icon cancel\" (click)=\"onClearSearchText()\">cancel</mat-icon>\r\n } @else {\r\n <mat-icon class=\"c-search-prefix-icon search\">search</mat-icon>\r\n }\r\n </ng-template>\r\n </sd-input>\r\n </div>\r\n }\r\n <div class=\"c-menu-tree-container\">\r\n <mat-tree [dataSource]=\"dataSource\" [treeControl]=\"treeControl\" [style.backgroundColor]=\"'transparent'\">\r\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: !hasChild\">\r\n <li\r\n class=\"c-menu-node\"\r\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\r\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\"\r\n [ngStyle]=\"{\r\n backgroundColor: (currentPath() | menuFocus: node) ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n <div aria-hidden=\"true\" class=\"c-menu-node-description\" (click)=\"navigate(node)\" [class.d-none]=\"!isShowSidebar()\">\r\n <div\r\n class=\"c-menu-node-description-content\"\r\n [ngStyle]=\"{\r\n color: (currentPath() | menuFocus: node) ? _sidebar.brandColor || '#2962FF' : '#1F1F1F',\r\n }\"\r\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\r\n </div>\r\n </li>\r\n </mat-nested-tree-node>\r\n\r\n <mat-nested-tree-node\r\n *matTreeNodeDef=\"let node; when: hasChild\"\r\n aria-hidden=\"true\"\r\n [class]=\"{ expanded: treeControl.isExpanded(node), isfocus: currentPath() | menuFocus: node }\">\r\n <li>\r\n <div\r\n class=\"c-menu-node\"\r\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\r\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\">\r\n <div class=\"d-flex align-items-center\" style=\"gap: 10px; width: 100%\">\r\n <div [class.d-none]=\"!isShowSidebar()\" class=\"c-menu-node-description\" (click)=\"onToggleMenuNode(node)\">\r\n <div\r\n class=\"c-menu-node-description-content\"\r\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\r\n <mat-icon class=\"c-menu-node-description-icon-expand\">\r\n {{ treeControl.isExpanded(node) ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\r\n </mat-icon>\r\n </div>\r\n </div>\r\n </div>\r\n <ul class=\"p-0\" [class.d-none]=\"!treeControl.isExpanded(node)\">\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </ul>\r\n </li>\r\n </mat-nested-tree-node>\r\n </mat-tree>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"c-footer\">\r\n <lib-layout-user\r\n [userInfo]=\"_userInfo\"\r\n [isMobileOrTablet]=\"isMobileOrTablet\"\r\n (menuOpened)=\"onUserMenuOpened()\"\r\n (menuClosed)=\"onUserMenuClosed()\"\r\n [isShowSidebar]=\"isShowSidebar()\"\r\n (toggleMenuLock)=\"toggleMenuLock($event)\">\r\n </lib-layout-user>\r\n </div>\r\n\r\n <div class=\"c-vertical\"></div>\r\n </div>\r\n}", styles: ["::ng-deep .mat-mdc-tooltip-panel:has(.c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140){pointer-events:none}:host ::ng-deep .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:16px!important}:host ::ng-deep .mat-nested-tree-node ul .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:32px!important}:host ::ng-deep .mat-nested-tree-node ul .mat-nested-tree-node ul .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:48px!important}ul,li{margin-top:0;margin-bottom:0;list-style-type:none}.wrapper{display:flex;flex-direction:column;width:290px;background-color:#fff}.wrapper .c-header{display:flex;align-items:center;height:52px;padding:3px;gap:16px}.wrapper .c-header .c-logo{display:flex;justify-content:center;align-items:center;width:52px;height:52px}.wrapper .c-header .c-logo img{width:32px;height:32px;object-fit:cover}.wrapper .c-header .c-title-menu-group{display:flex;align-items:center;font-size:18px;font-weight:500;flex:1}.wrapper .c-body{flex:1;overflow-y:hidden}.wrapper .c-body .c-menu{height:100%;display:flex}.wrapper .c-body .c-menu .c-menu-group{display:flex;flex-direction:column;align-items:center;width:60px;overflow-y:scroll;scrollbar-width:none}.wrapper .c-body .c-menu .c-menu-group .c-menu-group-icon{display:flex;justify-content:center;align-items:center;min-height:50px;width:52px;border-radius:8px;transition:all .15s}.wrapper .c-body .c-menu .c-menu-group .c-menu-group-icon img{height:24px;width:24px;object-fit:contain}.wrapper .c-body .c-menu .c-menu-tree{flex:1;display:flex;flex-direction:column;padding:3px 4px 3px 3px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon{cursor:pointer;color:#757575;padding:0}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon.search{width:20px;height:20px;font-size:18px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon.cancel{width:16px;height:16px;font-size:16px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container{flex:1;overflow-y:scroll;scrollbar-width:none}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node{width:100%;display:flex;cursor:pointer;min-height:44px;padding:8px;border-radius:8px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-icon{display:flex;justify-content:center;align-items:center;height:100%}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description{flex:1;display:flex;align-items:center}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-content{flex:1;display:flex;align-items:center;flex-wrap:wrap;white-space:pre-wrap;font-size:15px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-expand{text-align:left;background-color:transparent;border:none;font-size:20px}.wrapper .c-footer{height:80px}.wrapper .c-vertical{position:fixed;height:100vh;left:58px;width:2px;background-color:#f8f9fa;pointer-events:none}\n"], dependencies: [{ kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "tooltip", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "sdFocusForceBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTreeModule }, { kind: "directive", type: i3$1.MatNestedTreeNode, selector: "mat-nested-tree-node", inputs: ["matNestedTreeNode", "disabled", "tabIndex"], outputs: ["activation", "expandedChange"], exportAs: ["matNestedTreeNode"] }, { kind: "directive", type: i3$1.MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "component", type: i3$1.MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: i3$1.MatTreeNodeOutlet, selector: "[matTreeNodeOutlet]" }, { kind: "pipe", type: SdSafeHtmlPipe, name: "sdSafeHtml" }, { kind: "ngmodule", type: MatInputModule }, { kind: "pipe", type: MenuFocusPipe, name: "menuFocus" }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: HighlightSearchPipe, name: "highLightSearch" }, { kind: "directive", type: SdSuffixDefDirective, selector: "[sdSuffixDef]" }, { kind: "component", type: LayoutUserComponent, selector: "lib-layout-user", inputs: ["isMobileOrTablet", "isMenuLock", "isShowSidebar", "userInfo"], outputs: ["menuClosed", "menuOpened", "toggleMenuLock"] }] });
|
|
728
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SidebarComponent, isStandalone: true, selector: "sidebar", inputs: { isShowSidebar: { classPropertyName: "isShowSidebar", publicName: "isShowSidebar", isSignal: true, isRequired: true, transformFunction: null }, menus: { classPropertyName: "menus", publicName: "menus", isSignal: true, isRequired: true, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { expandSideBar: "expandSideBar", popupUserMenuClosed: "popupUserMenuClosed", popupUserMenuOpened: "popupUserMenuOpened", showSideBar: "showSideBar" }, ngImport: i0, template: "@let _userInfo = userInfo();\r\n@let _sidebar = sidebar();\r\n\r\n@if (_userInfo && _sidebar) {\r\n <div class=\"wrapper\" [style.height]=\"isMobileOrTablet ? screenHeight + 'px' : '100%'\">\r\n <div class=\"c-header\">\r\n @if (_sidebar.logoUrl) {\r\n <div class=\"c-logo\">\r\n <a href=\"javascript:;\" (click)=\"openHomePage()\">\r\n <img alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\r\n </a>\r\n </div>\r\n }\r\n <div class=\"c-title-menu-group\">\r\n <span>{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\r\n </div>\r\n </div>\r\n <div class=\"c-body\">\r\n <div class=\"c-menu\">\r\n <div class=\"c-menu-group\">\r\n @for (nodeMenuGroup of menus(); track nodeMenuGroup.id) {\r\n <button\r\n (mouseenter)=\"onMouseOverMenuGroupNode($event, nodeMenuGroup)\"\r\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, nodeMenuGroup)\"\r\n (click)=\"expandMenuGroup(nodeMenuGroup)\"\r\n [matTooltip]=\"nodeMenuGroup.tooltipTitle || nodeMenuGroup.title\"\r\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\r\n [matTooltipPosition]=\"'right'\"\r\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\r\n @if (nodeMenuGroup.iconUrl) {\r\n <span\r\n class=\"c-menu-group-icon\"\r\n [ngStyle]=\"{\r\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n <img width=\"24px\" height=\"24px\" [src]=\"nodeMenuGroup.iconUrl\" [alt]=\"nodeMenuGroup.title\" />\r\n </span>\r\n } @else {\r\n <mat-icon\r\n class=\"c-menu-group-icon\"\r\n [ngStyle]=\"{\r\n color: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\r\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n {{ nodeMenuGroup.icon || 'widgets' }}\r\n </mat-icon>\r\n }\r\n </button>\r\n }\r\n </div>\r\n <div class=\"c-menu-tree\">\r\n @if (totalMenuInMenusByGroup() >= 10) {\r\n <div style=\"padding: 0px 4px\" class=\"c-menu-tree-search\">\r\n <sd-input size=\"sm\" placeholder=\"T\u00ECm ki\u1EBFm\" [model]=\"searchText()\" (sdChange)=\"onFilterSearchText($event)\">\r\n <ng-template sdSuffixDef>\r\n @if (searchText()) {\r\n <mat-icon class=\"c-search-prefix-icon cancel\" (click)=\"onClearSearchText()\">cancel</mat-icon>\r\n } @else {\r\n <mat-icon class=\"c-search-prefix-icon search\">search</mat-icon>\r\n }\r\n </ng-template>\r\n </sd-input>\r\n </div>\r\n }\r\n <div class=\"c-menu-tree-container\">\r\n <mat-tree [dataSource]=\"dataSource\" [treeControl]=\"treeControl\" [style.backgroundColor]=\"'transparent'\">\r\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: !hasChild\">\r\n <li\r\n class=\"c-menu-node\"\r\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\r\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\"\r\n [ngStyle]=\"{\r\n backgroundColor: (currentPath() | menuFocus: node) ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n <div aria-hidden=\"true\" class=\"c-menu-node-description\" (click)=\"navigate(node)\" [class.d-none]=\"!isShowSidebar()\">\r\n <div\r\n class=\"c-menu-node-description-content\"\r\n [ngStyle]=\"{\r\n color: (currentPath() | menuFocus: node) ? _sidebar.brandColor || '#2962FF' : '#1F1F1F',\r\n }\"\r\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\r\n </div>\r\n </li>\r\n </mat-nested-tree-node>\r\n\r\n <mat-nested-tree-node\r\n *matTreeNodeDef=\"let node; when: hasChild\"\r\n aria-hidden=\"true\"\r\n [class]=\"{ expanded: treeControl.isExpanded(node), isfocus: currentPath() | menuFocus: node }\">\r\n <li>\r\n <div\r\n class=\"c-menu-node\"\r\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\r\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\">\r\n <div class=\"d-flex align-items-center\" style=\"gap: 10px; width: 100%\">\r\n <div [class.d-none]=\"!isShowSidebar()\" class=\"c-menu-node-description\" (click)=\"onToggleMenuNode(node)\">\r\n <div\r\n class=\"c-menu-node-description-content\"\r\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\r\n <mat-icon class=\"c-menu-node-description-icon-expand\">\r\n {{ treeControl.isExpanded(node) ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\r\n </mat-icon>\r\n </div>\r\n </div>\r\n </div>\r\n <ul class=\"p-0\" [class.d-none]=\"!treeControl.isExpanded(node)\">\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </ul>\r\n </li>\r\n </mat-nested-tree-node>\r\n </mat-tree>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"c-footer\">\r\n <lib-layout-user\r\n [userInfo]=\"_userInfo\"\r\n [isMobileOrTablet]=\"isMobileOrTablet\"\r\n (menuOpened)=\"onUserMenuOpened()\"\r\n (menuClosed)=\"onUserMenuClosed()\"\r\n [isShowSidebar]=\"isShowSidebar()\"\r\n (toggleMenuLock)=\"toggleMenuLock($event)\">\r\n </lib-layout-user>\r\n </div>\r\n\r\n <div class=\"c-vertical\"></div>\r\n </div>\r\n}", styles: ["::ng-deep .mat-mdc-tooltip-panel:has(.c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140){pointer-events:none}:host ::ng-deep .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:16px!important}:host ::ng-deep .mat-nested-tree-node ul .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:32px!important}:host ::ng-deep .mat-nested-tree-node ul .mat-nested-tree-node ul .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:48px!important}ul,li{margin-top:0;margin-bottom:0;list-style-type:none}.wrapper{display:flex;flex-direction:column;width:290px;background-color:#fff}.wrapper .c-header{display:flex;align-items:center;height:52px;padding:3px;gap:16px}.wrapper .c-header .c-logo{display:flex;justify-content:center;align-items:center;width:52px;height:52px}.wrapper .c-header .c-logo img{width:32px;height:32px;object-fit:cover}.wrapper .c-header .c-title-menu-group{display:flex;align-items:center;font-size:18px;font-weight:500;flex:1}.wrapper .c-body{flex:1;overflow-y:hidden}.wrapper .c-body .c-menu{height:100%;display:flex}.wrapper .c-body .c-menu .c-menu-group{display:flex;flex-direction:column;align-items:center;width:60px;overflow-y:scroll;scrollbar-width:none}.wrapper .c-body .c-menu .c-menu-group .c-menu-group-icon{display:flex;justify-content:center;align-items:center;min-height:50px;width:52px;border-radius:8px;transition:all .15s}.wrapper .c-body .c-menu .c-menu-group .c-menu-group-icon img{height:24px;width:24px;object-fit:contain}.wrapper .c-body .c-menu .c-menu-tree{flex:1;display:flex;flex-direction:column;padding:3px 4px 3px 3px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon{cursor:pointer;color:#757575;padding:0}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon.search{width:20px;height:20px;font-size:18px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon.cancel{width:16px;height:16px;font-size:16px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container{flex:1;overflow-y:scroll;scrollbar-width:none}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node{width:100%;display:flex;cursor:pointer;min-height:44px;padding:8px;border-radius:8px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-icon{display:flex;justify-content:center;align-items:center;height:100%}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description{flex:1;display:flex;align-items:center}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-content{flex:1;display:flex;align-items:center;flex-wrap:wrap;white-space:pre-wrap;font-size:15px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-expand{text-align:left;background-color:transparent;border:none;font-size:20px}.wrapper .c-footer{height:80px}.wrapper .c-vertical{position:fixed;height:100vh;left:58px;width:2px;background-color:#f8f9fa;pointer-events:none}\n"], dependencies: [{ kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "tooltip", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "sdFocusForceBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTreeModule }, { kind: "directive", type: i3$1.MatNestedTreeNode, selector: "mat-nested-tree-node", inputs: ["matNestedTreeNode", "disabled", "tabIndex"], outputs: ["activation", "expandedChange"], exportAs: ["matNestedTreeNode"] }, { kind: "directive", type: i3$1.MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "component", type: i3$1.MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: i3$1.MatTreeNodeOutlet, selector: "[matTreeNodeOutlet]" }, { kind: "pipe", type: SdSafeHtmlPipe, name: "sdSafeHtml" }, { kind: "ngmodule", type: MatInputModule }, { kind: "pipe", type: MenuFocusPipe, name: "menuFocus" }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: HighlightSearchPipe, name: "highLightSearch" }, { kind: "directive", type: SdSuffixDefDirective, selector: "[sdSuffixDef]" }, { kind: "component", type: LayoutUserComponent$1, selector: "lib-layout-user", inputs: ["isMobileOrTablet", "isMenuLock", "isShowSidebar", "userInfo"], outputs: ["menuClosed", "menuOpened", "toggleMenuLock"] }] });
|
|
729
729
|
}
|
|
730
730
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SidebarComponent, decorators: [{
|
|
731
731
|
type: Component,
|
|
@@ -742,7 +742,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
742
742
|
MatTooltipModule,
|
|
743
743
|
HighlightSearchPipe,
|
|
744
744
|
SdSuffixDefDirective,
|
|
745
|
-
LayoutUserComponent,
|
|
745
|
+
LayoutUserComponent$1,
|
|
746
746
|
], template: "@let _userInfo = userInfo();\r\n@let _sidebar = sidebar();\r\n\r\n@if (_userInfo && _sidebar) {\r\n <div class=\"wrapper\" [style.height]=\"isMobileOrTablet ? screenHeight + 'px' : '100%'\">\r\n <div class=\"c-header\">\r\n @if (_sidebar.logoUrl) {\r\n <div class=\"c-logo\">\r\n <a href=\"javascript:;\" (click)=\"openHomePage()\">\r\n <img alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\r\n </a>\r\n </div>\r\n }\r\n <div class=\"c-title-menu-group\">\r\n <span>{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\r\n </div>\r\n </div>\r\n <div class=\"c-body\">\r\n <div class=\"c-menu\">\r\n <div class=\"c-menu-group\">\r\n @for (nodeMenuGroup of menus(); track nodeMenuGroup.id) {\r\n <button\r\n (mouseenter)=\"onMouseOverMenuGroupNode($event, nodeMenuGroup)\"\r\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, nodeMenuGroup)\"\r\n (click)=\"expandMenuGroup(nodeMenuGroup)\"\r\n [matTooltip]=\"nodeMenuGroup.tooltipTitle || nodeMenuGroup.title\"\r\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\r\n [matTooltipPosition]=\"'right'\"\r\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\r\n @if (nodeMenuGroup.iconUrl) {\r\n <span\r\n class=\"c-menu-group-icon\"\r\n [ngStyle]=\"{\r\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n <img width=\"24px\" height=\"24px\" [src]=\"nodeMenuGroup.iconUrl\" [alt]=\"nodeMenuGroup.title\" />\r\n </span>\r\n } @else {\r\n <mat-icon\r\n class=\"c-menu-group-icon\"\r\n [ngStyle]=\"{\r\n color: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\r\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n {{ nodeMenuGroup.icon || 'widgets' }}\r\n </mat-icon>\r\n }\r\n </button>\r\n }\r\n </div>\r\n <div class=\"c-menu-tree\">\r\n @if (totalMenuInMenusByGroup() >= 10) {\r\n <div style=\"padding: 0px 4px\" class=\"c-menu-tree-search\">\r\n <sd-input size=\"sm\" placeholder=\"T\u00ECm ki\u1EBFm\" [model]=\"searchText()\" (sdChange)=\"onFilterSearchText($event)\">\r\n <ng-template sdSuffixDef>\r\n @if (searchText()) {\r\n <mat-icon class=\"c-search-prefix-icon cancel\" (click)=\"onClearSearchText()\">cancel</mat-icon>\r\n } @else {\r\n <mat-icon class=\"c-search-prefix-icon search\">search</mat-icon>\r\n }\r\n </ng-template>\r\n </sd-input>\r\n </div>\r\n }\r\n <div class=\"c-menu-tree-container\">\r\n <mat-tree [dataSource]=\"dataSource\" [treeControl]=\"treeControl\" [style.backgroundColor]=\"'transparent'\">\r\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: !hasChild\">\r\n <li\r\n class=\"c-menu-node\"\r\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\r\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\"\r\n [ngStyle]=\"{\r\n backgroundColor: (currentPath() | menuFocus: node) ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n <div aria-hidden=\"true\" class=\"c-menu-node-description\" (click)=\"navigate(node)\" [class.d-none]=\"!isShowSidebar()\">\r\n <div\r\n class=\"c-menu-node-description-content\"\r\n [ngStyle]=\"{\r\n color: (currentPath() | menuFocus: node) ? _sidebar.brandColor || '#2962FF' : '#1F1F1F',\r\n }\"\r\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\r\n </div>\r\n </li>\r\n </mat-nested-tree-node>\r\n\r\n <mat-nested-tree-node\r\n *matTreeNodeDef=\"let node; when: hasChild\"\r\n aria-hidden=\"true\"\r\n [class]=\"{ expanded: treeControl.isExpanded(node), isfocus: currentPath() | menuFocus: node }\">\r\n <li>\r\n <div\r\n class=\"c-menu-node\"\r\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\r\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\">\r\n <div class=\"d-flex align-items-center\" style=\"gap: 10px; width: 100%\">\r\n <div [class.d-none]=\"!isShowSidebar()\" class=\"c-menu-node-description\" (click)=\"onToggleMenuNode(node)\">\r\n <div\r\n class=\"c-menu-node-description-content\"\r\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\r\n <mat-icon class=\"c-menu-node-description-icon-expand\">\r\n {{ treeControl.isExpanded(node) ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\r\n </mat-icon>\r\n </div>\r\n </div>\r\n </div>\r\n <ul class=\"p-0\" [class.d-none]=\"!treeControl.isExpanded(node)\">\r\n <ng-container matTreeNodeOutlet></ng-container>\r\n </ul>\r\n </li>\r\n </mat-nested-tree-node>\r\n </mat-tree>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"c-footer\">\r\n <lib-layout-user\r\n [userInfo]=\"_userInfo\"\r\n [isMobileOrTablet]=\"isMobileOrTablet\"\r\n (menuOpened)=\"onUserMenuOpened()\"\r\n (menuClosed)=\"onUserMenuClosed()\"\r\n [isShowSidebar]=\"isShowSidebar()\"\r\n (toggleMenuLock)=\"toggleMenuLock($event)\">\r\n </lib-layout-user>\r\n </div>\r\n\r\n <div class=\"c-vertical\"></div>\r\n </div>\r\n}", styles: ["::ng-deep .mat-mdc-tooltip-panel:has(.c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140){pointer-events:none}:host ::ng-deep .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:16px!important}:host ::ng-deep .mat-nested-tree-node ul .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:32px!important}:host ::ng-deep .mat-nested-tree-node ul .mat-nested-tree-node ul .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:48px!important}ul,li{margin-top:0;margin-bottom:0;list-style-type:none}.wrapper{display:flex;flex-direction:column;width:290px;background-color:#fff}.wrapper .c-header{display:flex;align-items:center;height:52px;padding:3px;gap:16px}.wrapper .c-header .c-logo{display:flex;justify-content:center;align-items:center;width:52px;height:52px}.wrapper .c-header .c-logo img{width:32px;height:32px;object-fit:cover}.wrapper .c-header .c-title-menu-group{display:flex;align-items:center;font-size:18px;font-weight:500;flex:1}.wrapper .c-body{flex:1;overflow-y:hidden}.wrapper .c-body .c-menu{height:100%;display:flex}.wrapper .c-body .c-menu .c-menu-group{display:flex;flex-direction:column;align-items:center;width:60px;overflow-y:scroll;scrollbar-width:none}.wrapper .c-body .c-menu .c-menu-group .c-menu-group-icon{display:flex;justify-content:center;align-items:center;min-height:50px;width:52px;border-radius:8px;transition:all .15s}.wrapper .c-body .c-menu .c-menu-group .c-menu-group-icon img{height:24px;width:24px;object-fit:contain}.wrapper .c-body .c-menu .c-menu-tree{flex:1;display:flex;flex-direction:column;padding:3px 4px 3px 3px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon{cursor:pointer;color:#757575;padding:0}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon.search{width:20px;height:20px;font-size:18px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon.cancel{width:16px;height:16px;font-size:16px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container{flex:1;overflow-y:scroll;scrollbar-width:none}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node{width:100%;display:flex;cursor:pointer;min-height:44px;padding:8px;border-radius:8px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-icon{display:flex;justify-content:center;align-items:center;height:100%}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description{flex:1;display:flex;align-items:center}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-content{flex:1;display:flex;align-items:center;flex-wrap:wrap;white-space:pre-wrap;font-size:15px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-expand{text-align:left;background-color:transparent;border:none;font-size:20px}.wrapper .c-footer{height:80px}.wrapper .c-vertical{position:fixed;height:100vh;left:58px;width:2px;background-color:#f8f9fa;pointer-events:none}\n"] }]
|
|
747
747
|
}], ctorParameters: () => [] });
|
|
748
748
|
|
|
@@ -866,30 +866,283 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
866
866
|
args: [{ selector: 'sidebar-v1', imports: [MatSidenavModule, CommonModule, SidebarComponent], standalone: true, template: "<mat-sidenav-container class=\"c-layout-wrapper\">\r\n <mat-sidenav\r\n #sidenav\r\n [opened]=\"isShowSidebar()\"\r\n (openedChange)=\"isShowSidebar.set($event)\"\r\n class=\"c-layout-sidebar\"\r\n (click)=\"openSidebar()\"\r\n (mouseleave)=\"onMouseleaveSideBar()\"\r\n [mode]=\"isMobileOrTablet() ? 'over' : 'side'\"\r\n [fixedInViewport]=\"isMobileOrTablet()\">\r\n <sidebar\r\n [menus]=\"menus()\"\r\n [userInfo]=\"userInfo()\"\r\n [sidebar]=\"sidebar()\"\r\n [isShowSidebar]=\"isShowSidebar()\"\r\n (showSideBar)=\"onToggle($event)\"\r\n (expandSideBar)=\"onExpandSideBar()\"\r\n (popupUserMenuOpened)=\"onPopupOfSideBarOpened()\"\r\n (popupUserMenuClosed)=\"onPopupOfSideBarClosed()\">\r\n </sidebar>\r\n </mat-sidenav>\r\n\r\n <mat-sidenav-content class=\"c-layout-content\" [class.isShowSidebar]=\"isMenuLock()\">\r\n <mat-drawer-container class=\"c-mat-drawer-container\">\r\n <mat-drawer-content>\r\n <ng-content></ng-content>\r\n </mat-drawer-content>\r\n </mat-drawer-container>\r\n </mat-sidenav-content>\r\n</mat-sidenav-container>", styles: [":host ::ng-deep .c-layout-wrapper{width:100%}:host ::ng-deep .c-layout-wrapper .c-layout-sidebar{margin-top:0;width:60px;height:100vh!important;transform:none!important;overflow:hidden!important;visibility:visible!important;transition:width .15s!important;box-shadow:0 0 6px #0003!important}:host ::ng-deep .c-layout-wrapper .c-layout-sidebar .mat-drawer-inner-container{position:relative;overflow:visible;display:block!important}:host ::ng-deep .c-layout-wrapper .c-layout-sidebar.mat-drawer-opened{width:290px;transition:width .15s}:host ::ng-deep .c-layout-wrapper .c-layout-content{background-color:#fff;box-sizing:border-box;height:100vh!important;margin-left:60px!important}:host ::ng-deep .c-layout-wrapper .c-layout-content.isShowSidebar{margin-left:290px!important}:host ::ng-deep .c-layout-wrapper .c-layout-content .c-mat-drawer-container{height:100%}\n"] }]
|
|
867
867
|
}], ctorParameters: () => [] });
|
|
868
868
|
|
|
869
|
+
class LayoutUserComponent {
|
|
870
|
+
// ==========================================
|
|
871
|
+
// INJECT SERVICES
|
|
872
|
+
// ==========================================
|
|
873
|
+
#layoutConfiguration = inject(SD_LAYOUT_CONFIGURATION);
|
|
874
|
+
// ==========================================
|
|
875
|
+
// SIGNAL INPUTS & OUTPUTS
|
|
876
|
+
// ==========================================
|
|
877
|
+
isMobileOrTablet = input(false);
|
|
878
|
+
isMenuLock = input(false);
|
|
879
|
+
isShowSidebar = input(false);
|
|
880
|
+
userInfo = input.required();
|
|
881
|
+
menuClosed = output();
|
|
882
|
+
menuOpened = output();
|
|
883
|
+
toggleMenuLock = output();
|
|
884
|
+
// Config actions
|
|
885
|
+
singoutLayoutConfig = this.#layoutConfiguration.signout;
|
|
886
|
+
changePasswordLayoutConfig = this.#layoutConfiguration?.changePassword;
|
|
887
|
+
// Accordion state for mobile inline expand
|
|
888
|
+
isExpanded = signal(false);
|
|
889
|
+
// ==========================================
|
|
890
|
+
// EVENT HANDLERS
|
|
891
|
+
// ==========================================
|
|
892
|
+
onMenuOpened = () => {
|
|
893
|
+
this.menuOpened.emit();
|
|
894
|
+
};
|
|
895
|
+
onMenuClosed = () => {
|
|
896
|
+
this.menuClosed.emit();
|
|
897
|
+
};
|
|
898
|
+
keepOpenWhenClickInsideMenu = (event) => {
|
|
899
|
+
event.stopPropagation();
|
|
900
|
+
};
|
|
901
|
+
toggleExpanded = () => {
|
|
902
|
+
this.isExpanded.update(v => !v);
|
|
903
|
+
if (this.isExpanded()) {
|
|
904
|
+
this.menuOpened.emit();
|
|
905
|
+
}
|
|
906
|
+
else {
|
|
907
|
+
this.menuClosed.emit();
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
logout = () => {
|
|
911
|
+
this.singoutLayoutConfig();
|
|
912
|
+
};
|
|
913
|
+
changePassword = () => {
|
|
914
|
+
this.changePasswordLayoutConfig?.();
|
|
915
|
+
};
|
|
916
|
+
onToggleMenuLock = (event) => {
|
|
917
|
+
this.toggleMenuLock.emit(event);
|
|
918
|
+
};
|
|
919
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LayoutUserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
920
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: LayoutUserComponent, isStandalone: true, selector: "lib-layout-user", inputs: { isMobileOrTablet: { classPropertyName: "isMobileOrTablet", publicName: "isMobileOrTablet", isSignal: true, isRequired: false, transformFunction: null }, isMenuLock: { classPropertyName: "isMenuLock", publicName: "isMenuLock", isSignal: true, isRequired: false, transformFunction: null }, isShowSidebar: { classPropertyName: "isShowSidebar", publicName: "isShowSidebar", isSignal: true, isRequired: false, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { menuClosed: "menuClosed", menuOpened: "menuOpened", toggleMenuLock: "toggleMenuLock" }, ngImport: i0, template: "@let _userInfo = userInfo();\r\n@let avatar = _userInfo?.avatar || _userInfo?.fullName || _userInfo?.username || _userInfo?.email;\r\n\r\n@if (isMobileOrTablet()) {\r\n <!-- Mobile: accordion inline expand -->\r\n <div class=\"m-user-card\">\r\n <button class=\"m-user-row\" (click)=\"toggleExpanded()\">\r\n <sd-avatar [src]=\"avatar\" [size]=\"44\"></sd-avatar>\r\n <div class=\"m-user-info\">\r\n <span class=\"m-user-name\">{{ _userInfo?.fullName || _userInfo?.username }}</span>\r\n @if (_userInfo?.email) {\r\n <span class=\"m-user-email\">{{ _userInfo?.email }}</span>\r\n }\r\n </div>\r\n <mat-icon class=\"m-expand-icon\" [class.m-expand-icon--open]=\"isExpanded()\">\r\n keyboard_arrow_down\r\n </mat-icon>\r\n </button>\r\n\r\n @if (isExpanded()) {\r\n <div class=\"m-user-body\">\r\n @if (changePasswordLayoutConfig) {\r\n <button class=\"m-user-action\" (click)=\"changePassword()\">\r\n <mat-icon>lock_outline</mat-icon>\r\n <span>\u0110\u1ED5i m\u1EADt kh\u1EA9u</span>\r\n </button>\r\n }\r\n <button class=\"m-user-action m-user-action--logout\" (click)=\"logout()\">\r\n <mat-icon>logout</mat-icon>\r\n <span>\u0110\u0103ng xu\u1EA5t</span>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n} @else {\r\n <!-- Desktop: ch\u1EC9 hi\u1EC3n th\u1ECB avatar + n\u00FAt toggle -->\r\n <div class=\"c-layout-user-wrapper\">\r\n <div class=\"c-layout-user-avatar\" [matMenuTriggerFor]=\"userMenu\" (menuClosed)=\"onMenuClosed()\" (menuOpened)=\"onMenuOpened()\">\r\n <sd-avatar [src]=\"avatar\" [size]=\"32\"></sd-avatar>\r\n </div>\r\n\r\n <div aria-hidden=\"true\" mat-mini-fab class=\"c-layout-icon-toggle\" (click)=\"onToggleMenuLock($event)\">\r\n <mat-icon style=\"color: #8c8c8c\">\r\n {{ isShowSidebar() ? 'keyboard_arrow_right' : 'keyboard_arrow_left' }}\r\n </mat-icon>\r\n </div>\r\n </div>\r\n}\r\n\r\n<mat-menu #userMenu=\"matMenu\" xPosition=\"before\" backdropClass=\"c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0\">\r\n <div aria-hidden=\"true\" class=\"c-user-menu-wrapper\" (click)=\"keepOpenWhenClickInsideMenu($event)\">\r\n <div class=\"c-user-info-wrapper\">\r\n <div class=\"c-user-avatar\">\r\n <sd-avatar [src]=\"avatar\" [size]=\"40\"></sd-avatar>\r\n </div>\r\n <span class=\"c-user-name\">{{ _userInfo?.fullName || _userInfo?.username }}</span>\r\n <span class=\"c-user-email\">{{ _userInfo?.email }}</span>\r\n </div>\r\n\r\n @if (changePasswordLayoutConfig) {\r\n <div class=\"c-sign-button-wrapper\">\r\n <button class=\"c-account-options\" (click)=\"changePassword()\">\r\n <img alt=\"lock\" />\r\n <span>\u0110\u1ED5i m\u1EADt kh\u1EA9u</span>\r\n </button>\r\n </div>\r\n }\r\n\r\n <div class=\"c-sign-button-wrapper\">\r\n <button class=\"c-sign-button\" mat-flat-button (click)=\"logout()\">\u0110\u0103ng xu\u1EA5t</button>\r\n </div>\r\n </div>\r\n</mat-menu>\r\n", styles: ["@media(min-width:1024px){::ng-deep .c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0+* .cdk-overlay-pane{transform:translate(277px,83px)}}.m-user-card{width:100%}.m-user-row{display:flex;align-items:center;gap:12px;width:100%;padding:0;border:none;background:transparent;cursor:pointer;text-align:left;-webkit-tap-highlight-color:transparent}.m-user-info{flex:1;display:flex;flex-direction:column;gap:2px;overflow:hidden}.m-user-name{font-size:15px;font-weight:600;color:#1f1f1f;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.m-user-email{font-size:13px;color:#8c8c8c;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.m-expand-icon{color:#8c8c8c;flex-shrink:0;transition:transform .2s ease}.m-expand-icon--open{transform:rotate(180deg)}.m-user-body{margin-top:8px;border-top:1px solid #EBEBEB;padding-top:4px;display:flex;flex-direction:column}.m-user-action{display:flex;align-items:center;gap:12px;width:100%;padding:12px 4px;border:none;background:transparent;cursor:pointer;font-size:15px;color:#1f1f1f;-webkit-tap-highlight-color:transparent}.m-user-action mat-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}.m-user-action:active{background-color:#f5f5f5}.m-user-action--logout{color:#e53935}.m-user-action--logout mat-icon{color:#e53935}.c-layout-user-wrapper{display:flex;flex-direction:column;align-items:center;width:60px;height:80px}.c-layout-user-wrapper .c-layout-user-avatar{width:32px;height:32px;display:flex;align-items:center;justify-content:center;cursor:pointer}.c-layout-user-wrapper .c-layout-icon-toggle{background-color:transparent;border-top:1px solid #f0f0f0;box-shadow:none;margin-top:10px;width:32px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer}.c-user-menu-wrapper .c-user-info-wrapper{width:250px;padding:16px;display:flex;flex-direction:column;align-items:center;gap:8px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-avatar{width:40px;height:40px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-name{font-size:16px;font-weight:700;text-align:center}.c-user-menu-wrapper .c-user-info-wrapper .c-user-email{font-size:14px;color:#7a7a7a;text-align:center}.c-user-menu-wrapper .c-sign-button-wrapper{text-align:center;padding:16px 16px 8px;width:100%;border-top:1px solid #dee2e6}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options{all:unset;cursor:pointer;font-size:14px;display:flex;align-items:center;gap:8px}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options img{scale:.875;content:url('data:image/svg+xml,<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">%0D%0A <path%0D%0A d=\"M12 5.66667H11.3333V4.33333C11.3333 2.49333 9.83996 1 7.99996 1C6.15996 1 4.66663 2.49333 4.66663 4.33333V5.66667H3.99996C3.26663 5.66667 2.66663 6.26667 2.66663 7V13.6667C2.66663 14.4 3.26663 15 3.99996 15H12C12.7333 15 13.3333 14.4 13.3333 13.6667V7C13.3333 6.26667 12.7333 5.66667 12 5.66667ZM5.99996 4.33333C5.99996 3.22667 6.89329 2.33333 7.99996 2.33333C9.10663 2.33333 9.99996 3.22667 9.99996 4.33333V5.66667H5.99996V4.33333ZM12 13.6667H3.99996V7H12V13.6667ZM7.99996 11.6667C8.73329 11.6667 9.33329 11.0667 9.33329 10.3333C9.33329 9.6 8.73329 9 7.99996 9C7.26663 9 6.66663 9.6 6.66663 10.3333C6.66663 11.0667 7.26663 11.6667 7.99996 11.6667Z\"%0D%0A fill=\"%23757575\" />%0D%0A</svg>')}.c-user-menu-wrapper .c-sign-button-wrapper .c-sign-button{width:100%;color:#000;padding:16px;font-weight:700;background-color:#eef0f2}.c-avatar{max-width:100%;object-fit:cover}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: i1$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "component", type: SdAvatar, selector: "sd-avatar", inputs: ["src", "size"] }] });
|
|
921
|
+
}
|
|
922
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LayoutUserComponent, decorators: [{
|
|
923
|
+
type: Component,
|
|
924
|
+
args: [{ selector: 'lib-layout-user', imports: [MatMenuModule, MatButtonModule, MatIconModule, MatTooltipModule, SdAvatar], standalone: true, template: "@let _userInfo = userInfo();\r\n@let avatar = _userInfo?.avatar || _userInfo?.fullName || _userInfo?.username || _userInfo?.email;\r\n\r\n@if (isMobileOrTablet()) {\r\n <!-- Mobile: accordion inline expand -->\r\n <div class=\"m-user-card\">\r\n <button class=\"m-user-row\" (click)=\"toggleExpanded()\">\r\n <sd-avatar [src]=\"avatar\" [size]=\"44\"></sd-avatar>\r\n <div class=\"m-user-info\">\r\n <span class=\"m-user-name\">{{ _userInfo?.fullName || _userInfo?.username }}</span>\r\n @if (_userInfo?.email) {\r\n <span class=\"m-user-email\">{{ _userInfo?.email }}</span>\r\n }\r\n </div>\r\n <mat-icon class=\"m-expand-icon\" [class.m-expand-icon--open]=\"isExpanded()\">\r\n keyboard_arrow_down\r\n </mat-icon>\r\n </button>\r\n\r\n @if (isExpanded()) {\r\n <div class=\"m-user-body\">\r\n @if (changePasswordLayoutConfig) {\r\n <button class=\"m-user-action\" (click)=\"changePassword()\">\r\n <mat-icon>lock_outline</mat-icon>\r\n <span>\u0110\u1ED5i m\u1EADt kh\u1EA9u</span>\r\n </button>\r\n }\r\n <button class=\"m-user-action m-user-action--logout\" (click)=\"logout()\">\r\n <mat-icon>logout</mat-icon>\r\n <span>\u0110\u0103ng xu\u1EA5t</span>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n} @else {\r\n <!-- Desktop: ch\u1EC9 hi\u1EC3n th\u1ECB avatar + n\u00FAt toggle -->\r\n <div class=\"c-layout-user-wrapper\">\r\n <div class=\"c-layout-user-avatar\" [matMenuTriggerFor]=\"userMenu\" (menuClosed)=\"onMenuClosed()\" (menuOpened)=\"onMenuOpened()\">\r\n <sd-avatar [src]=\"avatar\" [size]=\"32\"></sd-avatar>\r\n </div>\r\n\r\n <div aria-hidden=\"true\" mat-mini-fab class=\"c-layout-icon-toggle\" (click)=\"onToggleMenuLock($event)\">\r\n <mat-icon style=\"color: #8c8c8c\">\r\n {{ isShowSidebar() ? 'keyboard_arrow_right' : 'keyboard_arrow_left' }}\r\n </mat-icon>\r\n </div>\r\n </div>\r\n}\r\n\r\n<mat-menu #userMenu=\"matMenu\" xPosition=\"before\" backdropClass=\"c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0\">\r\n <div aria-hidden=\"true\" class=\"c-user-menu-wrapper\" (click)=\"keepOpenWhenClickInsideMenu($event)\">\r\n <div class=\"c-user-info-wrapper\">\r\n <div class=\"c-user-avatar\">\r\n <sd-avatar [src]=\"avatar\" [size]=\"40\"></sd-avatar>\r\n </div>\r\n <span class=\"c-user-name\">{{ _userInfo?.fullName || _userInfo?.username }}</span>\r\n <span class=\"c-user-email\">{{ _userInfo?.email }}</span>\r\n </div>\r\n\r\n @if (changePasswordLayoutConfig) {\r\n <div class=\"c-sign-button-wrapper\">\r\n <button class=\"c-account-options\" (click)=\"changePassword()\">\r\n <img alt=\"lock\" />\r\n <span>\u0110\u1ED5i m\u1EADt kh\u1EA9u</span>\r\n </button>\r\n </div>\r\n }\r\n\r\n <div class=\"c-sign-button-wrapper\">\r\n <button class=\"c-sign-button\" mat-flat-button (click)=\"logout()\">\u0110\u0103ng xu\u1EA5t</button>\r\n </div>\r\n </div>\r\n</mat-menu>\r\n", styles: ["@media(min-width:1024px){::ng-deep .c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0+* .cdk-overlay-pane{transform:translate(277px,83px)}}.m-user-card{width:100%}.m-user-row{display:flex;align-items:center;gap:12px;width:100%;padding:0;border:none;background:transparent;cursor:pointer;text-align:left;-webkit-tap-highlight-color:transparent}.m-user-info{flex:1;display:flex;flex-direction:column;gap:2px;overflow:hidden}.m-user-name{font-size:15px;font-weight:600;color:#1f1f1f;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.m-user-email{font-size:13px;color:#8c8c8c;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.m-expand-icon{color:#8c8c8c;flex-shrink:0;transition:transform .2s ease}.m-expand-icon--open{transform:rotate(180deg)}.m-user-body{margin-top:8px;border-top:1px solid #EBEBEB;padding-top:4px;display:flex;flex-direction:column}.m-user-action{display:flex;align-items:center;gap:12px;width:100%;padding:12px 4px;border:none;background:transparent;cursor:pointer;font-size:15px;color:#1f1f1f;-webkit-tap-highlight-color:transparent}.m-user-action mat-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}.m-user-action:active{background-color:#f5f5f5}.m-user-action--logout{color:#e53935}.m-user-action--logout mat-icon{color:#e53935}.c-layout-user-wrapper{display:flex;flex-direction:column;align-items:center;width:60px;height:80px}.c-layout-user-wrapper .c-layout-user-avatar{width:32px;height:32px;display:flex;align-items:center;justify-content:center;cursor:pointer}.c-layout-user-wrapper .c-layout-icon-toggle{background-color:transparent;border-top:1px solid #f0f0f0;box-shadow:none;margin-top:10px;width:32px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer}.c-user-menu-wrapper .c-user-info-wrapper{width:250px;padding:16px;display:flex;flex-direction:column;align-items:center;gap:8px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-avatar{width:40px;height:40px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-name{font-size:16px;font-weight:700;text-align:center}.c-user-menu-wrapper .c-user-info-wrapper .c-user-email{font-size:14px;color:#7a7a7a;text-align:center}.c-user-menu-wrapper .c-sign-button-wrapper{text-align:center;padding:16px 16px 8px;width:100%;border-top:1px solid #dee2e6}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options{all:unset;cursor:pointer;font-size:14px;display:flex;align-items:center;gap:8px}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options img{scale:.875;content:url('data:image/svg+xml,<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">%0D%0A <path%0D%0A d=\"M12 5.66667H11.3333V4.33333C11.3333 2.49333 9.83996 1 7.99996 1C6.15996 1 4.66663 2.49333 4.66663 4.33333V5.66667H3.99996C3.26663 5.66667 2.66663 6.26667 2.66663 7V13.6667C2.66663 14.4 3.26663 15 3.99996 15H12C12.7333 15 13.3333 14.4 13.3333 13.6667V7C13.3333 6.26667 12.7333 5.66667 12 5.66667ZM5.99996 4.33333C5.99996 3.22667 6.89329 2.33333 7.99996 2.33333C9.10663 2.33333 9.99996 3.22667 9.99996 4.33333V5.66667H5.99996V4.33333ZM12 13.6667H3.99996V7H12V13.6667ZM7.99996 11.6667C8.73329 11.6667 9.33329 11.0667 9.33329 10.3333C9.33329 9.6 8.73329 9 7.99996 9C7.26663 9 6.66663 9.6 6.66663 10.3333C6.66663 11.0667 7.26663 11.6667 7.99996 11.6667Z\"%0D%0A fill=\"%23757575\" />%0D%0A</svg>')}.c-user-menu-wrapper .c-sign-button-wrapper .c-sign-button{width:100%;color:#000;padding:16px;font-weight:700;background-color:#eef0f2}.c-avatar{max-width:100%;object-fit:cover}\n"] }]
|
|
925
|
+
}] });
|
|
926
|
+
|
|
927
|
+
class SidebarMobileOverlayComponent {
|
|
928
|
+
#router = inject(Router);
|
|
929
|
+
#destroyRef = inject(DestroyRef);
|
|
930
|
+
#layoutStorageService = inject(SdLayoutStorageService);
|
|
931
|
+
// ==========================================
|
|
932
|
+
// INPUTS & OUTPUTS
|
|
933
|
+
// ==========================================
|
|
934
|
+
isShowSidebar = input(false);
|
|
935
|
+
menus = input.required();
|
|
936
|
+
userInfo = input.required();
|
|
937
|
+
sidebar = input.required();
|
|
938
|
+
// showSideBar(null) = đóng sidebar (tương thích với onToggle của main component)
|
|
939
|
+
showSideBar = output();
|
|
940
|
+
expandSideBar = output();
|
|
941
|
+
popupUserMenuOpened = output();
|
|
942
|
+
popupUserMenuClosed = output();
|
|
943
|
+
titleMenuGroupChanged = output();
|
|
944
|
+
// ==========================================
|
|
945
|
+
// STATE SIGNALS
|
|
946
|
+
// ==========================================
|
|
947
|
+
titleMenuGroup = signal('');
|
|
948
|
+
currentPath = signal(window.location.pathname);
|
|
949
|
+
// Lưu danh sách ID các menu group đang được mở
|
|
950
|
+
expandedMobileGroups = signal(new Set());
|
|
951
|
+
constructor() {
|
|
952
|
+
// Bind title khi menus thay đổi
|
|
953
|
+
effect(() => {
|
|
954
|
+
const currentMenus = this.menus();
|
|
955
|
+
untracked(() => {
|
|
956
|
+
const lastActiveMenuGroupId = this.#layoutStorageService.lastActiveMenuGroupId.get();
|
|
957
|
+
if (!lastActiveMenuGroupId) {
|
|
958
|
+
this.#layoutStorageService.lastActiveMenuGroupId.set(currentMenus?.[0]?.id ?? '');
|
|
959
|
+
}
|
|
960
|
+
this.#bindingMenuGroupByCurrentPath(currentMenus);
|
|
961
|
+
});
|
|
962
|
+
});
|
|
963
|
+
// Bind title khi điều hướng
|
|
964
|
+
this.#router.events.pipe(takeUntilDestroyed(this.#destroyRef)).subscribe(event => {
|
|
965
|
+
if (event instanceof NavigationEnd) {
|
|
966
|
+
if (this.currentPath() !== window.location.pathname) {
|
|
967
|
+
this.currentPath.set(window.location.pathname);
|
|
968
|
+
this.#bindingMenuGroupByCurrentPath(this.menus());
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
// ==========================================
|
|
974
|
+
// EVENT HANDLERS
|
|
975
|
+
// ==========================================
|
|
976
|
+
toggleMobileGroup(groupId) {
|
|
977
|
+
if (!groupId)
|
|
978
|
+
return;
|
|
979
|
+
this.expandedMobileGroups.update(groups => {
|
|
980
|
+
const newGroups = new Set(groups);
|
|
981
|
+
if (newGroups.has(groupId)) {
|
|
982
|
+
newGroups.delete(groupId);
|
|
983
|
+
}
|
|
984
|
+
else {
|
|
985
|
+
newGroups.add(groupId);
|
|
986
|
+
}
|
|
987
|
+
return newGroups;
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
isExpanded(groupId) {
|
|
991
|
+
if (!groupId)
|
|
992
|
+
return false;
|
|
993
|
+
return this.expandedMobileGroups().has(groupId);
|
|
994
|
+
}
|
|
995
|
+
navigate(args) {
|
|
996
|
+
const { path, queryParams } = args;
|
|
997
|
+
if (!path)
|
|
998
|
+
return;
|
|
999
|
+
if (path.includes('http')) {
|
|
1000
|
+
window.open(path);
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
this.#router.navigate([path.split('?')[0]], {
|
|
1004
|
+
queryParams: queryParams ?? {},
|
|
1005
|
+
state: { switchTab: true },
|
|
1006
|
+
});
|
|
1007
|
+
// Sau khi điều hướng trên mobile, tự động đóng sidebar
|
|
1008
|
+
this.onClose();
|
|
1009
|
+
}
|
|
1010
|
+
onClose() {
|
|
1011
|
+
this.showSideBar.emit(null);
|
|
1012
|
+
}
|
|
1013
|
+
// Kiểm tra menu có children (là SdLayoutChildrenMenu)
|
|
1014
|
+
hasChildren(menu) {
|
|
1015
|
+
return 'children' in menu && !!menu.children?.length;
|
|
1016
|
+
}
|
|
1017
|
+
// Lấy danh sách children an toàn (type-safe)
|
|
1018
|
+
getChildren(menu) {
|
|
1019
|
+
return 'children' in menu ? (menu.children ?? []) : [];
|
|
1020
|
+
}
|
|
1021
|
+
// Lấy path an toàn từ leaf menu (SdLayoutRootMenu)
|
|
1022
|
+
getPath(menu) {
|
|
1023
|
+
return 'path' in menu ? menu.path : undefined;
|
|
1024
|
+
}
|
|
1025
|
+
// Lấy queryParams an toàn từ leaf menu
|
|
1026
|
+
getQueryParams(menu) {
|
|
1027
|
+
return ('queryParams' in menu ? menu.queryParams : undefined) ?? {};
|
|
1028
|
+
}
|
|
1029
|
+
onUserMenuOpened = () => this.popupUserMenuOpened.emit();
|
|
1030
|
+
onUserMenuClosed = () => this.popupUserMenuClosed.emit();
|
|
1031
|
+
// ==========================================
|
|
1032
|
+
// PRIVATE LOGIC
|
|
1033
|
+
// ==========================================
|
|
1034
|
+
#bindingMenuGroupByCurrentPath = (menus) => {
|
|
1035
|
+
let menuGroupByPath = this.#getMenuGroupByCurrentPath(menus);
|
|
1036
|
+
if (!menuGroupByPath?.length) {
|
|
1037
|
+
const lastActiveId = this.#layoutStorageService.lastActiveMenuGroupId.get() || '';
|
|
1038
|
+
menuGroupByPath = menus?.filter(menu => menu?.id === lastActiveId) || [];
|
|
1039
|
+
}
|
|
1040
|
+
if (menuGroupByPath?.length) {
|
|
1041
|
+
const matchedGroup = menuGroupByPath[0];
|
|
1042
|
+
this.#layoutStorageService.lastActiveMenuGroupId.set(matchedGroup?.id || '');
|
|
1043
|
+
const title = matchedGroup?.tooltipTitle || matchedGroup?.title;
|
|
1044
|
+
this.titleMenuGroup.set(title);
|
|
1045
|
+
this.titleMenuGroupChanged.emit(title);
|
|
1046
|
+
}
|
|
1047
|
+
else {
|
|
1048
|
+
this.titleMenuGroup.set('');
|
|
1049
|
+
this.titleMenuGroupChanged.emit('');
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
#getMenuGroupByCurrentPath = (menus, menuGroup) => {
|
|
1053
|
+
for (const menu of menus) {
|
|
1054
|
+
if ('path' in menu && this.#isMenuPathMatchByCurrentPath(menu.path)) {
|
|
1055
|
+
return [menuGroup ?? menu];
|
|
1056
|
+
}
|
|
1057
|
+
if ('children' in menu && menu.children?.length) {
|
|
1058
|
+
const result = this.#getMenuGroupByCurrentPath(menu.children, menuGroup ?? menu);
|
|
1059
|
+
if (result?.length)
|
|
1060
|
+
return result;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
return [];
|
|
1064
|
+
};
|
|
1065
|
+
#isMenuPathMatchByCurrentPath = (path) => {
|
|
1066
|
+
if (!path)
|
|
1067
|
+
return false;
|
|
1068
|
+
if (this.currentPath() === path)
|
|
1069
|
+
return true;
|
|
1070
|
+
return this.#normalizePath(this.currentPath()).startsWith(this.#normalizePath(path));
|
|
1071
|
+
};
|
|
1072
|
+
#normalizePath = (p) => p.endsWith('/') ? p : p + '/';
|
|
1073
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SidebarMobileOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1074
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SidebarMobileOverlayComponent, isStandalone: true, selector: "sd-sidebar-mobile-overlay", inputs: { isShowSidebar: { classPropertyName: "isShowSidebar", publicName: "isShowSidebar", isSignal: true, isRequired: false, transformFunction: null }, menus: { classPropertyName: "menus", publicName: "menus", isSignal: true, isRequired: true, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { showSideBar: "showSideBar", expandSideBar: "expandSideBar", popupUserMenuOpened: "popupUserMenuOpened", popupUserMenuClosed: "popupUserMenuClosed", titleMenuGroupChanged: "titleMenuGroupChanged" }, ngImport: i0, template: "@let _userInfo = userInfo();\r\n@let _sidebar = sidebar();\r\n\r\n@if (_userInfo && _sidebar) {\r\n <div\r\n class=\"m-backdrop\"\r\n [class.m-backdrop--visible]=\"isShowSidebar()\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n (click)=\"onClose()\"\r\n (keydown.escape)=\"onClose()\">\r\n </div>\r\n\r\n <div class=\"m-wrapper\" [class.m-wrapper--open]=\"isShowSidebar()\">\r\n <div class=\"m-header\">\r\n <div class=\"m-title-group\">\r\n @if (_sidebar.logoUrl) {\r\n <img class=\"m-logo\" alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\r\n }\r\n <span class=\"m-title\">{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\r\n </div>\r\n <button class=\"m-close-btn\" (click)=\"onClose()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"m-user-section\">\r\n <lib-layout-user\r\n [userInfo]=\"_userInfo\"\r\n [isMobileOrTablet]=\"true\"\r\n (menuOpened)=\"onUserMenuOpened()\"\r\n (menuClosed)=\"onUserMenuClosed()\">\r\n </lib-layout-user>\r\n </div>\r\n\r\n <div class=\"m-menu-list\">\r\n @for (group of menus(); track group.id) {\r\n <div class=\"m-menu-card\">\r\n <button class=\"m-card-header\" (click)=\"toggleMobileGroup(group.id)\">\r\n <div class=\"m-card-header-left\">\r\n @if (group.iconUrl) {\r\n <img class=\"m-group-icon\" [src]=\"group.iconUrl\" [alt]=\"group.title\" />\r\n } @else {\r\n <mat-icon class=\"m-group-icon\">{{ group.icon || 'widgets' }}</mat-icon>\r\n }\r\n <span class=\"m-group-title\">{{ group.title }}</span>\r\n </div>\r\n <mat-icon class=\"m-expand-icon\">\r\n {{ expandedMobileGroups().has(group.id ?? '') ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\r\n </mat-icon>\r\n </button>\r\n\r\n @if (expandedMobileGroups().has(group.id ?? '') && hasChildren(group)) {\r\n <div class=\"m-card-body\">\r\n @for (child of getChildren(group); track child.id) {\r\n @if (hasChildren(child)) {\r\n <div class=\"m-sub-group\">\r\n <button class=\"m-sub-group-header\" (click)=\"toggleMobileGroup(child.id)\">\r\n <div class=\"m-item-left\">\r\n @if (child.iconUrl) {\r\n <img class=\"m-item-icon-img\" [src]=\"child.iconUrl\" alt=\"icon\" />\r\n } @else {\r\n <mat-icon class=\"m-item-icon\">{{ child.icon || 'folder' }}</mat-icon>\r\n }\r\n <span class=\"m-item-title\">{{ child.title }}</span>\r\n </div>\r\n <mat-icon class=\"m-expand-icon\">\r\n {{ expandedMobileGroups().has(child.id ?? '') ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\r\n </mat-icon>\r\n </button>\r\n @if (expandedMobileGroups().has(child.id ?? '')) {\r\n @for (subChild of getChildren(child); track subChild.id) {\r\n <button class=\"m-menu-item m-menu-item--indented\"\r\n (click)=\"navigate({ path: getPath(subChild), queryParams: getQueryParams(subChild) })\">\r\n <div class=\"m-item-left\">\r\n @if (subChild.iconUrl) {\r\n <img class=\"m-item-icon-img\" [src]=\"subChild.iconUrl\" alt=\"icon\" />\r\n } @else {\r\n <mat-icon class=\"m-item-icon\">{{ subChild.icon || 'insert_drive_file' }}</mat-icon>\r\n }\r\n <span class=\"m-item-title\">{{ subChild.title }}</span>\r\n </div>\r\n <mat-icon class=\"m-nav-icon\">chevron_right</mat-icon>\r\n </button>\r\n }\r\n }\r\n </div>\r\n } @else {\r\n <button class=\"m-menu-item\" (click)=\"navigate({ path: getPath(child), queryParams: getQueryParams(child) })\">\r\n <div class=\"m-item-left\">\r\n @if (child.iconUrl) {\r\n <img class=\"m-item-icon-img\" [src]=\"child.iconUrl\" alt=\"icon\" />\r\n } @else {\r\n <mat-icon class=\"m-item-icon\">{{ child.icon || 'insert_drive_file' }}</mat-icon>\r\n }\r\n <span class=\"m-item-title\">{{ child.title }}</span>\r\n </div>\r\n <mat-icon class=\"m-nav-icon\">chevron_right</mat-icon>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n}\r\n", styles: [":host{display:block;position:fixed;inset:0;z-index:1000;pointer-events:none}.m-backdrop{position:absolute;inset:0;background:#0006;opacity:0;pointer-events:none;transition:opacity .3s ease;cursor:pointer;outline:none}.m-backdrop--visible{opacity:1;pointer-events:auto}.m-wrapper{display:flex;flex-direction:column;position:absolute;inset:0;background-color:#f2f2f6;padding:16px;box-sizing:border-box;overflow-y:auto;pointer-events:none;padding-top:max(16px,env(safe-area-inset-top));padding-bottom:max(16px,env(safe-area-inset-bottom));transform:translate(-100%);transition:transform .3s cubic-bezier(.4,0,.2,1)}.m-wrapper--open{transform:translate(0);pointer-events:auto}.m-wrapper .m-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}.m-wrapper .m-header .m-title-group{display:flex;align-items:center;gap:12px}.m-wrapper .m-header .m-title-group .m-logo{width:32px;height:32px;object-fit:contain}.m-wrapper .m-header .m-title-group .m-title{font-size:18px;font-weight:600;color:#1f1f1f}.m-wrapper .m-header .m-close-btn{background:transparent;border:none;padding:0;color:#1f1f1f;display:flex;align-items:center;justify-content:center;cursor:pointer}.m-wrapper .m-header .m-close-btn mat-icon{font-size:28px;width:28px;height:28px}.m-wrapper .m-user-section{background-color:#fff;border-radius:12px;padding:12px 16px;margin-bottom:24px;box-shadow:0 1px 2px #00000005;border:1px solid #EBEBEB}.m-wrapper .m-user-section lib-layout-user{display:block;width:100%}.m-wrapper .m-menu-list{display:flex;flex-direction:column;gap:16px}.m-wrapper .m-menu-card{background-color:#fff;border-radius:12px;border:1px solid #EBEBEB;overflow:hidden}.m-wrapper .m-menu-card .m-card-header{display:flex;justify-content:space-between;align-items:center;width:100%;padding:16px;cursor:pointer;-webkit-user-select:none;user-select:none;border:none;background:transparent;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-header .m-card-header-left{display:flex;align-items:center;gap:16px}.m-wrapper .m-menu-card .m-card-header .m-card-header-left .m-group-icon{font-size:24px;width:24px;height:24px;color:#1f1f1f;object-fit:contain}.m-wrapper .m-menu-card .m-card-header .m-card-header-left .m-group-title{font-size:16px;font-weight:600;color:#1f1f1f}.m-wrapper .m-menu-card .m-card-header .m-expand-icon{color:#1f1f1f;transition:transform .2s ease}.m-wrapper .m-menu-card .m-card-body{display:flex;flex-direction:column;padding-bottom:8px}.m-wrapper .m-menu-card .m-card-body .m-menu-item{display:flex;justify-content:space-between;align-items:center;width:100%;padding:12px 16px 12px 24px;cursor:pointer;border:none;background:transparent;transition:background-color .2s;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-body .m-menu-item:active{background-color:#f5f5f5}.m-wrapper .m-menu-card .m-card-body .m-menu-item--indented{padding-left:48px}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left{display:flex;align-items:center;gap:12px}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-icon{font-size:20px;width:20px;height:20px;color:#8c8c8c}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-icon-img{width:20px;height:20px;object-fit:contain;opacity:.7}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-title{font-size:15px;color:#333}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-nav-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}.m-wrapper .m-menu-card .m-card-body .m-sub-group{border-top:1px solid #EBEBEB}.m-wrapper .m-menu-card .m-card-body .m-sub-group:first-child{border-top:none}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header{display:flex;justify-content:space-between;align-items:center;width:100%;padding:12px 16px 12px 24px;cursor:pointer;border:none;background:#fafafa;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header:active{background-color:#f0f0f0}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left{display:flex;align-items:center;gap:12px}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-icon{font-size:20px;width:20px;height:20px;color:#8c8c8c}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-icon-img{width:20px;height:20px;object-fit:contain;opacity:.7}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-title{font-size:15px;font-weight:500;color:#333}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-expand-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: LayoutUserComponent, selector: "lib-layout-user", inputs: ["isMobileOrTablet", "isMenuLock", "isShowSidebar", "userInfo"], outputs: ["menuClosed", "menuOpened", "toggleMenuLock"] }] });
|
|
1075
|
+
}
|
|
1076
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SidebarMobileOverlayComponent, decorators: [{
|
|
1077
|
+
type: Component,
|
|
1078
|
+
args: [{ selector: 'sd-sidebar-mobile-overlay', standalone: true, imports: [
|
|
1079
|
+
CommonModule,
|
|
1080
|
+
RouterModule,
|
|
1081
|
+
MatIconModule,
|
|
1082
|
+
LayoutUserComponent,
|
|
1083
|
+
], template: "@let _userInfo = userInfo();\r\n@let _sidebar = sidebar();\r\n\r\n@if (_userInfo && _sidebar) {\r\n <div\r\n class=\"m-backdrop\"\r\n [class.m-backdrop--visible]=\"isShowSidebar()\"\r\n role=\"button\"\r\n tabindex=\"0\"\r\n (click)=\"onClose()\"\r\n (keydown.escape)=\"onClose()\">\r\n </div>\r\n\r\n <div class=\"m-wrapper\" [class.m-wrapper--open]=\"isShowSidebar()\">\r\n <div class=\"m-header\">\r\n <div class=\"m-title-group\">\r\n @if (_sidebar.logoUrl) {\r\n <img class=\"m-logo\" alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\r\n }\r\n <span class=\"m-title\">{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\r\n </div>\r\n <button class=\"m-close-btn\" (click)=\"onClose()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"m-user-section\">\r\n <lib-layout-user\r\n [userInfo]=\"_userInfo\"\r\n [isMobileOrTablet]=\"true\"\r\n (menuOpened)=\"onUserMenuOpened()\"\r\n (menuClosed)=\"onUserMenuClosed()\">\r\n </lib-layout-user>\r\n </div>\r\n\r\n <div class=\"m-menu-list\">\r\n @for (group of menus(); track group.id) {\r\n <div class=\"m-menu-card\">\r\n <button class=\"m-card-header\" (click)=\"toggleMobileGroup(group.id)\">\r\n <div class=\"m-card-header-left\">\r\n @if (group.iconUrl) {\r\n <img class=\"m-group-icon\" [src]=\"group.iconUrl\" [alt]=\"group.title\" />\r\n } @else {\r\n <mat-icon class=\"m-group-icon\">{{ group.icon || 'widgets' }}</mat-icon>\r\n }\r\n <span class=\"m-group-title\">{{ group.title }}</span>\r\n </div>\r\n <mat-icon class=\"m-expand-icon\">\r\n {{ expandedMobileGroups().has(group.id ?? '') ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\r\n </mat-icon>\r\n </button>\r\n\r\n @if (expandedMobileGroups().has(group.id ?? '') && hasChildren(group)) {\r\n <div class=\"m-card-body\">\r\n @for (child of getChildren(group); track child.id) {\r\n @if (hasChildren(child)) {\r\n <div class=\"m-sub-group\">\r\n <button class=\"m-sub-group-header\" (click)=\"toggleMobileGroup(child.id)\">\r\n <div class=\"m-item-left\">\r\n @if (child.iconUrl) {\r\n <img class=\"m-item-icon-img\" [src]=\"child.iconUrl\" alt=\"icon\" />\r\n } @else {\r\n <mat-icon class=\"m-item-icon\">{{ child.icon || 'folder' }}</mat-icon>\r\n }\r\n <span class=\"m-item-title\">{{ child.title }}</span>\r\n </div>\r\n <mat-icon class=\"m-expand-icon\">\r\n {{ expandedMobileGroups().has(child.id ?? '') ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\r\n </mat-icon>\r\n </button>\r\n @if (expandedMobileGroups().has(child.id ?? '')) {\r\n @for (subChild of getChildren(child); track subChild.id) {\r\n <button class=\"m-menu-item m-menu-item--indented\"\r\n (click)=\"navigate({ path: getPath(subChild), queryParams: getQueryParams(subChild) })\">\r\n <div class=\"m-item-left\">\r\n @if (subChild.iconUrl) {\r\n <img class=\"m-item-icon-img\" [src]=\"subChild.iconUrl\" alt=\"icon\" />\r\n } @else {\r\n <mat-icon class=\"m-item-icon\">{{ subChild.icon || 'insert_drive_file' }}</mat-icon>\r\n }\r\n <span class=\"m-item-title\">{{ subChild.title }}</span>\r\n </div>\r\n <mat-icon class=\"m-nav-icon\">chevron_right</mat-icon>\r\n </button>\r\n }\r\n }\r\n </div>\r\n } @else {\r\n <button class=\"m-menu-item\" (click)=\"navigate({ path: getPath(child), queryParams: getQueryParams(child) })\">\r\n <div class=\"m-item-left\">\r\n @if (child.iconUrl) {\r\n <img class=\"m-item-icon-img\" [src]=\"child.iconUrl\" alt=\"icon\" />\r\n } @else {\r\n <mat-icon class=\"m-item-icon\">{{ child.icon || 'insert_drive_file' }}</mat-icon>\r\n }\r\n <span class=\"m-item-title\">{{ child.title }}</span>\r\n </div>\r\n <mat-icon class=\"m-nav-icon\">chevron_right</mat-icon>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n}\r\n", styles: [":host{display:block;position:fixed;inset:0;z-index:1000;pointer-events:none}.m-backdrop{position:absolute;inset:0;background:#0006;opacity:0;pointer-events:none;transition:opacity .3s ease;cursor:pointer;outline:none}.m-backdrop--visible{opacity:1;pointer-events:auto}.m-wrapper{display:flex;flex-direction:column;position:absolute;inset:0;background-color:#f2f2f6;padding:16px;box-sizing:border-box;overflow-y:auto;pointer-events:none;padding-top:max(16px,env(safe-area-inset-top));padding-bottom:max(16px,env(safe-area-inset-bottom));transform:translate(-100%);transition:transform .3s cubic-bezier(.4,0,.2,1)}.m-wrapper--open{transform:translate(0);pointer-events:auto}.m-wrapper .m-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}.m-wrapper .m-header .m-title-group{display:flex;align-items:center;gap:12px}.m-wrapper .m-header .m-title-group .m-logo{width:32px;height:32px;object-fit:contain}.m-wrapper .m-header .m-title-group .m-title{font-size:18px;font-weight:600;color:#1f1f1f}.m-wrapper .m-header .m-close-btn{background:transparent;border:none;padding:0;color:#1f1f1f;display:flex;align-items:center;justify-content:center;cursor:pointer}.m-wrapper .m-header .m-close-btn mat-icon{font-size:28px;width:28px;height:28px}.m-wrapper .m-user-section{background-color:#fff;border-radius:12px;padding:12px 16px;margin-bottom:24px;box-shadow:0 1px 2px #00000005;border:1px solid #EBEBEB}.m-wrapper .m-user-section lib-layout-user{display:block;width:100%}.m-wrapper .m-menu-list{display:flex;flex-direction:column;gap:16px}.m-wrapper .m-menu-card{background-color:#fff;border-radius:12px;border:1px solid #EBEBEB;overflow:hidden}.m-wrapper .m-menu-card .m-card-header{display:flex;justify-content:space-between;align-items:center;width:100%;padding:16px;cursor:pointer;-webkit-user-select:none;user-select:none;border:none;background:transparent;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-header .m-card-header-left{display:flex;align-items:center;gap:16px}.m-wrapper .m-menu-card .m-card-header .m-card-header-left .m-group-icon{font-size:24px;width:24px;height:24px;color:#1f1f1f;object-fit:contain}.m-wrapper .m-menu-card .m-card-header .m-card-header-left .m-group-title{font-size:16px;font-weight:600;color:#1f1f1f}.m-wrapper .m-menu-card .m-card-header .m-expand-icon{color:#1f1f1f;transition:transform .2s ease}.m-wrapper .m-menu-card .m-card-body{display:flex;flex-direction:column;padding-bottom:8px}.m-wrapper .m-menu-card .m-card-body .m-menu-item{display:flex;justify-content:space-between;align-items:center;width:100%;padding:12px 16px 12px 24px;cursor:pointer;border:none;background:transparent;transition:background-color .2s;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-body .m-menu-item:active{background-color:#f5f5f5}.m-wrapper .m-menu-card .m-card-body .m-menu-item--indented{padding-left:48px}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left{display:flex;align-items:center;gap:12px}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-icon{font-size:20px;width:20px;height:20px;color:#8c8c8c}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-icon-img{width:20px;height:20px;object-fit:contain;opacity:.7}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-title{font-size:15px;color:#333}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-nav-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}.m-wrapper .m-menu-card .m-card-body .m-sub-group{border-top:1px solid #EBEBEB}.m-wrapper .m-menu-card .m-card-body .m-sub-group:first-child{border-top:none}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header{display:flex;justify-content:space-between;align-items:center;width:100%;padding:12px 16px 12px 24px;cursor:pointer;border:none;background:#fafafa;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header:active{background-color:#f0f0f0}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left{display:flex;align-items:center;gap:12px}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-icon{font-size:20px;width:20px;height:20px;color:#8c8c8c}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-icon-img{width:20px;height:20px;object-fit:contain;opacity:.7}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-title{font-size:15px;font-weight:500;color:#333}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-expand-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}\n"] }]
|
|
1084
|
+
}], ctorParameters: () => [] });
|
|
1085
|
+
|
|
1086
|
+
class SidebarMobileV1Component {
|
|
1087
|
+
#layoutStorageService = inject(SdLayoutStorageService);
|
|
1088
|
+
menus = input([]);
|
|
1089
|
+
userInfo = input.required();
|
|
1090
|
+
sidebar = input.required();
|
|
1091
|
+
// Sidebar luôn bắt đầu đóng trên mobile
|
|
1092
|
+
isShowSidebar = signal(false);
|
|
1093
|
+
titleMenuGroup = signal('');
|
|
1094
|
+
constructor() {
|
|
1095
|
+
effect(() => {
|
|
1096
|
+
const isShow = this.isShowSidebar();
|
|
1097
|
+
untracked(() => {
|
|
1098
|
+
this.#layoutStorageService.isShowSidebar.set(isShow);
|
|
1099
|
+
});
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
openSidebar = () => {
|
|
1103
|
+
this.isShowSidebar.set(true);
|
|
1104
|
+
};
|
|
1105
|
+
onToggle = (_data) => {
|
|
1106
|
+
this.isShowSidebar.set(false);
|
|
1107
|
+
};
|
|
1108
|
+
onPopupOfSideBarOpened = () => { };
|
|
1109
|
+
onPopupOfSideBarClosed = () => { };
|
|
1110
|
+
onExpandSideBar = () => { };
|
|
1111
|
+
onMouseleaveSideBar = () => { };
|
|
1112
|
+
onTitleMenuGroupChanged = (title) => {
|
|
1113
|
+
this.titleMenuGroup.set(title);
|
|
1114
|
+
};
|
|
1115
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SidebarMobileV1Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1116
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SidebarMobileV1Component, isStandalone: true, selector: "sidebar-mobile-v1", inputs: { menus: { classPropertyName: "menus", publicName: "menus", isSignal: true, isRequired: false, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"c-mobile-layout\">\r\n <div class=\"c-mobile-topbar\">\r\n <div class=\"c-topbar-brand\">\r\n @if (sidebar().logoUrl) {\r\n <img class=\"c-topbar-logo\" [src]=\"sidebar().logoUrl\" alt=\"logo\" />\r\n }\r\n <span class=\"c-topbar-title\">{{ titleMenuGroup() || sidebar().defaultTitle || 'Back Office' }}</span>\r\n </div>\r\n <button class=\"c-hamburger-btn\" (click)=\"openSidebar()\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"c-mobile-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <sd-sidebar-mobile-overlay\r\n [menus]=\"menus()\"\r\n [userInfo]=\"userInfo()\"\r\n [sidebar]=\"sidebar()\"\r\n [isShowSidebar]=\"isShowSidebar()\"\r\n (showSideBar)=\"onToggle($event)\"\r\n (expandSideBar)=\"onExpandSideBar()\"\r\n (popupUserMenuOpened)=\"onPopupOfSideBarOpened()\"\r\n (popupUserMenuClosed)=\"onPopupOfSideBarClosed()\"\r\n (titleMenuGroupChanged)=\"onTitleMenuGroupChanged($event)\">\r\n </sd-sidebar-mobile-overlay>\r\n</div>\r\n", styles: [":host{display:block;height:100vh;position:relative;overflow:hidden}.c-mobile-layout{display:flex;flex-direction:column;height:100%;position:relative}.c-mobile-topbar{display:flex;align-items:center;justify-content:space-between;padding:0 16px;height:56px;background-color:#fff;border-bottom:1px solid #e0e0e0;flex-shrink:0}.c-mobile-topbar .c-topbar-brand{display:flex;align-items:center;gap:10px;overflow:hidden}.c-mobile-topbar .c-topbar-brand .c-topbar-logo{width:28px;height:28px;object-fit:contain;flex-shrink:0}.c-mobile-topbar .c-topbar-brand .c-topbar-title{font-size:16px;font-weight:600;color:#1f1f1f;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.c-mobile-topbar .c-hamburger-btn{display:flex;align-items:center;justify-content:center;background:none;border:none;cursor:pointer;padding:6px;border-radius:50%;color:#333;flex-shrink:0}.c-mobile-topbar .c-hamburger-btn:hover{background-color:#0000000f}.c-mobile-content{flex:1;overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: SidebarMobileOverlayComponent, selector: "sd-sidebar-mobile-overlay", inputs: ["isShowSidebar", "menus", "userInfo", "sidebar"], outputs: ["showSideBar", "expandSideBar", "popupUserMenuOpened", "popupUserMenuClosed", "titleMenuGroupChanged"] }] });
|
|
1117
|
+
}
|
|
1118
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SidebarMobileV1Component, decorators: [{
|
|
1119
|
+
type: Component,
|
|
1120
|
+
args: [{ selector: 'sidebar-mobile-v1', imports: [MatIconModule, CommonModule, SidebarMobileOverlayComponent], standalone: true, template: "<div class=\"c-mobile-layout\">\r\n <div class=\"c-mobile-topbar\">\r\n <div class=\"c-topbar-brand\">\r\n @if (sidebar().logoUrl) {\r\n <img class=\"c-topbar-logo\" [src]=\"sidebar().logoUrl\" alt=\"logo\" />\r\n }\r\n <span class=\"c-topbar-title\">{{ titleMenuGroup() || sidebar().defaultTitle || 'Back Office' }}</span>\r\n </div>\r\n <button class=\"c-hamburger-btn\" (click)=\"openSidebar()\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"c-mobile-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <sd-sidebar-mobile-overlay\r\n [menus]=\"menus()\"\r\n [userInfo]=\"userInfo()\"\r\n [sidebar]=\"sidebar()\"\r\n [isShowSidebar]=\"isShowSidebar()\"\r\n (showSideBar)=\"onToggle($event)\"\r\n (expandSideBar)=\"onExpandSideBar()\"\r\n (popupUserMenuOpened)=\"onPopupOfSideBarOpened()\"\r\n (popupUserMenuClosed)=\"onPopupOfSideBarClosed()\"\r\n (titleMenuGroupChanged)=\"onTitleMenuGroupChanged($event)\">\r\n </sd-sidebar-mobile-overlay>\r\n</div>\r\n", styles: [":host{display:block;height:100vh;position:relative;overflow:hidden}.c-mobile-layout{display:flex;flex-direction:column;height:100%;position:relative}.c-mobile-topbar{display:flex;align-items:center;justify-content:space-between;padding:0 16px;height:56px;background-color:#fff;border-bottom:1px solid #e0e0e0;flex-shrink:0}.c-mobile-topbar .c-topbar-brand{display:flex;align-items:center;gap:10px;overflow:hidden}.c-mobile-topbar .c-topbar-brand .c-topbar-logo{width:28px;height:28px;object-fit:contain;flex-shrink:0}.c-mobile-topbar .c-topbar-brand .c-topbar-title{font-size:16px;font-weight:600;color:#1f1f1f;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.c-mobile-topbar .c-hamburger-btn{display:flex;align-items:center;justify-content:center;background:none;border:none;cursor:pointer;padding:6px;border-radius:50%;color:#333;flex-shrink:0}.c-mobile-topbar .c-hamburger-btn:hover{background-color:#0000000f}.c-mobile-content{flex:1;overflow-y:auto}\n"] }]
|
|
1121
|
+
}], ctorParameters: () => [] });
|
|
1122
|
+
|
|
869
1123
|
class SdLayoutComponent {
|
|
870
1124
|
// ==========================================
|
|
871
1125
|
// INJECT SERVICES
|
|
872
1126
|
// ==========================================
|
|
873
1127
|
#menuPipe = inject(MenuPipe);
|
|
874
|
-
#layoutService = inject(SdLayoutService);
|
|
1128
|
+
#layoutService = inject(SdLayoutService);
|
|
875
1129
|
// ==========================================
|
|
876
1130
|
// SIGNAL INPUTS
|
|
877
1131
|
// ==========================================
|
|
878
1132
|
menusInput = input([], { alias: 'menus' });
|
|
879
|
-
// Tự động format qua MenuPipe mỗi khi menusInput từ component cha thay đổi
|
|
880
1133
|
menus = computed(() => this.#menuPipe.transform(this.menusInput() || []));
|
|
881
1134
|
// ==========================================
|
|
882
|
-
// CONSUME SHARED STATE
|
|
1135
|
+
// CONSUME SHARED STATE
|
|
883
1136
|
// ==========================================
|
|
884
|
-
// Bạn có thể gán biến ngắn gọn để xài trong HTML (ví dụ: userInfo() thay vì layoutService.userInfo())
|
|
885
1137
|
userInfo = this.#layoutService.userInfo;
|
|
886
1138
|
sidebar = this.#layoutService.sidebar;
|
|
1139
|
+
isMobileOrTablet = signal(SdUtilities.isMobile());
|
|
887
1140
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
888
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SdLayoutComponent, isStandalone: true, selector: "sd-layout", inputs: { menusInput: { classPropertyName: "menusInput", publicName: "menus", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@let _userInfo = userInfo();\r\n@let _sidebar = sidebar();\r\n\r\n@if (_userInfo && _sidebar?.version === 1) {\r\n <sidebar-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\r\n <ng-
|
|
1141
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SdLayoutComponent, isStandalone: true, selector: "sd-layout", inputs: { menusInput: { classPropertyName: "menusInput", publicName: "menus", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-template #projectedContent>\r\n <ng-content></ng-content>\r\n</ng-template>\r\n\r\n@let _userInfo = userInfo();\r\n@let _sidebar = sidebar();\r\n\r\n@if (_userInfo && _sidebar?.version === 1) {\r\n @if (!isMobileOrTablet()) {\r\n <sidebar-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\r\n <ng-container [ngTemplateOutlet]=\"projectedContent\"></ng-container>\r\n </sidebar-v1>\r\n } @else {\r\n <sidebar-mobile-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\r\n <ng-container [ngTemplateOutlet]=\"projectedContent\"></ng-container>\r\n </sidebar-mobile-v1>\r\n }\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: SidebarV1Component, selector: "sidebar-v1", inputs: ["menus", "userInfo", "sidebar"] }, { kind: "component", type: SidebarMobileV1Component, selector: "sidebar-mobile-v1", inputs: ["menus", "userInfo", "sidebar"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
889
1142
|
}
|
|
890
1143
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdLayoutComponent, decorators: [{
|
|
891
1144
|
type: Component,
|
|
892
|
-
args: [{ selector: 'sd-layout', imports: [SidebarV1Component], standalone: true, template: "@let _userInfo = userInfo();\r\n@let _sidebar = sidebar();\r\n\r\n@if (_userInfo && _sidebar?.version === 1) {\r\n <sidebar-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\r\n <ng-
|
|
1145
|
+
args: [{ selector: 'sd-layout', imports: [SidebarV1Component, SidebarMobileV1Component, NgTemplateOutlet], standalone: true, template: "<ng-template #projectedContent>\r\n <ng-content></ng-content>\r\n</ng-template>\r\n\r\n@let _userInfo = userInfo();\r\n@let _sidebar = sidebar();\r\n\r\n@if (_userInfo && _sidebar?.version === 1) {\r\n @if (!isMobileOrTablet()) {\r\n <sidebar-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\r\n <ng-container [ngTemplateOutlet]=\"projectedContent\"></ng-container>\r\n </sidebar-v1>\r\n } @else {\r\n <sidebar-mobile-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\r\n <ng-container [ngTemplateOutlet]=\"projectedContent\"></ng-container>\r\n </sidebar-mobile-v1>\r\n }\r\n}\r\n" }]
|
|
893
1146
|
}] });
|
|
894
1147
|
|
|
895
1148
|
// End
|
|
@@ -1188,5 +1441,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
1188
1441
|
* Generated bundle index. Do not edit.
|
|
1189
1442
|
*/
|
|
1190
1443
|
|
|
1191
|
-
export { ForbiddenModule, HomeModule, NotFoundModule, SD_LAYOUT_CONFIGURATION, SdLayoutComponent, SdLayoutModule, SdLayoutService, SdLayoutStorageService, SdPageComponent };
|
|
1444
|
+
export { ForbiddenModule, HomeModule, NotFoundModule, SD_LAYOUT_CONFIGURATION, SdLayoutComponent, SdLayoutModule, SdLayoutService, SdLayoutStorageService, SdPageComponent, SidebarMobileOverlayComponent, SidebarMobileV1Component };
|
|
1192
1445
|
//# sourceMappingURL=sd-angular-core-modules-layout.mjs.map
|