@sd-angular/core 19.0.19 → 19.0.30
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-form-generic.mjs +11 -11
- package/fesm2022/sd-angular-core-components-form-generic.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-query-bar.mjs +2 -2
- package/fesm2022/sd-angular-core-components-query-bar.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-query-builder.mjs +1 -1
- package/fesm2022/sd-angular-core-components-query-builder.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-table.mjs +6 -6
- package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-input-color.mjs +4 -2
- package/fesm2022/sd-angular-core-forms-input-color.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-input-number.mjs +6 -4
- package/fesm2022/sd-angular-core-forms-input-number.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-input.mjs +7 -4
- package/fesm2022/sd-angular-core-forms-input.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules-layout.mjs +130 -75
- package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
- package/forms/input/src/input.component.d.ts +3 -1
- package/forms/input-color/src/input-color.component.d.ts +3 -1
- package/forms/input-number/src/input-number.component.d.ts +3 -1
- package/modules/layout/components/sidebar-v1/components/sidebar/sidebar.component.d.ts +1 -0
- package/modules/layout/pipes/menu-focus.pipe.d.ts +6 -2
- package/modules/layout/utils/index.d.ts +1 -0
- package/modules/layout/utils/menu-path.util.d.ts +16 -0
- package/package.json +5 -5
|
@@ -8,7 +8,7 @@ import { __decorate } from 'tslib';
|
|
|
8
8
|
import * as i1$3 from '@angular/material/icon';
|
|
9
9
|
import { MatIconModule } from '@angular/material/icon';
|
|
10
10
|
import { SdAvatar, SdTabComponent, SdButton } from '@sd-angular/core/components';
|
|
11
|
-
import { I18nService,
|
|
11
|
+
import { I18nService, I18N_STORAGE_KEY, I18N_MESSAGES, TranslatePipe } from '@sd-angular/core/i18n';
|
|
12
12
|
import * as i1 from '@sd-angular/core/services';
|
|
13
13
|
import { resolveMaybeAsync } from '@sdcorejs/utils/models';
|
|
14
14
|
import { Utilities, StringUtilities, BrowserUtilities } from '@sdcorejs/utils/fns';
|
|
@@ -249,31 +249,104 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
249
249
|
}]
|
|
250
250
|
}], ctorParameters: () => [{ type: i1$1.SdPermissionService }] });
|
|
251
251
|
|
|
252
|
+
// End
|
|
253
|
+
/** Thêm '/' ở cuối để so khớp theo segment: '/appointment' không khớp nhầm '/appointments'. */
|
|
254
|
+
const normalizeMenuPath = (path) => {
|
|
255
|
+
return path.endsWith('/') ? path : path + '/';
|
|
256
|
+
};
|
|
257
|
+
/** Route hiện tại có nằm trong nhánh của `path` không (khớp chính xác hoặc khớp phần đầu). */
|
|
258
|
+
const isMenuPathMatch = (routePath, path) => {
|
|
259
|
+
if (!routePath || !path) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
if (routePath === path) {
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
return normalizeMenuPath(routePath).startsWith(normalizeMenuPath(path));
|
|
266
|
+
};
|
|
267
|
+
/** Mọi path trong cây menu khớp với route hiện tại. */
|
|
268
|
+
const collectMatchedMenuPaths = (menus, routePath) => {
|
|
269
|
+
const matched = [];
|
|
270
|
+
const visit = (items) => {
|
|
271
|
+
for (const item of items) {
|
|
272
|
+
if ('path' in item && isMenuPathMatch(routePath, item.path)) {
|
|
273
|
+
matched.push(item.path);
|
|
274
|
+
}
|
|
275
|
+
if ('children' in item && item.children?.length) {
|
|
276
|
+
visit(item.children);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
visit(menus ?? []);
|
|
281
|
+
return matched;
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* Path khớp sát nhất với route hiện tại trong cả cây menu.
|
|
285
|
+
* Khi cả '/appointment' và '/appointment/cs' cùng khớp route '/appointment/cs',
|
|
286
|
+
* chỉ path dài nhất được coi là active — path còn lại không được highlight.
|
|
287
|
+
* Hoà nhau thì lấy path xuất hiện trước theo thứ tự khai báo.
|
|
288
|
+
*/
|
|
289
|
+
const resolveActiveMenuPath = (menus, routePath) => {
|
|
290
|
+
const matched = collectMatchedMenuPaths(menus, routePath);
|
|
291
|
+
if (!matched.length) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
return matched.reduce((best, path) => (normalizeMenuPath(path).length > normalizeMenuPath(best).length ? path : best));
|
|
295
|
+
};
|
|
296
|
+
/** Chính menu này, hoặc bất kỳ menu con nào ở mọi cấp, có đúng path đó. */
|
|
297
|
+
const containsMenuPath = (menuItem, path) => {
|
|
298
|
+
if ('path' in menuItem && menuItem.path === path) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
if ('children' in menuItem && menuItem.children?.length) {
|
|
302
|
+
return menuItem.children.some(child => containsMenuPath(child, path));
|
|
303
|
+
}
|
|
304
|
+
return false;
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Resolve a translated tab name for `@SdTabComponent`.
|
|
309
|
+
*
|
|
310
|
+
* WHY not I18nService: the decorator runs at module-evaluation time, before
|
|
311
|
+
* Angular's DI exists, so the service cannot be injected. We read the language
|
|
312
|
+
* the app persisted and look the key up in the static catalog instead.
|
|
313
|
+
*/
|
|
314
|
+
function resolveTabName(key) {
|
|
315
|
+
const lang = (() => {
|
|
316
|
+
try {
|
|
317
|
+
const stored = localStorage.getItem(I18N_STORAGE_KEY);
|
|
318
|
+
if (stored)
|
|
319
|
+
return stored;
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
// localStorage can throw (private mode, SSR shim) — fall back below.
|
|
323
|
+
}
|
|
324
|
+
return 'vi';
|
|
325
|
+
})();
|
|
326
|
+
return I18N_MESSAGES[lang]?.[key] ?? I18N_MESSAGES.vi[key] ?? key;
|
|
327
|
+
}
|
|
328
|
+
|
|
252
329
|
// End
|
|
253
330
|
class MenuFocusPipe {
|
|
254
|
-
|
|
331
|
+
/**
|
|
332
|
+
* @param activeMenuPath Path khớp sát nhất với route hiện tại (xem `resolveActiveMenuPath`).
|
|
333
|
+
* Truyền vào thì chỉ menu chứa đúng path đó mới focus, nên '/appointment' không sáng khi đang ở
|
|
334
|
+
* '/appointment/cs'. Bỏ trống thì giữ cách khớp phần đầu cũ.
|
|
335
|
+
*/
|
|
336
|
+
transform(routePath, menuItem, activeMenuPath) {
|
|
255
337
|
if (!routePath) {
|
|
256
338
|
return false;
|
|
257
339
|
}
|
|
340
|
+
if (activeMenuPath !== undefined) {
|
|
341
|
+
return activeMenuPath ? containsMenuPath(menuItem, activeMenuPath) : false;
|
|
342
|
+
}
|
|
258
343
|
if ('children' in menuItem && menuItem.children) {
|
|
259
344
|
return menuItem.children.some(child => {
|
|
260
|
-
return 'path' in child && child.path ?
|
|
345
|
+
return 'path' in child && child.path ? isMenuPathMatch(routePath, child.path) : false;
|
|
261
346
|
});
|
|
262
347
|
}
|
|
263
|
-
return 'path' in menuItem &&
|
|
348
|
+
return 'path' in menuItem && isMenuPathMatch(routePath, menuItem.path);
|
|
264
349
|
}
|
|
265
|
-
#match = (routePath, path) => {
|
|
266
|
-
if (!path) {
|
|
267
|
-
return false;
|
|
268
|
-
}
|
|
269
|
-
if (routePath === path) {
|
|
270
|
-
return true;
|
|
271
|
-
}
|
|
272
|
-
return this.#normalizePath(routePath).startsWith(this.#normalizePath(path));
|
|
273
|
-
};
|
|
274
|
-
#normalizePath = (p) => {
|
|
275
|
-
return p.endsWith('/') ? p : p + '/';
|
|
276
|
-
};
|
|
277
350
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: MenuFocusPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
278
351
|
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: MenuFocusPipe, isStandalone: true, name: "menuFocus" });
|
|
279
352
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: MenuFocusPipe, providedIn: 'root' });
|
|
@@ -461,6 +534,8 @@ class SidebarComponent {
|
|
|
461
534
|
totalMenuInMenusByGroup = computed(() => this.#getTotalMenus(this.menusByGroup()));
|
|
462
535
|
pinnedNodeKeys = computed(() => new Set(this.pinnedMenuGroup().children?.map(m => this.#getMenuNodeKey(m)) ?? []));
|
|
463
536
|
isPinnedMenuGroupActive = computed(() => this.idMenuGroupActive() === this.pinnedMenuGroup().id);
|
|
537
|
+
// Path khớp sát nhất trong nhánh menu đang hiển thị. Nhờ nó '/appointment' hết sáng khi đang ở '/appointment/cs'.
|
|
538
|
+
activeMenuPath = computed(() => resolveActiveMenuPath(this.menusByGroup(), this.currentPath()));
|
|
464
539
|
// ==========================================
|
|
465
540
|
// DATA STRUCTURES
|
|
466
541
|
// ==========================================
|
|
@@ -661,7 +736,7 @@ class SidebarComponent {
|
|
|
661
736
|
}, this.#pinIconHoverTimerDelay));
|
|
662
737
|
}
|
|
663
738
|
}
|
|
664
|
-
if (!this.#menuFocusPipe.transform(this.currentPath(), menuItem)) {
|
|
739
|
+
if (!this.#menuFocusPipe.transform(this.currentPath(), menuItem, this.activeMenuPath())) {
|
|
665
740
|
const iconMenu = menuNode.querySelector('.c-menu-node-icon');
|
|
666
741
|
const content = menuNode.querySelector('.c-menu-node-description-content');
|
|
667
742
|
const iconExpand = menuNode.querySelector('.c-menu-node-description-icon-expand');
|
|
@@ -702,7 +777,7 @@ class SidebarComponent {
|
|
|
702
777
|
}
|
|
703
778
|
}
|
|
704
779
|
}
|
|
705
|
-
if (!this.#menuFocusPipe.transform(this.currentPath(), menuItem)) {
|
|
780
|
+
if (!this.#menuFocusPipe.transform(this.currentPath(), menuItem, this.activeMenuPath())) {
|
|
706
781
|
const iconMenu = menuNode.querySelector('.c-menu-node-icon');
|
|
707
782
|
const content = menuNode.querySelector('.c-menu-node-description-content');
|
|
708
783
|
const iconExpand = menuNode.querySelector('.c-menu-node-description-icon-expand');
|
|
@@ -740,19 +815,27 @@ class SidebarComponent {
|
|
|
740
815
|
}
|
|
741
816
|
return node.title || '';
|
|
742
817
|
};
|
|
743
|
-
#getMenuGroupByCurrentPath = (menus
|
|
818
|
+
#getMenuGroupByCurrentPath = (menus) => {
|
|
819
|
+
const activePath = resolveActiveMenuPath(menus, this.currentPath());
|
|
820
|
+
if (!activePath) {
|
|
821
|
+
return [];
|
|
822
|
+
}
|
|
823
|
+
const menuGroup = this.#findMenuGroupByPath(menus, activePath);
|
|
824
|
+
return menuGroup ? [menuGroup] : [];
|
|
825
|
+
};
|
|
826
|
+
#findMenuGroupByPath = (menus, activePath, menuGroup) => {
|
|
744
827
|
for (const menu of menus) {
|
|
745
|
-
if ('path' in menu &&
|
|
746
|
-
return
|
|
828
|
+
if ('path' in menu && menu.path === activePath) {
|
|
829
|
+
return menuGroup ?? menu;
|
|
747
830
|
}
|
|
748
831
|
if ('children' in menu && menu.children?.length) {
|
|
749
|
-
const result = this.#
|
|
750
|
-
if (result
|
|
832
|
+
const result = this.#findMenuGroupByPath(menu.children, activePath, menuGroup ?? menu);
|
|
833
|
+
if (result) {
|
|
751
834
|
return result;
|
|
752
835
|
}
|
|
753
836
|
}
|
|
754
837
|
}
|
|
755
|
-
return
|
|
838
|
+
return null;
|
|
756
839
|
};
|
|
757
840
|
#bindingMenuGroupByCurrentPath = (menus) => {
|
|
758
841
|
// Chỉ bindingGroup mới khi người dùng không searchText
|
|
@@ -820,13 +903,17 @@ class SidebarComponent {
|
|
|
820
903
|
}
|
|
821
904
|
};
|
|
822
905
|
#expandParentNodesByCurrentPath(menus) {
|
|
906
|
+
const activePath = resolveActiveMenuPath(menus, this.currentPath());
|
|
907
|
+
return activePath ? this.#expandParentNodesByPath(menus, activePath) : false;
|
|
908
|
+
}
|
|
909
|
+
#expandParentNodesByPath(menus, activePath) {
|
|
823
910
|
let shouldPropagate = false;
|
|
824
911
|
for (const menu of menus) {
|
|
825
|
-
if ('path' in menu &&
|
|
912
|
+
if ('path' in menu && menu.path === activePath) {
|
|
826
913
|
shouldPropagate = true;
|
|
827
914
|
}
|
|
828
915
|
if ('children' in menu && menu.children?.length) {
|
|
829
|
-
const childHasMatch = this.#
|
|
916
|
+
const childHasMatch = this.#expandParentNodesByPath(menu.children, activePath);
|
|
830
917
|
if (childHasMatch) {
|
|
831
918
|
this.treeControl.expand(menu);
|
|
832
919
|
shouldPropagate = true;
|
|
@@ -888,16 +975,6 @@ class SidebarComponent {
|
|
|
888
975
|
}
|
|
889
976
|
return matchedCount === needle.length;
|
|
890
977
|
};
|
|
891
|
-
#isMenuPathMatchByCurrentPath = (path) => {
|
|
892
|
-
if (!path) {
|
|
893
|
-
return false;
|
|
894
|
-
}
|
|
895
|
-
if (this.currentPath() === path) {
|
|
896
|
-
return true;
|
|
897
|
-
}
|
|
898
|
-
return this.#normalizePath(this.currentPath()).startsWith(this.#normalizePath(path));
|
|
899
|
-
};
|
|
900
|
-
#normalizePath = (p) => (p.endsWith('/') ? p : p + '/');
|
|
901
978
|
#closeMenu() {
|
|
902
979
|
this.showSideBar.emit(null);
|
|
903
980
|
}
|
|
@@ -954,7 +1031,7 @@ class SidebarComponent {
|
|
|
954
1031
|
return count;
|
|
955
1032
|
};
|
|
956
1033
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
957
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", 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();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar) {\n <div class=\"wrapper\" [style.height]=\"isMobileOrTablet ? screenHeight + 'px' : '100%'\">\n <div class=\"c-header\">\n @if (_sidebar.logoUrl) {\n <div class=\"c-logo\">\n <a href=\"javascript:;\" (click)=\"openHomePage()\">\n <img alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\n </a>\n </div>\n }\n <div class=\"c-title-menu-group\" [class.d-none]=\"!isShowSidebar()\">\n <span>{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\n </div>\n </div>\n <div class=\"c-body\">\n <div class=\"c-menu\">\n <div class=\"c-menu-group\">\n @if (_sidebar?.pin?.enabled && pinnedMenuGroup().children?.length) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, pinnedMenuGroup())\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, pinnedMenuGroup())\"\n (click)=\"expandPinnedGroup()\"\n [matTooltip]=\"'\u0110\u00E3 ghim'\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: isPinnedMenuGroupActive() ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: isPinnedMenuGroupActive() ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n push_pin\n </mat-icon>\n </button>\n }\n @for (nodeMenuGroup of menus(); track nodeMenuGroup.id) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, nodeMenuGroup)\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, nodeMenuGroup)\"\n (click)=\"expandMenuGroup(nodeMenuGroup)\"\n [matTooltip]=\"nodeMenuGroup.tooltipTitle || nodeMenuGroup.title\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n @if (nodeMenuGroup.iconUrl) {\n <span\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <img width=\"24px\" height=\"24px\" [src]=\"nodeMenuGroup.iconUrl\" [alt]=\"nodeMenuGroup.title\" />\n </span>\n } @else {\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n {{ nodeMenuGroup.icon || 'widgets' }}\n </mat-icon>\n }\n </button>\n }\n </div>\n <div class=\"c-menu-tree\" [class.d-none]=\"!isShowSidebar()\" [attr.inert]=\"!isShowSidebar() ? '' : null\">\n @if (totalMenuInMenusByGroup() >= 10) {\n <div style=\"padding: 0px 4px\" class=\"c-menu-tree-search\">\n <sd-input\n size=\"sm\"\n [placeholder]=\"'core.module.layout.sidebar.search' | translate\"\n [model]=\"searchText()\"\n (sdChange)=\"onFilterSearchText($event)\">\n <ng-template sdSuffixDef>\n @if (searchText()) {\n <mat-icon class=\"c-search-prefix-icon cancel\" (click)=\"onClearSearchText()\">cancel</mat-icon>\n } @else {\n <mat-icon class=\"c-search-prefix-icon search\">search</mat-icon>\n }\n </ng-template>\n </sd-input>\n </div>\n }\n <div class=\"c-menu-tree-container\">\n <mat-tree [dataSource]=\"dataSource\" [treeControl]=\"treeControl\" [style.backgroundColor]=\"'transparent'\">\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: !hasChild\">\n <li\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\"\n [ngStyle]=\"{\n backgroundColor: (currentPath() | menuFocus: node) ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <div aria-hidden=\"true\" class=\"c-menu-node-description\" (click)=\"navigate(node)\" [class.d-none]=\"!isShowSidebar()\">\n <div\n class=\"c-menu-node-description-content\"\n [ngStyle]=\"{\n color: (currentPath() | menuFocus: node) ? _sidebar.brandColor || '#2962FF' : '#1F1F1F',\n }\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n\n @if (_sidebar?.pin?.enabled) {\n <mat-icon\n class=\"c-menu-node-description-icon-pin\"\n [fontSet]=\"isPinnedNode(node) ? 'material-icons' : 'material-icons-outlined'\"\n [style.opacity]=\"isPinnedNode(node) || isHoveredNode(node) ? '1' : null\"\n [style.color]=\"isPinnedNode(node) || isHoveredNode(node) ? sidebar().brandColor || '#2962FF' : null\"\n (click)=\"onTogglePin($event, node)\"\n >push_pin\n </mat-icon>\n }\n </div>\n </li>\n </mat-nested-tree-node>\n\n <mat-nested-tree-node\n *matTreeNodeDef=\"let node; when: hasChild\"\n aria-hidden=\"true\"\n [class]=\"{ expanded: treeControl.isExpanded(node), isfocus: currentPath() | menuFocus: node }\">\n <li>\n <div\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\">\n <div class=\"d-flex align-items-center\" style=\"gap: 10px; width: 100%\">\n <div [class.d-none]=\"!isShowSidebar()\" class=\"c-menu-node-description\" (click)=\"onToggleMenuNode(node)\">\n <div\n class=\"c-menu-node-description-content\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n <mat-icon class=\"c-menu-node-description-icon-expand\">\n {{ treeControl.isExpanded(node) ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </div>\n </div>\n </div>\n <ul class=\"p-0\" [class.d-none]=\"!treeControl.isExpanded(node)\">\n <ng-container matTreeNodeOutlet></ng-container>\n </ul>\n </li>\n </mat-nested-tree-node>\n </mat-tree>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"c-footer\">\n <lib-layout-user\n [userInfo]=\"_userInfo\"\n [isMobileOrTablet]=\"isMobileOrTablet\"\n (menuOpened)=\"onUserMenuOpened()\"\n (menuClosed)=\"onUserMenuClosed()\"\n [isShowSidebar]=\"isShowSidebar()\"\n (toggleMenuLock)=\"toggleMenuLock($event)\">\n </lib-layout-user>\n </div>\n\n <div class=\"c-vertical\"></div>\n </div>\n}\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;flex:0 0 60px;width:60px;min-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{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:20px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-pin{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:18px;opacity:0}.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", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTreeModule }, { kind: "directive", type: i3.MatNestedTreeNode, selector: "mat-nested-tree-node", inputs: ["matNestedTreeNode", "disabled", "tabIndex"], outputs: ["activation", "expandedChange"], exportAs: ["matNestedTreeNode"] }, { kind: "directive", type: i3.MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "component", type: i3.MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: i3.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"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
1034
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", 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();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar) {\n <div class=\"wrapper\" [style.height]=\"isMobileOrTablet ? screenHeight + 'px' : '100%'\">\n <div class=\"c-header\">\n @if (_sidebar.logoUrl) {\n <div class=\"c-logo\">\n <a href=\"javascript:;\" (click)=\"openHomePage()\">\n <img alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\n </a>\n </div>\n }\n <div class=\"c-title-menu-group\" [class.d-none]=\"!isShowSidebar()\">\n <span>{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\n </div>\n </div>\n <div class=\"c-body\">\n <div class=\"c-menu\">\n <div class=\"c-menu-group\">\n @if (_sidebar?.pin?.enabled && pinnedMenuGroup().children?.length) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, pinnedMenuGroup())\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, pinnedMenuGroup())\"\n (click)=\"expandPinnedGroup()\"\n [matTooltip]=\"'\u0110\u00E3 ghim'\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: isPinnedMenuGroupActive() ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: isPinnedMenuGroupActive() ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n push_pin\n </mat-icon>\n </button>\n }\n @for (nodeMenuGroup of menus(); track nodeMenuGroup.id) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, nodeMenuGroup)\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, nodeMenuGroup)\"\n (click)=\"expandMenuGroup(nodeMenuGroup)\"\n [matTooltip]=\"nodeMenuGroup.tooltipTitle || nodeMenuGroup.title\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n @if (nodeMenuGroup.iconUrl) {\n <span\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <img width=\"24px\" height=\"24px\" [src]=\"nodeMenuGroup.iconUrl\" [alt]=\"nodeMenuGroup.title\" />\n </span>\n } @else {\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n {{ nodeMenuGroup.icon || 'widgets' }}\n </mat-icon>\n }\n </button>\n }\n </div>\n <div class=\"c-menu-tree\" [class.d-none]=\"!isShowSidebar()\" [attr.inert]=\"!isShowSidebar() ? '' : null\">\n @if (totalMenuInMenusByGroup() >= 10) {\n <div style=\"padding: 0px 4px\" class=\"c-menu-tree-search\">\n <sd-input\n size=\"sm\"\n [placeholder]=\"'core.module.layout.sidebar.search' | translate\"\n [model]=\"searchText()\"\n (sdChange)=\"onFilterSearchText($event)\">\n <ng-template sdSuffixDef>\n @if (searchText()) {\n <mat-icon class=\"c-search-prefix-icon cancel\" (click)=\"onClearSearchText()\">cancel</mat-icon>\n } @else {\n <mat-icon class=\"c-search-prefix-icon search\">search</mat-icon>\n }\n </ng-template>\n </sd-input>\n </div>\n }\n <div class=\"c-menu-tree-container\">\n <mat-tree [dataSource]=\"dataSource\" [treeControl]=\"treeControl\" [style.backgroundColor]=\"'transparent'\">\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: !hasChild\">\n <li\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\"\n [ngStyle]=\"{\n backgroundColor: (currentPath() | menuFocus: node : activeMenuPath()) ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <div aria-hidden=\"true\" class=\"c-menu-node-description\" (click)=\"navigate(node)\" [class.d-none]=\"!isShowSidebar()\">\n <div\n class=\"c-menu-node-description-content\"\n [ngStyle]=\"{\n color: (currentPath() | menuFocus: node : activeMenuPath()) ? _sidebar.brandColor || '#2962FF' : '#1F1F1F',\n }\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n\n @if (_sidebar?.pin?.enabled) {\n <mat-icon\n class=\"c-menu-node-description-icon-pin\"\n [fontSet]=\"isPinnedNode(node) ? 'material-icons' : 'material-icons-outlined'\"\n [style.opacity]=\"isPinnedNode(node) || isHoveredNode(node) ? '1' : null\"\n [style.color]=\"isPinnedNode(node) || isHoveredNode(node) ? sidebar().brandColor || '#2962FF' : null\"\n (click)=\"onTogglePin($event, node)\"\n >push_pin\n </mat-icon>\n }\n </div>\n </li>\n </mat-nested-tree-node>\n\n <mat-nested-tree-node\n *matTreeNodeDef=\"let node; when: hasChild\"\n aria-hidden=\"true\"\n [class]=\"{ expanded: treeControl.isExpanded(node), isfocus: currentPath() | menuFocus: node : activeMenuPath() }\">\n <li>\n <div\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\">\n <div class=\"d-flex align-items-center\" style=\"gap: 10px; width: 100%\">\n <div [class.d-none]=\"!isShowSidebar()\" class=\"c-menu-node-description\" (click)=\"onToggleMenuNode(node)\">\n <div\n class=\"c-menu-node-description-content\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n <mat-icon class=\"c-menu-node-description-icon-expand\">\n {{ treeControl.isExpanded(node) ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </div>\n </div>\n </div>\n <ul class=\"p-0\" [class.d-none]=\"!treeControl.isExpanded(node)\">\n <ng-container matTreeNodeOutlet></ng-container>\n </ul>\n </li>\n </mat-nested-tree-node>\n </mat-tree>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"c-footer\">\n <lib-layout-user\n [userInfo]=\"_userInfo\"\n [isMobileOrTablet]=\"isMobileOrTablet\"\n (menuOpened)=\"onUserMenuOpened()\"\n (menuClosed)=\"onUserMenuClosed()\"\n [isShowSidebar]=\"isShowSidebar()\"\n (toggleMenuLock)=\"toggleMenuLock($event)\">\n </lib-layout-user>\n </div>\n\n <div class=\"c-vertical\"></div>\n </div>\n}\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;flex:0 0 60px;width:60px;min-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{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:20px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-pin{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:18px;opacity:0}.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", "clearable", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTreeModule }, { kind: "directive", type: i3.MatNestedTreeNode, selector: "mat-nested-tree-node", inputs: ["matNestedTreeNode", "disabled", "tabIndex"], outputs: ["activation", "expandedChange"], exportAs: ["matNestedTreeNode"] }, { kind: "directive", type: i3.MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "component", type: i3.MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: i3.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"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
958
1035
|
}
|
|
959
1036
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarComponent, decorators: [{
|
|
960
1037
|
type: Component,
|
|
@@ -973,7 +1050,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
973
1050
|
SdSuffixDefDirective,
|
|
974
1051
|
LayoutUserComponent$1,
|
|
975
1052
|
TranslatePipe,
|
|
976
|
-
], template: "@let _userInfo = userInfo();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar) {\n <div class=\"wrapper\" [style.height]=\"isMobileOrTablet ? screenHeight + 'px' : '100%'\">\n <div class=\"c-header\">\n @if (_sidebar.logoUrl) {\n <div class=\"c-logo\">\n <a href=\"javascript:;\" (click)=\"openHomePage()\">\n <img alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\n </a>\n </div>\n }\n <div class=\"c-title-menu-group\" [class.d-none]=\"!isShowSidebar()\">\n <span>{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\n </div>\n </div>\n <div class=\"c-body\">\n <div class=\"c-menu\">\n <div class=\"c-menu-group\">\n @if (_sidebar?.pin?.enabled && pinnedMenuGroup().children?.length) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, pinnedMenuGroup())\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, pinnedMenuGroup())\"\n (click)=\"expandPinnedGroup()\"\n [matTooltip]=\"'\u0110\u00E3 ghim'\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: isPinnedMenuGroupActive() ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: isPinnedMenuGroupActive() ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n push_pin\n </mat-icon>\n </button>\n }\n @for (nodeMenuGroup of menus(); track nodeMenuGroup.id) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, nodeMenuGroup)\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, nodeMenuGroup)\"\n (click)=\"expandMenuGroup(nodeMenuGroup)\"\n [matTooltip]=\"nodeMenuGroup.tooltipTitle || nodeMenuGroup.title\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n @if (nodeMenuGroup.iconUrl) {\n <span\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <img width=\"24px\" height=\"24px\" [src]=\"nodeMenuGroup.iconUrl\" [alt]=\"nodeMenuGroup.title\" />\n </span>\n } @else {\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n {{ nodeMenuGroup.icon || 'widgets' }}\n </mat-icon>\n }\n </button>\n }\n </div>\n <div class=\"c-menu-tree\" [class.d-none]=\"!isShowSidebar()\" [attr.inert]=\"!isShowSidebar() ? '' : null\">\n @if (totalMenuInMenusByGroup() >= 10) {\n <div style=\"padding: 0px 4px\" class=\"c-menu-tree-search\">\n <sd-input\n size=\"sm\"\n [placeholder]=\"'core.module.layout.sidebar.search' | translate\"\n [model]=\"searchText()\"\n (sdChange)=\"onFilterSearchText($event)\">\n <ng-template sdSuffixDef>\n @if (searchText()) {\n <mat-icon class=\"c-search-prefix-icon cancel\" (click)=\"onClearSearchText()\">cancel</mat-icon>\n } @else {\n <mat-icon class=\"c-search-prefix-icon search\">search</mat-icon>\n }\n </ng-template>\n </sd-input>\n </div>\n }\n <div class=\"c-menu-tree-container\">\n <mat-tree [dataSource]=\"dataSource\" [treeControl]=\"treeControl\" [style.backgroundColor]=\"'transparent'\">\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: !hasChild\">\n <li\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\"\n [ngStyle]=\"{\n backgroundColor: (currentPath() | menuFocus: node) ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <div aria-hidden=\"true\" class=\"c-menu-node-description\" (click)=\"navigate(node)\" [class.d-none]=\"!isShowSidebar()\">\n <div\n class=\"c-menu-node-description-content\"\n [ngStyle]=\"{\n color: (currentPath() | menuFocus: node) ? _sidebar.brandColor || '#2962FF' : '#1F1F1F',\n }\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n\n @if (_sidebar?.pin?.enabled) {\n <mat-icon\n class=\"c-menu-node-description-icon-pin\"\n [fontSet]=\"isPinnedNode(node) ? 'material-icons' : 'material-icons-outlined'\"\n [style.opacity]=\"isPinnedNode(node) || isHoveredNode(node) ? '1' : null\"\n [style.color]=\"isPinnedNode(node) || isHoveredNode(node) ? sidebar().brandColor || '#2962FF' : null\"\n (click)=\"onTogglePin($event, node)\"\n >push_pin\n </mat-icon>\n }\n </div>\n </li>\n </mat-nested-tree-node>\n\n <mat-nested-tree-node\n *matTreeNodeDef=\"let node; when: hasChild\"\n aria-hidden=\"true\"\n [class]=\"{ expanded: treeControl.isExpanded(node), isfocus: currentPath() | menuFocus: node }\">\n <li>\n <div\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\">\n <div class=\"d-flex align-items-center\" style=\"gap: 10px; width: 100%\">\n <div [class.d-none]=\"!isShowSidebar()\" class=\"c-menu-node-description\" (click)=\"onToggleMenuNode(node)\">\n <div\n class=\"c-menu-node-description-content\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n <mat-icon class=\"c-menu-node-description-icon-expand\">\n {{ treeControl.isExpanded(node) ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </div>\n </div>\n </div>\n <ul class=\"p-0\" [class.d-none]=\"!treeControl.isExpanded(node)\">\n <ng-container matTreeNodeOutlet></ng-container>\n </ul>\n </li>\n </mat-nested-tree-node>\n </mat-tree>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"c-footer\">\n <lib-layout-user\n [userInfo]=\"_userInfo\"\n [isMobileOrTablet]=\"isMobileOrTablet\"\n (menuOpened)=\"onUserMenuOpened()\"\n (menuClosed)=\"onUserMenuClosed()\"\n [isShowSidebar]=\"isShowSidebar()\"\n (toggleMenuLock)=\"toggleMenuLock($event)\">\n </lib-layout-user>\n </div>\n\n <div class=\"c-vertical\"></div>\n </div>\n}\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;flex:0 0 60px;width:60px;min-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{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:20px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-pin{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:18px;opacity:0}.wrapper .c-footer{height:80px}.wrapper .c-vertical{position:fixed;height:100vh;left:58px;width:2px;background-color:#f8f9fa;pointer-events:none}\n"] }]
|
|
1053
|
+
], template: "@let _userInfo = userInfo();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar) {\n <div class=\"wrapper\" [style.height]=\"isMobileOrTablet ? screenHeight + 'px' : '100%'\">\n <div class=\"c-header\">\n @if (_sidebar.logoUrl) {\n <div class=\"c-logo\">\n <a href=\"javascript:;\" (click)=\"openHomePage()\">\n <img alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\n </a>\n </div>\n }\n <div class=\"c-title-menu-group\" [class.d-none]=\"!isShowSidebar()\">\n <span>{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\n </div>\n </div>\n <div class=\"c-body\">\n <div class=\"c-menu\">\n <div class=\"c-menu-group\">\n @if (_sidebar?.pin?.enabled && pinnedMenuGroup().children?.length) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, pinnedMenuGroup())\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, pinnedMenuGroup())\"\n (click)=\"expandPinnedGroup()\"\n [matTooltip]=\"'\u0110\u00E3 ghim'\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: isPinnedMenuGroupActive() ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: isPinnedMenuGroupActive() ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n push_pin\n </mat-icon>\n </button>\n }\n @for (nodeMenuGroup of menus(); track nodeMenuGroup.id) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, nodeMenuGroup)\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, nodeMenuGroup)\"\n (click)=\"expandMenuGroup(nodeMenuGroup)\"\n [matTooltip]=\"nodeMenuGroup.tooltipTitle || nodeMenuGroup.title\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n @if (nodeMenuGroup.iconUrl) {\n <span\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <img width=\"24px\" height=\"24px\" [src]=\"nodeMenuGroup.iconUrl\" [alt]=\"nodeMenuGroup.title\" />\n </span>\n } @else {\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n {{ nodeMenuGroup.icon || 'widgets' }}\n </mat-icon>\n }\n </button>\n }\n </div>\n <div class=\"c-menu-tree\" [class.d-none]=\"!isShowSidebar()\" [attr.inert]=\"!isShowSidebar() ? '' : null\">\n @if (totalMenuInMenusByGroup() >= 10) {\n <div style=\"padding: 0px 4px\" class=\"c-menu-tree-search\">\n <sd-input\n size=\"sm\"\n [placeholder]=\"'core.module.layout.sidebar.search' | translate\"\n [model]=\"searchText()\"\n (sdChange)=\"onFilterSearchText($event)\">\n <ng-template sdSuffixDef>\n @if (searchText()) {\n <mat-icon class=\"c-search-prefix-icon cancel\" (click)=\"onClearSearchText()\">cancel</mat-icon>\n } @else {\n <mat-icon class=\"c-search-prefix-icon search\">search</mat-icon>\n }\n </ng-template>\n </sd-input>\n </div>\n }\n <div class=\"c-menu-tree-container\">\n <mat-tree [dataSource]=\"dataSource\" [treeControl]=\"treeControl\" [style.backgroundColor]=\"'transparent'\">\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: !hasChild\">\n <li\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\"\n [ngStyle]=\"{\n backgroundColor: (currentPath() | menuFocus: node : activeMenuPath()) ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <div aria-hidden=\"true\" class=\"c-menu-node-description\" (click)=\"navigate(node)\" [class.d-none]=\"!isShowSidebar()\">\n <div\n class=\"c-menu-node-description-content\"\n [ngStyle]=\"{\n color: (currentPath() | menuFocus: node : activeMenuPath()) ? _sidebar.brandColor || '#2962FF' : '#1F1F1F',\n }\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n\n @if (_sidebar?.pin?.enabled) {\n <mat-icon\n class=\"c-menu-node-description-icon-pin\"\n [fontSet]=\"isPinnedNode(node) ? 'material-icons' : 'material-icons-outlined'\"\n [style.opacity]=\"isPinnedNode(node) || isHoveredNode(node) ? '1' : null\"\n [style.color]=\"isPinnedNode(node) || isHoveredNode(node) ? sidebar().brandColor || '#2962FF' : null\"\n (click)=\"onTogglePin($event, node)\"\n >push_pin\n </mat-icon>\n }\n </div>\n </li>\n </mat-nested-tree-node>\n\n <mat-nested-tree-node\n *matTreeNodeDef=\"let node; when: hasChild\"\n aria-hidden=\"true\"\n [class]=\"{ expanded: treeControl.isExpanded(node), isfocus: currentPath() | menuFocus: node : activeMenuPath() }\">\n <li>\n <div\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\">\n <div class=\"d-flex align-items-center\" style=\"gap: 10px; width: 100%\">\n <div [class.d-none]=\"!isShowSidebar()\" class=\"c-menu-node-description\" (click)=\"onToggleMenuNode(node)\">\n <div\n class=\"c-menu-node-description-content\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n <mat-icon class=\"c-menu-node-description-icon-expand\">\n {{ treeControl.isExpanded(node) ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </div>\n </div>\n </div>\n <ul class=\"p-0\" [class.d-none]=\"!treeControl.isExpanded(node)\">\n <ng-container matTreeNodeOutlet></ng-container>\n </ul>\n </li>\n </mat-nested-tree-node>\n </mat-tree>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"c-footer\">\n <lib-layout-user\n [userInfo]=\"_userInfo\"\n [isMobileOrTablet]=\"isMobileOrTablet\"\n (menuOpened)=\"onUserMenuOpened()\"\n (menuClosed)=\"onUserMenuClosed()\"\n [isShowSidebar]=\"isShowSidebar()\"\n (toggleMenuLock)=\"toggleMenuLock($event)\">\n </lib-layout-user>\n </div>\n\n <div class=\"c-vertical\"></div>\n </div>\n}\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;flex:0 0 60px;width:60px;min-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{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:20px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-pin{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:18px;opacity:0}.wrapper .c-footer{height:80px}.wrapper .c-vertical{position:fixed;height:100vh;left:58px;width:2px;background-color:#f8f9fa;pointer-events:none}\n"] }]
|
|
977
1054
|
}], ctorParameters: () => [] });
|
|
978
1055
|
|
|
979
1056
|
class SidebarV1Component {
|
|
@@ -1291,27 +1368,27 @@ class SidebarMobileOverlayComponent {
|
|
|
1291
1368
|
this.titleMenuGroupChanged.emit('');
|
|
1292
1369
|
}
|
|
1293
1370
|
};
|
|
1294
|
-
#getMenuGroupByCurrentPath = (menus
|
|
1371
|
+
#getMenuGroupByCurrentPath = (menus) => {
|
|
1372
|
+
// Nhiều menu cùng khớp route thì chỉ path sát nhất được chọn, tránh nhận nhầm group của path cha
|
|
1373
|
+
const activePath = resolveActiveMenuPath(menus, this.currentPath());
|
|
1374
|
+
if (!activePath)
|
|
1375
|
+
return [];
|
|
1376
|
+
const menuGroup = this.#findMenuGroupByPath(menus, activePath);
|
|
1377
|
+
return menuGroup ? [menuGroup] : [];
|
|
1378
|
+
};
|
|
1379
|
+
#findMenuGroupByPath = (menus, activePath, menuGroup) => {
|
|
1295
1380
|
for (const menu of menus) {
|
|
1296
|
-
if ('path' in menu &&
|
|
1297
|
-
return
|
|
1381
|
+
if ('path' in menu && menu.path === activePath) {
|
|
1382
|
+
return menuGroup ?? menu;
|
|
1298
1383
|
}
|
|
1299
1384
|
if ('children' in menu && menu.children?.length) {
|
|
1300
|
-
const result = this.#
|
|
1301
|
-
if (result
|
|
1385
|
+
const result = this.#findMenuGroupByPath(menu.children, activePath, menuGroup ?? menu);
|
|
1386
|
+
if (result)
|
|
1302
1387
|
return result;
|
|
1303
1388
|
}
|
|
1304
1389
|
}
|
|
1305
|
-
return
|
|
1390
|
+
return null;
|
|
1306
1391
|
};
|
|
1307
|
-
#isMenuPathMatchByCurrentPath = (path) => {
|
|
1308
|
-
if (!path)
|
|
1309
|
-
return false;
|
|
1310
|
-
if (this.currentPath() === path)
|
|
1311
|
-
return true;
|
|
1312
|
-
return this.#normalizePath(this.currentPath()).startsWith(this.#normalizePath(path));
|
|
1313
|
-
};
|
|
1314
|
-
#normalizePath = (p) => p.endsWith('/') ? p : p + '/';
|
|
1315
1392
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarMobileOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1316
1393
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", 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();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar) {\n <div\n class=\"m-backdrop\"\n [class.m-backdrop--visible]=\"isShowSidebar()\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"onClose()\"\n (keydown.escape)=\"onClose()\">\n </div>\n\n <div class=\"m-wrapper\" [class.m-wrapper--open]=\"isShowSidebar()\">\n <div class=\"m-header\">\n <div class=\"m-title-group\">\n @if (_sidebar.logoUrl) {\n <img class=\"m-logo\" alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\n }\n <span class=\"m-title\">{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\n </div>\n <button class=\"m-close-btn\" (click)=\"onClose()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <div class=\"m-user-section\">\n <lib-layout-user\n [userInfo]=\"_userInfo\"\n [isMobileOrTablet]=\"true\"\n (menuOpened)=\"onUserMenuOpened()\"\n (menuClosed)=\"onUserMenuClosed()\">\n </lib-layout-user>\n </div>\n\n <div class=\"m-menu-list\">\n @for (group of menus(); track group.id) {\n <div class=\"m-menu-card\">\n <button class=\"m-card-header\" (click)=\"toggleMobileGroup(group.id)\">\n <div class=\"m-card-header-left\">\n @if (group.iconUrl) {\n <img class=\"m-group-icon\" [src]=\"group.iconUrl\" [alt]=\"group.title\" />\n } @else {\n <mat-icon class=\"m-group-icon\">{{ group.icon || 'widgets' }}</mat-icon>\n }\n <span class=\"m-group-title\">{{ group.title }}</span>\n </div>\n <mat-icon class=\"m-expand-icon\">\n {{ expandedMobileGroups().has(group.id ?? '') ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </button>\n\n @if (expandedMobileGroups().has(group.id ?? '') && hasChildren(group)) {\n <div class=\"m-card-body\">\n @for (child of getChildren(group); track child.id) {\n @if (hasChildren(child)) {\n <div class=\"m-sub-group\">\n <button class=\"m-sub-group-header\" (click)=\"toggleMobileGroup(child.id)\">\n <div class=\"m-item-left\">\n @if (child.iconUrl) {\n <img class=\"m-item-icon-img\" [src]=\"child.iconUrl\" alt=\"icon\" />\n } @else {\n <mat-icon class=\"m-item-icon\">{{ child.icon || 'folder' }}</mat-icon>\n }\n <span class=\"m-item-title\">{{ child.title }}</span>\n </div>\n <mat-icon class=\"m-expand-icon\">\n {{ expandedMobileGroups().has(child.id ?? '') ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </button>\n @if (expandedMobileGroups().has(child.id ?? '')) {\n @for (subChild of getChildren(child); track subChild.id) {\n <button class=\"m-menu-item m-menu-item--indented\"\n (click)=\"navigate({ path: getPath(subChild), queryParams: getQueryParams(subChild) })\">\n <div class=\"m-item-left\">\n @if (subChild.iconUrl) {\n <img class=\"m-item-icon-img\" [src]=\"subChild.iconUrl\" alt=\"icon\" />\n } @else {\n <mat-icon class=\"m-item-icon\">{{ subChild.icon || 'insert_drive_file' }}</mat-icon>\n }\n <span class=\"m-item-title\">{{ subChild.title }}</span>\n </div>\n <mat-icon class=\"m-nav-icon\">chevron_right</mat-icon>\n </button>\n }\n }\n </div>\n } @else {\n <button class=\"m-menu-item\" (click)=\"navigate({ path: getPath(child), queryParams: getQueryParams(child) })\">\n <div class=\"m-item-left\">\n @if (child.iconUrl) {\n <img class=\"m-item-icon-img\" [src]=\"child.iconUrl\" alt=\"icon\" />\n } @else {\n <mat-icon class=\"m-item-icon\">{{ child.icon || 'insert_drive_file' }}</mat-icon>\n }\n <span class=\"m-item-title\">{{ child.title }}</span>\n </div>\n <mat-icon class=\"m-nav-icon\">chevron_right</mat-icon>\n </button>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n}\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: i1$3.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"] }] });
|
|
1317
1394
|
}
|
|
@@ -1387,28 +1464,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
1387
1464
|
args: [{ selector: 'sd-layout', imports: [SidebarV1Component, SidebarMobileV1Component, NgTemplateOutlet], standalone: true, template: "<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n\n@let _userInfo = userInfo();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar?.version === 1) {\n @if (!isMobileOrTablet()) {\n <sidebar-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\n <ng-container [ngTemplateOutlet]=\"projectedContent\"></ng-container>\n </sidebar-v1>\n } @else {\n <sidebar-mobile-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\n <ng-container [ngTemplateOutlet]=\"projectedContent\"></ng-container>\n </sidebar-mobile-v1>\n }\n}\n" }]
|
|
1388
1465
|
}] });
|
|
1389
1466
|
|
|
1390
|
-
/**
|
|
1391
|
-
* Resolve a translated tab name for `@SdTabComponent`.
|
|
1392
|
-
*
|
|
1393
|
-
* WHY not I18nService: the decorator runs at module-evaluation time, before
|
|
1394
|
-
* Angular's DI exists, so the service cannot be injected. We read the language
|
|
1395
|
-
* the app persisted and look the key up in the static catalog instead.
|
|
1396
|
-
*/
|
|
1397
|
-
function resolveTabName(key) {
|
|
1398
|
-
const lang = (() => {
|
|
1399
|
-
try {
|
|
1400
|
-
const stored = localStorage.getItem(I18N_STORAGE_KEY);
|
|
1401
|
-
if (stored)
|
|
1402
|
-
return stored;
|
|
1403
|
-
}
|
|
1404
|
-
catch {
|
|
1405
|
-
// localStorage can throw (private mode, SSR shim) — fall back below.
|
|
1406
|
-
}
|
|
1407
|
-
return 'vi';
|
|
1408
|
-
})();
|
|
1409
|
-
return I18N_MESSAGES[lang]?.[key] ?? I18N_MESSAGES.vi[key] ?? key;
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
1467
|
// End
|
|
1413
1468
|
let HomePageComponent = class HomePageComponent {
|
|
1414
1469
|
// ==========================================
|
|
@@ -1720,5 +1775,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
1720
1775
|
* Generated bundle index. Do not edit.
|
|
1721
1776
|
*/
|
|
1722
1777
|
|
|
1723
|
-
export { ForbiddenModule, HomeModule, NotFoundModule, SD_LAYOUT_CONFIGURATION, SdLayoutComponent, SdLayoutModule, SdLayoutService, SdLayoutStorageService, SdPageComponent, SidebarMobileOverlayComponent, SidebarMobileV1Component, resolveTabName };
|
|
1778
|
+
export { ForbiddenModule, HomeModule, NotFoundModule, SD_LAYOUT_CONFIGURATION, SdLayoutComponent, SdLayoutModule, SdLayoutService, SdLayoutStorageService, SdPageComponent, SidebarMobileOverlayComponent, SidebarMobileV1Component, collectMatchedMenuPaths, containsMenuPath, isMenuPathMatch, normalizeMenuPath, resolveActiveMenuPath, resolveTabName };
|
|
1724
1779
|
//# sourceMappingURL=sd-angular-core-modules-layout.mjs.map
|