@tolle_/tolle-ui 0.0.29-beta → 0.0.31-beta

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.
@@ -1,7 +1,7 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { twMerge } from 'tailwind-merge';
3
3
  import * as i0 from '@angular/core';
4
- import { Component, Input, forwardRef, ViewChild, Injectable, Optional, HostListener, ContentChildren, EventEmitter, Output, Directive, inject, PLATFORM_ID, Inject, InjectionToken, APP_INITIALIZER, ChangeDetectorRef, ChangeDetectionStrategy, TemplateRef, Injector, HostBinding } from '@angular/core';
4
+ import { Component, Input, forwardRef, ViewChild, Injectable, Optional, HostListener, ContentChildren, EventEmitter, Output, Directive, inject, PLATFORM_ID, Inject, InjectionToken, APP_INITIALIZER, ChangeDetectorRef, ChangeDetectionStrategy, TemplateRef, Injector, HostBinding, ViewChildren } from '@angular/core';
5
5
  import * as i1 from '@angular/common';
6
6
  import { CommonModule, isPlatformBrowser, DOCUMENT, NgIf, NgTemplateOutlet } from '@angular/common';
7
7
  import { cva } from 'class-variance-authority';
@@ -10,9 +10,12 @@ import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
10
10
  import { autoUpdate, computePosition, offset, flip, shift, size } from '@floating-ui/dom';
11
11
  import { Subject, Subscription, BehaviorSubject } from 'rxjs';
12
12
  import { format, startOfWeek, startOfMonth, endOfWeek, endOfMonth, eachDayOfInterval, subMonths, subYears, addMonths, addYears, setMonth, setYear, isSameDay, isToday, isSameMonth, isBefore, startOfDay, parse, isValid, isWithinInterval } from 'date-fns';
13
+ import { trigger, state, style, transition, animate } from '@angular/animations';
13
14
  import * as i1$1 from '@angular/cdk/overlay';
14
15
  import { OverlayConfig } from '@angular/cdk/overlay';
15
16
  import { ComponentPortal } from '@angular/cdk/portal';
17
+ import * as i1$2 from '@angular/router';
18
+ import { RouterModule } from '@angular/router';
16
19
 
17
20
  function cn(...inputs) {
18
21
  return twMerge(clsx(inputs));
@@ -2563,10 +2566,7 @@ class CalendarComponent {
2563
2566
  if (this.minDate && isBefore(date, this.minDate)) {
2564
2567
  return true;
2565
2568
  }
2566
- if (this.maxDate && isBefore(this.maxDate, date)) {
2567
- return true;
2568
- }
2569
- return false;
2569
+ return !!(this.maxDate && isBefore(this.maxDate, date));
2570
2570
  }
2571
2571
  isTodayDisabled() {
2572
2572
  return this.isDateDisabled(new Date());
@@ -4170,21 +4170,42 @@ class AccordionItemComponent {
4170
4170
  <button
4171
4171
  type="button"
4172
4172
  (click)="toggle()"
4173
- class="flex flex-1 items-center justify-between py-4 font-medium transition-all [&[data-state=open]>i]:rotate-180"
4173
+ [attr.aria-expanded]="isOpen"
4174
4174
  [attr.data-state]="isOpen ? 'open' : 'closed'"
4175
+ class="flex flex-1 items-center justify-between py-4 font-medium transition-all group [&[data-state=open]>i]:rotate-180"
4175
4176
  >
4176
- <span class="text-left">{{ title }}</span>
4177
- <i class="ri-arrow-down-s-line text-muted-foreground transition-transform"></i>
4177
+ <span class="text-left group-hover:underline">{{ title }}</span>
4178
+ <i class="ri-arrow-down-s-line text-muted-foreground text-lg transition-transform duration-200 hover:no-underline"></i>
4178
4179
  </button>
4179
4180
 
4180
4181
  <div
4181
- *ngIf="isOpen"
4182
- class="pb-4 text-sm text-muted-foreground overflow-hidden"
4183
- >
4184
- <ng-content></ng-content>
4182
+ [@expandCollapse]="isOpen ? 'expanded' : 'collapsed'"
4183
+ class="overflow-hidden">
4184
+ <div class="pb-4 pt-0 text-sm text-muted-foreground">
4185
+ <ng-content></ng-content>
4186
+ </div>
4185
4187
  </div>
4186
4188
  </div>
4187
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
4189
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], animations: [
4190
+ trigger('expandCollapse', [
4191
+ state('collapsed', style({
4192
+ height: '0px',
4193
+ opacity: '0',
4194
+ overflow: 'hidden',
4195
+ visibility: 'hidden'
4196
+ })),
4197
+ state('expanded', style({
4198
+ height: '*', // "Star" means actual content height
4199
+ opacity: '1',
4200
+ overflow: 'hidden',
4201
+ visibility: 'visible'
4202
+ })),
4203
+ // Use cubic-bezier to match Tailwind/shadcn-ui default ease
4204
+ transition('collapsed <=> expanded', [
4205
+ animate('300ms cubic-bezier(0.87, 0, 0.13, 1)')
4206
+ ])
4207
+ ])
4208
+ ] });
4188
4209
  }
