@sd-angular/core 19.0.0-beta.96 → 19.0.0-beta.97

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.
Files changed (31) hide show
  1. package/components/document-builder/src/components/header-footer-builder/header-footer-builder.component.d.ts +2 -2
  2. package/components/document-builder/src/document-builder.model.d.ts +6 -2
  3. package/components/editor/src/editor.component.d.ts +8 -0
  4. package/components/editor/src/models/image-upload.plugin.model.d.ts +33 -0
  5. package/components/editor/src/plugins/image-upload/utils/style.utils.d.ts +1 -0
  6. package/components/table/index.d.ts +1 -0
  7. package/components/table/src/models/index.d.ts +1 -0
  8. package/components/table/src/models/table-item.model.d.ts +10 -0
  9. package/components/table/src/models/table-option-style.model.d.ts +6 -1
  10. package/components/table/src/models/table-option-tree.model.d.ts +12 -0
  11. package/components/table/src/models/table-option.model.d.ts +6 -0
  12. package/components/table/src/pipes/index.d.ts +1 -0
  13. package/components/table/src/pipes/sd-tree.pipe.d.ts +9 -0
  14. package/components/table/src/services/tree/tree.util.d.ts +14 -0
  15. package/components/table/src/table.component.d.ts +3 -0
  16. package/fesm2022/sd-angular-core-components-document-builder.mjs +9 -4
  17. package/fesm2022/sd-angular-core-components-document-builder.mjs.map +1 -1
  18. package/fesm2022/sd-angular-core-components-editor.mjs +222 -97
  19. package/fesm2022/sd-angular-core-components-editor.mjs.map +1 -1
  20. package/fesm2022/sd-angular-core-components-tab-router.mjs +57 -15
  21. package/fesm2022/sd-angular-core-components-tab-router.mjs.map +1 -1
  22. package/fesm2022/sd-angular-core-components-table.mjs +325 -41
  23. package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
  24. package/fesm2022/sd-angular-core-modules-layout.mjs +172 -37
  25. package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
  26. package/modules/layout/components/sidebar-v1/components/sidebar/sidebar.component.d.ts +8 -1
  27. package/modules/layout/configurations/layout.configuration.d.ts +8 -0
  28. package/modules/layout/services/storage/storage.service.d.ts +2 -0
  29. package/package.json +70 -70
  30. package/sd-angular-core-19.0.0-beta.97.tgz +0 -0
  31. package/sd-angular-core-19.0.0-beta.96.tgz +0 -0
@@ -57,6 +57,7 @@ class SdLayoutStorageService {
57
57
  isShowSidebar;
58
58
  menuLockStatus;
59
59
  lastActiveMenuGroupId;
60
+ pinnedMenuGroup;
60
61
  // End
61
62
  constructor(sdStorageService) {
62
63
  this.sdStorageService = sdStorageService;
@@ -64,6 +65,7 @@ class SdLayoutStorageService {
64
65
  this.isShowSidebar = this.sdStorageService.create('cb07c316-ed6d-4620-9e92-53dbef6aa983');
65
66
  this.menuLockStatus = this.sdStorageService.create('2c2f4816-18b3-4ec3-8177-7b90bff036c3');
66
67
  this.lastActiveMenuGroupId = this.sdStorageService.create('2e6961d0-3380-4a94-a6a1-38837560cd96');
68
+ this.pinnedMenuGroup = this.sdStorageService.create('e81da122-5dab-4250-b309-64197fb19d44');
67
69
  // End
68
70
  }
69
71
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutStorageService, deps: [{ token: i1.SdStorageService }], target: i0.ɵɵFactoryTarget.Injectable });
@@ -405,29 +407,49 @@ class SidebarComponent {
405
407
  titleMenuGroup = signal('');
406
408
  idMenuGroupActive = signal('');
407
409
  menusByGroup = signal([]);
410
+ #hoveredMenuNodeKey = signal(null);
411
+ #pinIconHoverTimerId = signal(null);
412
+ pinnedMenuGroup = signal(this.#layoutStorageService.pinnedMenuGroup.get() ?? {
413
+ id: 'pinned-menu-group',
414
+ title: 'Đã ghim',
415
+ children: [],
416
+ });
408
417
  // ==========================================
409
418
  // COMPUTED STATE
410
419
  // ==========================================
