@eric-emg/symphiq-components 1.2.17 → 1.2.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -82,6 +82,26 @@ Embedded mode:
82
82
 
83
83
  **Note:** When `embedded` is `true` and you have a custom scrolling container outside the dashboard component, you should provide the `scrollContainerId` input with the ID of that container element. If `scrollContainerId` is not provided, the component will fall back to using its internal container for scroll tracking.
84
84
 
85
+ #### Ionic Framework Support
86
+
87
+ The component automatically detects and supports **Ionic `<ion-content>` elements**:
88
+
89
+ ```typescript
90
+ @Component({
91
+ template: `
92
+ <ion-content id="mainContent">
93
+ <symphiq-funnel-analysis-dashboard
94
+ [funnelAnalysis]="data"
95
+ [embedded]="true"
96
+ [scrollContainerId]="'mainContent'">
97
+ </symphiq-funnel-analysis-dashboard>
98
+ </ion-content>
99
+ `
100
+ })
101
+ ```
102
+
103
+ When an `ion-content` element is detected, the component will automatically call `getScrollElement()` to attach the scroll listener to the correct internal scrollable element within the shadow DOM.
104
+
85
105
  ### Preview Component
86
106
 
87
107
  The library includes a compact preview component for displaying funnel analysis summaries:
@@ -21360,21 +21360,74 @@ class SymphiqFunnelAnalysisDashboardComponent {
21360
21360
  // Set up container scroll listener when in embedded mode
21361
21361
  if (this.embedded()) {
21362
21362
  let container = null;
21363
+ console.log('[Scroll Debug] Embedded mode detected, setting up scroll listener');
21364
+ console.log('[Scroll Debug] scrollContainerId:', this.scrollContainerId());
21363
21365
  // If a scroll container ID is provided, use that element
21364
21366
  if (this.scrollContainerId()) {
21365
- container = document.getElementById(this.scrollContainerId());
21366
- if (!container) {
21367
- console.warn(`Scroll container with id "${this.scrollContainerId()}" not found. Scroll tracking will not work.`);
21367
+ const element = document.getElementById(this.scrollContainerId());
21368
+ if (!element) {
21369
+ console.warn(`[Scroll Debug] Scroll container with id "${this.scrollContainerId()}" not found. Scroll tracking will not work.`);
21370
+ }
21371
+ else {
21372
+ console.log('[Scroll Debug] Found external scroll container:', element);
21373
+ console.log('[Scroll Debug] Container tag name:', element.tagName);
21374
+ // Check if this is an Ionic ion-content element
21375
+ if (element.tagName.toLowerCase() === 'ion-content') {
21376
+ console.log('[Scroll Debug] Detected Ionic ion-content, attempting to get scrollable element');
21377
+ // Try to get the scroll element from Ionic's ion-content
21378
+ // Ionic stores the scrollable element in the component itself
21379
+ const ionContent = element;
21380
+ // Method 1: Try getScrollElement() method (Ionic 4+)
21381
+ if (typeof ionContent.getScrollElement === 'function') {
21382
+ console.log('[Scroll Debug] Using getScrollElement() method');
21383
+ ionContent.getScrollElement().then((scrollElement) => {
21384
+ console.log('[Scroll Debug] Got Ionic scroll element:', scrollElement);
21385
+ console.log('[Scroll Debug] Ionic scroll element dimensions:', {
21386
+ clientHeight: scrollElement.clientHeight,
21387
+ scrollHeight: scrollElement.scrollHeight,
21388
+ scrollTop: scrollElement.scrollTop,
21389
+ hasOverflow: scrollElement.scrollHeight > scrollElement.clientHeight
21390
+ });
21391
+ scrollElement.addEventListener('scroll', () => this.onContainerScroll(scrollElement), { passive: true });
21392
+ console.log('[Scroll Debug] Attached scroll listener to Ionic scroll element');
21393
+ }).catch((error) => {
21394
+ console.error('[Scroll Debug] Error getting Ionic scroll element:', error);
21395
+ });
21396
+ }
21397
+ else {
21398
+ console.warn('[Scroll Debug] ion-content does not have getScrollElement() method');
21399
+ // Fallback: attach to ion-content itself (may not work)
21400
+ container = element;
21401
+ }
21402
+ }
21403
+ else {
21404
+ // Regular HTML element
21405
+ container = element;
21406
+ console.log('[Scroll Debug] Container dimensions:', {
21407
+ clientHeight: container.clientHeight,
21408
+ scrollHeight: container.scrollHeight,
21409
+ scrollTop: container.scrollTop,
21410
+ hasOverflow: container.scrollHeight > container.clientHeight
21411
+ });
21412
+ }
21368
21413
  }
21369
- console.info(`Scroll container with id "${this.scrollContainerId()}" found!`);
21370
21414
  }
21371
21415
  else if (this.dashboardContainer) {
21372
21416
  // Fall back to internal dashboard container
21373
21417
  container = this.dashboardContainer.nativeElement;
21418
+ console.log('[Scroll Debug] Using internal dashboard container:', container);
21374
21419
  }
21420
+ // Only attach listener for non-Ionic elements (Ionic handled above)
21375
21421
  if (container) {
21422
+ console.log('[Scroll Debug] Attaching scroll listener to container');
21376
21423
  container.addEventListener('scroll', () => this.onContainerScroll(container), { passive: true });
21377
21424
  }
21425
+ else if (!this.scrollContainerId() || document.getElementById(this.scrollContainerId())?.tagName.toLowerCase() !== 'ion-content') {
21426
+ console.warn('[Scroll Debug] No scroll container found!');
21427
+ }
21428
+ }
21429
+ else {
21430
+ console.log('[Scroll Debug] Not in embedded mode, using window scroll');
21378
21431
  }
21379
21432
  }
21380
21433
  handleSearchResult(result) {
@@ -21584,6 +21637,7 @@ class SymphiqFunnelAnalysisDashboardComponent {
21584
21637
  }
21585
21638
  onContainerScroll(container) {
21586
21639
  if (!this.embedded()) {
21640
+ console.log('[Scroll Debug] onContainerScroll called but not in embedded mode, returning');
21587
21641
  return;
21588
21642
  }
21589
21643
  const scrollPosition = container.scrollTop;
@@ -21592,15 +21646,26 @@ class SymphiqFunnelAnalysisDashboardComponent {
21592
21646
  const scrollHeight = container.scrollHeight;
21593
21647
  const maxScroll = scrollHeight - containerHeight;
21594
21648
  const progress = maxScroll > 0 ? (scrollPosition / maxScroll) * 100 : 0;
21649
+ console.log('[Scroll Debug] Container scroll event:', {
21650
+ scrollPosition,
21651
+ containerHeight,
21652
+ scrollHeight,
21653
+ maxScroll,
21654
+ progress: progress.toFixed(2) + '%',
21655
+ currentScrollProgress: this.scrollProgress(),
21656
+ isScrolled: this.isScrolled()
21657
+ });
21595
21658
  this.scrollProgress.set(Math.min(100, Math.max(0, progress)));
21596
21659
  // Skip header state updates during programmatic scrolling
21597
21660
  if (this.isProgrammaticScroll) {
21661
+ console.log('[Scroll Debug] Skipping header update - programmatic scroll');
21598
21662
  return;
21599
21663
  }
21600
21664
  // Check if we're in cooldown period after a recent state change
21601
21665
  const now = Date.now();
21602
21666
  const timeSinceLastChange = now - this.lastStateChangeTime;
21603
21667
  if (timeSinceLastChange < this.STATE_CHANGE_COOLDOWN) {
21668
+ console.log('[Scroll Debug] Skipping header update - in cooldown period', timeSinceLastChange + 'ms');
21604
21669
  return;
21605
21670
  }
21606
21671
  // Clear any pending timeout
@@ -21616,16 +21681,22 @@ class SymphiqFunnelAnalysisDashboardComponent {
21616
21681
  // If currently expanded and we scroll past collapse threshold, collapse
21617
21682
  if (!currentState && scrollPosition > COLLAPSE_THRESHOLD) {
21618
21683
  newState = true;
21684
+ console.log('[Scroll Debug] Triggering COLLAPSE - scrollPosition:', scrollPosition, '> threshold:', COLLAPSE_THRESHOLD);
21619
21685
  }
21620
21686
  // If currently collapsed and we scroll back above expand threshold, expand
21621
21687
  else if (currentState && scrollPosition < EXPAND_THRESHOLD) {
21622
21688
  newState = false;
21689
+ console.log('[Scroll Debug] Triggering EXPAND - scrollPosition:', scrollPosition, '< threshold:', EXPAND_THRESHOLD);
21623
21690
  }
21624
21691
  // Only update state if it actually changed
21625
21692
  if (newState !== currentState) {
21693
+ console.log('[Scroll Debug] State change detected:', currentState, '->', newState);
21626
21694
  this.isScrolled.set(newState);
21627
21695
  this.lastStateChangeTime = Date.now();
21628
21696
  }
21697
+ else {
21698
+ console.log('[Scroll Debug] No state change needed. Current state:', currentState, 'Position:', scrollPosition);
21699
+ }
21629
21700
  this.lastScrollPosition = scrollPosition;
21630
21701
  }
21631
21702
  onScroll() {
@@ -23504,7 +23575,7 @@ class SymphiqFunnelAnalysisPreviewComponent {
23504
23575
  this.onViewAnalysis.emit();
23505
23576
  }
23506
23577
  static { this.ɵfac = function SymphiqFunnelAnalysisPreviewComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SymphiqFunnelAnalysisPreviewComponent)(); }; }
23507
- static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SymphiqFunnelAnalysisPreviewComponent, selectors: [["symphiq-funnel-analysis-preview"]], inputs: { analysisInput: [1, "funnelAnalysis", "analysisInput"], viewMode: [1, "viewMode"] }, outputs: { onViewAnalysis: "onViewAnalysis" }, decls: 34, vars: 40, consts: [[1, "w-full", "sm:max-w-md", "mx-auto", "rounded-xl", "border", "shadow-lg", "backdrop-blur-lg", "transition-all", "duration-300", "sm:hover:shadow-xl", "sm:hover:scale-[1.01]", "overflow-hidden"], [1, "px-3", "py-2", "sm:px-4", "sm:py-3", "border-b", "flex", "items-center", "justify-between", "gap-2", "sm:gap-3"], [1, "flex-1", "min-w-0"], [1, "text-sm", "font-bold", "truncate"], [1, "text-xs", "truncate", "cursor-help", 3, "libSymphiqTooltip", "tooltipPosition"], [1, "flex", "items-center", "gap-1.5", "sm:gap-2", "flex-shrink-0"], ["tooltipType", "badge", 1, "px-2", "py-1", "rounded", "text-center", "min-w-[44px]", "min-h-[44px]", "flex", "items-center", "justify-center", 3, "libSymphiqTooltip", "tooltipPosition"], [1, "text-lg", "font-bold"], [1, "p-3", "sm:p-4", "space-y-2.5", "sm:space-y-3"], ["tooltipType", "metric", 1, "rounded-lg", "p-2.5", "sm:p-3", "border", "transition-all", "duration-200", "sm:hover:scale-105", "cursor-help", "active:scale-[0.98]", 3, "class", "libSymphiqTooltip", "tooltipPosition"], [1, "grid", "grid-cols-2", "gap-1.5", "sm:gap-2"], ["tooltipType", "metric", 1, "rounded-lg", "p-1.5", "sm:p-2", "border", "transition-all", "duration-200", "sm:hover:scale-105", "active:scale-[0.98]", 3, "class", "libSymphiqTooltip", "tooltipPosition"], [1, "rounded-lg", "p-2.5", "sm:p-3", "border", "transition-all", "duration-200", "sm:hover:scale-105", "active:scale-[0.98]", 3, "class"], [1, "rounded-lg", "p-2.5", "sm:p-3", "border", "transition-all", "duration-200", "sm:hover:scale-105", "active:scale-[0.98]"], [1, "flex", "items-center", "justify-between", "mb-2"], [1, "flex", "items-center", "gap-1.5", "sm:gap-2"], [1, "text-lg"], [1, "text-xs", "sm:text-sm", "font-bold"], ["tooltipType", "competitive", 1, "px-2", "py-0.5", "rounded", "text-xs", "font-bold", 3, "class", "animate-pulse", "libSymphiqTooltip", "tooltipPosition"], ["tooltipType", "narrative", 1, "text-xs", "leading-relaxed", "line-clamp-3", "cursor-help", 3, "libSymphiqTooltip", "tooltipPosition"], [1, "px-3", "py-1.5", "sm:px-4", "sm:py-2", "border-t"], [1, "w-full", "py-2.5", "sm:py-2", "rounded-lg", "font-semibold", "text-xs", "transition-all", "duration-300", "sm:hover:scale-105", "active:scale-[0.98]", "flex", "items-center", "justify-center", "gap-2", "group", "cursor-pointer", "min-h-[44px]", 3, "click"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-3", "h-3", "transition-transform", "duration-300", "group-hover:translate-x-1"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M13 7l5 5m0 0l-5 5m5-5H6"], ["tooltipType", "metric", 1, "rounded-lg", "p-2.5", "sm:p-3", "border", "transition-all", "duration-200", "sm:hover:scale-105", "cursor-help", "active:scale-[0.98]", 3, "libSymphiqTooltip", "tooltipPosition"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-3.5", "h-3.5", "sm:w-4", "sm:h-4"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"], [1, "text-xs", "font-semibold"], ["tooltipType", "status", 1, "px-2", "py-1", "rounded", "text-xs", "font-bold", "flex", "items-center", "gap-1", "relative", "z-10", "min-h-[32px]", 3, "mouseenter", "mouseleave", "libSymphiqTooltip", "tooltipPosition"], [1, "flex", "items-baseline", "justify-between"], [1, "text-lg", "sm:text-xl", "font-bold"], [1, "flex", "items-center", "gap-1"], ["fill", "currentColor", "viewBox", "0 0 20 20", 1, "w-3", "h-3"], ["fill-rule", "evenodd", "d", "M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L11 7.414V15a1 1 0 11-2 0V7.414L6.707 9.707a1 1 0 01-1.414 0z", "clip-rule", "evenodd"], ["tooltipType", "metric", 1, "rounded-lg", "p-1.5", "sm:p-2", "border", "transition-all", "duration-200", "sm:hover:scale-105", "active:scale-[0.98]", 3, "libSymphiqTooltip", "tooltipPosition"], [1, "flex", "items-center", "justify-between", "mb-1"], [1, "text-xs", "font-medium", "truncate", "flex-1"], [1, "w-2", "h-2", "rounded-full", "flex-shrink-0"], [1, "flex", "items-center", "justify-between"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"], ["tooltipType", "insightsList", 1, "px-2", "py-0.5", "rounded", "text-xs", "font-bold", 3, "libSymphiqTooltip", "tooltipPosition"], ["tooltipType", "competitive", 1, "px-2", "py-0.5", "rounded", "text-xs", "font-bold", 3, "libSymphiqTooltip", "tooltipPosition"]], template: function SymphiqFunnelAnalysisPreviewComponent_Template(rf, ctx) { if (rf & 1) {
23578
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SymphiqFunnelAnalysisPreviewComponent, selectors: [["symphiq-funnel-analysis-preview"]], inputs: { analysisInput: [1, "funnelAnalysis", "analysisInput"], viewMode: [1, "viewMode"] }, outputs: { onViewAnalysis: "onViewAnalysis" }, decls: 34, vars: 40, consts: [[1, "w-full", "sm:max-w-md", "rounded-xl", "border", "shadow-lg", "backdrop-blur-lg", "transition-all", "duration-300", "sm:hover:shadow-xl", "sm:hover:scale-[1.01]", "overflow-hidden"], [1, "px-3", "py-2", "sm:px-4", "sm:py-3", "border-b", "flex", "items-center", "justify-between", "gap-2", "sm:gap-3"], [1, "flex-1", "min-w-0"], [1, "text-sm", "font-bold", "truncate"], [1, "text-xs", "truncate", "cursor-help", 3, "libSymphiqTooltip", "tooltipPosition"], [1, "flex", "items-center", "gap-1.5", "sm:gap-2", "flex-shrink-0"], ["tooltipType", "badge", 1, "px-2", "py-1", "rounded", "text-center", "min-w-[44px]", "min-h-[44px]", "flex", "items-center", "justify-center", 3, "libSymphiqTooltip", "tooltipPosition"], [1, "text-lg", "font-bold"], [1, "p-3", "sm:p-4", "space-y-2.5", "sm:space-y-3"], ["tooltipType", "metric", 1, "rounded-lg", "p-2.5", "sm:p-3", "border", "transition-all", "duration-200", "sm:hover:scale-105", "cursor-help", "active:scale-[0.98]", 3, "class", "libSymphiqTooltip", "tooltipPosition"], [1, "grid", "grid-cols-2", "gap-1.5", "sm:gap-2"], ["tooltipType", "metric", 1, "rounded-lg", "p-1.5", "sm:p-2", "border", "transition-all", "duration-200", "sm:hover:scale-105", "active:scale-[0.98]", 3, "class", "libSymphiqTooltip", "tooltipPosition"], [1, "rounded-lg", "p-2.5", "sm:p-3", "border", "transition-all", "duration-200", "sm:hover:scale-105", "active:scale-[0.98]", 3, "class"], [1, "rounded-lg", "p-2.5", "sm:p-3", "border", "transition-all", "duration-200", "sm:hover:scale-105", "active:scale-[0.98]"], [1, "flex", "items-center", "justify-between", "mb-2"], [1, "flex", "items-center", "gap-1.5", "sm:gap-2"], [1, "text-lg"], [1, "text-xs", "sm:text-sm", "font-bold"], ["tooltipType", "competitive", 1, "px-2", "py-0.5", "rounded", "text-xs", "font-bold", 3, "class", "animate-pulse", "libSymphiqTooltip", "tooltipPosition"], ["tooltipType", "narrative", 1, "text-xs", "leading-relaxed", "line-clamp-3", "cursor-help", 3, "libSymphiqTooltip", "tooltipPosition"], [1, "px-3", "py-1.5", "sm:px-4", "sm:py-2", "border-t"], [1, "w-full", "py-2.5", "sm:py-2", "rounded-lg", "font-semibold", "text-xs", "transition-all", "duration-300", "sm:hover:scale-105", "active:scale-[0.98]", "flex", "items-center", "justify-center", "gap-2", "group", "cursor-pointer", "min-h-[44px]", 3, "click"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-3", "h-3", "transition-transform", "duration-300", "group-hover:translate-x-1"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M13 7l5 5m0 0l-5 5m5-5H6"], ["tooltipType", "metric", 1, "rounded-lg", "p-2.5", "sm:p-3", "border", "transition-all", "duration-200", "sm:hover:scale-105", "cursor-help", "active:scale-[0.98]", 3, "libSymphiqTooltip", "tooltipPosition"], ["fill", "none", "stroke", "currentColor", "viewBox", "0 0 24 24", 1, "w-3.5", "h-3.5", "sm:w-4", "sm:h-4"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"], [1, "text-xs", "font-semibold"], ["tooltipType", "status", 1, "px-2", "py-1", "rounded", "text-xs", "font-bold", "flex", "items-center", "gap-1", "relative", "z-10", "min-h-[32px]", 3, "mouseenter", "mouseleave", "libSymphiqTooltip", "tooltipPosition"], [1, "flex", "items-baseline", "justify-between"], [1, "text-lg", "sm:text-xl", "font-bold"], [1, "flex", "items-center", "gap-1"], ["fill", "currentColor", "viewBox", "0 0 20 20", 1, "w-3", "h-3"], ["fill-rule", "evenodd", "d", "M5.293 9.707a1 1 0 010-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 01-1.414 1.414L11 7.414V15a1 1 0 11-2 0V7.414L6.707 9.707a1 1 0 01-1.414 0z", "clip-rule", "evenodd"], ["tooltipType", "metric", 1, "rounded-lg", "p-1.5", "sm:p-2", "border", "transition-all", "duration-200", "sm:hover:scale-105", "active:scale-[0.98]", 3, "libSymphiqTooltip", "tooltipPosition"], [1, "flex", "items-center", "justify-between", "mb-1"], [1, "text-xs", "font-medium", "truncate", "flex-1"], [1, "w-2", "h-2", "rounded-full", "flex-shrink-0"], [1, "flex", "items-center", "justify-between"], ["stroke-linecap", "round", "stroke-linejoin", "round", "stroke-width", "2", "d", "M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"], ["tooltipType", "insightsList", 1, "px-2", "py-0.5", "rounded", "text-xs", "font-bold", 3, "libSymphiqTooltip", "tooltipPosition"], ["tooltipType", "competitive", 1, "px-2", "py-0.5", "rounded", "text-xs", "font-bold", 3, "libSymphiqTooltip", "tooltipPosition"]], template: function SymphiqFunnelAnalysisPreviewComponent_Template(rf, ctx) { if (rf & 1) {
23508
23579
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "h3", 3);
23509
23580
  i0.ɵɵtext(4, "Funnel Analysis");
23510
23581
  i0.ɵɵelementEnd();
@@ -23594,7 +23665,7 @@ class SymphiqFunnelAnalysisPreviewComponent {
23594
23665
  args: [{ selector: 'symphiq-funnel-analysis-preview', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, TooltipDirective, TooltipContainerComponent], template: `
23595
23666
  <div
23596
23667
  [class]="containerClass()"
23597
- class="w-full sm:max-w-md mx-auto rounded-xl border shadow-lg backdrop-blur-lg transition-all duration-300 sm:hover:shadow-xl sm:hover:scale-[1.01] overflow-hidden">
23668
+ class="w-full sm:max-w-md rounded-xl border shadow-lg backdrop-blur-lg transition-all duration-300 sm:hover:shadow-xl sm:hover:scale-[1.01] overflow-hidden">
23598
23669
 
23599
23670
  <!-- Compact Header -->
23600
23671
  <div [class]="headerClass()" class="px-3 py-2 sm:px-4 sm:py-3 border-b flex items-center justify-between gap-2 sm:gap-3">