@naniteninja/dashboard-components-lib 2.1.10 → 2.1.12

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.
@@ -5158,6 +5158,7 @@ class LibDashboardSwipeableTabsComponent {
5158
5158
  this.showGlobalMenu = false;
5159
5159
  this.activeContextMenuNode = null;
5160
5160
  this.contextMenuPosition = { x: 0, y: 0 };
5161
+ this.globalMenuClickListener = null;
5161
5162
  this.settingsTriggerPortalViewRef = null;
5162
5163
  this.settingsTriggerPortalEl = null;
5163
5164
  this.settingsTriggerPortaled = false;
@@ -5170,6 +5171,8 @@ class LibDashboardSwipeableTabsComponent {
5170
5171
  this.settingsTriggerRafId = null;
5171
5172
  this.contextMenuViewRef = null;
5172
5173
  this.contextMenuClickListener = null;
5174
+ this.confirmDialogViewRef = null;
5175
+ this.confirmDialogKeyListener = null;
5173
5176
  this.pendingGroupingMode = null;
5174
5177
  this.alertViewRef = null;
5175
5178
  this.alertDismissTimer = null;
@@ -5191,6 +5194,8 @@ class LibDashboardSwipeableTabsComponent {
5191
5194
  this.dragMoveSubject = new Subject();
5192
5195
  this.destroy$ = new Subject();
5193
5196
  this.recentlyDroppedId = null;
5197
+ this.runtimeIdSeq = 0;
5198
+ this.runtimeIdByObject = new WeakMap();
5194
5199
  // ── Auto-sort ─────────────────────────────────────────────────────────────
5195
5200
  this.colorChangeSubject = new Subject();
5196
5201
  this.COLOR_CHANGE_DEBOUNCE_MS = 800;
@@ -5391,6 +5396,7 @@ class LibDashboardSwipeableTabsComponent {
5391
5396
  }
5392
5397
  ngOnDestroy() {
5393
5398
  this.closeMenus();
5399
+ this.dismissConfirmDialog();
5394
5400
  this.dismissAlert();
5395
5401
  this.stopEdgeScroll();
5396
5402
  this.destroy$.next();
@@ -5431,8 +5437,21 @@ class LibDashboardSwipeableTabsComponent {
5431
5437
  if (event)
5432
5438
  event.stopPropagation();
5433
5439
  this.ngZone.run(() => {
5440
+ this.pendingGroupingMode = null;
5441
+ this.dismissConfirmDialog();
5434
5442
  this.showGlobalMenu = !this.showGlobalMenu;
5435
5443
  this.activeContextMenuNode = null;
5444
+ if (this.showGlobalMenu) {
5445
+ if (!this.globalMenuClickListener) {
5446
+ this.globalMenuClickListener = this.renderer.listen('document', 'click', () => this.closeMenus());
5447
+ }
5448
+ }
5449
+ else {
5450
+ if (this.globalMenuClickListener) {
5451
+ this.globalMenuClickListener();
5452
+ this.globalMenuClickListener = null;
5453
+ }
5454
+ }
5436
5455
  this.cdr.markForCheck();
5437
5456
  });
5438
5457
  }
@@ -5449,12 +5468,8 @@ class LibDashboardSwipeableTabsComponent {
5449
5468
  const hasManualGroups = this.tabNodes.some(n => n.type === 'group');
5450
5469
  if (hasManualGroups && mode !== 'none') {
5451
5470
  this.pendingGroupingMode = mode;
5452
- this.cdr.detectChanges(); // Ensure showGlobalMenu = false is applied
5453
- setTimeout(() => {
5454
- if (this.confirmPopper) {
5455
- this.confirmPopper.show();
5456
- }
5457
- }, 100);
5471
+ this.dismissConfirmDialog();
5472
+ this.openConfirmDialog();
5458
5473
  return;
5459
5474
  }
5460
5475
  this.executeGroupBy(mode);
@@ -5502,22 +5517,41 @@ class LibDashboardSwipeableTabsComponent {
5502
5517
  }
5503
5518
  }
5504
5519
  // ═══════════════════════════════════════════════════════════════════════════
5505
- // CONFIRMATION DIALOG (POPPER)
5520
+ // CONFIRMATION DIALOG (PORTAL)
5506
5521
  // ═══════════════════════════════════════════════════════════════════════════
5522
+ openConfirmDialog() {
5523
+ if (this.confirmDialogViewRef)
5524
+ return;
5525
+ this.confirmDialogViewRef = this.viewContainerRef.createEmbeddedView(this.confirmDialogTemplate);
5526
+ this.confirmDialogViewRef.detectChanges();
5527
+ this.confirmDialogViewRef.rootNodes.forEach(n => document.body.appendChild(n));
5528
+ this.confirmDialogKeyListener = this.renderer.listen('document', 'keydown', (event) => {
5529
+ if (event.key !== 'Escape')
5530
+ return;
5531
+ this.ngZone.run(() => this.cancelGroupBy());
5532
+ });
5533
+ }
5534
+ dismissConfirmDialog() {
5535
+ if (this.confirmDialogKeyListener) {
5536
+ this.confirmDialogKeyListener();
5537
+ this.confirmDialogKeyListener = null;
5538
+ }
5539
+ if (this.confirmDialogViewRef) {
5540
+ this.confirmDialogViewRef.rootNodes.forEach(n => this.renderer.removeChild(document.body, n));
5541
+ this.confirmDialogViewRef.destroy();
5542
+ this.confirmDialogViewRef = null;
5543
+ }
5544
+ }
5507
5545
  confirmGroupBy() {
5508
5546
  if (this.pendingGroupingMode) {
5509
5547
  this.executeGroupBy(this.pendingGroupingMode);
5510
5548
  this.pendingGroupingMode = null;
5511
5549
  }
5512
- if (this.confirmPopper) {
5513
- this.confirmPopper.hide();
5514
- }
5550
+ this.dismissConfirmDialog();
5515
5551
  }
5516
5552
  cancelGroupBy() {
5517
5553
  this.pendingGroupingMode = null;
5518
- if (this.confirmPopper) {
5519
- this.confirmPopper.hide();
5520
- }
5554
+ this.dismissConfirmDialog();
5521
5555
  }
5522
5556
  // ═══════════════════════════════════════════════════════════════════════════
5523
5557
  // ALERT (TOASTR)
@@ -5548,6 +5582,12 @@ class LibDashboardSwipeableTabsComponent {
5548
5582
  // GROUP BY
5549
5583
  // ═══════════════════════════════════════════════════════════════════════════
5550
5584
  executeGroupBy(mode) {
5585
+ this.pendingGroupingMode = null;
5586
+ this.dismissConfirmDialog();
5587
+ if (this.globalMenuClickListener) {
5588
+ this.globalMenuClickListener();
5589
+ this.globalMenuClickListener = null;
5590
+ }
5551
5591
  this.currentGroupingMode = mode;
5552
5592
  if (mode === 'none') {
5553
5593
  // Flatten all groups → individual ungrouped nodes
@@ -5557,7 +5597,7 @@ class LibDashboardSwipeableTabsComponent {
5557
5597
  flat.push(node);
5558
5598
  }
5559
5599
  else {
5560
- node.data.items.forEach((item) => flat.push({ id: `ungrouped-${this.getSafeId(item)}`, type: 'item', data: item }));
5600
+ node.data.items.forEach((item) => flat.push({ id: `ungrouped-${this.getRuntimeId(item)}`, type: 'item', data: item }));
5561
5601
  }
5562
5602
  });
5563
5603
  this.tabNodes = flat;
@@ -5584,7 +5624,7 @@ class LibDashboardSwipeableTabsComponent {
5584
5624
  groups[safeId].data.items.push(item);
5585
5625
  }
5586
5626
  else {
5587
- unassigned.push({ id: this.getSafeId(item) || `item-${Date.now()}`, type: 'item', data: item });
5627
+ unassigned.push({ id: `item-${this.getRuntimeId(item)}`, type: 'item', data: item });
5588
5628
  }
5589
5629
  });
5590
5630
  // Sort items within each group by response time
@@ -5645,12 +5685,14 @@ class LibDashboardSwipeableTabsComponent {
5645
5685
  */
5646
5686
  mergeNewItemsAfterRestore(storedRule) {
5647
5687
  const restoredIds = this.collectCurrentIds();
5648
- const newItems = this.items.filter(i => !restoredIds.has(this.getSafeId(i)));
5688
+ const newItems = this.items.filter(i => {
5689
+ const id = this.getSafeId(i);
5690
+ return id ? !restoredIds.has(id) : true;
5691
+ });
5649
5692
  if (!newItems.length) {
5650
5693
  this.refreshDataReferences();
5651
5694
  return;
5652
5695
  }
5653
- const now = Date.now();
5654
5696
  if (storedRule === 'response') {
5655
5697
  this.executeGroupBy('response');
5656
5698
  }
@@ -5659,18 +5701,21 @@ class LibDashboardSwipeableTabsComponent {
5659
5701
  }
5660
5702
  else {
5661
5703
  // Manual/None → leftmost ungrouped
5662
- [...newItems].reverse().forEach(item => this.tabNodes.unshift({ id: `new-${this.getSafeId(item)}`, type: 'item', data: item }));
5704
+ [...newItems].reverse().forEach(item => this.tabNodes.unshift({ id: `new-${this.getRuntimeId(item)}`, type: 'item', data: item }));
5663
5705
  }
5664
5706
  this.refreshDataReferences();
5665
5707
  }
5666
5708
  mergeAsUngroupedLeft() {
5667
5709
  const currentIds = this.collectCurrentIds();
5668
- const newItems = this.items.filter(i => !currentIds.has(this.getSafeId(i)));
5710
+ const newItems = this.items.filter(i => {
5711
+ const id = this.getSafeId(i);
5712
+ return id ? !currentIds.has(id) : true;
5713
+ });
5669
5714
  if (!newItems.length) {
5670
5715
  this.refreshDataReferences();
5671
5716
  return;
5672
5717
  }
5673
- [...newItems].reverse().forEach(item => this.tabNodes.unshift({ id: `new-${this.getSafeId(item)}`, type: 'item', data: item }));
5718
+ [...newItems].reverse().forEach(item => this.tabNodes.unshift({ id: `new-${this.getRuntimeId(item)}`, type: 'item', data: item }));
5674
5719
  this.refreshDataReferences();
5675
5720
  }
5676
5721
  mergePerResponseRule() { this.executeGroupBy('response'); }
@@ -5678,8 +5723,10 @@ class LibDashboardSwipeableTabsComponent {
5678
5723
  collectCurrentIds() {
5679
5724
  const ids = new Set();
5680
5725
  this.tabNodes.forEach(n => n.type === 'group'
5681
- ? n.data.items.forEach((i) => ids.add(this.getSafeId(i)))
5682
- : ids.add(this.getSafeId(n.data)));
5726
+ ? n.data.items.forEach((i) => { const id = this.getSafeId(i); if (id)
5727
+ ids.add(id); })
5728
+ : (() => { const id = this.getSafeId(n.data); if (id)
5729
+ ids.add(id); })());
5683
5730
  return ids;
5684
5731
  }
5685
5732
  getStoredRule() {
@@ -5727,6 +5774,10 @@ class LibDashboardSwipeableTabsComponent {
5727
5774
  closeMenus() {
5728
5775
  this.showGlobalMenu = false;
5729
5776
  this.activeContextMenuNode = null;
5777
+ if (this.globalMenuClickListener) {
5778
+ this.globalMenuClickListener();
5779
+ this.globalMenuClickListener = null;
5780
+ }
5730
5781
  if (this.contextMenuViewRef) {
5731
5782
  this.contextMenuViewRef.rootNodes.forEach(n => this.renderer.removeChild(document.body, n));
5732
5783
  this.contextMenuViewRef.destroy();
@@ -6214,17 +6265,21 @@ class LibDashboardSwipeableTabsComponent {
6214
6265
  }
6215
6266
  updateDisplayItems() {
6216
6267
  const prevActive = this.displayItems?.length > 0 ? this.displayItems[this.activeIndex] : null;
6217
- const itemMap = new Map(this.items.map(i => [this.getSafeId(i), i]));
6268
+ const itemMap = new Map(this.items.map(i => [this.getSafeId(i), i]).filter(([id]) => !!id));
6218
6269
  this.displayItems = [];
6219
6270
  this.tabNodes.forEach(node => {
6220
6271
  if (node.type === 'item') {
6221
- const fresh = itemMap.get(this.getSafeId(node.data));
6272
+ const id = this.getSafeId(node.data);
6273
+ const fresh = id ? itemMap.get(id) : undefined;
6222
6274
  if (fresh)
6223
6275
  node.data = fresh;
6224
6276
  this.displayItems.push(node.data);
6225
6277
  }
6226
6278
  else {
6227
- node.data.items = node.data.items.map((item) => itemMap.get(this.getSafeId(item)) ?? item);
6279
+ node.data.items = node.data.items.map((item) => {
6280
+ const itemId = this.getSafeId(item);
6281
+ return itemId ? itemMap.get(itemId) ?? item : item;
6282
+ });
6228
6283
  this.displayItems.push(...node.data.items);
6229
6284
  }
6230
6285
  });
@@ -6674,11 +6729,22 @@ class LibDashboardSwipeableTabsComponent {
6674
6729
  trackByItem(index, item) {
6675
6730
  if (!item)
6676
6731
  return `index-${index}`;
6677
- const id = item._id || item.id;
6678
- if (!id)
6679
- return `index-${index}`;
6680
- const s = String(id);
6681
- return s === '[object Object]' ? `index-${index}` : `id-${s}`;
6732
+ return `rid-${this.getRuntimeId(item)}`;
6733
+ }
6734
+ getRuntimeId(item) {
6735
+ const safe = this.getSafeId(item);
6736
+ if (safe)
6737
+ return safe;
6738
+ if (item && typeof item === 'object') {
6739
+ const obj = item;
6740
+ const existing = this.runtimeIdByObject.get(obj);
6741
+ if (existing)
6742
+ return existing;
6743
+ const next = `anon-${++this.runtimeIdSeq}`;
6744
+ this.runtimeIdByObject.set(obj, next);
6745
+ return next;
6746
+ }
6747
+ return `anon-${++this.runtimeIdSeq}`;
6682
6748
  }
6683
6749
  getSafeId(item) {
6684
6750
  if (!item)
@@ -6794,11 +6860,11 @@ class LibDashboardSwipeableTabsComponent {
6794
6860
  requestAnimationFrame(() => { ref.mainSwiperInstance?.update(); ref.thumbsSwiperInstance?.update(); });
6795
6861
  }
6796
6862
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LibDashboardSwipeableTabsComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ViewContainerRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
6797
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LibDashboardSwipeableTabsComponent, isStandalone: true, selector: "lib-dashboard-swipeable-tabs", inputs: { thumbsSwiperOptions: "thumbsSwiperOptions", mainSwiperOptions: "mainSwiperOptions", activeIndex: "activeIndex", bottomThumbs: "bottomThumbs", slideContentMaxHeight: "slideContentMaxHeight", mainSwiperHeight: "mainSwiperHeight", subMainSwiperHeight: "subMainSwiperHeight", thumbsSwiperHeight: "thumbsSwiperHeight", generalSwiperHeight: "generalSwiperHeight", enableGrouping: "enableGrouping", enableDragAndDrop: "enableDragAndDrop", enableTabBarScrollDrag: "enableTabBarScrollDrag", items: "items", thumbTemplate: "thumbTemplate", contentTemplate: "contentTemplate", groupingAdapter: "groupingAdapter", showPrefRejectButton: "showPrefRejectButton", menuPosition: "menuPosition" }, outputs: { repositionModeChange: "repositionModeChange", activeIndexChange: "activeIndexChange", itemClicked: "itemClicked", expandedIdChange: "expandedIdChange" }, queries: [{ propertyName: "thumbSlides", first: true, predicate: ["thumbSlides"], descendants: true }], viewQueries: [{ propertyName: "thumbSwiper", first: true, predicate: ["thumbSwiper"], descendants: true }, { propertyName: "mainSwiper", first: true, predicate: ["mainSwiper"], descendants: true }, { propertyName: "settingsTriggerWrapperEl", first: true, predicate: ["settingsTriggerWrapperEl"], descendants: true }, { propertyName: "settingsTriggerPortalTemplate", first: true, predicate: ["settingsTriggerPortalTemplate"], descendants: true }, { propertyName: "contextMenuTemplate", first: true, predicate: ["contextMenuTemplate"], descendants: true }, { propertyName: "confirmPopper", first: true, predicate: ["confirmPopper"], descendants: true }, { propertyName: "alertTemplate", first: true, predicate: ["alertTemplate"], descendants: true }, { propertyName: "tabBarContainer", first: true, predicate: ["tabBarContainer"], descendants: true }, { propertyName: "expandedPortalTemplate", first: true, predicate: ["expandedPortalTemplate"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"swipeable-tabs-container\"\n [class.bottom-thumbs]=\"bottomThumbs\"\n [ngStyle]=\"{ height: generalSwiperHeight }\"\n [style.--thumbs-height]=\"thumbsSwiperHeight\"\n>\n\n <!-- \u2500\u2500 LEGACY MODE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (!enableGrouping) {\n <ng-container>\n <swiper-container #thumbSwiper init=\"false\" class=\"thumb-swiper container-sides-shadow\" [ngStyle]=\"{ height: thumbsSwiperHeight }\">\n <ng-content select=\"[thumb-slides]\"></ng-content>\n </swiper-container>\n <div class=\"swiper-container main-swiper\" [style.max-height]=\"slideContentMaxHeight\" [ngStyle]=\"{ height: mainSwiperHeight }\">\n <swiper-container #mainSwiper init=\"false\" class=\"main-swiper\" [class.container-sides-shadow]=\"activeIndex !== 0\" [ngStyle]=\"{ height: subMainSwiperHeight }\">\n <ng-content select=\"[main-slides]\"></ng-content>\n </swiper-container>\n </div>\n </ng-container>\n }\n\n <!-- \u2500\u2500 GROUPING MODE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (enableGrouping) {\n <ng-container>\n\n <!-- Settings trigger -->\n <div class=\"settings-trigger-wrapper\" #settingsTriggerWrapperEl>\n <div class=\"settings-trigger\" [class.settings-trigger--hidden]=\"settingsTriggerPortaled\" (click)=\"toggleGlobalMenu($event)\" [libPopper]=\"confirmPopper\" [popperTrigger]=\"'none'\">\n <i class=\"pi pi-cog\"></i>\n </div>\n @if (showGlobalMenu) {\n <div class=\"global-menu\" [ngClass]=\"'menu-' + menuPosition\" (click)=\"$event.stopPropagation()\">\n <div class=\"menu-item\" (click)=\"requestGroupBy('response')\">Group by Response</div>\n <div class=\"menu-item\" (click)=\"requestGroupBy('client')\">Group by Client</div>\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"restoreCustomGroups()\">Restore Custom Groups</div>\n <div class=\"menu-item\" (click)=\"storeCustomGroups()\">Store Custom Groups</div>\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"ungroupAll()\">Ungroup All</div>\n </div>\n }\n </div>\n\n <ng-template #settingsTriggerPortalTemplate>\n <div\n class=\"settings-trigger-wrapper settings-trigger-wrapper-portal\"\n [style.left.px]=\"settingsTriggerPortalLeft\"\n [style.top.px]=\"settingsTriggerPortalTop\"\n >\n <div class=\"settings-trigger\" (click)=\"toggleGlobalMenu($event)\" [libPopper]=\"confirmPopper\" [popperTrigger]=\"'none'\">\n <i class=\"pi pi-cog\"></i>\n </div>\n </div>\n </ng-template>\n\n <!-- Tab Bar -->\n <div class=\"tab-bar-container\"\n #tabBarContainer\n cdkScrollable\n [class.dragging-active]=\"isDragging\"\n [class.grouping-animating]=\"groupingAnimating\"\n [class.grab-cursor]=\"!repositionMode && !isScrollDragging\"\n [class.grabbing-cursor]=\"isScrollDragging\"\n [ngStyle]=\"{ minHeight: thumbsSwiperHeight }\"\n tabindex=\"0\">\n\n <div\n cdkDropList\n [id]=\"rootDropListId\"\n [cdkDropListConnectedTo]=\"connectedDropLists\"\n [cdkDropListEnterPredicate]=\"canDropToRoot\"\n cdkDropListOrientation=\"horizontal\"\n [cdkDropListData]=\"tabNodes\"\n (cdkDropListDropped)=\"drop($event)\"\n class=\"tab-list-root\">\n\n @for (node of tabNodes; track trackByNode($index, node); let i = $index) {\n <div cdkDrag\n [cdkDragData]=\"node\"\n [cdkDragDisabled]=\"!enableDragAndDrop || isRootNodeDragDisabled(node)\"\n (cdkDragStarted)=\"dragStarted($event)\"\n (cdkDragMoved)=\"onDragMoved($event)\"\n (cdkDragEnded)=\"dragEnded($event)\"\n class=\"tab-node-wrapper\"\n [class.potential-group-target]=\"isItem(node) && potentialGroupTargetId === getSafeId(node.data)\"\n [attr.data-id]=\"isItem(node) ? getSafeId(node.data) : null\"\n (mousedown)=\"onNodeDown($event)\"\n (touchstart)=\"onNodeDown($event)\"\n (mouseup)=\"onNodeMouseUp()\"\n (touchend)=\"onNodeMouseUp()\">\n\n <div *cdkDragPreview>\n <ng-container *ngTemplateOutlet=\"nodePreviewTemplate; context: { node: node }\"></ng-container>\n </div>\n <div *cdkDragPlaceholder [class.reposition-placeholder]=\"repositionMode\"></div>\n\n <!-- \u2500\u2500 Case 1: Ungrouped Item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isItem(node)) {\n <ng-container>\n <div class=\"tab-item ungrouped\"\n [class.is-expanded-source]=\"expandedItemId === getSafeId(node.data)\"\n [attr.data-expanded-id]=\"expandedItemId === getSafeId(node.data) ? expandedItemId : null\"\n [class.active]=\"displayItems.indexOf(node.data) === activeIndex\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(node.data)\"\n (click)=\"onItemClick($event, node)\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: false, expanded: false }\"></ng-container>\n </div>\n\n @if (potentialGroupTargetId === getSafeId(node.data)) {\n <div class=\"visual-group-wrapper\">\n <div class=\"group-header-vertical\"></div>\n <div class=\"group-list-visual\">\n <div class=\"tab-item\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: true, expanded: false }\"></ng-container>\n </div>\n <div class=\"tab-item ghost-item\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: draggedItemData?.data, grouped: true, expanded: false }\"></ng-container>\n </div>\n </div>\n </div>\n }\n </ng-container>\n }\n\n <!-- \u2500\u2500 Case 2: Group Container \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isGroup(node)) {\n <ng-container>\n <div class=\"group-container\"\n [class.collapsed]=\"node.data.collapsed\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(node.data)\"\n [class.pulsating-group]=\"repositionMode && repositionTargetId === getSafeId(node.data)\"\n [style.border-color]=\"node.data.color\"\n [style.--group-accent-color]=\"node.data.color\"\n cdkDragHandle\n [cdkDragHandleDisabled]=\"!enableDragAndDrop || isRootNodeDragDisabled(node) || repositionTargetGroupId === node.id\"\n (mousedown)=\"onNodeDown($event)\"\n (touchstart)=\"onNodeDown($event)\"\n (mouseup)=\"onNodeMouseUp()\"\n (touchend)=\"onNodeMouseUp()\">\n\n <div class=\"group-header-vertical\" (click)=\"toggleGroup(node.data)\">\n <div class=\"group-title-vertical\">\n <span class=\"group-title-text\">{{ getTruncatedTitle(node.data.title, node.data.collapsed) }}</span>\n </div>\n <div class=\"group-ellipsis-vertical\"\n (click)=\"openContextMenu($event, node); $event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (touchstart)=\"$event.stopPropagation()\">\n <div class=\"group-ellipsis-dot\"></div>\n <div class=\"group-ellipsis-dot\"></div>\n <div class=\"group-ellipsis-dot\"></div>\n </div>\n </div>\n\n <div cdkDropList\n [id]=\"'group-list-' + getSafeId(node.data)\"\n [cdkDropListConnectedTo]=\"connectedDropLists\"\n [cdkDropListData]=\"node.data.items\"\n (cdkDropListDropped)=\"drop($event)\"\n [cdkDropListEnterPredicate]=\"canDropToGroup\"\n cdkDropListOrientation=\"horizontal\"\n class=\"group-list\"\n [class.collapsed-drop-target]=\"node.data.collapsed && isDragging\">\n\n @for (item of node.data.items; track trackByItem($index, item)) {\n <div class=\"tab-item\"\n cdkDrag\n [class.is-expanded-source]=\"expandedItemId === getSafeId(item)\"\n [attr.data-expanded-id]=\"expandedItemId === getSafeId(item) ? expandedItemId : null\"\n [cdkDragData]=\"{ type: 'item', data: item }\"\n [cdkDragDisabled]=\"!enableDragAndDrop || isItemDragDisabled(getSafeId(item), node.id)\"\n (cdkDragStarted)=\"dragStarted($event)\"\n (cdkDragMoved)=\"onDragMoved($event)\"\n (cdkDragEnded)=\"dragEnded($event)\"\n [class.active]=\"displayItems.indexOf(item) === activeIndex\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(item)\"\n (click)=\"onItemClick($event, { type: 'item', data: item, id: getSafeId(item) })\">\n\n <div *cdkDragPreview>\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: item, grouped: true, expanded: false }\"></ng-container>\n </div>\n <div *cdkDragPlaceholder [class.reposition-placeholder]=\"repositionMode\"></div>\n\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: item, grouped: true, expanded: false }\"></ng-container>\n </div>\n }\n </div>\n </div>\n </ng-container>\n }\n </div>\n }\n\n <!-- Drag preview template -->\n <ng-template #nodePreviewTemplate let-node=\"node\">\n @if (isItem(node)) {\n <div class=\"tab-item ungrouped\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: false, expanded: false }\"></ng-container>\n </div>\n }\n @if (isGroup(node)) {\n <div class=\"group-container collapsed\"\n [style.border-color]=\"node.data.color\"\n [style.--group-accent-color]=\"node.data.color\">\n <div class=\"group-header-vertical\">\n <div class=\"group-title-vertical\">\n <span class=\"group-title-text\">{{ getTruncatedTitle(node.data.title, true) }}</span>\n </div>\n </div>\n </div>\n }\n </ng-template>\n\n </div>\n </div>\n\n <ng-template #expandedPortalTemplate>\n @if (expandedItemId && portalRect && !(isDragging && getSafeId(draggedItemData?.data) === expandedItemId)) {\n <div class=\"expanded-item-portal\"\n [attr.data-expanded-portal-id]=\"expandedItemId\"\n [style.left.px]=\"portalRect.left\"\n [style.top.px]=\"portalRect.top\"\n [style.width.px]=\"portalRect.width\"\n (pointerdown)=\"onScrollPointerDown($event)\"\n (mousedown)=\"onPortalDown($event)\"\n (touchstart)=\"onPortalDown($event)\"\n (click)=\"onPortalClick($event)\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: expandedItemRef, grouped: false, expanded: true }\"></ng-container>\n </div>\n }\n </ng-template>\n\n @if (showPrefRejectButton) {\n <button type=\"button\" class=\"tabs-pref-reject-button\">\n <span class=\"tabs-pref-reject-button__icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\">\n <g>\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M10.9353 4.11938C11.1384 4.3225 11.1384 4.65183 10.9353 4.85495L2.35324 13.437C2.15012 13.6401 1.82079 13.6401 1.61767 13.437C1.41455 13.2339 1.41455 12.9046 1.61767 12.7014L10.1997 4.11938C10.4028 3.91626 10.7322 3.91626 10.9353 4.11938Z\" fill=\"#FE3C72\"/>\n <circle cx=\"6.14645\" cy=\"8.64816\" r=\"4.0\" stroke=\"#FE3C72\" stroke-width=\"1\"/>\n </g>\n </svg>\n </span>\n <span class=\"tabs-pref-reject-button__label\">Reject</span>\n </button>\n }\n\n <!-- Global menu overlay -->\n @if (showGlobalMenu) {\n <div class=\"global-menu-overlay\" (click)=\"toggleGlobalMenu($event)\"></div>\n }\n\n <!-- Context menu overlay -->\n @if (activeContextMenuNode) {\n <div class=\"context-menu-overlay\" (click)=\"closeMenus()\"></div>\n }\n\n <!-- \u2500\u2500 Context menu (portal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <ng-template #contextMenuTemplate>\n @if (activeContextMenuNode) {\n <div class=\"context-menu\"\n [style.left.px]=\"contextMenuPosition.x\"\n [style.top.px]=\"contextMenuPosition.y\"\n style=\"position: fixed; z-index: 100000;\">\n @if (activeContextMenuNode?.type === 'group' || activeContextMenuNode?.type === 'item') {\n <div class=\"menu-item\" (click)=\"toggleRepositionMode()\">\n {{ repositionMode && (!repositionTargetId || repositionTargetId === getSafeId(activeContextMenuNode?.data)) ? 'End Reposition' : 'Reposition' }}\n </div>\n }\n @if (activeContextMenuNode?.type === 'group') {\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"handleMenuAction('ungroup', activeContextMenuNode!)\">Ungroup</div>\n }\n </div>\n }\n </ng-template>\n\n <!-- \u2500\u2500 Confirmation dialog (Popper) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <lib-popper-content #confirmPopper>\n <div class=\"popover-container\">\n <div class=\"m-title f-w-700 f-lg h-160 f-white\">Overwrite Manual Groups?</div>\n <span class=\"message f-w-400 f-md h-150 f-gray\">\n This operation will discard your current manual arrangement.\n Continue?\n </span>\n <div class=\"buttons\">\n <lib-secondary-btn (click)=\"cancelGroupBy()\" type=\"button\">Cancel</lib-secondary-btn>\n <lib-primary-btn (click)=\"confirmGroupBy()\" type=\"button\">Continue</lib-primary-btn>\n </div>\n </div>\n </lib-popper-content>\n\n <!-- \u2500\u2500 Alert / Toastr (portal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <ng-template #alertTemplate>\n <div class=\"tabs-alert-host\">\n <lib-alert-popup\n [title]=\"alertTitle\"\n [description]=\"alertDescription\"\n [timeState]=\"alertTimeState\"\n (closed)=\"dismissAlert()\">\n </lib-alert-popup>\n </div>\n </ng-template>\n\n <!-- Main Content Swiper -->\n <div class=\"swiper-container main-swiper\" [style.max-height]=\"slideContentMaxHeight\" [ngStyle]=\"{ height: mainSwiperHeight }\">\n <swiper-container #mainSwiper init=\"false\" class=\"main-swiper\"\n [class.container-sides-shadow]=\"activeIndex !== 0\"\n [ngStyle]=\"{ height: subMainSwiperHeight }\">\n @for (item of displayItems; track trackByItem($index, item)) {\n <swiper-slide>\n <ng-container *ngTemplateOutlet=\"contentTemplate; context: { $implicit: item, index: $index }\"></ng-container>\n </swiper-slide>\n }\n </swiper-container>\n </div>\n\n </ng-container>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%;min-width:0;height:100%;display:flex;flex-direction:column;padding-top:0;font-family:Gilroy,sans-serif}.swipeable-tabs-container{position:relative;display:flex;width:100%;height:100%;min-height:0;flex-direction:column;flex:1}.swipeable-tabs-container.bottom-thumbs{flex-direction:column-reverse}.swipeable-tabs-container>.main-swiper{flex:1;display:flex;flex-direction:column;z-index:100}.swipeable-tabs-container swiper-container{position:relative;display:block;overflow:auto;width:100%;height:100%}.swipeable-tabs-container swiper-container{scrollbar-width:none}.swipeable-tabs-container swiper-container::-webkit-scrollbar{display:none}.expanded-item-portal{position:fixed;transform:translate(-50%,-50%);z-index:1000;pointer-events:auto}.settings-trigger-wrapper{position:absolute;top:-15px;right:0;z-index:3000;pointer-events:none}.settings-trigger-wrapper.settings-trigger-wrapper-portal{position:fixed;top:0;right:auto;z-index:3000;pointer-events:none}.settings-trigger{padding:8px;cursor:pointer;color:#fffc;transition:all .3s ease;pointer-events:auto;display:flex;align-items:center;justify-content:center;background:transparent;background:radial-gradient(circle,rgba(0,0,0,.9) 0%,transparent 70%);box-shadow:none;border:none;border-radius:50%}.settings-trigger:hover{color:#fff;background:radial-gradient(circle,rgba(0,0,0,.95) 0%,transparent 70%)}.settings-trigger i{font-size:1.5rem;filter:drop-shadow(0px 0px 2px rgba(0,0,0,.8))}.settings-trigger.settings-trigger--hidden{visibility:hidden;pointer-events:none}.global-menu-overlay,.context-menu-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:2000;background:transparent}.global-menu{position:absolute;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 3px 0 6px #c8c8d259,inset 0 -6px 12px #403d4680,inset 0 -3px 6px #403d46cc,inset 16px 0 10px -2px #3a3a44e6,inset 0 -16px 10px -2px #3a3a44e6;border:none;border-radius:13px;padding:5px 0;min-width:150px;z-index:3001;display:flex;flex-direction:column;overflow:hidden;right:0;left:auto;pointer-events:auto}.popover-container{pointer-events:auto;z-index:5000}.menu-up{top:auto;bottom:100%;margin-bottom:10px;margin-top:0;transform-origin:bottom right;animation:fadeIn .2s ease-out}.menu-down{top:100%;bottom:auto;margin-top:10px;margin-bottom:0;transform-origin:top right;animation:fadeInDown .2s ease-out}.context-menu{position:fixed;margin-left:-17px;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 3px 0 6px #c8c8d259,inset 0 -6px 12px #403d4680,inset 0 -3px 6px #403d46cc,inset 16px 0 10px -2px #3a3a44e6,inset 0 -16px 10px -2px #3a3a44e6;border:none;border-radius:13px;padding:5px 0;min-width:150px;z-index:1002;display:flex;flex-direction:column;overflow:hidden}.context-menu{animation:scaleIn .15s ease-out}.menu-item{padding:12px 20px;color:#ffffffe6;font-family:Gilroy,sans-serif;font-weight:700;font-size:11px;line-height:100%;letter-spacing:.07px;vertical-align:middle;cursor:pointer;transition:background .2s;white-space:nowrap;display:flex;align-items:center}.menu-item:hover{background:#ffffff1a}.global-menu .menu-item{justify-content:flex-end;text-align:right;padding-right:20px}.context-menu .menu-item{justify-content:flex-start;text-align:left;padding-left:20px}.menu-separator{height:1px;background:linear-gradient(to right,transparent,rgba(255,255,255,.3),transparent);margin:8px auto;width:50%}.global-menu .menu-separator{margin-left:auto;margin-right:10%}.context-menu .menu-separator{margin-right:auto;margin-left:10%}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeInDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes scaleIn{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}.item-ellipsis{cursor:pointer;color:#ffffff80;padding:2px;border-radius:50%;transition:all .2s}.item-ellipsis:hover{color:#fff;background:#ffffff1a}.item-ellipsis i{font-size:.9rem}.tab-item{width:54px;min-width:27px;height:54px;display:flex;align-items:center;justify-content:center;line-height:0}.tab-item img,.tab-item .avatar{width:auto;height:auto;object-fit:cover;border-radius:50%;margin:0}.tab-item.is-expanded-source{visibility:hidden;min-width:174px!important;flex-shrink:0}.tab-item.expanded-item{height:auto!important;width:auto!important}.tab-item.ungrouped{position:relative}.tab-item.ungrouped .item-ellipsis{position:absolute;bottom:0;right:0;z-index:10;background:#00000080}.tab-bar-container{display:flex;flex-direction:row;overflow-x:auto;overflow-y:hidden;width:100%;max-width:100%;min-width:0;flex-shrink:0;position:relative;z-index:1000;pointer-events:auto;-ms-overflow-style:none;scrollbar-width:none}.tab-bar-container:focus{outline:none}.tab-bar-container.grab-cursor{cursor:grab}.tab-bar-container.grabbing-cursor{cursor:grabbing;-webkit-user-select:none;user-select:none}.tab-bar-container::-webkit-scrollbar{display:none}.tab-bar-container.grouping-animating .cdk-drag-animating{transition:none!important}.tab-bar-container.grouping-animating .tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder){transition:none!important}.tab-bar-container.grouping-animating .cdk-drag-preview{display:none!important}.tabs-pref-reject-button{position:absolute;left:30%;transform:translate(-50%);bottom:calc(var(--thumbs-height, 40px) + 5px);display:inline-flex;align-items:center;gap:6px;padding:0 10px;height:29px;border:none;border-radius:8px;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 2px 4px #00000040,0 4px 4px #00000040,2px -2px 3px #0006 inset,0 -2px 8px #fff3 inset;color:#d9d9d9;font-family:Gilroy,sans-serif;font-size:8px;letter-spacing:.07px;cursor:pointer;z-index:1100}.tabs-pref-reject-button__icon{display:flex;align-items:center;justify-content:center}.tabs-pref-reject-button__label{line-height:1}.tab-list-root{display:flex;flex-direction:row;align-items:center;gap:10px;padding:0 100px 0 20px;min-width:100%;width:max-content;flex-shrink:0;flex-grow:1;height:100%}.tab-list-root .cdk-drag-placeholder{width:2px!important;min-width:2px!important;height:40px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;flex:0 0 auto;visibility:visible!important}.tab-node-wrapper{display:flex;align-items:center;flex-shrink:0;pointer-events:auto;position:relative;z-index:2;width:auto;min-width:min-content}.cdk-drag-preview{box-sizing:border-box;border-radius:0;box-shadow:none;z-index:9999!important;opacity:.5;width:auto;height:auto;display:inline-flex;align-items:center;justify-content:center;overflow:visible;pointer-events:none;scrollbar-width:none}.cdk-drag-preview::-webkit-scrollbar{display:none}.recently-dropped{opacity:.5;animation:fadeBackIn 1s ease-in forwards;animation-delay:2s}@keyframes fadeBackIn{0%{opacity:.5}to{opacity:1}}.cdk-drag-placeholder{opacity:0}.hidden-placeholder~.cdk-drag-preview,.tab-node-wrapper:has(.hidden-placeholder){transition:none!important}.tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.group-container{border:none;position:relative;display:flex;flex-direction:row;align-items:flex-start;padding:0 0 0 4px;box-sizing:border-box;isolation:isolate;margin-right:20px;background:transparent;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);box-shadow:0 8px 32px #0000005e,inset 0 1px #ffffff4d;border-radius:9px;overflow:visible;transition:all .3s ease}.group-container.pulsating-group{animation:pulsate-group-border 1.5s infinite}.group-container:before{content:\"\";position:absolute;inset:0 auto 0 0;width:min(45px,50%);background:linear-gradient(to right,var(--group-accent-color, rgba(255, 255, 255, .1)),transparent);opacity:.6;filter:blur(15px);z-index:0;pointer-events:none;border-radius:inherit;clip-path:inset(0 0 0 0 round 9px)}.group-container:not(:has(.tab-item.is-expanded-source)){overflow:hidden}.group-container:has(.tab-item.is-expanded-source){overflow:visible;z-index:50}.group-container:has(.tab-item.is-expanded-source):before{clip-path:inset(0 0 0 0 round 9px);overflow:hidden}.group-container.collapsed{width:auto;max-width:none;padding-left:2px}.group-container.collapsed .group-list,.group-container.collapsed .group-ellipsis-vertical{display:none}.group-container.collapsed:before{width:min(32px,30%)}.group-container:has(.tab-item.expanded-item){overflow:visible;z-index:50}@keyframes pulsate-group-border{0%{box-shadow:0 0 #ffffffb3,0 8px 32px #0000005e,inset 0 1px #ffffff4d}70%{box-shadow:0 0 0 6px #fff0,0 8px 32px #0000005e,inset 0 1px #ffffff4d}to{box-shadow:0 0 #fff0,0 8px 32px #0000005e,inset 0 1px #ffffff4d}}.group-title-text{font-family:Calistoga,serif;font-weight:400;font-style:normal;font-size:10px;line-height:100%;letter-spacing:0%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#fff6;max-height:40px;text-align:center;width:100%;display:block;margin-top:6px}.group-header-vertical{width:30px;align-self:stretch;display:flex;flex-direction:column;padding:0 2px;cursor:grab;z-index:20;position:relative;height:54px;max-height:54px;background:transparent}.group-header-vertical:before{content:\"\";position:absolute;inset:0;background:linear-gradient(to right,var(--group-accent-color, rgba(255, 255, 255, .1)),transparent);opacity:.5;filter:blur(4px);z-index:-1}.group-header-vertical>*{position:relative;z-index:1}.group-container.collapsed{border-radius:13px}.group-container.collapsed .group-header-vertical{justify-content:center;align-items:center;width:18px}.group-container.collapsed .group-title-text{margin-bottom:5px;text-align:center}.group-container:not(.collapsed) .group-header-vertical{justify-content:space-around;align-items:flex-start;padding-left:0;padding-bottom:0;padding-top:0}.group-title-vertical{display:flex;align-items:center;justify-content:center;writing-mode:vertical-rl;transform:rotate(180deg);padding:0;margin-bottom:0;overflow:hidden;min-height:40px}.group-ellipsis-vertical{cursor:pointer;align-items:center;justify-content:space-between;width:100%;height:auto;position:static;margin:-11px 0 0;padding-left:0;display:flex;justify-content:flex-start;gap:3px;padding-bottom:5px}.group-ellipsis-vertical:hover{opacity:.7}.group-ellipsis-vertical .group-ellipsis-dot{width:3px;height:3px;background-color:#fff;border-radius:50%!important;display:block}.tab-bar-container.dragging-active .group-header-vertical{z-index:1;pointer-events:none}.group-list{padding-top:2px;display:flex;align-items:center;justify-content:space-around;min-width:40px;margin-left:-13.5px;margin-right:-11.5px;margin-top:-7.5px;gap:20px;border-radius:4px;position:relative;z-index:1;pointer-events:auto}.group-list .tab-item.is-expanded-source,.group-list .tab-item.is-expanded-source.cdk-drag-placeholder{min-width:174px!important;visibility:visible!important;opacity:.5}.group-list.collapsed-drop-target{position:absolute;top:0;left:0;width:100%;height:100%;min-width:unset;background:#ffffff4d;border:2px dashed rgba(255,255,255,.8);z-index:50;border-radius:16px}.group-list.collapsed-drop-target .tab-item{display:none}.reposition-placeholder{width:2px!important;min-width:2px!important;height:40px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;border:none;box-shadow:none;flex:0 0 auto}.group-list .cdk-drag-placeholder{width:2px!important;min-width:2px!important;height:46px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;border:none;box-shadow:0 0 6px 2px #fe3c7299!important;flex:0 0 auto;visibility:visible!important}.hidden-placeholder{visibility:hidden!important;pointer-events:none!important}.tab-node-wrapper.potential-group-target .tab-item.ungrouped{display:none}.visual-group-wrapper{border:none;display:flex;flex-direction:row;align-items:flex-start;padding:3px 3px 3px 4px;background:transparent;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);box-shadow:0 8px 32px #0000005e,inset 0 1px #ffffff4d;border-radius:9px;overflow:hidden;border:1px solid rgba(255,255,255,.2)}.visual-group-wrapper .group-header-vertical{width:18px;height:54px;background:#ffffff1a}.visual-group-wrapper .group-list-visual{display:flex;align-items:center;justify-content:space-around;gap:4.5px;margin-left:-4px;padding-top:2px}.visual-group-wrapper .ghost-item{opacity:.3;filter:grayscale(100%)}.grabbing-cursor{cursor:grabbing!important}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder),.group-list.cdk-drop-list-dragging .tab-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}@keyframes pulse{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}.tabs-confirm-backdrop{position:fixed;inset:0;z-index:200000;background:#0000008c;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center}.tabs-confirm-dialog{background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 0 -6px 12px #403d4680;border-radius:16px;padding:24px 28px 20px;max-width:340px;width:calc(100vw - 48px);display:flex;flex-direction:column;gap:12px}.tabs-confirm-dialog__title{font-family:Calistoga,serif;font-size:14px;font-weight:400;color:#fff;line-height:1.3}.tabs-confirm-dialog__description{font-family:Gilroy,sans-serif;font-size:11px;font-weight:500;color:#ffffffb3;line-height:1.5}.tabs-confirm-dialog__actions{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}.tabs-confirm-btn{font-family:Gilroy,sans-serif;font-weight:700;font-size:11px;letter-spacing:.07px;border:none;border-radius:8px;padding:8px 18px;cursor:pointer;transition:opacity .2s}.tabs-confirm-btn:hover{opacity:.85}.tabs-confirm-btn--cancel{background:#ffffff1a;color:#ffffffbf}.tabs-confirm-btn--confirm{background:#fe3c72;color:#fff}.tabs-alert-host{position:fixed;top:20px;right:20px;z-index:300000;pointer-events:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2$1.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: i3$2.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i3$2.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i3$2.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: i3$2.CdkDragPreview, selector: "ng-template[cdkDragPreview]", inputs: ["data", "matchSize"] }, { kind: "directive", type: i3$2.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: AlertPopupComponent, selector: "lib-alert-popup", inputs: ["title", "description", "timeState", "number"], outputs: ["closed"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i1.PrimaryBtnComponent, selector: "lib-primary-btn", inputs: ["hoverOutline", "disabled", "type", "form", "label", "showArrowIcon", "disableTextShadow", "loading$"] }, { kind: "component", type: i1.SecondaryBtnComponent, selector: "lib-secondary-btn", inputs: ["hoverOutline", "disabled", "type", "form", "label", "showArrowIcon", "disableTextShadow", "loading$"] }, { kind: "ngmodule", type: PopperModule }, { kind: "directive", type: i1.PopperDirective, selector: "[libPopper]", inputs: ["libPopper", "popperTrigger", "popperHideOnClickOutside", "openOnInit"], exportAs: ["libPopper"] }, { kind: "component", type: i1.LibPopperContentComponent, selector: "lib-popper-content", inputs: ["arrowClass", "popperClass", "openOnInit"], outputs: ["visibilityChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
6863
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: LibDashboardSwipeableTabsComponent, isStandalone: true, selector: "lib-dashboard-swipeable-tabs", inputs: { thumbsSwiperOptions: "thumbsSwiperOptions", mainSwiperOptions: "mainSwiperOptions", activeIndex: "activeIndex", bottomThumbs: "bottomThumbs", slideContentMaxHeight: "slideContentMaxHeight", mainSwiperHeight: "mainSwiperHeight", subMainSwiperHeight: "subMainSwiperHeight", thumbsSwiperHeight: "thumbsSwiperHeight", generalSwiperHeight: "generalSwiperHeight", enableGrouping: "enableGrouping", enableDragAndDrop: "enableDragAndDrop", enableTabBarScrollDrag: "enableTabBarScrollDrag", items: "items", thumbTemplate: "thumbTemplate", contentTemplate: "contentTemplate", groupingAdapter: "groupingAdapter", showPrefRejectButton: "showPrefRejectButton", menuPosition: "menuPosition" }, outputs: { repositionModeChange: "repositionModeChange", activeIndexChange: "activeIndexChange", itemClicked: "itemClicked", expandedIdChange: "expandedIdChange" }, queries: [{ propertyName: "thumbSlides", first: true, predicate: ["thumbSlides"], descendants: true }], viewQueries: [{ propertyName: "thumbSwiper", first: true, predicate: ["thumbSwiper"], descendants: true }, { propertyName: "mainSwiper", first: true, predicate: ["mainSwiper"], descendants: true }, { propertyName: "settingsTriggerWrapperEl", first: true, predicate: ["settingsTriggerWrapperEl"], descendants: true }, { propertyName: "settingsTriggerPortalTemplate", first: true, predicate: ["settingsTriggerPortalTemplate"], descendants: true }, { propertyName: "contextMenuTemplate", first: true, predicate: ["contextMenuTemplate"], descendants: true }, { propertyName: "confirmDialogTemplate", first: true, predicate: ["confirmDialogTemplate"], descendants: true }, { propertyName: "alertTemplate", first: true, predicate: ["alertTemplate"], descendants: true }, { propertyName: "tabBarContainer", first: true, predicate: ["tabBarContainer"], descendants: true }, { propertyName: "expandedPortalTemplate", first: true, predicate: ["expandedPortalTemplate"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"swipeable-tabs-container\"\n [class.bottom-thumbs]=\"bottomThumbs\"\n [ngStyle]=\"{ height: generalSwiperHeight }\"\n [style.--thumbs-height]=\"thumbsSwiperHeight\"\n>\n\n <!-- \u2500\u2500 LEGACY MODE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (!enableGrouping) {\n <ng-container>\n <swiper-container #thumbSwiper init=\"false\" class=\"thumb-swiper container-sides-shadow\" [ngStyle]=\"{ height: thumbsSwiperHeight }\">\n <ng-content select=\"[thumb-slides]\"></ng-content>\n </swiper-container>\n <div class=\"swiper-container main-swiper\" [style.max-height]=\"slideContentMaxHeight\" [ngStyle]=\"{ height: mainSwiperHeight }\">\n <swiper-container #mainSwiper init=\"false\" class=\"main-swiper\" [class.container-sides-shadow]=\"activeIndex !== 0\" [ngStyle]=\"{ height: subMainSwiperHeight }\">\n <ng-content select=\"[main-slides]\"></ng-content>\n </swiper-container>\n </div>\n </ng-container>\n }\n\n <!-- \u2500\u2500 GROUPING MODE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (enableGrouping) {\n <ng-container>\n\n <!-- Settings trigger -->\n <div class=\"settings-trigger-wrapper\" #settingsTriggerWrapperEl>\n <div class=\"settings-trigger\" [class.settings-trigger--hidden]=\"settingsTriggerPortaled\" (click)=\"toggleGlobalMenu($event)\">\n <i class=\"pi pi-cog\"></i>\n </div>\n @if (showGlobalMenu) {\n <div class=\"global-menu\" [ngClass]=\"'menu-' + menuPosition\" (click)=\"$event.stopPropagation()\">\n <div class=\"menu-item\" (click)=\"requestGroupBy('response')\">Group by Response</div>\n <div class=\"menu-item\" (click)=\"requestGroupBy('client')\">Group by Client</div>\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"restoreCustomGroups()\">Restore Custom Groups</div>\n <div class=\"menu-item\" (click)=\"storeCustomGroups()\">Store Custom Groups</div>\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"ungroupAll()\">Ungroup All</div>\n </div>\n }\n </div>\n\n <ng-template #settingsTriggerPortalTemplate>\n <div\n class=\"settings-trigger-wrapper settings-trigger-wrapper-portal\"\n [style.left.px]=\"settingsTriggerPortalLeft\"\n [style.top.px]=\"settingsTriggerPortalTop\"\n >\n <div class=\"settings-trigger\" (click)=\"toggleGlobalMenu($event)\">\n <i class=\"pi pi-cog\"></i>\n </div>\n </div>\n </ng-template>\n\n <!-- Tab Bar -->\n <div class=\"tab-bar-container\"\n #tabBarContainer\n cdkScrollable\n [class.dragging-active]=\"isDragging\"\n [class.grouping-animating]=\"groupingAnimating\"\n [class.grab-cursor]=\"!repositionMode && !isScrollDragging\"\n [class.grabbing-cursor]=\"isScrollDragging\"\n [ngStyle]=\"{ minHeight: thumbsSwiperHeight }\"\n tabindex=\"0\">\n\n <div\n cdkDropList\n [id]=\"rootDropListId\"\n [cdkDropListConnectedTo]=\"connectedDropLists\"\n [cdkDropListEnterPredicate]=\"canDropToRoot\"\n cdkDropListOrientation=\"horizontal\"\n [cdkDropListData]=\"tabNodes\"\n (cdkDropListDropped)=\"drop($event)\"\n class=\"tab-list-root\">\n\n @for (node of tabNodes; track trackByNode($index, node); let i = $index) {\n <div cdkDrag\n [cdkDragData]=\"node\"\n [cdkDragDisabled]=\"!enableDragAndDrop || isRootNodeDragDisabled(node)\"\n (cdkDragStarted)=\"dragStarted($event)\"\n (cdkDragMoved)=\"onDragMoved($event)\"\n (cdkDragEnded)=\"dragEnded($event)\"\n class=\"tab-node-wrapper\"\n [class.potential-group-target]=\"isItem(node) && potentialGroupTargetId === getSafeId(node.data)\"\n [attr.data-id]=\"isItem(node) ? getSafeId(node.data) : null\"\n (mousedown)=\"onNodeDown($event)\"\n (touchstart)=\"onNodeDown($event)\"\n (mouseup)=\"onNodeMouseUp()\"\n (touchend)=\"onNodeMouseUp()\">\n\n <div *cdkDragPreview>\n <ng-container *ngTemplateOutlet=\"nodePreviewTemplate; context: { node: node }\"></ng-container>\n </div>\n <div *cdkDragPlaceholder [class.reposition-placeholder]=\"repositionMode\"></div>\n\n <!-- \u2500\u2500 Case 1: Ungrouped Item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isItem(node)) {\n <ng-container>\n <div class=\"tab-item ungrouped\"\n [class.is-expanded-source]=\"expandedItemId === getSafeId(node.data)\"\n [attr.data-expanded-id]=\"expandedItemId === getSafeId(node.data) ? expandedItemId : null\"\n [class.active]=\"displayItems.indexOf(node.data) === activeIndex\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(node.data)\"\n (click)=\"onItemClick($event, node)\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: false, expanded: false }\"></ng-container>\n </div>\n\n @if (potentialGroupTargetId === getSafeId(node.data)) {\n <div class=\"visual-group-wrapper\">\n <div class=\"group-header-vertical\"></div>\n <div class=\"group-list-visual\">\n <div class=\"tab-item\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: true, expanded: false }\"></ng-container>\n </div>\n <div class=\"tab-item ghost-item\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: draggedItemData?.data, grouped: true, expanded: false }\"></ng-container>\n </div>\n </div>\n </div>\n }\n </ng-container>\n }\n\n <!-- \u2500\u2500 Case 2: Group Container \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isGroup(node)) {\n <ng-container>\n <div class=\"group-container\"\n [class.collapsed]=\"node.data.collapsed\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(node.data)\"\n [class.pulsating-group]=\"repositionMode && repositionTargetId === getSafeId(node.data)\"\n [style.border-color]=\"node.data.color\"\n [style.--group-accent-color]=\"node.data.color\"\n cdkDragHandle\n [cdkDragHandleDisabled]=\"!enableDragAndDrop || isRootNodeDragDisabled(node) || repositionTargetGroupId === node.id\"\n (mousedown)=\"onNodeDown($event)\"\n (touchstart)=\"onNodeDown($event)\"\n (mouseup)=\"onNodeMouseUp()\"\n (touchend)=\"onNodeMouseUp()\">\n\n <div class=\"group-header-vertical\" (click)=\"toggleGroup(node.data)\">\n <div class=\"group-title-vertical\">\n <span class=\"group-title-text\">{{ getTruncatedTitle(node.data.title, node.data.collapsed) }}</span>\n </div>\n <div class=\"group-ellipsis-vertical\"\n (click)=\"openContextMenu($event, node); $event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (touchstart)=\"$event.stopPropagation()\">\n <div class=\"group-ellipsis-dot\"></div>\n <div class=\"group-ellipsis-dot\"></div>\n <div class=\"group-ellipsis-dot\"></div>\n </div>\n </div>\n\n <div cdkDropList\n [id]=\"'group-list-' + getSafeId(node.data)\"\n [cdkDropListConnectedTo]=\"connectedDropLists\"\n [cdkDropListData]=\"node.data.items\"\n (cdkDropListDropped)=\"drop($event)\"\n [cdkDropListEnterPredicate]=\"canDropToGroup\"\n cdkDropListOrientation=\"horizontal\"\n class=\"group-list\"\n [class.collapsed-drop-target]=\"node.data.collapsed && isDragging\">\n\n @for (item of node.data.items; track trackByItem($index, item)) {\n <div class=\"tab-item\"\n cdkDrag\n [class.is-expanded-source]=\"expandedItemId === getSafeId(item)\"\n [attr.data-expanded-id]=\"expandedItemId === getSafeId(item) ? expandedItemId : null\"\n [cdkDragData]=\"{ type: 'item', data: item }\"\n [cdkDragDisabled]=\"!enableDragAndDrop || isItemDragDisabled(getSafeId(item), node.id)\"\n (cdkDragStarted)=\"dragStarted($event)\"\n (cdkDragMoved)=\"onDragMoved($event)\"\n (cdkDragEnded)=\"dragEnded($event)\"\n [class.active]=\"displayItems.indexOf(item) === activeIndex\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(item)\"\n (click)=\"onItemClick($event, { type: 'item', data: item, id: getSafeId(item) })\">\n\n <div *cdkDragPreview>\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: item, grouped: true, expanded: false }\"></ng-container>\n </div>\n <div *cdkDragPlaceholder [class.reposition-placeholder]=\"repositionMode\"></div>\n\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: item, grouped: true, expanded: false }\"></ng-container>\n </div>\n }\n </div>\n </div>\n </ng-container>\n }\n </div>\n }\n\n <!-- Drag preview template -->\n <ng-template #nodePreviewTemplate let-node=\"node\">\n @if (isItem(node)) {\n <div class=\"tab-item ungrouped\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: false, expanded: false }\"></ng-container>\n </div>\n }\n @if (isGroup(node)) {\n <div class=\"group-container collapsed\"\n [style.border-color]=\"node.data.color\"\n [style.--group-accent-color]=\"node.data.color\">\n <div class=\"group-header-vertical\">\n <div class=\"group-title-vertical\">\n <span class=\"group-title-text\">{{ getTruncatedTitle(node.data.title, true) }}</span>\n </div>\n </div>\n </div>\n }\n </ng-template>\n\n </div>\n </div>\n\n <ng-template #expandedPortalTemplate>\n @if (expandedItemId && portalRect && !(isDragging && getSafeId(draggedItemData?.data) === expandedItemId)) {\n <div class=\"expanded-item-portal\"\n [attr.data-expanded-portal-id]=\"expandedItemId\"\n [style.left.px]=\"portalRect.left\"\n [style.top.px]=\"portalRect.top\"\n [style.width.px]=\"portalRect.width\"\n (pointerdown)=\"onScrollPointerDown($event)\"\n (mousedown)=\"onPortalDown($event)\"\n (touchstart)=\"onPortalDown($event)\"\n (click)=\"onPortalClick($event)\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: expandedItemRef, grouped: false, expanded: true }\"></ng-container>\n </div>\n }\n </ng-template>\n\n @if (showPrefRejectButton) {\n <button type=\"button\" class=\"tabs-pref-reject-button\">\n <span class=\"tabs-pref-reject-button__icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\">\n <g>\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M10.9353 4.11938C11.1384 4.3225 11.1384 4.65183 10.9353 4.85495L2.35324 13.437C2.15012 13.6401 1.82079 13.6401 1.61767 13.437C1.41455 13.2339 1.41455 12.9046 1.61767 12.7014L10.1997 4.11938C10.4028 3.91626 10.7322 3.91626 10.9353 4.11938Z\" fill=\"#FE3C72\"/>\n <circle cx=\"6.14645\" cy=\"8.64816\" r=\"4.0\" stroke=\"#FE3C72\" stroke-width=\"1\"/>\n </g>\n </svg>\n </span>\n <span class=\"tabs-pref-reject-button__label\">Reject</span>\n </button>\n }\n\n <!-- Global menu overlay -->\n @if (showGlobalMenu) {\n <div class=\"global-menu-overlay\" (click)=\"toggleGlobalMenu($event)\"></div>\n }\n\n <!-- Context menu overlay -->\n @if (activeContextMenuNode) {\n <div class=\"context-menu-overlay\" (click)=\"closeMenus()\"></div>\n }\n\n <!-- \u2500\u2500 Context menu (portal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <ng-template #contextMenuTemplate>\n @if (activeContextMenuNode) {\n <div class=\"context-menu\"\n [style.left.px]=\"contextMenuPosition.x\"\n [style.top.px]=\"contextMenuPosition.y\"\n style=\"position: fixed; z-index: 100000;\">\n @if (activeContextMenuNode?.type === 'group' || activeContextMenuNode?.type === 'item') {\n <div class=\"menu-item\" (click)=\"toggleRepositionMode()\">\n {{ repositionMode && (!repositionTargetId || repositionTargetId === getSafeId(activeContextMenuNode?.data)) ? 'End Reposition' : 'Reposition' }}\n </div>\n }\n @if (activeContextMenuNode?.type === 'group') {\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"handleMenuAction('ungroup', activeContextMenuNode!)\">Ungroup</div>\n }\n </div>\n }\n </ng-template>\n\n <!-- \u2500\u2500 Confirmation dialog (Portal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <ng-template #confirmDialogTemplate>\n <div class=\"confirm-dialog-overlay\" (click)=\"cancelGroupBy()\">\n <div class=\"confirm-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"m-title f-w-700 f-lg h-160 f-white\">Overwrite Manual Groups?</div>\n <span class=\"message f-w-400 f-md h-150 f-gray\">\n This operation will discard your current manual arrangement.\n Continue?\n </span>\n <div class=\"buttons\">\n <lib-secondary-btn (click)=\"cancelGroupBy()\" type=\"button\">Cancel</lib-secondary-btn>\n <lib-primary-btn (click)=\"confirmGroupBy()\" type=\"button\">Continue</lib-primary-btn>\n </div>\n </div>\n </div>\n </ng-template>\n\n <!-- \u2500\u2500 Alert / Toastr (portal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <ng-template #alertTemplate>\n <div class=\"tabs-alert-host\">\n <lib-alert-popup\n [title]=\"alertTitle\"\n [description]=\"alertDescription\"\n [timeState]=\"alertTimeState\"\n (closed)=\"dismissAlert()\">\n </lib-alert-popup>\n </div>\n </ng-template>\n\n <!-- Main Content Swiper -->\n <div class=\"swiper-container main-swiper\" [style.max-height]=\"slideContentMaxHeight\" [ngStyle]=\"{ height: mainSwiperHeight }\">\n <swiper-container #mainSwiper init=\"false\" class=\"main-swiper\"\n [class.container-sides-shadow]=\"activeIndex !== 0\"\n [ngStyle]=\"{ height: subMainSwiperHeight }\">\n @for (item of displayItems; track trackByItem($index, item)) {\n <swiper-slide>\n <ng-container *ngTemplateOutlet=\"contentTemplate; context: { $implicit: item, index: $index }\"></ng-container>\n </swiper-slide>\n }\n </swiper-container>\n </div>\n\n </ng-container>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%;min-width:0;height:100%;display:flex;flex-direction:column;padding-top:0;font-family:Gilroy,sans-serif}.swipeable-tabs-container{position:relative;display:flex;width:100%;height:100%;min-height:0;flex-direction:column;flex:1}.swipeable-tabs-container.bottom-thumbs{flex-direction:column-reverse}.swipeable-tabs-container>.main-swiper{flex:1;display:flex;flex-direction:column;z-index:100}.swipeable-tabs-container swiper-container{position:relative;display:block;overflow:auto;width:100%;height:100%}.swipeable-tabs-container swiper-container{scrollbar-width:none}.swipeable-tabs-container swiper-container::-webkit-scrollbar{display:none}.expanded-item-portal{position:fixed;transform:translate(-50%,-50%);z-index:1000;pointer-events:auto}.settings-trigger-wrapper{position:absolute;top:-15px;right:0;z-index:3000;pointer-events:none}.settings-trigger-wrapper.settings-trigger-wrapper-portal{position:fixed;top:0;right:auto;z-index:3000;pointer-events:none}.settings-trigger{padding:8px;cursor:pointer;color:#fffc;transition:all .3s ease;pointer-events:auto;display:flex;align-items:center;justify-content:center;background:transparent;background:radial-gradient(circle,rgba(0,0,0,.9) 0%,transparent 70%);box-shadow:none;border:none;border-radius:50%}.settings-trigger:hover{color:#fff;background:radial-gradient(circle,rgba(0,0,0,.95) 0%,transparent 70%)}.settings-trigger i{font-size:1.5rem;filter:drop-shadow(0px 0px 2px rgba(0,0,0,.8))}.settings-trigger.settings-trigger--hidden{visibility:hidden;pointer-events:none}.global-menu-overlay,.context-menu-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:2000;background:transparent}.confirm-dialog-overlay{position:fixed;inset:0;width:100vw;height:100vh;z-index:100000;background:#0000008c;display:flex;align-items:center;justify-content:center;padding:24px;pointer-events:auto}.confirm-dialog{width:min(420px,100%);background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 3px 0 6px #c8c8d259,inset 0 -6px 12px #403d4680,inset 0 -3px 6px #403d46cc,inset 16px 0 10px -2px #3a3a44e6,inset 0 -16px 10px -2px #3a3a44e6;border-radius:13px;padding:16px;pointer-events:auto}.confirm-dialog .buttons{display:flex;justify-content:flex-end;gap:12px;margin-top:16px}.global-menu{position:absolute;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 3px 0 6px #c8c8d259,inset 0 -6px 12px #403d4680,inset 0 -3px 6px #403d46cc,inset 16px 0 10px -2px #3a3a44e6,inset 0 -16px 10px -2px #3a3a44e6;border:none;border-radius:13px;padding:5px 0;min-width:150px;z-index:3001;display:flex;flex-direction:column;overflow:hidden;right:0;left:auto;pointer-events:auto}.menu-up{top:auto;bottom:100%;margin-bottom:10px;margin-top:0;transform-origin:bottom right;animation:fadeIn .2s ease-out}.menu-down{top:100%;bottom:auto;margin-top:10px;margin-bottom:0;transform-origin:top right;animation:fadeInDown .2s ease-out}.context-menu{position:fixed;margin-left:-17px;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 3px 0 6px #c8c8d259,inset 0 -6px 12px #403d4680,inset 0 -3px 6px #403d46cc,inset 16px 0 10px -2px #3a3a44e6,inset 0 -16px 10px -2px #3a3a44e6;border:none;border-radius:13px;padding:5px 0;min-width:150px;z-index:1002;display:flex;flex-direction:column;overflow:hidden}.context-menu{animation:scaleIn .15s ease-out}.menu-item{padding:12px 20px;color:#ffffffe6;font-family:Gilroy,sans-serif;font-weight:700;font-size:11px;line-height:100%;letter-spacing:.07px;vertical-align:middle;cursor:pointer;transition:background .2s;white-space:nowrap;display:flex;align-items:center}.menu-item:hover{background:#ffffff1a}.global-menu .menu-item{justify-content:flex-end;text-align:right;padding-right:20px}.context-menu .menu-item{justify-content:flex-start;text-align:left;padding-left:20px}.menu-separator{height:1px;background:linear-gradient(to right,transparent,rgba(255,255,255,.3),transparent);margin:8px auto;width:50%}.global-menu .menu-separator{margin-left:auto;margin-right:10%}.context-menu .menu-separator{margin-right:auto;margin-left:10%}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeInDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes scaleIn{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}.item-ellipsis{cursor:pointer;color:#ffffff80;padding:2px;border-radius:50%;transition:all .2s}.item-ellipsis:hover{color:#fff;background:#ffffff1a}.item-ellipsis i{font-size:.9rem}.tab-item{width:54px;min-width:27px;height:54px;display:flex;align-items:center;justify-content:center;line-height:0}.tab-item img,.tab-item .avatar{width:auto;height:auto;object-fit:cover;border-radius:50%;margin:0}.tab-item.is-expanded-source{visibility:hidden;min-width:174px!important;flex-shrink:0}.tab-item.expanded-item{height:auto!important;width:auto!important}.tab-item.ungrouped{position:relative}.tab-item.ungrouped .item-ellipsis{position:absolute;bottom:0;right:0;z-index:10;background:#00000080}.tab-bar-container{display:flex;flex-direction:row;overflow-x:auto;overflow-y:hidden;width:100%;max-width:100%;min-width:0;flex-shrink:0;position:relative;z-index:1000;pointer-events:auto;-ms-overflow-style:none;scrollbar-width:none}.tab-bar-container:focus{outline:none}.tab-bar-container.grab-cursor{cursor:grab}.tab-bar-container.grabbing-cursor{cursor:grabbing;-webkit-user-select:none;user-select:none}.tab-bar-container::-webkit-scrollbar{display:none}.tab-bar-container.grouping-animating .cdk-drag-animating{transition:none!important}.tab-bar-container.grouping-animating .tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder){transition:none!important}.tab-bar-container.grouping-animating .cdk-drag-preview{display:none!important}.tabs-pref-reject-button{position:absolute;left:30%;transform:translate(-50%);bottom:calc(var(--thumbs-height, 40px) + 5px);display:inline-flex;align-items:center;gap:6px;padding:0 10px;height:29px;border:none;border-radius:8px;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 2px 4px #00000040,0 4px 4px #00000040,2px -2px 3px #0006 inset,0 -2px 8px #fff3 inset;color:#d9d9d9;font-family:Gilroy,sans-serif;font-size:8px;letter-spacing:.07px;cursor:pointer;z-index:1100}.tabs-pref-reject-button__icon{display:flex;align-items:center;justify-content:center}.tabs-pref-reject-button__label{line-height:1}.tab-list-root{display:flex;flex-direction:row;align-items:center;gap:10px;padding:0 100px 0 20px;min-width:100%;width:max-content;flex-shrink:0;flex-grow:1;height:100%}.tab-list-root .cdk-drag-placeholder{width:2px!important;min-width:2px!important;height:40px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;flex:0 0 auto;visibility:visible!important}.tab-node-wrapper{display:flex;align-items:center;flex-shrink:0;pointer-events:auto;position:relative;z-index:2;width:auto;min-width:min-content}.cdk-drag-preview{box-sizing:border-box;border-radius:0;box-shadow:none;z-index:9999!important;opacity:.5;width:auto;height:auto;display:inline-flex;align-items:center;justify-content:center;overflow:visible;pointer-events:none;scrollbar-width:none}.cdk-drag-preview::-webkit-scrollbar{display:none}.recently-dropped{opacity:.5;animation:fadeBackIn 1s ease-in forwards;animation-delay:2s}@keyframes fadeBackIn{0%{opacity:.5}to{opacity:1}}.cdk-drag-placeholder{opacity:0}.hidden-placeholder~.cdk-drag-preview,.tab-node-wrapper:has(.hidden-placeholder){transition:none!important}.tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.group-container{border:none;position:relative;display:flex;flex-direction:row;align-items:flex-start;padding:0 0 0 4px;box-sizing:border-box;isolation:isolate;margin-right:20px;background:transparent;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);box-shadow:0 8px 32px #0000005e,inset 0 1px #ffffff4d;border-radius:9px;overflow:visible;transition:all .3s ease}.group-container.pulsating-group{animation:pulsate-group-border 1.5s infinite}.group-container:before{content:\"\";position:absolute;inset:0 auto 0 0;width:min(45px,50%);background:linear-gradient(to right,var(--group-accent-color, rgba(255, 255, 255, .1)),transparent);opacity:.6;filter:blur(15px);z-index:0;pointer-events:none;border-radius:inherit;clip-path:inset(0 0 0 0 round 9px)}.group-container:not(:has(.tab-item.is-expanded-source)){overflow:hidden}.group-container:has(.tab-item.is-expanded-source){overflow:visible;z-index:50}.group-container:has(.tab-item.is-expanded-source):before{clip-path:inset(0 0 0 0 round 9px);overflow:hidden}.group-container.collapsed{width:auto;max-width:none;padding-left:2px}.group-container.collapsed .group-list,.group-container.collapsed .group-ellipsis-vertical{display:none}.group-container.collapsed:before{width:min(32px,30%)}.group-container:has(.tab-item.expanded-item){overflow:visible;z-index:50}@keyframes pulsate-group-border{0%{box-shadow:0 0 #ffffffb3,0 8px 32px #0000005e,inset 0 1px #ffffff4d}70%{box-shadow:0 0 0 6px #fff0,0 8px 32px #0000005e,inset 0 1px #ffffff4d}to{box-shadow:0 0 #fff0,0 8px 32px #0000005e,inset 0 1px #ffffff4d}}.group-title-text{font-family:Calistoga,serif;font-weight:400;font-style:normal;font-size:10px;line-height:100%;letter-spacing:0%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#fff6;max-height:40px;text-align:center;width:100%;display:block;margin-top:6px}.group-header-vertical{width:30px;align-self:stretch;display:flex;flex-direction:column;padding:0 2px;cursor:grab;z-index:20;position:relative;height:54px;max-height:54px;background:transparent}.group-header-vertical:before{content:\"\";position:absolute;inset:0;background:linear-gradient(to right,var(--group-accent-color, rgba(255, 255, 255, .1)),transparent);opacity:.5;filter:blur(4px);z-index:-1}.group-header-vertical>*{position:relative;z-index:1}.group-container.collapsed{border-radius:13px}.group-container.collapsed .group-header-vertical{justify-content:center;align-items:center;width:18px}.group-container.collapsed .group-title-text{margin-bottom:5px;text-align:center}.group-container:not(.collapsed) .group-header-vertical{justify-content:space-around;align-items:flex-start;padding-left:0;padding-bottom:0;padding-top:0}.group-title-vertical{display:flex;align-items:center;justify-content:center;writing-mode:vertical-rl;transform:rotate(180deg);padding:0;margin-bottom:0;overflow:hidden;min-height:40px}.group-ellipsis-vertical{cursor:pointer;align-items:center;justify-content:space-between;width:100%;height:auto;position:static;margin:-11px 0 0;padding-left:0;display:flex;justify-content:flex-start;gap:3px;padding-bottom:5px}.group-ellipsis-vertical:hover{opacity:.7}.group-ellipsis-vertical .group-ellipsis-dot{width:3px;height:3px;background-color:#fff;border-radius:50%!important;display:block}.tab-bar-container.dragging-active .group-header-vertical{z-index:1;pointer-events:none}.group-list{padding-top:2px;display:flex;align-items:center;justify-content:space-around;min-width:40px;margin-left:-13.5px;margin-right:-11.5px;margin-top:-7.5px;gap:20px;border-radius:4px;position:relative;z-index:1;pointer-events:auto}.group-list .tab-item.is-expanded-source,.group-list .tab-item.is-expanded-source.cdk-drag-placeholder{min-width:174px!important;visibility:visible!important;opacity:.5}.group-list.collapsed-drop-target{position:absolute;top:0;left:0;width:100%;height:100%;min-width:unset;background:#ffffff4d;border:2px dashed rgba(255,255,255,.8);z-index:50;border-radius:16px}.group-list.collapsed-drop-target .tab-item{display:none}.reposition-placeholder{width:2px!important;min-width:2px!important;height:40px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;border:none;box-shadow:none;flex:0 0 auto}.group-list .cdk-drag-placeholder{width:2px!important;min-width:2px!important;height:46px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;border:none;box-shadow:0 0 6px 2px #fe3c7299!important;flex:0 0 auto;visibility:visible!important}.hidden-placeholder{visibility:hidden!important;pointer-events:none!important}.tab-node-wrapper.potential-group-target .tab-item.ungrouped{display:none}.visual-group-wrapper{border:none;display:flex;flex-direction:row;align-items:flex-start;padding:3px 3px 3px 4px;background:transparent;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);box-shadow:0 8px 32px #0000005e,inset 0 1px #ffffff4d;border-radius:9px;overflow:hidden;border:1px solid rgba(255,255,255,.2)}.visual-group-wrapper .group-header-vertical{width:18px;height:54px;background:#ffffff1a}.visual-group-wrapper .group-list-visual{display:flex;align-items:center;justify-content:space-around;gap:4.5px;margin-left:-4px;padding-top:2px}.visual-group-wrapper .ghost-item{opacity:.3;filter:grayscale(100%)}.grabbing-cursor{cursor:grabbing!important}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder),.group-list.cdk-drop-list-dragging .tab-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}@keyframes pulse{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}.tabs-confirm-backdrop{position:fixed;inset:0;z-index:200000;background:#0000008c;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center}.tabs-confirm-dialog{background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 0 -6px 12px #403d4680;border-radius:16px;padding:24px 28px 20px;max-width:340px;width:calc(100vw - 48px);display:flex;flex-direction:column;gap:12px}.tabs-confirm-dialog__title{font-family:Calistoga,serif;font-size:14px;font-weight:400;color:#fff;line-height:1.3}.tabs-confirm-dialog__description{font-family:Gilroy,sans-serif;font-size:11px;font-weight:500;color:#ffffffb3;line-height:1.5}.tabs-confirm-dialog__actions{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}.tabs-confirm-btn{font-family:Gilroy,sans-serif;font-weight:700;font-size:11px;letter-spacing:.07px;border:none;border-radius:8px;padding:8px 18px;cursor:pointer;transition:opacity .2s}.tabs-confirm-btn:hover{opacity:.85}.tabs-confirm-btn--cancel{background:#ffffff1a;color:#ffffffbf}.tabs-confirm-btn--confirm{background:#fe3c72;color:#fff}.tabs-alert-host{position:fixed;top:20px;right:20px;z-index:300000;pointer-events:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2$1.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: i3$2.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i3$2.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i3$2.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: i3$2.CdkDragPreview, selector: "ng-template[cdkDragPreview]", inputs: ["data", "matchSize"] }, { kind: "directive", type: i3$2.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: AlertPopupComponent, selector: "lib-alert-popup", inputs: ["title", "description", "timeState", "number"], outputs: ["closed"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i1.PrimaryBtnComponent, selector: "lib-primary-btn", inputs: ["hoverOutline", "disabled", "type", "form", "label", "showArrowIcon", "disableTextShadow", "loading$"] }, { kind: "component", type: i1.SecondaryBtnComponent, selector: "lib-secondary-btn", inputs: ["hoverOutline", "disabled", "type", "form", "label", "showArrowIcon", "disableTextShadow", "loading$"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
6798
6864
  }
6799
6865
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: LibDashboardSwipeableTabsComponent, decorators: [{
6800
6866
  type: Component,
6801
- args: [{ selector: 'lib-dashboard-swipeable-tabs', imports: [CommonModule, TranslateModule, DragDropModule, CdkScrollable, AlertPopupComponent, ButtonsModule, PopperModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"swipeable-tabs-container\"\n [class.bottom-thumbs]=\"bottomThumbs\"\n [ngStyle]=\"{ height: generalSwiperHeight }\"\n [style.--thumbs-height]=\"thumbsSwiperHeight\"\n>\n\n <!-- \u2500\u2500 LEGACY MODE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (!enableGrouping) {\n <ng-container>\n <swiper-container #thumbSwiper init=\"false\" class=\"thumb-swiper container-sides-shadow\" [ngStyle]=\"{ height: thumbsSwiperHeight }\">\n <ng-content select=\"[thumb-slides]\"></ng-content>\n </swiper-container>\n <div class=\"swiper-container main-swiper\" [style.max-height]=\"slideContentMaxHeight\" [ngStyle]=\"{ height: mainSwiperHeight }\">\n <swiper-container #mainSwiper init=\"false\" class=\"main-swiper\" [class.container-sides-shadow]=\"activeIndex !== 0\" [ngStyle]=\"{ height: subMainSwiperHeight }\">\n <ng-content select=\"[main-slides]\"></ng-content>\n </swiper-container>\n </div>\n </ng-container>\n }\n\n <!-- \u2500\u2500 GROUPING MODE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (enableGrouping) {\n <ng-container>\n\n <!-- Settings trigger -->\n <div class=\"settings-trigger-wrapper\" #settingsTriggerWrapperEl>\n <div class=\"settings-trigger\" [class.settings-trigger--hidden]=\"settingsTriggerPortaled\" (click)=\"toggleGlobalMenu($event)\" [libPopper]=\"confirmPopper\" [popperTrigger]=\"'none'\">\n <i class=\"pi pi-cog\"></i>\n </div>\n @if (showGlobalMenu) {\n <div class=\"global-menu\" [ngClass]=\"'menu-' + menuPosition\" (click)=\"$event.stopPropagation()\">\n <div class=\"menu-item\" (click)=\"requestGroupBy('response')\">Group by Response</div>\n <div class=\"menu-item\" (click)=\"requestGroupBy('client')\">Group by Client</div>\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"restoreCustomGroups()\">Restore Custom Groups</div>\n <div class=\"menu-item\" (click)=\"storeCustomGroups()\">Store Custom Groups</div>\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"ungroupAll()\">Ungroup All</div>\n </div>\n }\n </div>\n\n <ng-template #settingsTriggerPortalTemplate>\n <div\n class=\"settings-trigger-wrapper settings-trigger-wrapper-portal\"\n [style.left.px]=\"settingsTriggerPortalLeft\"\n [style.top.px]=\"settingsTriggerPortalTop\"\n >\n <div class=\"settings-trigger\" (click)=\"toggleGlobalMenu($event)\" [libPopper]=\"confirmPopper\" [popperTrigger]=\"'none'\">\n <i class=\"pi pi-cog\"></i>\n </div>\n </div>\n </ng-template>\n\n <!-- Tab Bar -->\n <div class=\"tab-bar-container\"\n #tabBarContainer\n cdkScrollable\n [class.dragging-active]=\"isDragging\"\n [class.grouping-animating]=\"groupingAnimating\"\n [class.grab-cursor]=\"!repositionMode && !isScrollDragging\"\n [class.grabbing-cursor]=\"isScrollDragging\"\n [ngStyle]=\"{ minHeight: thumbsSwiperHeight }\"\n tabindex=\"0\">\n\n <div\n cdkDropList\n [id]=\"rootDropListId\"\n [cdkDropListConnectedTo]=\"connectedDropLists\"\n [cdkDropListEnterPredicate]=\"canDropToRoot\"\n cdkDropListOrientation=\"horizontal\"\n [cdkDropListData]=\"tabNodes\"\n (cdkDropListDropped)=\"drop($event)\"\n class=\"tab-list-root\">\n\n @for (node of tabNodes; track trackByNode($index, node); let i = $index) {\n <div cdkDrag\n [cdkDragData]=\"node\"\n [cdkDragDisabled]=\"!enableDragAndDrop || isRootNodeDragDisabled(node)\"\n (cdkDragStarted)=\"dragStarted($event)\"\n (cdkDragMoved)=\"onDragMoved($event)\"\n (cdkDragEnded)=\"dragEnded($event)\"\n class=\"tab-node-wrapper\"\n [class.potential-group-target]=\"isItem(node) && potentialGroupTargetId === getSafeId(node.data)\"\n [attr.data-id]=\"isItem(node) ? getSafeId(node.data) : null\"\n (mousedown)=\"onNodeDown($event)\"\n (touchstart)=\"onNodeDown($event)\"\n (mouseup)=\"onNodeMouseUp()\"\n (touchend)=\"onNodeMouseUp()\">\n\n <div *cdkDragPreview>\n <ng-container *ngTemplateOutlet=\"nodePreviewTemplate; context: { node: node }\"></ng-container>\n </div>\n <div *cdkDragPlaceholder [class.reposition-placeholder]=\"repositionMode\"></div>\n\n <!-- \u2500\u2500 Case 1: Ungrouped Item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isItem(node)) {\n <ng-container>\n <div class=\"tab-item ungrouped\"\n [class.is-expanded-source]=\"expandedItemId === getSafeId(node.data)\"\n [attr.data-expanded-id]=\"expandedItemId === getSafeId(node.data) ? expandedItemId : null\"\n [class.active]=\"displayItems.indexOf(node.data) === activeIndex\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(node.data)\"\n (click)=\"onItemClick($event, node)\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: false, expanded: false }\"></ng-container>\n </div>\n\n @if (potentialGroupTargetId === getSafeId(node.data)) {\n <div class=\"visual-group-wrapper\">\n <div class=\"group-header-vertical\"></div>\n <div class=\"group-list-visual\">\n <div class=\"tab-item\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: true, expanded: false }\"></ng-container>\n </div>\n <div class=\"tab-item ghost-item\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: draggedItemData?.data, grouped: true, expanded: false }\"></ng-container>\n </div>\n </div>\n </div>\n }\n </ng-container>\n }\n\n <!-- \u2500\u2500 Case 2: Group Container \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isGroup(node)) {\n <ng-container>\n <div class=\"group-container\"\n [class.collapsed]=\"node.data.collapsed\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(node.data)\"\n [class.pulsating-group]=\"repositionMode && repositionTargetId === getSafeId(node.data)\"\n [style.border-color]=\"node.data.color\"\n [style.--group-accent-color]=\"node.data.color\"\n cdkDragHandle\n [cdkDragHandleDisabled]=\"!enableDragAndDrop || isRootNodeDragDisabled(node) || repositionTargetGroupId === node.id\"\n (mousedown)=\"onNodeDown($event)\"\n (touchstart)=\"onNodeDown($event)\"\n (mouseup)=\"onNodeMouseUp()\"\n (touchend)=\"onNodeMouseUp()\">\n\n <div class=\"group-header-vertical\" (click)=\"toggleGroup(node.data)\">\n <div class=\"group-title-vertical\">\n <span class=\"group-title-text\">{{ getTruncatedTitle(node.data.title, node.data.collapsed) }}</span>\n </div>\n <div class=\"group-ellipsis-vertical\"\n (click)=\"openContextMenu($event, node); $event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (touchstart)=\"$event.stopPropagation()\">\n <div class=\"group-ellipsis-dot\"></div>\n <div class=\"group-ellipsis-dot\"></div>\n <div class=\"group-ellipsis-dot\"></div>\n </div>\n </div>\n\n <div cdkDropList\n [id]=\"'group-list-' + getSafeId(node.data)\"\n [cdkDropListConnectedTo]=\"connectedDropLists\"\n [cdkDropListData]=\"node.data.items\"\n (cdkDropListDropped)=\"drop($event)\"\n [cdkDropListEnterPredicate]=\"canDropToGroup\"\n cdkDropListOrientation=\"horizontal\"\n class=\"group-list\"\n [class.collapsed-drop-target]=\"node.data.collapsed && isDragging\">\n\n @for (item of node.data.items; track trackByItem($index, item)) {\n <div class=\"tab-item\"\n cdkDrag\n [class.is-expanded-source]=\"expandedItemId === getSafeId(item)\"\n [attr.data-expanded-id]=\"expandedItemId === getSafeId(item) ? expandedItemId : null\"\n [cdkDragData]=\"{ type: 'item', data: item }\"\n [cdkDragDisabled]=\"!enableDragAndDrop || isItemDragDisabled(getSafeId(item), node.id)\"\n (cdkDragStarted)=\"dragStarted($event)\"\n (cdkDragMoved)=\"onDragMoved($event)\"\n (cdkDragEnded)=\"dragEnded($event)\"\n [class.active]=\"displayItems.indexOf(item) === activeIndex\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(item)\"\n (click)=\"onItemClick($event, { type: 'item', data: item, id: getSafeId(item) })\">\n\n <div *cdkDragPreview>\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: item, grouped: true, expanded: false }\"></ng-container>\n </div>\n <div *cdkDragPlaceholder [class.reposition-placeholder]=\"repositionMode\"></div>\n\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: item, grouped: true, expanded: false }\"></ng-container>\n </div>\n }\n </div>\n </div>\n </ng-container>\n }\n </div>\n }\n\n <!-- Drag preview template -->\n <ng-template #nodePreviewTemplate let-node=\"node\">\n @if (isItem(node)) {\n <div class=\"tab-item ungrouped\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: false, expanded: false }\"></ng-container>\n </div>\n }\n @if (isGroup(node)) {\n <div class=\"group-container collapsed\"\n [style.border-color]=\"node.data.color\"\n [style.--group-accent-color]=\"node.data.color\">\n <div class=\"group-header-vertical\">\n <div class=\"group-title-vertical\">\n <span class=\"group-title-text\">{{ getTruncatedTitle(node.data.title, true) }}</span>\n </div>\n </div>\n </div>\n }\n </ng-template>\n\n </div>\n </div>\n\n <ng-template #expandedPortalTemplate>\n @if (expandedItemId && portalRect && !(isDragging && getSafeId(draggedItemData?.data) === expandedItemId)) {\n <div class=\"expanded-item-portal\"\n [attr.data-expanded-portal-id]=\"expandedItemId\"\n [style.left.px]=\"portalRect.left\"\n [style.top.px]=\"portalRect.top\"\n [style.width.px]=\"portalRect.width\"\n (pointerdown)=\"onScrollPointerDown($event)\"\n (mousedown)=\"onPortalDown($event)\"\n (touchstart)=\"onPortalDown($event)\"\n (click)=\"onPortalClick($event)\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: expandedItemRef, grouped: false, expanded: true }\"></ng-container>\n </div>\n }\n </ng-template>\n\n @if (showPrefRejectButton) {\n <button type=\"button\" class=\"tabs-pref-reject-button\">\n <span class=\"tabs-pref-reject-button__icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\">\n <g>\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M10.9353 4.11938C11.1384 4.3225 11.1384 4.65183 10.9353 4.85495L2.35324 13.437C2.15012 13.6401 1.82079 13.6401 1.61767 13.437C1.41455 13.2339 1.41455 12.9046 1.61767 12.7014L10.1997 4.11938C10.4028 3.91626 10.7322 3.91626 10.9353 4.11938Z\" fill=\"#FE3C72\"/>\n <circle cx=\"6.14645\" cy=\"8.64816\" r=\"4.0\" stroke=\"#FE3C72\" stroke-width=\"1\"/>\n </g>\n </svg>\n </span>\n <span class=\"tabs-pref-reject-button__label\">Reject</span>\n </button>\n }\n\n <!-- Global menu overlay -->\n @if (showGlobalMenu) {\n <div class=\"global-menu-overlay\" (click)=\"toggleGlobalMenu($event)\"></div>\n }\n\n <!-- Context menu overlay -->\n @if (activeContextMenuNode) {\n <div class=\"context-menu-overlay\" (click)=\"closeMenus()\"></div>\n }\n\n <!-- \u2500\u2500 Context menu (portal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <ng-template #contextMenuTemplate>\n @if (activeContextMenuNode) {\n <div class=\"context-menu\"\n [style.left.px]=\"contextMenuPosition.x\"\n [style.top.px]=\"contextMenuPosition.y\"\n style=\"position: fixed; z-index: 100000;\">\n @if (activeContextMenuNode?.type === 'group' || activeContextMenuNode?.type === 'item') {\n <div class=\"menu-item\" (click)=\"toggleRepositionMode()\">\n {{ repositionMode && (!repositionTargetId || repositionTargetId === getSafeId(activeContextMenuNode?.data)) ? 'End Reposition' : 'Reposition' }}\n </div>\n }\n @if (activeContextMenuNode?.type === 'group') {\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"handleMenuAction('ungroup', activeContextMenuNode!)\">Ungroup</div>\n }\n </div>\n }\n </ng-template>\n\n <!-- \u2500\u2500 Confirmation dialog (Popper) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <lib-popper-content #confirmPopper>\n <div class=\"popover-container\">\n <div class=\"m-title f-w-700 f-lg h-160 f-white\">Overwrite Manual Groups?</div>\n <span class=\"message f-w-400 f-md h-150 f-gray\">\n This operation will discard your current manual arrangement.\n Continue?\n </span>\n <div class=\"buttons\">\n <lib-secondary-btn (click)=\"cancelGroupBy()\" type=\"button\">Cancel</lib-secondary-btn>\n <lib-primary-btn (click)=\"confirmGroupBy()\" type=\"button\">Continue</lib-primary-btn>\n </div>\n </div>\n </lib-popper-content>\n\n <!-- \u2500\u2500 Alert / Toastr (portal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <ng-template #alertTemplate>\n <div class=\"tabs-alert-host\">\n <lib-alert-popup\n [title]=\"alertTitle\"\n [description]=\"alertDescription\"\n [timeState]=\"alertTimeState\"\n (closed)=\"dismissAlert()\">\n </lib-alert-popup>\n </div>\n </ng-template>\n\n <!-- Main Content Swiper -->\n <div class=\"swiper-container main-swiper\" [style.max-height]=\"slideContentMaxHeight\" [ngStyle]=\"{ height: mainSwiperHeight }\">\n <swiper-container #mainSwiper init=\"false\" class=\"main-swiper\"\n [class.container-sides-shadow]=\"activeIndex !== 0\"\n [ngStyle]=\"{ height: subMainSwiperHeight }\">\n @for (item of displayItems; track trackByItem($index, item)) {\n <swiper-slide>\n <ng-container *ngTemplateOutlet=\"contentTemplate; context: { $implicit: item, index: $index }\"></ng-container>\n </swiper-slide>\n }\n </swiper-container>\n </div>\n\n </ng-container>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%;min-width:0;height:100%;display:flex;flex-direction:column;padding-top:0;font-family:Gilroy,sans-serif}.swipeable-tabs-container{position:relative;display:flex;width:100%;height:100%;min-height:0;flex-direction:column;flex:1}.swipeable-tabs-container.bottom-thumbs{flex-direction:column-reverse}.swipeable-tabs-container>.main-swiper{flex:1;display:flex;flex-direction:column;z-index:100}.swipeable-tabs-container swiper-container{position:relative;display:block;overflow:auto;width:100%;height:100%}.swipeable-tabs-container swiper-container{scrollbar-width:none}.swipeable-tabs-container swiper-container::-webkit-scrollbar{display:none}.expanded-item-portal{position:fixed;transform:translate(-50%,-50%);z-index:1000;pointer-events:auto}.settings-trigger-wrapper{position:absolute;top:-15px;right:0;z-index:3000;pointer-events:none}.settings-trigger-wrapper.settings-trigger-wrapper-portal{position:fixed;top:0;right:auto;z-index:3000;pointer-events:none}.settings-trigger{padding:8px;cursor:pointer;color:#fffc;transition:all .3s ease;pointer-events:auto;display:flex;align-items:center;justify-content:center;background:transparent;background:radial-gradient(circle,rgba(0,0,0,.9) 0%,transparent 70%);box-shadow:none;border:none;border-radius:50%}.settings-trigger:hover{color:#fff;background:radial-gradient(circle,rgba(0,0,0,.95) 0%,transparent 70%)}.settings-trigger i{font-size:1.5rem;filter:drop-shadow(0px 0px 2px rgba(0,0,0,.8))}.settings-trigger.settings-trigger--hidden{visibility:hidden;pointer-events:none}.global-menu-overlay,.context-menu-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:2000;background:transparent}.global-menu{position:absolute;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 3px 0 6px #c8c8d259,inset 0 -6px 12px #403d4680,inset 0 -3px 6px #403d46cc,inset 16px 0 10px -2px #3a3a44e6,inset 0 -16px 10px -2px #3a3a44e6;border:none;border-radius:13px;padding:5px 0;min-width:150px;z-index:3001;display:flex;flex-direction:column;overflow:hidden;right:0;left:auto;pointer-events:auto}.popover-container{pointer-events:auto;z-index:5000}.menu-up{top:auto;bottom:100%;margin-bottom:10px;margin-top:0;transform-origin:bottom right;animation:fadeIn .2s ease-out}.menu-down{top:100%;bottom:auto;margin-top:10px;margin-bottom:0;transform-origin:top right;animation:fadeInDown .2s ease-out}.context-menu{position:fixed;margin-left:-17px;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 3px 0 6px #c8c8d259,inset 0 -6px 12px #403d4680,inset 0 -3px 6px #403d46cc,inset 16px 0 10px -2px #3a3a44e6,inset 0 -16px 10px -2px #3a3a44e6;border:none;border-radius:13px;padding:5px 0;min-width:150px;z-index:1002;display:flex;flex-direction:column;overflow:hidden}.context-menu{animation:scaleIn .15s ease-out}.menu-item{padding:12px 20px;color:#ffffffe6;font-family:Gilroy,sans-serif;font-weight:700;font-size:11px;line-height:100%;letter-spacing:.07px;vertical-align:middle;cursor:pointer;transition:background .2s;white-space:nowrap;display:flex;align-items:center}.menu-item:hover{background:#ffffff1a}.global-menu .menu-item{justify-content:flex-end;text-align:right;padding-right:20px}.context-menu .menu-item{justify-content:flex-start;text-align:left;padding-left:20px}.menu-separator{height:1px;background:linear-gradient(to right,transparent,rgba(255,255,255,.3),transparent);margin:8px auto;width:50%}.global-menu .menu-separator{margin-left:auto;margin-right:10%}.context-menu .menu-separator{margin-right:auto;margin-left:10%}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeInDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes scaleIn{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}.item-ellipsis{cursor:pointer;color:#ffffff80;padding:2px;border-radius:50%;transition:all .2s}.item-ellipsis:hover{color:#fff;background:#ffffff1a}.item-ellipsis i{font-size:.9rem}.tab-item{width:54px;min-width:27px;height:54px;display:flex;align-items:center;justify-content:center;line-height:0}.tab-item img,.tab-item .avatar{width:auto;height:auto;object-fit:cover;border-radius:50%;margin:0}.tab-item.is-expanded-source{visibility:hidden;min-width:174px!important;flex-shrink:0}.tab-item.expanded-item{height:auto!important;width:auto!important}.tab-item.ungrouped{position:relative}.tab-item.ungrouped .item-ellipsis{position:absolute;bottom:0;right:0;z-index:10;background:#00000080}.tab-bar-container{display:flex;flex-direction:row;overflow-x:auto;overflow-y:hidden;width:100%;max-width:100%;min-width:0;flex-shrink:0;position:relative;z-index:1000;pointer-events:auto;-ms-overflow-style:none;scrollbar-width:none}.tab-bar-container:focus{outline:none}.tab-bar-container.grab-cursor{cursor:grab}.tab-bar-container.grabbing-cursor{cursor:grabbing;-webkit-user-select:none;user-select:none}.tab-bar-container::-webkit-scrollbar{display:none}.tab-bar-container.grouping-animating .cdk-drag-animating{transition:none!important}.tab-bar-container.grouping-animating .tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder){transition:none!important}.tab-bar-container.grouping-animating .cdk-drag-preview{display:none!important}.tabs-pref-reject-button{position:absolute;left:30%;transform:translate(-50%);bottom:calc(var(--thumbs-height, 40px) + 5px);display:inline-flex;align-items:center;gap:6px;padding:0 10px;height:29px;border:none;border-radius:8px;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 2px 4px #00000040,0 4px 4px #00000040,2px -2px 3px #0006 inset,0 -2px 8px #fff3 inset;color:#d9d9d9;font-family:Gilroy,sans-serif;font-size:8px;letter-spacing:.07px;cursor:pointer;z-index:1100}.tabs-pref-reject-button__icon{display:flex;align-items:center;justify-content:center}.tabs-pref-reject-button__label{line-height:1}.tab-list-root{display:flex;flex-direction:row;align-items:center;gap:10px;padding:0 100px 0 20px;min-width:100%;width:max-content;flex-shrink:0;flex-grow:1;height:100%}.tab-list-root .cdk-drag-placeholder{width:2px!important;min-width:2px!important;height:40px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;flex:0 0 auto;visibility:visible!important}.tab-node-wrapper{display:flex;align-items:center;flex-shrink:0;pointer-events:auto;position:relative;z-index:2;width:auto;min-width:min-content}.cdk-drag-preview{box-sizing:border-box;border-radius:0;box-shadow:none;z-index:9999!important;opacity:.5;width:auto;height:auto;display:inline-flex;align-items:center;justify-content:center;overflow:visible;pointer-events:none;scrollbar-width:none}.cdk-drag-preview::-webkit-scrollbar{display:none}.recently-dropped{opacity:.5;animation:fadeBackIn 1s ease-in forwards;animation-delay:2s}@keyframes fadeBackIn{0%{opacity:.5}to{opacity:1}}.cdk-drag-placeholder{opacity:0}.hidden-placeholder~.cdk-drag-preview,.tab-node-wrapper:has(.hidden-placeholder){transition:none!important}.tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.group-container{border:none;position:relative;display:flex;flex-direction:row;align-items:flex-start;padding:0 0 0 4px;box-sizing:border-box;isolation:isolate;margin-right:20px;background:transparent;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);box-shadow:0 8px 32px #0000005e,inset 0 1px #ffffff4d;border-radius:9px;overflow:visible;transition:all .3s ease}.group-container.pulsating-group{animation:pulsate-group-border 1.5s infinite}.group-container:before{content:\"\";position:absolute;inset:0 auto 0 0;width:min(45px,50%);background:linear-gradient(to right,var(--group-accent-color, rgba(255, 255, 255, .1)),transparent);opacity:.6;filter:blur(15px);z-index:0;pointer-events:none;border-radius:inherit;clip-path:inset(0 0 0 0 round 9px)}.group-container:not(:has(.tab-item.is-expanded-source)){overflow:hidden}.group-container:has(.tab-item.is-expanded-source){overflow:visible;z-index:50}.group-container:has(.tab-item.is-expanded-source):before{clip-path:inset(0 0 0 0 round 9px);overflow:hidden}.group-container.collapsed{width:auto;max-width:none;padding-left:2px}.group-container.collapsed .group-list,.group-container.collapsed .group-ellipsis-vertical{display:none}.group-container.collapsed:before{width:min(32px,30%)}.group-container:has(.tab-item.expanded-item){overflow:visible;z-index:50}@keyframes pulsate-group-border{0%{box-shadow:0 0 #ffffffb3,0 8px 32px #0000005e,inset 0 1px #ffffff4d}70%{box-shadow:0 0 0 6px #fff0,0 8px 32px #0000005e,inset 0 1px #ffffff4d}to{box-shadow:0 0 #fff0,0 8px 32px #0000005e,inset 0 1px #ffffff4d}}.group-title-text{font-family:Calistoga,serif;font-weight:400;font-style:normal;font-size:10px;line-height:100%;letter-spacing:0%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#fff6;max-height:40px;text-align:center;width:100%;display:block;margin-top:6px}.group-header-vertical{width:30px;align-self:stretch;display:flex;flex-direction:column;padding:0 2px;cursor:grab;z-index:20;position:relative;height:54px;max-height:54px;background:transparent}.group-header-vertical:before{content:\"\";position:absolute;inset:0;background:linear-gradient(to right,var(--group-accent-color, rgba(255, 255, 255, .1)),transparent);opacity:.5;filter:blur(4px);z-index:-1}.group-header-vertical>*{position:relative;z-index:1}.group-container.collapsed{border-radius:13px}.group-container.collapsed .group-header-vertical{justify-content:center;align-items:center;width:18px}.group-container.collapsed .group-title-text{margin-bottom:5px;text-align:center}.group-container:not(.collapsed) .group-header-vertical{justify-content:space-around;align-items:flex-start;padding-left:0;padding-bottom:0;padding-top:0}.group-title-vertical{display:flex;align-items:center;justify-content:center;writing-mode:vertical-rl;transform:rotate(180deg);padding:0;margin-bottom:0;overflow:hidden;min-height:40px}.group-ellipsis-vertical{cursor:pointer;align-items:center;justify-content:space-between;width:100%;height:auto;position:static;margin:-11px 0 0;padding-left:0;display:flex;justify-content:flex-start;gap:3px;padding-bottom:5px}.group-ellipsis-vertical:hover{opacity:.7}.group-ellipsis-vertical .group-ellipsis-dot{width:3px;height:3px;background-color:#fff;border-radius:50%!important;display:block}.tab-bar-container.dragging-active .group-header-vertical{z-index:1;pointer-events:none}.group-list{padding-top:2px;display:flex;align-items:center;justify-content:space-around;min-width:40px;margin-left:-13.5px;margin-right:-11.5px;margin-top:-7.5px;gap:20px;border-radius:4px;position:relative;z-index:1;pointer-events:auto}.group-list .tab-item.is-expanded-source,.group-list .tab-item.is-expanded-source.cdk-drag-placeholder{min-width:174px!important;visibility:visible!important;opacity:.5}.group-list.collapsed-drop-target{position:absolute;top:0;left:0;width:100%;height:100%;min-width:unset;background:#ffffff4d;border:2px dashed rgba(255,255,255,.8);z-index:50;border-radius:16px}.group-list.collapsed-drop-target .tab-item{display:none}.reposition-placeholder{width:2px!important;min-width:2px!important;height:40px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;border:none;box-shadow:none;flex:0 0 auto}.group-list .cdk-drag-placeholder{width:2px!important;min-width:2px!important;height:46px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;border:none;box-shadow:0 0 6px 2px #fe3c7299!important;flex:0 0 auto;visibility:visible!important}.hidden-placeholder{visibility:hidden!important;pointer-events:none!important}.tab-node-wrapper.potential-group-target .tab-item.ungrouped{display:none}.visual-group-wrapper{border:none;display:flex;flex-direction:row;align-items:flex-start;padding:3px 3px 3px 4px;background:transparent;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);box-shadow:0 8px 32px #0000005e,inset 0 1px #ffffff4d;border-radius:9px;overflow:hidden;border:1px solid rgba(255,255,255,.2)}.visual-group-wrapper .group-header-vertical{width:18px;height:54px;background:#ffffff1a}.visual-group-wrapper .group-list-visual{display:flex;align-items:center;justify-content:space-around;gap:4.5px;margin-left:-4px;padding-top:2px}.visual-group-wrapper .ghost-item{opacity:.3;filter:grayscale(100%)}.grabbing-cursor{cursor:grabbing!important}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder),.group-list.cdk-drop-list-dragging .tab-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}@keyframes pulse{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}.tabs-confirm-backdrop{position:fixed;inset:0;z-index:200000;background:#0000008c;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center}.tabs-confirm-dialog{background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 0 -6px 12px #403d4680;border-radius:16px;padding:24px 28px 20px;max-width:340px;width:calc(100vw - 48px);display:flex;flex-direction:column;gap:12px}.tabs-confirm-dialog__title{font-family:Calistoga,serif;font-size:14px;font-weight:400;color:#fff;line-height:1.3}.tabs-confirm-dialog__description{font-family:Gilroy,sans-serif;font-size:11px;font-weight:500;color:#ffffffb3;line-height:1.5}.tabs-confirm-dialog__actions{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}.tabs-confirm-btn{font-family:Gilroy,sans-serif;font-weight:700;font-size:11px;letter-spacing:.07px;border:none;border-radius:8px;padding:8px 18px;cursor:pointer;transition:opacity .2s}.tabs-confirm-btn:hover{opacity:.85}.tabs-confirm-btn--cancel{background:#ffffff1a;color:#ffffffbf}.tabs-confirm-btn--confirm{background:#fe3c72;color:#fff}.tabs-alert-host{position:fixed;top:20px;right:20px;z-index:300000;pointer-events:auto}\n"] }]
6867
+ args: [{ selector: 'lib-dashboard-swipeable-tabs', imports: [CommonModule, TranslateModule, DragDropModule, CdkScrollable, AlertPopupComponent, ButtonsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"swipeable-tabs-container\"\n [class.bottom-thumbs]=\"bottomThumbs\"\n [ngStyle]=\"{ height: generalSwiperHeight }\"\n [style.--thumbs-height]=\"thumbsSwiperHeight\"\n>\n\n <!-- \u2500\u2500 LEGACY MODE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (!enableGrouping) {\n <ng-container>\n <swiper-container #thumbSwiper init=\"false\" class=\"thumb-swiper container-sides-shadow\" [ngStyle]=\"{ height: thumbsSwiperHeight }\">\n <ng-content select=\"[thumb-slides]\"></ng-content>\n </swiper-container>\n <div class=\"swiper-container main-swiper\" [style.max-height]=\"slideContentMaxHeight\" [ngStyle]=\"{ height: mainSwiperHeight }\">\n <swiper-container #mainSwiper init=\"false\" class=\"main-swiper\" [class.container-sides-shadow]=\"activeIndex !== 0\" [ngStyle]=\"{ height: subMainSwiperHeight }\">\n <ng-content select=\"[main-slides]\"></ng-content>\n </swiper-container>\n </div>\n </ng-container>\n }\n\n <!-- \u2500\u2500 GROUPING MODE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (enableGrouping) {\n <ng-container>\n\n <!-- Settings trigger -->\n <div class=\"settings-trigger-wrapper\" #settingsTriggerWrapperEl>\n <div class=\"settings-trigger\" [class.settings-trigger--hidden]=\"settingsTriggerPortaled\" (click)=\"toggleGlobalMenu($event)\">\n <i class=\"pi pi-cog\"></i>\n </div>\n @if (showGlobalMenu) {\n <div class=\"global-menu\" [ngClass]=\"'menu-' + menuPosition\" (click)=\"$event.stopPropagation()\">\n <div class=\"menu-item\" (click)=\"requestGroupBy('response')\">Group by Response</div>\n <div class=\"menu-item\" (click)=\"requestGroupBy('client')\">Group by Client</div>\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"restoreCustomGroups()\">Restore Custom Groups</div>\n <div class=\"menu-item\" (click)=\"storeCustomGroups()\">Store Custom Groups</div>\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"ungroupAll()\">Ungroup All</div>\n </div>\n }\n </div>\n\n <ng-template #settingsTriggerPortalTemplate>\n <div\n class=\"settings-trigger-wrapper settings-trigger-wrapper-portal\"\n [style.left.px]=\"settingsTriggerPortalLeft\"\n [style.top.px]=\"settingsTriggerPortalTop\"\n >\n <div class=\"settings-trigger\" (click)=\"toggleGlobalMenu($event)\">\n <i class=\"pi pi-cog\"></i>\n </div>\n </div>\n </ng-template>\n\n <!-- Tab Bar -->\n <div class=\"tab-bar-container\"\n #tabBarContainer\n cdkScrollable\n [class.dragging-active]=\"isDragging\"\n [class.grouping-animating]=\"groupingAnimating\"\n [class.grab-cursor]=\"!repositionMode && !isScrollDragging\"\n [class.grabbing-cursor]=\"isScrollDragging\"\n [ngStyle]=\"{ minHeight: thumbsSwiperHeight }\"\n tabindex=\"0\">\n\n <div\n cdkDropList\n [id]=\"rootDropListId\"\n [cdkDropListConnectedTo]=\"connectedDropLists\"\n [cdkDropListEnterPredicate]=\"canDropToRoot\"\n cdkDropListOrientation=\"horizontal\"\n [cdkDropListData]=\"tabNodes\"\n (cdkDropListDropped)=\"drop($event)\"\n class=\"tab-list-root\">\n\n @for (node of tabNodes; track trackByNode($index, node); let i = $index) {\n <div cdkDrag\n [cdkDragData]=\"node\"\n [cdkDragDisabled]=\"!enableDragAndDrop || isRootNodeDragDisabled(node)\"\n (cdkDragStarted)=\"dragStarted($event)\"\n (cdkDragMoved)=\"onDragMoved($event)\"\n (cdkDragEnded)=\"dragEnded($event)\"\n class=\"tab-node-wrapper\"\n [class.potential-group-target]=\"isItem(node) && potentialGroupTargetId === getSafeId(node.data)\"\n [attr.data-id]=\"isItem(node) ? getSafeId(node.data) : null\"\n (mousedown)=\"onNodeDown($event)\"\n (touchstart)=\"onNodeDown($event)\"\n (mouseup)=\"onNodeMouseUp()\"\n (touchend)=\"onNodeMouseUp()\">\n\n <div *cdkDragPreview>\n <ng-container *ngTemplateOutlet=\"nodePreviewTemplate; context: { node: node }\"></ng-container>\n </div>\n <div *cdkDragPlaceholder [class.reposition-placeholder]=\"repositionMode\"></div>\n\n <!-- \u2500\u2500 Case 1: Ungrouped Item \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isItem(node)) {\n <ng-container>\n <div class=\"tab-item ungrouped\"\n [class.is-expanded-source]=\"expandedItemId === getSafeId(node.data)\"\n [attr.data-expanded-id]=\"expandedItemId === getSafeId(node.data) ? expandedItemId : null\"\n [class.active]=\"displayItems.indexOf(node.data) === activeIndex\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(node.data)\"\n (click)=\"onItemClick($event, node)\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: false, expanded: false }\"></ng-container>\n </div>\n\n @if (potentialGroupTargetId === getSafeId(node.data)) {\n <div class=\"visual-group-wrapper\">\n <div class=\"group-header-vertical\"></div>\n <div class=\"group-list-visual\">\n <div class=\"tab-item\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: true, expanded: false }\"></ng-container>\n </div>\n <div class=\"tab-item ghost-item\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: draggedItemData?.data, grouped: true, expanded: false }\"></ng-container>\n </div>\n </div>\n </div>\n }\n </ng-container>\n }\n\n <!-- \u2500\u2500 Case 2: Group Container \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isGroup(node)) {\n <ng-container>\n <div class=\"group-container\"\n [class.collapsed]=\"node.data.collapsed\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(node.data)\"\n [class.pulsating-group]=\"repositionMode && repositionTargetId === getSafeId(node.data)\"\n [style.border-color]=\"node.data.color\"\n [style.--group-accent-color]=\"node.data.color\"\n cdkDragHandle\n [cdkDragHandleDisabled]=\"!enableDragAndDrop || isRootNodeDragDisabled(node) || repositionTargetGroupId === node.id\"\n (mousedown)=\"onNodeDown($event)\"\n (touchstart)=\"onNodeDown($event)\"\n (mouseup)=\"onNodeMouseUp()\"\n (touchend)=\"onNodeMouseUp()\">\n\n <div class=\"group-header-vertical\" (click)=\"toggleGroup(node.data)\">\n <div class=\"group-title-vertical\">\n <span class=\"group-title-text\">{{ getTruncatedTitle(node.data.title, node.data.collapsed) }}</span>\n </div>\n <div class=\"group-ellipsis-vertical\"\n (click)=\"openContextMenu($event, node); $event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (touchstart)=\"$event.stopPropagation()\">\n <div class=\"group-ellipsis-dot\"></div>\n <div class=\"group-ellipsis-dot\"></div>\n <div class=\"group-ellipsis-dot\"></div>\n </div>\n </div>\n\n <div cdkDropList\n [id]=\"'group-list-' + getSafeId(node.data)\"\n [cdkDropListConnectedTo]=\"connectedDropLists\"\n [cdkDropListData]=\"node.data.items\"\n (cdkDropListDropped)=\"drop($event)\"\n [cdkDropListEnterPredicate]=\"canDropToGroup\"\n cdkDropListOrientation=\"horizontal\"\n class=\"group-list\"\n [class.collapsed-drop-target]=\"node.data.collapsed && isDragging\">\n\n @for (item of node.data.items; track trackByItem($index, item)) {\n <div class=\"tab-item\"\n cdkDrag\n [class.is-expanded-source]=\"expandedItemId === getSafeId(item)\"\n [attr.data-expanded-id]=\"expandedItemId === getSafeId(item) ? expandedItemId : null\"\n [cdkDragData]=\"{ type: 'item', data: item }\"\n [cdkDragDisabled]=\"!enableDragAndDrop || isItemDragDisabled(getSafeId(item), node.id)\"\n (cdkDragStarted)=\"dragStarted($event)\"\n (cdkDragMoved)=\"onDragMoved($event)\"\n (cdkDragEnded)=\"dragEnded($event)\"\n [class.active]=\"displayItems.indexOf(item) === activeIndex\"\n [class.recently-dropped]=\"recentlyDroppedId === getSafeId(item)\"\n (click)=\"onItemClick($event, { type: 'item', data: item, id: getSafeId(item) })\">\n\n <div *cdkDragPreview>\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: item, grouped: true, expanded: false }\"></ng-container>\n </div>\n <div *cdkDragPlaceholder [class.reposition-placeholder]=\"repositionMode\"></div>\n\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: item, grouped: true, expanded: false }\"></ng-container>\n </div>\n }\n </div>\n </div>\n </ng-container>\n }\n </div>\n }\n\n <!-- Drag preview template -->\n <ng-template #nodePreviewTemplate let-node=\"node\">\n @if (isItem(node)) {\n <div class=\"tab-item ungrouped\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: node.data, grouped: false, expanded: false }\"></ng-container>\n </div>\n }\n @if (isGroup(node)) {\n <div class=\"group-container collapsed\"\n [style.border-color]=\"node.data.color\"\n [style.--group-accent-color]=\"node.data.color\">\n <div class=\"group-header-vertical\">\n <div class=\"group-title-vertical\">\n <span class=\"group-title-text\">{{ getTruncatedTitle(node.data.title, true) }}</span>\n </div>\n </div>\n </div>\n }\n </ng-template>\n\n </div>\n </div>\n\n <ng-template #expandedPortalTemplate>\n @if (expandedItemId && portalRect && !(isDragging && getSafeId(draggedItemData?.data) === expandedItemId)) {\n <div class=\"expanded-item-portal\"\n [attr.data-expanded-portal-id]=\"expandedItemId\"\n [style.left.px]=\"portalRect.left\"\n [style.top.px]=\"portalRect.top\"\n [style.width.px]=\"portalRect.width\"\n (pointerdown)=\"onScrollPointerDown($event)\"\n (mousedown)=\"onPortalDown($event)\"\n (touchstart)=\"onPortalDown($event)\"\n (click)=\"onPortalClick($event)\">\n <ng-container *ngTemplateOutlet=\"thumbTemplate; context: { $implicit: expandedItemRef, grouped: false, expanded: true }\"></ng-container>\n </div>\n }\n </ng-template>\n\n @if (showPrefRejectButton) {\n <button type=\"button\" class=\"tabs-pref-reject-button\">\n <span class=\"tabs-pref-reject-button__icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\">\n <g>\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M10.9353 4.11938C11.1384 4.3225 11.1384 4.65183 10.9353 4.85495L2.35324 13.437C2.15012 13.6401 1.82079 13.6401 1.61767 13.437C1.41455 13.2339 1.41455 12.9046 1.61767 12.7014L10.1997 4.11938C10.4028 3.91626 10.7322 3.91626 10.9353 4.11938Z\" fill=\"#FE3C72\"/>\n <circle cx=\"6.14645\" cy=\"8.64816\" r=\"4.0\" stroke=\"#FE3C72\" stroke-width=\"1\"/>\n </g>\n </svg>\n </span>\n <span class=\"tabs-pref-reject-button__label\">Reject</span>\n </button>\n }\n\n <!-- Global menu overlay -->\n @if (showGlobalMenu) {\n <div class=\"global-menu-overlay\" (click)=\"toggleGlobalMenu($event)\"></div>\n }\n\n <!-- Context menu overlay -->\n @if (activeContextMenuNode) {\n <div class=\"context-menu-overlay\" (click)=\"closeMenus()\"></div>\n }\n\n <!-- \u2500\u2500 Context menu (portal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <ng-template #contextMenuTemplate>\n @if (activeContextMenuNode) {\n <div class=\"context-menu\"\n [style.left.px]=\"contextMenuPosition.x\"\n [style.top.px]=\"contextMenuPosition.y\"\n style=\"position: fixed; z-index: 100000;\">\n @if (activeContextMenuNode?.type === 'group' || activeContextMenuNode?.type === 'item') {\n <div class=\"menu-item\" (click)=\"toggleRepositionMode()\">\n {{ repositionMode && (!repositionTargetId || repositionTargetId === getSafeId(activeContextMenuNode?.data)) ? 'End Reposition' : 'Reposition' }}\n </div>\n }\n @if (activeContextMenuNode?.type === 'group') {\n <div class=\"menu-separator\"></div>\n <div class=\"menu-item\" (click)=\"handleMenuAction('ungroup', activeContextMenuNode!)\">Ungroup</div>\n }\n </div>\n }\n </ng-template>\n\n <!-- \u2500\u2500 Confirmation dialog (Portal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <ng-template #confirmDialogTemplate>\n <div class=\"confirm-dialog-overlay\" (click)=\"cancelGroupBy()\">\n <div class=\"confirm-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"m-title f-w-700 f-lg h-160 f-white\">Overwrite Manual Groups?</div>\n <span class=\"message f-w-400 f-md h-150 f-gray\">\n This operation will discard your current manual arrangement.\n Continue?\n </span>\n <div class=\"buttons\">\n <lib-secondary-btn (click)=\"cancelGroupBy()\" type=\"button\">Cancel</lib-secondary-btn>\n <lib-primary-btn (click)=\"confirmGroupBy()\" type=\"button\">Continue</lib-primary-btn>\n </div>\n </div>\n </div>\n </ng-template>\n\n <!-- \u2500\u2500 Alert / Toastr (portal) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <ng-template #alertTemplate>\n <div class=\"tabs-alert-host\">\n <lib-alert-popup\n [title]=\"alertTitle\"\n [description]=\"alertDescription\"\n [timeState]=\"alertTimeState\"\n (closed)=\"dismissAlert()\">\n </lib-alert-popup>\n </div>\n </ng-template>\n\n <!-- Main Content Swiper -->\n <div class=\"swiper-container main-swiper\" [style.max-height]=\"slideContentMaxHeight\" [ngStyle]=\"{ height: mainSwiperHeight }\">\n <swiper-container #mainSwiper init=\"false\" class=\"main-swiper\"\n [class.container-sides-shadow]=\"activeIndex !== 0\"\n [ngStyle]=\"{ height: subMainSwiperHeight }\">\n @for (item of displayItems; track trackByItem($index, item)) {\n <swiper-slide>\n <ng-container *ngTemplateOutlet=\"contentTemplate; context: { $implicit: item, index: $index }\"></ng-container>\n </swiper-slide>\n }\n </swiper-container>\n </div>\n\n </ng-container>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%;min-width:0;height:100%;display:flex;flex-direction:column;padding-top:0;font-family:Gilroy,sans-serif}.swipeable-tabs-container{position:relative;display:flex;width:100%;height:100%;min-height:0;flex-direction:column;flex:1}.swipeable-tabs-container.bottom-thumbs{flex-direction:column-reverse}.swipeable-tabs-container>.main-swiper{flex:1;display:flex;flex-direction:column;z-index:100}.swipeable-tabs-container swiper-container{position:relative;display:block;overflow:auto;width:100%;height:100%}.swipeable-tabs-container swiper-container{scrollbar-width:none}.swipeable-tabs-container swiper-container::-webkit-scrollbar{display:none}.expanded-item-portal{position:fixed;transform:translate(-50%,-50%);z-index:1000;pointer-events:auto}.settings-trigger-wrapper{position:absolute;top:-15px;right:0;z-index:3000;pointer-events:none}.settings-trigger-wrapper.settings-trigger-wrapper-portal{position:fixed;top:0;right:auto;z-index:3000;pointer-events:none}.settings-trigger{padding:8px;cursor:pointer;color:#fffc;transition:all .3s ease;pointer-events:auto;display:flex;align-items:center;justify-content:center;background:transparent;background:radial-gradient(circle,rgba(0,0,0,.9) 0%,transparent 70%);box-shadow:none;border:none;border-radius:50%}.settings-trigger:hover{color:#fff;background:radial-gradient(circle,rgba(0,0,0,.95) 0%,transparent 70%)}.settings-trigger i{font-size:1.5rem;filter:drop-shadow(0px 0px 2px rgba(0,0,0,.8))}.settings-trigger.settings-trigger--hidden{visibility:hidden;pointer-events:none}.global-menu-overlay,.context-menu-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:2000;background:transparent}.confirm-dialog-overlay{position:fixed;inset:0;width:100vw;height:100vh;z-index:100000;background:#0000008c;display:flex;align-items:center;justify-content:center;padding:24px;pointer-events:auto}.confirm-dialog{width:min(420px,100%);background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 3px 0 6px #c8c8d259,inset 0 -6px 12px #403d4680,inset 0 -3px 6px #403d46cc,inset 16px 0 10px -2px #3a3a44e6,inset 0 -16px 10px -2px #3a3a44e6;border-radius:13px;padding:16px;pointer-events:auto}.confirm-dialog .buttons{display:flex;justify-content:flex-end;gap:12px;margin-top:16px}.global-menu{position:absolute;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 3px 0 6px #c8c8d259,inset 0 -6px 12px #403d4680,inset 0 -3px 6px #403d46cc,inset 16px 0 10px -2px #3a3a44e6,inset 0 -16px 10px -2px #3a3a44e6;border:none;border-radius:13px;padding:5px 0;min-width:150px;z-index:3001;display:flex;flex-direction:column;overflow:hidden;right:0;left:auto;pointer-events:auto}.menu-up{top:auto;bottom:100%;margin-bottom:10px;margin-top:0;transform-origin:bottom right;animation:fadeIn .2s ease-out}.menu-down{top:100%;bottom:auto;margin-top:10px;margin-bottom:0;transform-origin:top right;animation:fadeInDown .2s ease-out}.context-menu{position:fixed;margin-left:-17px;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 3px 0 6px #c8c8d259,inset 0 -6px 12px #403d4680,inset 0 -3px 6px #403d46cc,inset 16px 0 10px -2px #3a3a44e6,inset 0 -16px 10px -2px #3a3a44e6;border:none;border-radius:13px;padding:5px 0;min-width:150px;z-index:1002;display:flex;flex-direction:column;overflow:hidden}.context-menu{animation:scaleIn .15s ease-out}.menu-item{padding:12px 20px;color:#ffffffe6;font-family:Gilroy,sans-serif;font-weight:700;font-size:11px;line-height:100%;letter-spacing:.07px;vertical-align:middle;cursor:pointer;transition:background .2s;white-space:nowrap;display:flex;align-items:center}.menu-item:hover{background:#ffffff1a}.global-menu .menu-item{justify-content:flex-end;text-align:right;padding-right:20px}.context-menu .menu-item{justify-content:flex-start;text-align:left;padding-left:20px}.menu-separator{height:1px;background:linear-gradient(to right,transparent,rgba(255,255,255,.3),transparent);margin:8px auto;width:50%}.global-menu .menu-separator{margin-left:auto;margin-right:10%}.context-menu .menu-separator{margin-right:auto;margin-left:10%}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeInDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes scaleIn{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}.item-ellipsis{cursor:pointer;color:#ffffff80;padding:2px;border-radius:50%;transition:all .2s}.item-ellipsis:hover{color:#fff;background:#ffffff1a}.item-ellipsis i{font-size:.9rem}.tab-item{width:54px;min-width:27px;height:54px;display:flex;align-items:center;justify-content:center;line-height:0}.tab-item img,.tab-item .avatar{width:auto;height:auto;object-fit:cover;border-radius:50%;margin:0}.tab-item.is-expanded-source{visibility:hidden;min-width:174px!important;flex-shrink:0}.tab-item.expanded-item{height:auto!important;width:auto!important}.tab-item.ungrouped{position:relative}.tab-item.ungrouped .item-ellipsis{position:absolute;bottom:0;right:0;z-index:10;background:#00000080}.tab-bar-container{display:flex;flex-direction:row;overflow-x:auto;overflow-y:hidden;width:100%;max-width:100%;min-width:0;flex-shrink:0;position:relative;z-index:1000;pointer-events:auto;-ms-overflow-style:none;scrollbar-width:none}.tab-bar-container:focus{outline:none}.tab-bar-container.grab-cursor{cursor:grab}.tab-bar-container.grabbing-cursor{cursor:grabbing;-webkit-user-select:none;user-select:none}.tab-bar-container::-webkit-scrollbar{display:none}.tab-bar-container.grouping-animating .cdk-drag-animating{transition:none!important}.tab-bar-container.grouping-animating .tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder){transition:none!important}.tab-bar-container.grouping-animating .cdk-drag-preview{display:none!important}.tabs-pref-reject-button{position:absolute;left:30%;transform:translate(-50%);bottom:calc(var(--thumbs-height, 40px) + 5px);display:inline-flex;align-items:center;gap:6px;padding:0 10px;height:29px;border:none;border-radius:8px;background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 2px 4px #00000040,0 4px 4px #00000040,2px -2px 3px #0006 inset,0 -2px 8px #fff3 inset;color:#d9d9d9;font-family:Gilroy,sans-serif;font-size:8px;letter-spacing:.07px;cursor:pointer;z-index:1100}.tabs-pref-reject-button__icon{display:flex;align-items:center;justify-content:center}.tabs-pref-reject-button__label{line-height:1}.tab-list-root{display:flex;flex-direction:row;align-items:center;gap:10px;padding:0 100px 0 20px;min-width:100%;width:max-content;flex-shrink:0;flex-grow:1;height:100%}.tab-list-root .cdk-drag-placeholder{width:2px!important;min-width:2px!important;height:40px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;flex:0 0 auto;visibility:visible!important}.tab-node-wrapper{display:flex;align-items:center;flex-shrink:0;pointer-events:auto;position:relative;z-index:2;width:auto;min-width:min-content}.cdk-drag-preview{box-sizing:border-box;border-radius:0;box-shadow:none;z-index:9999!important;opacity:.5;width:auto;height:auto;display:inline-flex;align-items:center;justify-content:center;overflow:visible;pointer-events:none;scrollbar-width:none}.cdk-drag-preview::-webkit-scrollbar{display:none}.recently-dropped{opacity:.5;animation:fadeBackIn 1s ease-in forwards;animation-delay:2s}@keyframes fadeBackIn{0%{opacity:.5}to{opacity:1}}.cdk-drag-placeholder{opacity:0}.hidden-placeholder~.cdk-drag-preview,.tab-node-wrapper:has(.hidden-placeholder){transition:none!important}.tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.group-container{border:none;position:relative;display:flex;flex-direction:row;align-items:flex-start;padding:0 0 0 4px;box-sizing:border-box;isolation:isolate;margin-right:20px;background:transparent;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);box-shadow:0 8px 32px #0000005e,inset 0 1px #ffffff4d;border-radius:9px;overflow:visible;transition:all .3s ease}.group-container.pulsating-group{animation:pulsate-group-border 1.5s infinite}.group-container:before{content:\"\";position:absolute;inset:0 auto 0 0;width:min(45px,50%);background:linear-gradient(to right,var(--group-accent-color, rgba(255, 255, 255, .1)),transparent);opacity:.6;filter:blur(15px);z-index:0;pointer-events:none;border-radius:inherit;clip-path:inset(0 0 0 0 round 9px)}.group-container:not(:has(.tab-item.is-expanded-source)){overflow:hidden}.group-container:has(.tab-item.is-expanded-source){overflow:visible;z-index:50}.group-container:has(.tab-item.is-expanded-source):before{clip-path:inset(0 0 0 0 round 9px);overflow:hidden}.group-container.collapsed{width:auto;max-width:none;padding-left:2px}.group-container.collapsed .group-list,.group-container.collapsed .group-ellipsis-vertical{display:none}.group-container.collapsed:before{width:min(32px,30%)}.group-container:has(.tab-item.expanded-item){overflow:visible;z-index:50}@keyframes pulsate-group-border{0%{box-shadow:0 0 #ffffffb3,0 8px 32px #0000005e,inset 0 1px #ffffff4d}70%{box-shadow:0 0 0 6px #fff0,0 8px 32px #0000005e,inset 0 1px #ffffff4d}to{box-shadow:0 0 #fff0,0 8px 32px #0000005e,inset 0 1px #ffffff4d}}.group-title-text{font-family:Calistoga,serif;font-weight:400;font-style:normal;font-size:10px;line-height:100%;letter-spacing:0%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#fff6;max-height:40px;text-align:center;width:100%;display:block;margin-top:6px}.group-header-vertical{width:30px;align-self:stretch;display:flex;flex-direction:column;padding:0 2px;cursor:grab;z-index:20;position:relative;height:54px;max-height:54px;background:transparent}.group-header-vertical:before{content:\"\";position:absolute;inset:0;background:linear-gradient(to right,var(--group-accent-color, rgba(255, 255, 255, .1)),transparent);opacity:.5;filter:blur(4px);z-index:-1}.group-header-vertical>*{position:relative;z-index:1}.group-container.collapsed{border-radius:13px}.group-container.collapsed .group-header-vertical{justify-content:center;align-items:center;width:18px}.group-container.collapsed .group-title-text{margin-bottom:5px;text-align:center}.group-container:not(.collapsed) .group-header-vertical{justify-content:space-around;align-items:flex-start;padding-left:0;padding-bottom:0;padding-top:0}.group-title-vertical{display:flex;align-items:center;justify-content:center;writing-mode:vertical-rl;transform:rotate(180deg);padding:0;margin-bottom:0;overflow:hidden;min-height:40px}.group-ellipsis-vertical{cursor:pointer;align-items:center;justify-content:space-between;width:100%;height:auto;position:static;margin:-11px 0 0;padding-left:0;display:flex;justify-content:flex-start;gap:3px;padding-bottom:5px}.group-ellipsis-vertical:hover{opacity:.7}.group-ellipsis-vertical .group-ellipsis-dot{width:3px;height:3px;background-color:#fff;border-radius:50%!important;display:block}.tab-bar-container.dragging-active .group-header-vertical{z-index:1;pointer-events:none}.group-list{padding-top:2px;display:flex;align-items:center;justify-content:space-around;min-width:40px;margin-left:-13.5px;margin-right:-11.5px;margin-top:-7.5px;gap:20px;border-radius:4px;position:relative;z-index:1;pointer-events:auto}.group-list .tab-item.is-expanded-source,.group-list .tab-item.is-expanded-source.cdk-drag-placeholder{min-width:174px!important;visibility:visible!important;opacity:.5}.group-list.collapsed-drop-target{position:absolute;top:0;left:0;width:100%;height:100%;min-width:unset;background:#ffffff4d;border:2px dashed rgba(255,255,255,.8);z-index:50;border-radius:16px}.group-list.collapsed-drop-target .tab-item{display:none}.reposition-placeholder{width:2px!important;min-width:2px!important;height:40px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;border:none;box-shadow:none;flex:0 0 auto}.group-list .cdk-drag-placeholder{width:2px!important;min-width:2px!important;height:46px!important;background-color:#fe3c72!important;margin:0 4px;opacity:1!important;border-radius:1px;border:none;box-shadow:0 0 6px 2px #fe3c7299!important;flex:0 0 auto;visibility:visible!important}.hidden-placeholder{visibility:hidden!important;pointer-events:none!important}.tab-node-wrapper.potential-group-target .tab-item.ungrouped{display:none}.visual-group-wrapper{border:none;display:flex;flex-direction:row;align-items:flex-start;padding:3px 3px 3px 4px;background:transparent;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);box-shadow:0 8px 32px #0000005e,inset 0 1px #ffffff4d;border-radius:9px;overflow:hidden;border:1px solid rgba(255,255,255,.2)}.visual-group-wrapper .group-header-vertical{width:18px;height:54px;background:#ffffff1a}.visual-group-wrapper .group-list-visual{display:flex;align-items:center;justify-content:space-around;gap:4.5px;margin-left:-4px;padding-top:2px}.visual-group-wrapper .ghost-item{opacity:.3;filter:grayscale(100%)}.grabbing-cursor{cursor:grabbing!important}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.tab-list-root.cdk-drop-list-dragging .tab-node-wrapper:not(.cdk-drag-placeholder),.group-list.cdk-drop-list-dragging .tab-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}@keyframes pulse{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}.tabs-confirm-backdrop{position:fixed;inset:0;z-index:200000;background:#0000008c;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center}.tabs-confirm-dialog{background:linear-gradient(180deg,#403d46,#3e3b44);box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d,inset 6px 0 12px #c8c8d240,inset 0 -6px 12px #403d4680;border-radius:16px;padding:24px 28px 20px;max-width:340px;width:calc(100vw - 48px);display:flex;flex-direction:column;gap:12px}.tabs-confirm-dialog__title{font-family:Calistoga,serif;font-size:14px;font-weight:400;color:#fff;line-height:1.3}.tabs-confirm-dialog__description{font-family:Gilroy,sans-serif;font-size:11px;font-weight:500;color:#ffffffb3;line-height:1.5}.tabs-confirm-dialog__actions{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}.tabs-confirm-btn{font-family:Gilroy,sans-serif;font-weight:700;font-size:11px;letter-spacing:.07px;border:none;border-radius:8px;padding:8px 18px;cursor:pointer;transition:opacity .2s}.tabs-confirm-btn:hover{opacity:.85}.tabs-confirm-btn--cancel{background:#ffffff1a;color:#ffffffbf}.tabs-confirm-btn--confirm{background:#fe3c72;color:#fff}.tabs-alert-host{position:fixed;top:20px;right:20px;z-index:300000;pointer-events:auto}\n"] }]
6802
6868
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ViewContainerRef }, { type: i0.NgZone }], propDecorators: { thumbSwiper: [{
6803
6869
  type: ViewChild,
6804
6870
  args: ['thumbSwiper', { static: false }]
@@ -6861,9 +6927,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
6861
6927
  }], contextMenuTemplate: [{
6862
6928
  type: ViewChild,
6863
6929
  args: ['contextMenuTemplate']
6864
- }], confirmPopper: [{
6930
+ }], confirmDialogTemplate: [{
6865
6931
  type: ViewChild,
6866
- args: ['confirmPopper']
6932
+ args: ['confirmDialogTemplate']
6867
6933
  }], alertTemplate: [{
6868
6934
  type: ViewChild,
6869
6935
  args: ['alertTemplate']