4189
4210
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AccordionItemComponent, decorators: [{
4190
4211
  type: Component,
@@ -4192,23 +4213,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
4192
4213
  selector: 'tolle-accordion-item',
4193
4214
  standalone: true,
4194
4215
  imports: [CommonModule],
4216
+ animations: [
4217
+ trigger('expandCollapse', [
4218
+ state('collapsed', style({
4219
+ height: '0px',
4220
+ opacity: '0',
4221
+ overflow: 'hidden',
4222
+ visibility: 'hidden'
4223
+ })),
4224
+ state('expanded', style({
4225
+ height: '*', // "Star" means actual content height
4226
+ opacity: '1',
4227
+ overflow: 'hidden',
4228
+ visibility: 'visible'
4229
+ })),
4230
+ // Use cubic-bezier to match Tailwind/shadcn-ui default ease
4231
+ transition('collapsed <=> expanded', [
4232
+ animate('300ms cubic-bezier(0.87, 0, 0.13, 1)')
4233
+ ])
4234
+ ])
4235
+ ],
4195
4236
  template: `
4196
4237
  <div [class]="cn('flex flex-col border-b border-border', class)">
4197
4238
  <button
4198
4239
  type="button"
4199
4240
  (click)="toggle()"
4200
- class="flex flex-1 items-center justify-between py-4 font-medium transition-all [&[data-state=open]>i]:rotate-180"
4241
+ [attr.aria-expanded]="isOpen"
4201
4242
  [attr.data-state]="isOpen ? 'open' : 'closed'"
4243
+ class="flex flex-1 items-center justify-between py-4 font-medium transition-all group [&[data-state=open]>i]:rotate-180"
4202
4244
  >
4203
- <span class="text-left">{{ title }}</span>
4204
- <i class="ri-arrow-down-s-line text-muted-foreground transition-transform"></i>
4245
+ <span class="text-left group-hover:underline">{{ title }}</span>
4246
+ <i class="ri-arrow-down-s-line text-muted-foreground text-lg transition-transform duration-200 hover:no-underline"></i>
4205
4247
  </button>
4206
4248
 
4207
4249
  <div
4208
- *ngIf="isOpen"
4209
- class="pb-4 text-sm text-muted-foreground overflow-hidden"
4210
- >
4211
- <ng-content></ng-content>
4250
+ [@expandCollapse]="isOpen ? 'expanded' : 'collapsed'"
4251
+ class="overflow-hidden">
4252
+ <div class="pb-4 pt-0 text-sm text-muted-foreground">
4253
+ <ng-content></ng-content>
4254
+ </div>
4212
4255
  </div>
4213
4256
  </div>
4214
4257
  `
@@ -4226,31 +4269,36 @@ class AccordionComponent {
4226
4269
  class = '';
4227
4270
  items;
4228
4271
  ngAfterContentInit() {
4272
+ // 1. Assign IDs and Listeners on load
4273
+ this.initItems();
4274
+ // 2. Re-init if items change dynamically (optional but good for robustness)
4275
+ this.items.changes.subscribe(() => this.initItems());
4276
+ }
4277
+ initItems() {
4229
4278
  this.items.forEach((item, index) => {
4230
- // Assign unique ID if none provided
4279
+ // Auto-assign ID if missing
4231
4280
  if (item.id === undefined)
4232
- item.id = index;
4233
- // Hook into the item's toggle event
4281
+ item.id = `accordion-item-${index}`;
4282
+ // Set up the toggle bridge
4234
4283
  item.onToggle = (id) => this.handleToggle(id);
4235
4284
  });
4236
4285
  }
4237
4286
  handleToggle(selectedId) {
4238
4287
  this.items.forEach(item => {
4239
4288
  if (item.id === selectedId) {
4289
+ // Toggle the clicked item
4240
4290
  item.isOpen = !item.isOpen;
4241
4291
  }
4242
- else {
4243
- // If type is 'single', close all other items
4244
- if (this.type === 'single') {
4245
- item.isOpen = false;
4246
- }
4292
+ else if (this.type === 'single') {
4293
+ // Close others if in single mode
4294
+ item.isOpen = false;
4247
4295
  }
4248
4296
  });
4249
4297
  }
4250
4298
  cn = cn;
4251
4299
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4252
4300
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: AccordionComponent, isStandalone: true, selector: "tolle-accordion", inputs: { type: "type", class: "class" }, queries: [{ propertyName: "items", predicate: AccordionItemComponent }], ngImport: i0, template: `
4253
- <div [class]="cn('w-full border-t border-border', class)">
4301
+ <div [class]="cn('w-full', class)">
4254
4302
  <ng-content></ng-content>
4255
4303
  </div>
4256
4304
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
@@ -4260,9 +4308,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
4260
4308
  args: [{
4261
4309
  selector: 'tolle-accordion',
4262
4310
  standalone: true,
4263
- imports: [CommonModule],
4311
+ imports: [CommonModule], // No AccordionItemComponent import needed here if projected via ng-content
4264
4312
  template: `
4265
- <div [class]="cn('w-full border-t border-border', class)">
4313
+ <div [class]="cn('w-full', class)">
4266
4314
  <ng-content></ng-content>
4267
4315
  </div>
4268
4316
  `
@@ -5474,13 +5522,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
5474
5522
  type: Input
5475
5523
  }] } });
5476
5524
 
5477
- const alertVariants = cva("relative w-full rounded-lg border p-4 transition-all duration-300 [&>i~div]:pl-7 [&>i]:absolute [&>i]:left-4 [&>i]:top-4 [&>i]:text-foreground", {
5525
+ const alertVariants = cva("relative w-full rounded-lg border p-4 [&>i+div]:translate-y-[-3px] [&>i]:absolute [&>i]:left-4 [&>i]:top-4 [&>i]:text-foreground [&>i~div]:pl-7", {
5478
5526
  variants: {
5479
5527
  variant: {
5480
5528
  default: "bg-background text-foreground",
5481
- destructive: "border-destructive/50 text-destructive dark:border-destructive [&>i]:text-destructive",
5482
- success: "border-emerald-500/50 text-emerald-700 dark:text-emerald-400 [&>i]:text-emerald-600",
5483
- warning: "border-amber-500/50 text-amber-700 dark:text-amber-400 [&>i]:text-amber-600",
5529
+ destructive: "border-red-500/50 text-red-500 dark:border-red-500 [&>i]:text-red-500",
5530
+ success: "border-emerald-500/50 text-emerald-700 dark:border-emerald-500 [&>i]:text-emerald-600 dark:text-emerald-400",
5531
+ warning: "border-amber-500/50 text-amber-700 dark:border-amber-500 [&>i]:text-amber-600 dark:text-amber-400",
5532
+ info: "border-blue-500/50 text-blue-700 dark:border-blue-500 [&>i]:text-blue-600 dark:text-blue-400",
5484
5533
  },
5485
5534
  },
5486
5535
  defaultVariants: {
@@ -5494,24 +5543,18 @@ class AlertComponent {
5494
5543
  dismissible = false;
5495
5544
  onClose = new EventEmitter();
5496
5545
  dismissed = false;
5497
- isDismissing = false;
5498
5546
  alertVariants = alertVariants;
5499
5547
  cn = cn;
5500
5548
  dismiss() {
5501
- this.isDismissing = true;
5502
- // Wait for animation to finish before removing from DOM
5503
- setTimeout(() => {
5504
- this.dismissed = true;
5505
- this.onClose.emit();
5506
- }, 300);
5549
+ this.dismissed = true;
5550
+ this.onClose.emit();
5507
5551
  }
5508
5552
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5509
5553
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: AlertComponent, isStandalone: true, selector: "tolle-alert", inputs: { variant: "variant", title: "title", class: "class", dismissible: "dismissible" }, outputs: { onClose: "onClose" }, ngImport: i0, template: `
5510
5554
  <div
5511
5555
  *ngIf="!dismissed"
5556
+ @fade
5512
5557
  [class]="cn(alertVariants({ variant }), class)"
5513
- [class.opacity-0]="isDismissing"
5514
- [class.scale-95]="isDismissing"
5515
5558
  role="alert"
5516
5559
  >
5517
5560
  <ng-content select="[icon]"></ng-content>
@@ -5519,22 +5562,30 @@ class AlertComponent {
5519
5562
  <button
5520
5563
  *ngIf="dismissible"
5521
5564
  (click)="dismiss()"
5522
- class="absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 group-hover:opacity-100"
5523
- [class.opacity-100]="dismissible"
5565
+ class="absolute right-2 top-2 rounded-md p-1 opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
5566
+ type="button"
5524
5567
  >
5525
5568
  <i class="ri-close-line text-lg"></i>
5569
+ <span class="sr-only">Close</span>
5526
5570
  </button>
5527
5571
 
5528
5572
  <div>
5529
5573
  <h5 *ngIf="title" class="mb-1 font-medium leading-none tracking-tight">
5530
5574
  {{ title }}
5531
5575
  </h5>
5532
- <div class="text-sm [&_p]:leading-relaxed">
5576
+ <div class="text-sm [&_p]:leading-relaxed opacity-90">
5533
5577
  <ng-content></ng-content>
5534
5578
  </div>
5535
5579
  </div>
5536
5580
  </div>
5537
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
5581
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [
5582
+ trigger('fade', [
5583
+ transition(':leave', [
5584
+ style({ opacity: 1, transform: 'scale(1)' }),
5585
+ animate('300ms ease-in-out', style({ opacity: 0, transform: 'scale(0.95)', height: 0, margin: 0, padding: 0 }))
5586
+ ])
5587
+ ])
5588
+ ] });
5538
5589
  }
5539
5590
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AlertComponent, decorators: [{
5540
5591
  type: Component,
@@ -5542,12 +5593,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
5542
5593
  selector: 'tolle-alert',
5543
5594
  standalone: true,
5544
5595
  imports: [CommonModule],
5596
+ animations: [
5597
+ trigger('fade', [
5598
+ transition(':leave', [
5599
+ style({ opacity: 1, transform: 'scale(1)' }),
5600
+ animate('300ms ease-in-out', style({ opacity: 0, transform: 'scale(0.95)', height: 0, margin: 0, padding: 0 }))
5601
+ ])
5602
+ ])
5603
+ ],
5545
5604
  template: `
5546
5605
  <div
5547
5606
  *ngIf="!dismissed"
5607
+ @fade
5548
5608
  [class]="cn(alertVariants({ variant }), class)"
5549
- [class.opacity-0]="isDismissing"
5550
- [class.scale-95]="isDismissing"
5551
5609
  role="alert"
5552
5610
  >
5553
5611
  <ng-content select="[icon]"></ng-content>
@@ -5555,22 +5613,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
5555
5613
  <button
5556
5614
  *ngIf="dismissible"
5557
5615
  (click)="dismiss()"
5558
- class="absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 group-hover:opacity-100"
5559
- [class.opacity-100]="dismissible"
5616
+ class="absolute right-2 top-2 rounded-md p-1 opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
5617
+ type="button"
5560
5618
  >
5561
5619
  <i class="ri-close-line text-lg"></i>
5620
+ <span class="sr-only">Close</span>
5562
5621
  </button>
5563
5622
 
5564
5623
  <div>
5565
5624
  <h5 *ngIf="title" class="mb-1 font-medium leading-none tracking-tight">
5566
5625
  {{ title }}
5567
5626
  </h5>
5568
- <div class="text-sm [&_p]:leading-relaxed">
5627
+ <div class="text-sm [&_p]:leading-relaxed opacity-90">
5569
5628
  <ng-content></ng-content>
5570
5629
  </div>
5571
5630
  </div>
5572
5631
  </div>
5573
- `,
5632
+ `
5574
5633
  }]
5575
5634
  }], propDecorators: { variant: [{
5576
5635
  type: Input
@@ -6447,6 +6506,619 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
6447
6506
  type: Input
6448
6507
  }] } });
6449
6508
 
6509
+ class SegmentedComponent {
6510
+ cdr;
6511
+ items = [];
6512
+ class = '';
6513
+ disabled = false;
6514
+ itemTemplate; // Allow custom content
6515
+ value = null;
6516
+ gliderLeft = 0;
6517
+ gliderWidth = 0;
6518
+ hasValue = false;
6519
+ itemElements;
6520
+ onChange = () => { };
6521
+ onTouched = () => { };
6522
+ constructor(cdr) {
6523
+ this.cdr = cdr;
6524
+ }
6525
+ ngAfterViewInit() {
6526
+ setTimeout(() => this.updateGlider());
6527
+ }
6528
+ ngOnChanges(changes) {
6529
+ // Recalculate if items change or if value changes externally
6530
+ if (changes['items'] && !changes['items'].firstChange) {
6531
+ setTimeout(() => this.updateGlider());
6532
+ }
6533
+ }
6534
+ select(val) {
6535
+ if (this.disabled)
6536
+ return;
6537
+ const item = this.items.find(i => i.value === val);
6538
+ if (item?.disabled)
6539
+ return;
6540
+ this.value = val;
6541
+ this.onChange(val);
6542
+ this.onTouched();
6543
+ this.updateGlider();
6544
+ }
6545
+ updateGlider() {
6546
+ if (!this.itemElements || !this.items.length)
6547
+ return;
6548
+ const index = this.items.findIndex(i => i.value === this.value);
6549
+ if (index === -1) {
6550
+ this.hasValue = false;
6551
+ this.gliderWidth = 0;
6552
+ return;
6553
+ }
6554
+ const activeElement = this.itemElements.get(index)?.nativeElement;
6555
+ if (activeElement) {
6556
+ this.hasValue = true;
6557
+ this.gliderLeft = activeElement.offsetLeft;
6558
+ this.gliderWidth = activeElement.offsetWidth;
6559
+ this.cdr.detectChanges();
6560
+ }
6561
+ }
6562
+ // CVA Implementation
6563
+ writeValue(val) {
6564
+ this.value = val;
6565
+ setTimeout(() => this.updateGlider());
6566
+ }
6567
+ registerOnChange(fn) { this.onChange = fn; }
6568
+ registerOnTouched(fn) { this.onTouched = fn; }
6569
+ setDisabledState(isDisabled) {
6570
+ this.disabled = isDisabled;
6571
+ this.cdr.markForCheck();
6572
+ }
6573
+ cn = cn;
6574
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SegmentedComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
6575
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: SegmentedComponent, isStandalone: true, selector: "tolle-segment", inputs: { items: "items", class: "class", disabled: "disabled", itemTemplate: "itemTemplate" }, providers: [
6576
+ {
6577
+ provide: NG_VALUE_ACCESSOR,
6578
+ useExisting: forwardRef(() => SegmentedComponent),
6579
+ multi: true
6580
+ }
6581
+ ], viewQueries: [{ propertyName: "itemElements", predicate: ["itemEls"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
6582
+ <div
6583
+ #container
6584
+ [class]="cn(
6585
+ 'relative flex items-center p-1 bg-muted rounded-lg select-none w-full gap-1',
6586
+ class
6587
+ )"
6588
+ role="tablist"
6589
+ >
6590
+ <div
6591
+ class="absolute top-1 bottom-1 bg-background shadow-sm rounded-md transition-all duration-300 ease-[cubic-bezier(0.2,0.0,0.2,1)]"
6592
+ [style.left.px]="gliderLeft"
6593
+ [style.width.px]="gliderWidth"
6594
+ [class.opacity-0]="!hasValue"
6595
+ ></div>
6596
+
6597
+ <button
6598
+ *ngFor="let item of items"
6599
+ #itemEls
6600
+ type="button"
6601
+ role="tab"
6602
+ [disabled]="item.disabled || disabled"
6603
+ [attr.aria-selected]="value === item.value"
6604
+ (click)="select(item.value)"
6605
+ [class]="cn(
6606
+ 'relative z-10 flex-1 px-3 py-1.5 text-sm font-medium transition-colors duration-200 rounded-md text-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
6607
+ 'flex items-center justify-center gap-2',
6608
+ value === item.value
6609
+ ? 'text-foreground'
6610
+ : 'text-muted-foreground hover:text-foreground/70',
6611
+ item.disabled && 'opacity-50 cursor-not-allowed',
6612
+ item.class
6613
+ )"
6614
+ >
6615
+ <ng-container *ngIf="itemTemplate; else defaultContent">
6616
+ <ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: item, selected: value === item.value }">
6617
+ </ng-container>
6618
+ </ng-container>
6619
+
6620
+ <ng-template #defaultContent>
6621
+ <i *ngIf="item.icon" [class]="item.icon"></i>
6622
+ <span class="truncate">{{ item.label }}</span>
6623
+ </ng-template>
6624
+ </button>
6625
+ </div>
6626
+ `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }] });
6627
+ }
6628
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SegmentedComponent, decorators: [{
6629
+ type: Component,
6630
+ args: [{ selector: 'tolle-segment', standalone: true, imports: [CommonModule, FormsModule], providers: [
6631
+ {
6632
+ provide: NG_VALUE_ACCESSOR,
6633
+ useExisting: forwardRef(() => SegmentedComponent),
6634
+ multi: true
6635
+ }
6636
+ ], template: `
6637
+ <div
6638
+ #container
6639
+ [class]="cn(
6640
+ 'relative flex items-center p-1 bg-muted rounded-lg select-none w-full gap-1',
6641
+ class
6642
+ )"
6643
+ role="tablist"
6644
+ >
6645
+ <div
6646
+ class="absolute top-1 bottom-1 bg-background shadow-sm rounded-md transition-all duration-300 ease-[cubic-bezier(0.2,0.0,0.2,1)]"
6647
+ [style.left.px]="gliderLeft"
6648
+ [style.width.px]="gliderWidth"
6649
+ [class.opacity-0]="!hasValue"
6650
+ ></div>
6651
+
6652
+ <button
6653
+ *ngFor="let item of items"
6654
+ #itemEls
6655
+ type="button"
6656
+ role="tab"
6657
+ [disabled]="item.disabled || disabled"
6658
+ [attr.aria-selected]="value === item.value"
6659
+ (click)="select(item.value)"
6660
+ [class]="cn(
6661
+ 'relative z-10 flex-1 px-3 py-1.5 text-sm font-medium transition-colors duration-200 rounded-md text-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
6662
+ 'flex items-center justify-center gap-2',
6663
+ value === item.value
6664
+ ? 'text-foreground'
6665
+ : 'text-muted-foreground hover:text-foreground/70',
6666
+ item.disabled && 'opacity-50 cursor-not-allowed',
6667
+ item.class
6668
+ )"
6669
+ >
6670
+ <ng-container *ngIf="itemTemplate; else defaultContent">
6671
+ <ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: item, selected: value === item.value }">
6672
+ </ng-container>
6673
+ </ng-container>
6674
+
6675
+ <ng-template #defaultContent>
6676
+ <i *ngIf="item.icon" [class]="item.icon"></i>
6677
+ <span class="truncate">{{ item.label }}</span>
6678
+ </ng-template>
6679
+ </button>
6680
+ </div>
6681
+ `, styles: [":host{display:block}\n"] }]
6682
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { items: [{
6683
+ type: Input
6684
+ }], class: [{
6685
+ type: Input
6686
+ }], disabled: [{
6687
+ type: Input
6688
+ }], itemTemplate: [{
6689
+ type: Input
6690
+ }], itemElements: [{
6691
+ type: ViewChildren,
6692
+ args: ['itemEls']
6693
+ }] } });
6694
+
6695
+ class SidebarComponent {
6696
+ items = [];
6697
+ collapsed = false;
6698
+ class = '';
6699
+ expandedParents = new Set();
6700
+ expandedChildren = new Set();
6701
+ cn = cn;
6702
+ ngOnChanges(changes) {
6703
+ if (changes['collapsed'] && this.collapsed) {
6704
+ this.collapseAll();
6705
+ return;
6706
+ }
6707
+ if (changes['items']) {
6708
+ this.initializeState();
6709
+ }
6710
+ }
6711
+ // --- STATE INIT ---
6712
+ initializeState() {
6713
+ this.collapseAll();
6714
+ if (!this.items)
6715
+ return;
6716
+ this.items.forEach((group, gIndex) => {
6717
+ group.items.forEach((item, iIndex) => {
6718
+ const parentId = this.getParentId(group, item, gIndex, iIndex);
6719
+ if (item.expanded) {
6720
+ this.expandedParents.add(parentId);
6721
+ }
6722
+ if (item.items) {
6723
+ item.items.forEach((subItem, sIndex) => {
6724
+ if (subItem.expanded) {
6725
+ const childId = this.getChildId(group, item, subItem, gIndex, iIndex, sIndex);
6726
+ this.expandedChildren.add(childId);
6727
+ this.expandedParents.add(parentId);
6728
+ }
6729
+ });
6730
+ }
6731
+ });
6732
+ });
6733
+ }
6734
+ // --- ID GENERATORS (Now using Group Index correctly) ---
6735
+ getGroupId(group, index) {
6736
+ return group.id || group.title || `g-${index}`;
6737
+ }
6738
+ getParentId(group, item, gIndex, iIndex) {
6739
+ const groupId = this.getGroupId(group, gIndex);
6740
+ const itemId = item.id || item.title || `p-${iIndex}`;
6741
+ return `${groupId}__${itemId}`;
6742
+ }
6743
+ getChildId(group, parent, subItem, gIndex, iIndex, sIndex) {
6744
+ const parentId = this.getParentId(group, parent, gIndex, iIndex);
6745
+ const subItemId = subItem.id || subItem.title || `c-${sIndex}`;
6746
+ return `${parentId}__${subItemId}`;
6747
+ }
6748
+ // --- ACTIONS ---
6749
+ toggleParent(group, item, gIndex, iIndex) {
6750
+ if (this.collapsed)
6751
+ return;
6752
+ const id = this.getParentId(group, item, gIndex, iIndex);
6753
+ // Create new Set reference to ensure Change Detection triggers
6754
+ const newSet = new Set(this.expandedParents);
6755
+ if (newSet.has(id)) {
6756
+ newSet.delete(id);
6757
+ }
6758
+ else {
6759
+ newSet.add(id);
6760
+ }
6761
+ this.expandedParents = newSet;
6762
+ }
6763
+ toggleChild(group, parent, subItem, gIndex, iIndex, sIndex) {
6764
+ const id = this.getChildId(group, parent, subItem, gIndex, iIndex, sIndex);
6765
+ // Create new Set reference
6766
+ const newSet = new Set(this.expandedChildren);
6767
+ if (newSet.has(id)) {
6768
+ newSet.delete(id);
6769
+ }
6770
+ else {
6771
+ newSet.add(id);
6772
+ }
6773
+ this.expandedChildren = newSet;
6774
+ }
6775
+ collapseAll() {
6776
+ this.expandedParents = new Set();
6777
+ this.expandedChildren = new Set();
6778
+ }
6779
+ // --- TEMPLATE HELPERS ---
6780
+ isParentExpanded(group, item, gIndex, iIndex) {
6781
+ return this.expandedParents.has(this.getParentId(group, item, gIndex, iIndex));
6782
+ }
6783
+ isChildExpanded(group, parent, subItem, gIndex, iIndex, sIndex) {
6784
+ return this.expandedChildren.has(this.getChildId(group, parent, subItem, gIndex, iIndex, sIndex));
6785
+ }
6786
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6787
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SidebarComponent, isStandalone: true, selector: "tolle-sidebar", inputs: { items: "items", collapsed: "collapsed", class: "class" }, usesOnChanges: true, ngImport: i0, template: `
6788
+ <aside [class]="cn(
6789
+ 'flex flex-col h-full border-r bg-background transition-[width] duration-300 ease-in-out shrink-0 overflow-hidden',
6790
+ collapsed ? 'w-16' : 'w-64',
6791
+ class
6792
+ )">
6793
+ <div class="flex h-14 shrink-0 items-center border-b px-3 overflow-hidden whitespace-nowrap">
6794
+ <ng-content select="[header]"></ng-content>
6795
+ </div>
6796
+
6797
+ <div class="flex-1 min-h-0 overflow-y-auto overflow-x-hidden py-4 px-3 custom-scrollbar">
6798
+
6799
+ @for (group of items; track group.id || group.title || $index; let gIndex = $index) {
6800
+ <div class="mb-6">
6801
+
6802
+ <div [class]="cn(
6803
+ 'mb-2 px-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground/70 transition-all duration-200 overflow-hidden',
6804
+ collapsed ? 'opacity-0 h-0 mb-0 px-0' : 'opacity-100 h-auto'
6805
+ )">
6806
+ {{ group.title }}
6807
+ </div>
6808
+
6809
+ <div class="flex flex-col gap-1">
6810
+ @for (item of group.items; track item.id || item.title || $index; let i = $index) {
6811
+
6812
+ @if (item.items && item.items.length) {
6813
+ <div class="relative">
6814
+ <button
6815
+ type="button"
6816
+ (click)="toggleParent(group, item, gIndex, i)"
6817
+ [disabled]="collapsed"
6818
+ [attr.aria-expanded]="isParentExpanded(group, item, gIndex, i)"
6819
+ [class]="cn(
6820
+ 'group w-full relative flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors',
6821
+ 'hover:bg-accent hover:text-accent-foreground',
6822
+ isParentExpanded(group, item, gIndex, i) ? 'text-foreground bg-accent/50' : 'text-muted-foreground',
6823
+ collapsed ? 'justify-center' : 'justify-start'
6824
+ )"
6825
+ >
6826
+ <i [class]="cn(
6827
+ item.icon || 'ri-circle-fill',
6828
+ 'h-4 w-4 text-lg shrink-0 transition-transform',
6829
+ !collapsed && 'group-hover:scale-110'
6830
+ )"></i>
6831
+
6832
+ <span [class]="cn(
6833
+ 'truncate transition-all duration-300',
6834
+ collapsed ? 'opacity-0 w-0 ml-0' : 'opacity-100 w-auto ml-3'
6835
+ )">
6836
+ {{ item.title }}
6837
+ </span>
6838
+
6839
+ @if (!collapsed) {
6840
+ <i [class]="cn(
6841
+ 'ri-arrow-down-s-line ml-auto transition-transform duration-300',
6842
+ isParentExpanded(group, item, gIndex, i) ? 'rotate-180' : ''
6843
+ )"></i>
6844
+ }
6845
+ </button>
6846
+
6847
+ <div [class]="cn(
6848
+ 'grid transition-[grid-template-rows] duration-300 ease-in-out',
6849
+ isParentExpanded(group, item, gIndex, i) && !collapsed ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0'
6850
+ )">
6851
+ <div class="overflow-hidden">
6852
+ <div class="flex flex-col gap-1 mt-1 ml-4 border-l border-border/50 pl-2">
6853
+
6854
+ @for (subItem of item.items; track subItem.id || subItem.title || $index; let j = $index) {
6855
+
6856
+ @if (subItem.items && subItem.items.length) {
6857
+ <div class="relative">
6858
+ <button
6859
+ type="button"
6860
+ (click)="toggleChild(group, item, subItem, gIndex, i, j); $event.stopPropagation()"
6861
+ [class]="cn(
6862
+ 'group w-full relative flex items-center rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
6863
+ 'hover:bg-accent hover:text-accent-foreground text-muted-foreground',
6864
+ isChildExpanded(group, item, subItem, gIndex, i, j) ? 'text-foreground bg-accent/30' : ''
6865
+ )"
6866
+ >
6867
+ <span class="w-1.5 h-1.5 rounded-full bg-border shrink-0"></span>
6868
+ <span class="ml-2 truncate">{{ subItem.title }}</span>
6869
+ <i [class]="cn(
6870
+ 'ri-arrow-right-s-line ml-auto transition-transform duration-300 text-xs',
6871
+ isChildExpanded(group, item, subItem, gIndex, i, j) ? 'rotate-90' : ''
6872
+ )"></i>
6873
+ </button>
6874
+
6875
+ <div [class]="cn(
6876
+ 'grid transition-[grid-template-rows] duration-300 ease-in-out',
6877
+ isChildExpanded(group, item, subItem, gIndex, i, j) ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0'
6878
+ )">
6879
+ <div class="overflow-hidden">
6880
+ <div class="flex flex-col gap-1 mt-1 ml-4 border-l border-border/30 pl-2">
6881
+ @for (grandChild of subItem.items; track grandChild.title) {
6882
+ <a
6883
+ [routerLink]="grandChild.url"
6884
+ routerLinkActive="bg-accent/50 text-accent-foreground"
6885
+ [routerLinkActiveOptions]="{ exact: true }"
6886
+ class="flex items-center gap-2 hover:no-underline rounded-md px-3 py-1.5 text-sm transition-colors hover:bg-accent hover:text-accent-foreground text-muted-foreground whitespace-nowrap"
6887
+ >
6888
+ <span class="w-1.5 h-1.5 rounded-full bg-border/70 shrink-0"></span>
6889
+ <span class="truncate">{{ grandChild.title }}</span>
6890
+ </a>
6891
+ }
6892
+ </div>
6893
+ </div>
6894
+ </div>
6895
+ </div>
6896
+ }
6897
+ @else {
6898
+ <a
6899
+ [routerLink]="subItem.url"
6900
+ routerLinkActive="bg-accent/50 text-accent-foreground"
6901
+ [routerLinkActiveOptions]="{ exact: true }"
6902
+ class="flex items-center gap-2 hover:no-underline rounded-md px-3 py-1.5 text-sm transition-colors hover:bg-accent hover:text-accent-foreground text-muted-foreground whitespace-nowrap"
6903
+ >
6904
+ <span class="w-1.5 h-1.5 rounded-full bg-border shrink-0"></span>
6905
+ <span class="truncate">{{ subItem.title }}</span>
6906
+ </a>
6907
+ }
6908
+ }
6909
+ </div>
6910
+ </div>
6911
+ </div>
6912
+ </div>
6913
+ }
6914
+ @else {
6915
+ <a
6916
+ [routerLink]="item.url"
6917
+ routerLinkActive="bg-primary/10 text-primary"
6918
+ [routerLinkActiveOptions]="{ exact: true }"
6919
+ [class]="cn(
6920
+ 'group relative hover:no-underline flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors',
6921
+ 'hover:bg-accent hover:text-accent-foreground text-muted-foreground',
6922
+ collapsed ? 'justify-center' : 'justify-start'
6923
+ )"
6924
+ >
6925
+ <i [class]="cn(
6926
+ item.icon || 'ri-circle-fill',
6927
+ 'h-4 w-4 text-lg shrink-0 transition-transform',
6928
+ !collapsed && 'group-hover:scale-110'
6929
+ )"></i>
6930
+ <span [class]="cn(
6931
+ 'truncate transition-all duration-300',
6932
+ collapsed ? 'opacity-0 w-0 ml-0' : 'opacity-100 w-auto ml-3'
6933
+ )">
6934
+ {{ item.title }}
6935
+ </span>
6936
+ </a>
6937
+ }
6938
+ }
6939
+ </div>
6940
+ </div>
6941
+ }
6942
+ </div>
6943
+
6944
+ <div class="border-t shrink-0 p-3 overflow-hidden whitespace-nowrap">
6945
+ <ng-content select="[footer]"></ng-content>
6946
+ </div>
6947
+ </aside>
6948
+ `, isInline: true, styles: [":host{display:block;height:100%}.custom-scrollbar{scrollbar-width:thin;scrollbar-color:rgba(156,163,175,.3) transparent}.custom-scrollbar::-webkit-scrollbar{width:4px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background-color:#9ca3af4d;border-radius:20px}button:disabled{cursor:not-allowed;opacity:.6}*{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ml-4{margin-left:1rem}.border-l{border-left-width:1px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1$2.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
6949
+ }
6950
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SidebarComponent, decorators: [{
6951
+ type: Component,
6952
+ args: [{ selector: 'tolle-sidebar', standalone: true, imports: [CommonModule, RouterModule], template: `
6953
+ <aside [class]="cn(
6954
+ 'flex flex-col h-full border-r bg-background transition-[width] duration-300 ease-in-out shrink-0 overflow-hidden',
6955
+ collapsed ? 'w-16' : 'w-64',
6956
+ class
6957
+ )">
6958
+ <div class="flex h-14 shrink-0 items-center border-b px-3 overflow-hidden whitespace-nowrap">
6959
+ <ng-content select="[header]"></ng-content>
6960
+ </div>
6961
+
6962
+ <div class="flex-1 min-h-0 overflow-y-auto overflow-x-hidden py-4 px-3 custom-scrollbar">
6963
+
6964
+ @for (group of items; track group.id || group.title || $index; let gIndex = $index) {
6965
+ <div class="mb-6">
6966
+
6967
+ <div [class]="cn(
6968
+ 'mb-2 px-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground/70 transition-all duration-200 overflow-hidden',
6969
+ collapsed ? 'opacity-0 h-0 mb-0 px-0' : 'opacity-100 h-auto'
6970
+ )">
6971
+ {{ group.title }}
6972
+ </div>
6973
+
6974
+ <div class="flex flex-col gap-1">
6975
+ @for (item of group.items; track item.id || item.title || $index; let i = $index) {
6976
+
6977
+ @if (item.items && item.items.length) {
6978
+ <div class="relative">
6979
+ <button
6980
+ type="button"
6981
+ (click)="toggleParent(group, item, gIndex, i)"
6982
+ [disabled]="collapsed"
6983
+ [attr.aria-expanded]="isParentExpanded(group, item, gIndex, i)"
6984
+ [class]="cn(
6985
+ 'group w-full relative flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors',
6986
+ 'hover:bg-accent hover:text-accent-foreground',
6987
+ isParentExpanded(group, item, gIndex, i) ? 'text-foreground bg-accent/50' : 'text-muted-foreground',
6988
+ collapsed ? 'justify-center' : 'justify-start'
6989
+ )"
6990
+ >
6991
+ <i [class]="cn(
6992
+ item.icon || 'ri-circle-fill',
6993
+ 'h-4 w-4 text-lg shrink-0 transition-transform',
6994
+ !collapsed && 'group-hover:scale-110'
6995
+ )"></i>
6996
+
6997
+ <span [class]="cn(
6998
+ 'truncate transition-all duration-300',
6999
+ collapsed ? 'opacity-0 w-0 ml-0' : 'opacity-100 w-auto ml-3'
7000
+ )">
7001
+ {{ item.title }}
7002
+ </span>
7003
+
7004
+ @if (!collapsed) {
7005
+ <i [class]="cn(
7006
+ 'ri-arrow-down-s-line ml-auto transition-transform duration-300',
7007
+ isParentExpanded(group, item, gIndex, i) ? 'rotate-180' : ''
7008
+ )"></i>
7009
+ }
7010
+ </button>
7011
+
7012
+ <div [class]="cn(
7013
+ 'grid transition-[grid-template-rows] duration-300 ease-in-out',
7014
+ isParentExpanded(group, item, gIndex, i) && !collapsed ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0'
7015
+ )">
7016
+ <div class="overflow-hidden">
7017
+ <div class="flex flex-col gap-1 mt-1 ml-4 border-l border-border/50 pl-2">
7018
+
7019
+ @for (subItem of item.items; track subItem.id || subItem.title || $index; let j = $index) {
7020
+
7021
+ @if (subItem.items && subItem.items.length) {
7022
+ <div class="relative">
7023
+ <button
7024
+ type="button"
7025
+ (click)="toggleChild(group, item, subItem, gIndex, i, j); $event.stopPropagation()"
7026
+ [class]="cn(
7027
+ 'group w-full relative flex items-center rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
7028
+ 'hover:bg-accent hover:text-accent-foreground text-muted-foreground',
7029
+ isChildExpanded(group, item, subItem, gIndex, i, j) ? 'text-foreground bg-accent/30' : ''
7030
+ )"
7031
+ >
7032
+ <span class="w-1.5 h-1.5 rounded-full bg-border shrink-0"></span>
7033
+ <span class="ml-2 truncate">{{ subItem.title }}</span>
7034
+ <i [class]="cn(
7035
+ 'ri-arrow-right-s-line ml-auto transition-transform duration-300 text-xs',
7036
+ isChildExpanded(group, item, subItem, gIndex, i, j) ? 'rotate-90' : ''
7037
+ )"></i>
7038
+ </button>
7039
+
7040
+ <div [class]="cn(
7041
+ 'grid transition-[grid-template-rows] duration-300 ease-in-out',
7042
+ isChildExpanded(group, item, subItem, gIndex, i, j) ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0'
7043
+ )">
7044
+ <div class="overflow-hidden">
7045
+ <div class="flex flex-col gap-1 mt-1 ml-4 border-l border-border/30 pl-2">
7046
+ @for (grandChild of subItem.items; track grandChild.title) {
7047
+ <a
7048
+ [routerLink]="grandChild.url"
7049
+ routerLinkActive="bg-accent/50 text-accent-foreground"
7050
+ [routerLinkActiveOptions]="{ exact: true }"
7051
+ class="flex items-center gap-2 hover:no-underline rounded-md px-3 py-1.5 text-sm transition-colors hover:bg-accent hover:text-accent-foreground text-muted-foreground whitespace-nowrap"
7052
+ >
7053
+ <span class="w-1.5 h-1.5 rounded-full bg-border/70 shrink-0"></span>
7054
+ <span class="truncate">{{ grandChild.title }}</span>
7055
+ </a>
7056
+ }
7057
+ </div>
7058
+ </div>
7059
+ </div>
7060
+ </div>
7061
+ }
7062
+ @else {
7063
+ <a
7064
+ [routerLink]="subItem.url"
7065
+ routerLinkActive="bg-accent/50 text-accent-foreground"
7066
+ [routerLinkActiveOptions]="{ exact: true }"
7067
+ class="flex items-center gap-2 hover:no-underline rounded-md px-3 py-1.5 text-sm transition-colors hover:bg-accent hover:text-accent-foreground text-muted-foreground whitespace-nowrap"
7068
+ >
7069
+ <span class="w-1.5 h-1.5 rounded-full bg-border shrink-0"></span>
7070
+ <span class="truncate">{{ subItem.title }}</span>
7071
+ </a>
7072
+ }
7073
+ }
7074
+ </div>
7075
+ </div>
7076
+ </div>
7077
+ </div>
7078
+ }
7079
+ @else {
7080
+ <a
7081
+ [routerLink]="item.url"
7082
+ routerLinkActive="bg-primary/10 text-primary"
7083
+ [routerLinkActiveOptions]="{ exact: true }"
7084
+ [class]="cn(
7085
+ 'group relative hover:no-underline flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors',
7086
+ 'hover:bg-accent hover:text-accent-foreground text-muted-foreground',
7087
+ collapsed ? 'justify-center' : 'justify-start'
7088
+ )"
7089
+ >
7090
+ <i [class]="cn(
7091
+ item.icon || 'ri-circle-fill',
7092
+ 'h-4 w-4 text-lg shrink-0 transition-transform',
7093
+ !collapsed && 'group-hover:scale-110'
7094
+ )"></i>
7095
+ <span [class]="cn(
7096
+ 'truncate transition-all duration-300',
7097
+ collapsed ? 'opacity-0 w-0 ml-0' : 'opacity-100 w-auto ml-3'
7098
+ )">
7099
+ {{ item.title }}
7100
+ </span>
7101
+ </a>
7102
+ }
7103
+ }
7104
+ </div>
7105
+ </div>
7106
+ }
7107
+ </div>
7108
+
7109
+ <div class="border-t shrink-0 p-3 overflow-hidden whitespace-nowrap">
7110
+ <ng-content select="[footer]"></ng-content>
7111
+ </div>
7112
+ </aside>
7113
+ `, styles: [":host{display:block;height:100%}.custom-scrollbar{scrollbar-width:thin;scrollbar-color:rgba(156,163,175,.3) transparent}.custom-scrollbar::-webkit-scrollbar{width:4px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background-color:#9ca3af4d;border-radius:20px}button:disabled{cursor:not-allowed;opacity:.6}*{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ml-4{margin-left:1rem}.border-l{border-left-width:1px}\n"] }]
7114
+ }], propDecorators: { items: [{
7115
+ type: Input
7116
+ }], collapsed: [{
7117
+ type: Input
7118
+ }], class: [{
7119
+ type: Input
7120
+ }] } });
7121
+
6450
7122
  /*
6451
7123
  * Public API Surface of tolle
6452
7124
  */