411
420
  totalMenuInMenusByGroup = computed(() => this.#getTotalMenus(this.menusByGroup()));
421
+ pinnedNodeKeys = computed(() => new Set(this.pinnedMenuGroup().children?.map(m => this.#getMenuNodeKey(m)) ?? []));
422
+ isPinnedMenuGroupActive = computed(() => this.idMenuGroupActive() === this.pinnedMenuGroup().id);
412
423
  // ==========================================
413
424
  // DATA STRUCTURES
414
425
  // ==========================================
426
+ #pinIconHoverTimerDelay = 300;
427
+ #isFirstBindingMenu = signal(true);
415
428
  dataSource = new MatTreeNestedDataSource();
416
429
  treeControl = new NestedTreeControl(node => ('children' in node && node.children?.length ? node.children : []));
417
430
  constructor() {
418
- // 1. EFFECT: Lắng nghe menus đầu vào thay đổi
431
+ this.#setupEffects();
432
+ this.#setupSubscriptions();
433
+ }
434
+ #setupEffects() {
419
435
  effect(() => {
420
436
  const currentMenus = this.menus();
421
437
  untracked(() => {
422
438
  const lastActiveMenuGroupId = this.#layoutStorageService.lastActiveMenuGroupId.get();
423
- // Lần đầu vào web, nếu user chưa thao tác gì sẽ mặc định hiện menuGroup đầu tiên
424
- if (!lastActiveMenuGroupId) {
425
- this.#layoutStorageService.lastActiveMenuGroupId.set(currentMenus?.[0]?.id ?? '');
439
+ const pinnedGroup = this.pinnedMenuGroup();
440
+ const isPinEnabled = this.sidebar()?.pin?.enabled;
441
+ // Xử lý khi lần đầu vào web (nếu chưa có active group)
442
+ if (!lastActiveMenuGroupId || (lastActiveMenuGroupId === pinnedGroup?.id && !isPinEnabled)) {
443
+ // Ưu tiên pinnedGroup nếu đủ điều kiện, còn không lấy menu đầu tiền dev khai báo
444
+ const targetId = isPinEnabled && pinnedGroup?.children?.length ? pinnedGroup?.id : currentMenus?.[0]?.id;
445
+ this.#layoutStorageService.lastActiveMenuGroupId.set(targetId ?? '');
426
446
  }
427
447
  this.#bindingMenuGroupByCurrentPath(currentMenus);
448
+ this.#isFirstBindingMenu.set(false);
428
449
  });
429
450
  });
430
- // 2. Lắng nghe Router Event (Sử dụng takeUntilDestroyed thay thế ngOnDestroy)
451
+ }
452
+ #setupSubscriptions() {
431
453
  this.#router.events.pipe(takeUntilDestroyed(this.#destroyRef)).subscribe(event => {
432
454
  if (event instanceof NavigationEnd) {
433
455
  if (this.currentPath() !== window.location.pathname) {
@@ -444,6 +466,29 @@ class SidebarComponent {
444
466
  onToggleMenuNode = (menu) => {
445
467
  this.treeControl.toggle(menu);
446
468
  };
469
+ isPinnedNode = (node) => this.pinnedNodeKeys().has(this.#getMenuNodeKey(node));
470
+ isHoveredNode = (node) => this.#hoveredMenuNodeKey() === this.#getMenuNodeKey(node);
471
+ expandPinnedGroup = () => {
472
+ const group = this.pinnedMenuGroup();
473
+ this.idMenuGroupActive.set(group.id);
474
+ this.#layoutStorageService.lastActiveMenuGroupId.set(group.id || '');
475
+ this.titleMenuGroup.set(group.title);
476
+ this.#setMenusByGroup(group.children ?? []);
477
+ this.searchText.set('');
478
+ this.expandSideBar.emit();
479
+ };
480
+ onTogglePin = (event, node) => {
481
+ event.stopPropagation();
482
+ const key = this.#getMenuNodeKey(node);
483
+ this.pinnedMenuGroup.update(group => {
484
+ const children = group.children ?? [];
485
+ const exists = children.some(m => this.#getMenuNodeKey(m) === key);
486
+ const updatedChildren = exists ? children.filter(m => this.#getMenuNodeKey(m) !== key) : [...children, node];
487
+ const updatedGroup = { id: 'pinned-menu-group', title: 'Đã ghim', children: updatedChildren };
488
+ this.#layoutStorageService.pinnedMenuGroup.set(updatedGroup);
489
+ return updatedGroup;
490
+ });
491
+ };
447
492
  #onExpandAllMenuNodes = (menus) => {
448
493
  menus?.forEach(menu => {
449
494
  this.treeControl.expand(menu);
@@ -511,8 +556,7 @@ class SidebarComponent {
511
556
  }
512
557
  // Case 2: Menu có children
513
558
  if ('children' in menuGroupNode && menuGroupNode.children?.length) {
514
- this.menusByGroup.set(menuGroupNode.children);
515
- this.dataSource.data = this.menusByGroup();
559
+ this.#setMenusByGroup(menuGroupNode.children);
516
560
  this.searchText.set('');
517
561
  this.onFilterSearchText('');
518
562
  this.expandSideBar.emit();
@@ -557,8 +601,26 @@ class SidebarComponent {
557
601
  }
558
602
  };
559
603
  onMouseOverMenuNode = (event, menuItem) => {
604
+ const menuNode = event.currentTarget;
605
+ const brandColor = this.sidebar()?.brandColor || '#2962FF';
606
+ // Nếu có bật config pin menu
607
+ if (this.sidebar()?.pin?.enabled) {
608
+ const iconPin = menuNode.querySelector('.c-menu-node-description-icon-pin');
609
+ if (iconPin) {
610
+ if (this.#pinIconHoverTimerId()) {
611
+ clearTimeout(this.#pinIconHoverTimerId());
612
+ this.#pinIconHoverTimerId.set(null);
613
+ }
614
+ this.#pinIconHoverTimerId.set(setTimeout(() => {
615
+ this.#hoveredMenuNodeKey.set(this.#getMenuNodeKey(menuItem));
616
+ iconPin.style.color = brandColor;
617
+ iconPin.style.transition = 'all 0.15s';
618
+ iconPin.style.opacity = '1';
619
+ this.#pinIconHoverTimerId.set(null);
620
+ }, this.#pinIconHoverTimerDelay));
621
+ }
622
+ }
560
623
  if (!this.#menuFocusPipe.transform(this.currentPath(), menuItem)) {
561
- const menuNode = event.currentTarget;
562
624
  const iconMenu = menuNode.querySelector('.c-menu-node-icon');
563
625
  const content = menuNode.querySelector('.c-menu-node-description-content');
564
626
  const iconExpand = menuNode.querySelector('.c-menu-node-description-icon-expand');
@@ -566,7 +628,6 @@ class SidebarComponent {
566
628
  if (menuNode) {
567
629
  menuNode.style.transition = 'all 0.15s';
568
630
  menuNode.style.backgroundColor = brandLightColorOpacity || 'rgba(248, 249, 250, 0.6)';
569
- const brandColor = this.sidebar()?.brandColor || '#2962FF';
570
631
  if (iconMenu) {
571
632
  iconMenu.style.transition = 'all 0.15s';
572
633
  iconMenu.style.color = brandColor;
@@ -583,8 +644,24 @@ class SidebarComponent {
583
644
  }
584
645
  };
585
646
  onMouseLeaveMenuNode = (event, menuItem) => {
647
+ const menuNode = event.currentTarget;
648
+ // Nếu có bật config pin menu
649
+ if (this.sidebar()?.pin?.enabled) {
650
+ const iconPin = menuNode.querySelector('.c-menu-node-description-icon-pin');
651
+ if (iconPin) {
652
+ if (this.#pinIconHoverTimerId()) {
653
+ clearTimeout(this.#pinIconHoverTimerId());
654
+ this.#pinIconHoverTimerId.set(null);
655
+ }
656
+ this.#hoveredMenuNodeKey.set(null);
657
+ iconPin.style.transition = 'all 0.15s';
658
+ if (!this.isPinnedNode(menuItem)) {
659
+ iconPin.style.color = '#8C8C8C';
660
+ iconPin.style.opacity = '0';
661
+ }
662
+ }
663
+ }
586
664
  if (!this.#menuFocusPipe.transform(this.currentPath(), menuItem)) {
587
- const menuNode = event.currentTarget;
588
665
  const iconMenu = menuNode.querySelector('.c-menu-node-icon');
589
666
  const content = menuNode.querySelector('.c-menu-node-description-content');
590
667
  const iconExpand = menuNode.querySelector('.c-menu-node-description-icon-expand');
@@ -609,6 +686,19 @@ class SidebarComponent {
609
686
  // ==========================================
610
687
  // PRIVATE LOGIC
611
688
  // ==========================================
689
+ #setMenusByGroup = (menus) => {
690
+ this.menusByGroup.set(menus);
691
+ this.dataSource.data = menus;
692
+ };
693
+ #getMenuNodeKey = (node) => {
694
+ if (node?.id) {
695
+ return node.id;
696
+ }
697
+ if ('path' in node && node.path) {
698
+ return node.path;
699
+ }
700
+ return node.title || '';
701
+ };
612
702
  #getMenuGroupByCurrentPath = (menus, menuGroup) => {
613
703
  for (const menu of menus) {
614
704
  if ('path' in menu && this.#isMenuPathMatchByCurrentPath(menu.path)) {
@@ -616,31 +706,68 @@ class SidebarComponent {
616
706
  }
617
707
  if ('children' in menu && menu.children?.length) {
618
708
  const result = this.#getMenuGroupByCurrentPath(menu.children, menuGroup ?? menu);
619
- if (result?.length)
709
+ if (result?.length) {
620
710
  return result;
711
+ }
621
712
  }
622
713
  }
623
714
  return [];
624
715
  };
625
716
  #bindingMenuGroupByCurrentPath = (menus) => {
626
- const normalizeSearchText = this.#normalizeSearchText(this.searchText());
627
- if (!normalizeSearchText || normalizeSearchText.length < 3) {
717
+ // Chỉ bindingGroup mới khi người dùng không searchText
718
+ if (!this.#getValidSearchText()) {
719
+ const pinnedChildren = this.pinnedMenuGroup()?.children ?? [];
720
+ // Ưu tiên: Current path khớp với item trong pinMenuGroup thì lần đầu vào trang sẽ hiện pinnedMenuGroup
721
+ const isPinnedPathMatchValid = this.sidebar()?.pin?.enabled &&
722
+ pinnedChildren?.length &&
723
+ this.#getMenuGroupByCurrentPath(pinnedChildren)?.length &&
724
+ this.#isFirstBindingMenu() &&
725
+ this.idMenuGroupActive() !== this.pinnedMenuGroup()?.id;
726
+ if (isPinnedPathMatchValid) {
727
+ const pinned = this.pinnedMenuGroup();
728
+ this.idMenuGroupActive.set(pinned.id);
729
+ this.#layoutStorageService.lastActiveMenuGroupId.set(pinned.id ?? '');
730
+ this.titleMenuGroup.set(pinned.title);
731
+ this.#setMenusByGroup(pinnedChildren);
732
+ this.#expandParentNodesByCurrentPath(pinnedChildren);
733
+ return;
734
+ }
628
735
  let menuGroupByPath = this.#getMenuGroupByCurrentPath(menus);
736
+ // Nếu không tìm được path nào khớp với menu
629
737
  if (!menuGroupByPath?.length) {
630
738
  const lastActiveId = this.#layoutStorageService.lastActiveMenuGroupId.get() || '';
739
+ // Nếu có pinned group thì hiện mậc định là pinnedMenuGroup
740
+ if (this.sidebar()?.pin?.enabled && lastActiveId === this.pinnedMenuGroup()?.id && pinnedChildren?.length) {
741
+ const pinned = this.pinnedMenuGroup();
742
+ this.idMenuGroupActive.set(pinned.id);
743
+ this.titleMenuGroup.set(pinned.title);
744
+ this.#setMenusByGroup(pinnedChildren);
745
+ this.#expandParentNodesByCurrentPath(pinnedChildren);
746
+ return;
747
+ }
748
+ // Nếu không có pinnedMenuGroup thì menuGroup lấy từ thao tác cuối cùng của người dùng
631
749
  menuGroupByPath = this.menus()?.filter(menu => menu?.id === lastActiveId) || [];
632
750
  }
751
+ // Kiểm tra lại menuGroupPath đã thực sự tìm được chưa?
633
752
  if (menuGroupByPath?.length) {
634
- const matchedGroup = menuGroupByPath[0];
635
- this.idMenuGroupActive.set(matchedGroup?.id);
636
- this.#layoutStorageService.lastActiveMenuGroupId.set(matchedGroup?.id || '');
637
- this.titleMenuGroup.set(matchedGroup?.tooltipTitle || matchedGroup?.title);
638
- if ('children' in matchedGroup && matchedGroup.children?.length) {
639
- this.menusByGroup.set(matchedGroup.children);
640
- this.#expandParentNodesByCurrentPath(this.menusByGroup());
753
+ // Nếu user đang ở pinedGroup và curentPath có chứa trong pinnedMenuGroup thì return luôn, không chuyển sang menuGroup mới
754
+ if (this.sidebar()?.pin?.enabled &&
755
+ this.idMenuGroupActive() === this.pinnedMenuGroup()?.id &&
756
+ this.#getMenuGroupByCurrentPath(pinnedChildren)?.length) {
757
+ return;
641
758
  }
642
759
  else {
643
- this.menusByGroup.set([]);
760
+ const matchedGroup = menuGroupByPath[0];
761
+ this.idMenuGroupActive.set(matchedGroup?.id);
762
+ this.#layoutStorageService.lastActiveMenuGroupId.set(matchedGroup?.id || '');
763
+ this.titleMenuGroup.set(matchedGroup?.tooltipTitle || matchedGroup?.title);
764
+ if ('children' in matchedGroup && matchedGroup.children?.length) {
765
+ this.menusByGroup.set(matchedGroup.children);
766
+ this.#expandParentNodesByCurrentPath(this.menusByGroup());
767
+ }
768
+ else {
769
+ this.menusByGroup.set([]);
770
+ }
644
771
  }
645
772
  }
646
773
  else {
@@ -668,14 +795,14 @@ class SidebarComponent {
668
795
  return shouldPropagate;
669
796
  }
670
797
  #filterMenuBySearchText = (menus) => {
671
- const normalizeSearchText = this.#normalizeSearchText(this.searchText());
672
- if (!normalizeSearchText || normalizeSearchText.length < 2) {
798
+ const validSearchText = this.#getValidSearchText();
799
+ if (!validSearchText) {
673
800
  this.dataSource.data = menus;
674
801
  this.#onCollapseAllMenuNodes(menus);
675
802
  this.#expandParentNodesByCurrentPath(menus);
676
803
  }
677
804
  else {
678
- const aliasSearchText = SdUtilities.changeAliasLowerCase(normalizeSearchText);
805
+ const aliasSearchText = SdUtilities.changeAliasLowerCase(validSearchText);
679
806
  this.dataSource.data = this.#getMenuByAliasSearchText(menus, aliasSearchText);
680
807
  if (this.dataSource.data?.length) {
681
808
  this.#onExpandAllMenuNodes(this.dataSource.data);
@@ -701,10 +828,12 @@ class SidebarComponent {
701
828
  return result;
702
829
  };
703
830
  #isMenuPathMatchByCurrentPath = (path) => {
704
- if (!path)
831
+ if (!path) {
705
832
  return false;
706
- if (this.currentPath() === path)
833
+ }
834
+ if (this.currentPath() === path) {
707
835
  return true;
836
+ }
708
837
  return this.#normalizePath(this.currentPath()).startsWith(this.#normalizePath(path));
709
838
  };
710
839
  #normalizePath = (p) => (p.endsWith('/') ? p : p + '/');
@@ -712,8 +841,9 @@ class SidebarComponent {
712
841
  this.showSideBar.emit(null);
713
842
  }
714
843
  #convertColor = (input, opacity = 1) => {
715
- if (!input)
844
+ if (!input) {
716
845
  return '';
846
+ }
717
847
  input = input.trim();
718
848
  const hexRegex = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
719
849
  const rgbRegex = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i;
@@ -738,6 +868,10 @@ class SidebarComponent {
738
868
  }
739
869
  return input;
740
870
  };
871
+ #getValidSearchText = () => {
872
+ const normalized = this.#normalizeSearchText(this.searchText());
873
+ return normalized && normalized.length >= 2 ? normalized : '';
874
+ };
741
875
  #normalizeSearchText = (searchText) => {
742
876
  let str = searchText?.toString() ?? '';
743
877
  /* eslint-disable no-useless-escape */
@@ -759,7 +893,7 @@ class SidebarComponent {
759
893
  return count;
760
894
  };
761
895
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
762
- 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();\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]=\"'core.module.layout.sidebar.search' | translate\" [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$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" }] });
896
+ 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();\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 @if (_sidebar?.pin?.enabled && pinnedMenuGroup()?.children?.length) {\r\n <button\r\n (mouseenter)=\"onMouseOverMenuGroupNode($event, pinnedMenuGroup())\"\r\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, pinnedMenuGroup())\"\r\n (click)=\"expandPinnedGroup()\"\r\n [matTooltip]=\"'\u0110\u00E3 ghim'\"\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 <mat-icon\r\n class=\"c-menu-group-icon\"\r\n [ngStyle]=\"{\r\n color: isPinnedMenuGroupActive() ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\r\n backgroundColor: isPinnedMenuGroupActive() ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n push_pin\r\n </mat-icon>\r\n </button>\r\n }\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]=\"'core.module.layout.sidebar.search' | translate\" [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\r\n @if (_sidebar?.pin?.enabled) {\r\n <mat-icon\r\n class=\"c-menu-node-description-icon-pin\"\r\n [fontSet]=\"isPinnedNode(node) ? 'material-icons' : 'material-icons-outlined'\"\r\n [style.opacity]=\"isPinnedNode(node) || isHoveredNode(node) ? '1' : null\"\r\n [style.color]=\"isPinnedNode(node) || isHoveredNode(node) ? sidebar()?.brandColor || '#2962FF' : null\"\r\n (click)=\"onTogglePin($event, node)\"\r\n >push_pin\r\n </mat-icon>\r\n }\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}\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{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", "tooltip", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "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" }] });
763
897
  }
764
898
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarComponent, decorators: [{
765
899
  type: Component,
@@ -778,7 +912,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
778
912
  SdSuffixDefDirective,
779
913
  LayoutUserComponent$1,
780
914
  TranslatePipe,
781
- ], 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]=\"'core.module.layout.sidebar.search' | translate\" [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"] }]
915
+ ], 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 @if (_sidebar?.pin?.enabled && pinnedMenuGroup()?.children?.length) {\r\n <button\r\n (mouseenter)=\"onMouseOverMenuGroupNode($event, pinnedMenuGroup())\"\r\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, pinnedMenuGroup())\"\r\n (click)=\"expandPinnedGroup()\"\r\n [matTooltip]=\"'\u0110\u00E3 ghim'\"\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 <mat-icon\r\n class=\"c-menu-group-icon\"\r\n [ngStyle]=\"{\r\n color: isPinnedMenuGroupActive() ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\r\n backgroundColor: isPinnedMenuGroupActive() ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\r\n }\">\r\n push_pin\r\n </mat-icon>\r\n </button>\r\n }\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]=\"'core.module.layout.sidebar.search' | translate\" [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\r\n @if (_sidebar?.pin?.enabled) {\r\n <mat-icon\r\n class=\"c-menu-node-description-icon-pin\"\r\n [fontSet]=\"isPinnedNode(node) ? 'material-icons' : 'material-icons-outlined'\"\r\n [style.opacity]=\"isPinnedNode(node) || isHoveredNode(node) ? '1' : null\"\r\n [style.color]=\"isPinnedNode(node) || isHoveredNode(node) ? sidebar()?.brandColor || '#2962FF' : null\"\r\n (click)=\"onTogglePin($event, node)\"\r\n >push_pin\r\n </mat-icon>\r\n }\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}\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{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"] }]
782
916
  }], ctorParameters: () => [] });
783
917
 
784
918
  class SidebarV1Component {
@@ -1187,6 +1321,15 @@ let HomePageComponent = class HomePageComponent {
1187
1321
  // ==========================================
1188
1322
  #layoutService = inject(SdLayoutService);
1189
1323
  #i18n = inject(I18nService);
1324
+ // Map Language code → BCP 47 locale tag dùng cho Intl date formatting
1325
+ // WHY: must be declared before todayInfo — field init runs top-to-bottom; #getTodayInfo reads #localeMap.
1326
+ #localeMap = {
1327
+ vi: 'vi-VN',
1328
+ en: 'en-US',
1329
+ ja: 'ja-JP',
1330
+ ko: 'ko-KR',
1331
+ zh: 'zh-CN',
1332
+ };
1190
1333
  // ==========================================
1191
1334
  // SIGNALS (STATE)
1192
1335
  // ==========================================
@@ -1206,14 +1349,6 @@ let HomePageComponent = class HomePageComponent {
1206
1349
  // ==========================================
1207
1350
  // PRIVATE METHODS
1208
1351
  // ==========================================
1209
- // Map Language code → BCP 47 locale tag dùng cho Intl date formatting
1210
- #localeMap = {
1211
- vi: 'vi-VN',
1212
- en: 'en-US',
1213
- ja: 'ja-JP',
1214
- ko: 'ko-KR',
1215
- zh: 'zh-CN',
1216
- };
1217
1352
  #getTimezone() {
1218
1353
  const now = new Date();
1219
1354
  const timezoneOffset = now.getTimezoneOffset();