@@ -6455,5 +7127,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
6455
7127
  * Generated bundle index. Do not edit.
6456
7128
  */
6457
7129
 
6458
- export { AccordionComponent, AccordionItemComponent, AlertComponent, AvatarComponent, AvatarFallbackComponent, BadgeComponent, BreadcrumbComponent, BreadcrumbItemComponent, BreadcrumbLinkComponent, BreadcrumbSeparatorComponent, ButtonComponent, ButtonGroupComponent, CalendarComponent, CardComponent, CardContentComponent, CardFooterComponent, CardHeaderComponent, CardTitleComponent, CheckboxComponent, DataTableComponent, DatePickerComponent, DateRangePickerComponent, DropdownItemComponent, DropdownLabelComponent, DropdownMenuComponent, DropdownSeparatorComponent, DropdownTriggerDirective, EmptyStateComponent, InputComponent, MaskedInputComponent, Modal, ModalComponent, ModalRef, ModalService, ModalStackService, MultiSelectComponent, OtpComponent, OtpGroupComponent, OtpSlotComponent, PaginationComponent, PopoverComponent, PopoverContentComponent, RadioGroupComponent, RadioItemComponent, RangeCalendarComponent, SelectComponent, SelectGroupComponent, SelectItemComponent, SelectSeparatorComponent, SkeletonComponent, SwitchComponent, TOLLE_CONFIG, TextareaComponent, ThemeService, ToastContainerComponent, ToastService, TolleCellDirective, TooltipDirective, cn, provideTolleConfig };
7130
+ export { AccordionComponent, AccordionItemComponent, AlertComponent, AvatarComponent, AvatarFallbackComponent, BadgeComponent, BreadcrumbComponent, BreadcrumbItemComponent, BreadcrumbLinkComponent, BreadcrumbSeparatorComponent, ButtonComponent, ButtonGroupComponent, CalendarComponent, CardComponent, CardContentComponent, CardFooterComponent, CardHeaderComponent, CardTitleComponent, CheckboxComponent, DataTableComponent, DatePickerComponent, DateRangePickerComponent, DropdownItemComponent, DropdownLabelComponent, DropdownMenuComponent, DropdownSeparatorComponent, DropdownTriggerDirective, EmptyStateComponent, InputComponent, MaskedInputComponent, Modal, ModalComponent, ModalRef, ModalService, ModalStackService, MultiSelectComponent, OtpComponent, OtpGroupComponent, OtpSlotComponent, PaginationComponent, PopoverComponent, PopoverContentComponent, RadioGroupComponent, RadioItemComponent, RangeCalendarComponent, SegmentedComponent, SelectComponent, SelectGroupComponent, SelectItemComponent, SelectSeparatorComponent, SidebarComponent, SkeletonComponent, SwitchComponent, TOLLE_CONFIG, TextareaComponent, ThemeService, ToastContainerComponent, ToastService, TolleCellDirective, TooltipDirective, cn, provideTolleConfig };
6459
7131
  //# sourceMappingURL=tolle-ui.mjs.map