@life-cockpit/angular-ui-kit 1.3.0 → 1.3.1

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
@@ -52,8 +52,10 @@ export class MyComponent {}
52
52
  | Accordion | `lc-accordion` | Expandable/collapsible content panels |
53
53
  | Button | `lc-button` | Primary, secondary, and text buttons |
54
54
  | Card | `lc-card` | Content container with elevation |
55
+ | Chat | `lc-chat` | Conversational UI with streaming, custom message templates |
55
56
  | Icon | `lc-icon` | SVG icon display |
56
57
  | Logo | `lc-logo` | Life Cockpit logo |
58
+ | Markdown | `lc-markdown` | GFM markdown renderer with code block highlighting |
57
59
  | Menu | `lc-menu` | Dropdown menu |
58
60
  | Typography | `lc-typography` | Text with preset styles |
59
61
 
@@ -62,6 +64,7 @@ export class MyComponent {}
62
64
  | Component | Selector | Description |
63
65
  |-----------|----------|-------------|
64
66
  | Checkbox | `lc-checkbox` | Checkbox input |
67
+ | Combobox | `lc-combobox` | Async autocomplete with single/multiple selection |
65
68
  | Datepicker | `lc-datepicker` | Date selection |
66
69
  | Email Input | `lc-email-input` | Email-specific input |
67
70
  | Input | `lc-input` | Text input field |
@@ -103,6 +106,7 @@ export class MyComponent {}
103
106
  | Field Group | `lc-field-group` | Grouped form fields |
104
107
  | Filter Bar | `lc-filter-bar` | Filter controls |
105
108
  | List | `lc-list` | List display |
109
+ | Log Viewer | `lc-log-viewer` | Streaming log/terminal viewer with virtualization |
106
110
  | Metric Card | `lc-metric-card` | KPI/metric display |
107
111
  | Skeleton | `lc-skeleton` | Loading placeholder |
108
112
  | Spinner | `lc-spinner` | Loading indicator |
@@ -115,14 +119,22 @@ export class MyComponent {}
115
119
  | Component | Selector | Description |
116
120
  |-----------|----------|-------------|
117
121
  | Alert | `lc-alert` | Inline alert message |
122
+ | Confirm Dialog | `lc-confirm-dialog` | Confirmation dialog with text-match support |
118
123
  | Error Display | `lc-error-display` | Error state display |
119
124
  | Modal | `lc-modal` | Dialog/modal window |
120
125
  | Toast | `lc-toast` | Notification toast |
121
126
  | Tooltip | `lcTooltip` | Tooltip directive |
122
127
 
128
+ ### Services
129
+
130
+ | Service | Description |
131
+ |---------|-------------|
132
+ | `ConfirmService` | Imperative confirm/destructive/warning dialogs returning `Promise<boolean>` |
133
+ | `ThemeService` | Toggle light/dark theme |
134
+
123
135
  ## Theming
124
136
 
125
- The library supports light and dark themes. Use the `ThemeService` to switch themes:
137
+ The library supports light and dark themes:
126
138
 
127
139
  ```typescript
128
140
  import { ThemeService } from '@life-cockpit/angular-ui-kit';
@@ -137,6 +149,38 @@ export class AppComponent {
137
149
  }
138
150
  ```
139
151
 
152
+ ## Chat with Rich Content
153
+
154
+ The Chat component supports custom message templates for embedding any component inside chat bubbles:
155
+
156
+ ```typescript
157
+ import { ChatComponent, ChatMessage, DiffViewerComponent } from '@life-cockpit/angular-ui-kit';
158
+
159
+ @Component({
160
+ imports: [ChatComponent, DiffViewerComponent],
161
+ template: `
162
+ <lc-chat [messages]="messages" title="Spec Author">
163
+ <ng-template #messageTemplate let-msg>
164
+ {{ msg.content }}
165
+ @if (msg.data?.diff) {
166
+ <lc-diff-viewer
167
+ [oldText]="msg.data.oldText"
168
+ [newText]="msg.data.newText"
169
+ mode="inline"
170
+ />
171
+ }
172
+ </ng-template>
173
+ </lc-chat>
174
+ `,
175
+ })
176
+ export class SpecAuthorComponent {
177
+ messages: ChatMessage[] = [
178
+ { id: '1', role: 'agent', content: 'Ziel ausgefüllt:', name: 'Agent',
179
+ data: { diff: true, oldText: '## Ziel\n\n_TBD_', newText: '## Ziel\n\nOnboarding-Plattform' } },
180
+ ];
181
+ }
182
+ ```
183
+
140
184
  ## Design Tokens
141
185
 
142
186
  Design tokens for colors, spacing, typography, elevation, and more are available as TypeScript constants:
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { inject, PLATFORM_ID, signal, Injectable, input, computed, effect, ChangeDetectionStrategy, Component, model, EventEmitter, ViewChild, Output, Input, ViewEncapsulation, output, HostListener, forwardRef, ElementRef, viewChild, ChangeDetectorRef, ViewChildren, HostBinding, ViewContainerRef, Renderer2, Directive, TemplateRef, ContentChildren, ContentChild, SecurityContext, NgZone, ApplicationRef, EnvironmentInjector, createComponent } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
- import { isPlatformBrowser, CommonModule, SlicePipe, NgStyle } from '@angular/common';
4
+ import { isPlatformBrowser, CommonModule, SlicePipe, NgTemplateOutlet, NgStyle } from '@angular/common';
5
5
  import * as i1$4 from '@angular/platform-browser';
6
6
  import { DomSanitizer } from '@angular/platform-browser';
7
7
  import { HttpClient } from '@angular/common/http';
@@ -10507,6 +10507,8 @@ class ChatComponent {
10507
10507
  showTimestamps = input(true, ...(ngDevMode ? [{ debugName: "showTimestamps" }] : /* istanbul ignore next */ []));
10508
10508
  /** Emits when user sends a message. */
10509
10509
  messageSend = output();
10510
+ /** Custom template for rendering message content. Context: { $implicit: ChatMessage } */
10511
+ messageTemplate;
10510
10512
  inputValue = signal('', ...(ngDevMode ? [{ debugName: "inputValue" }] : /* istanbul ignore next */ []));
10511
10513
  shouldScroll = false;
10512
10514
  scrollContainer;
@@ -10552,12 +10554,15 @@ class ChatComponent {
10552
10554
  }
10553
10555
  }
10554
10556
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
10555
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: ChatComponent, isStandalone: true, selector: "lc-chat", inputs: { messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, isStreaming: { classPropertyName: "isStreaming", publicName: "isStreaming", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showAvatars: { classPropertyName: "showAvatars", publicName: "showAvatars", isSignal: true, isRequired: false, transformFunction: null }, showTimestamps: { classPropertyName: "showTimestamps", publicName: "showTimestamps", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { messageSend: "messageSend" }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], ngImport: i0, template: "<div class=\"lc-chat\">\n @if (showHeader()) {\n <div class=\"lc-chat__header\">\n <span class=\"lc-chat__title\">{{ title() }}</span>\n @if (isStreaming()) {\n <span class=\"lc-chat__streaming-badge\">Streaming\u2026</span>\n }\n </div>\n }\n\n <div class=\"lc-chat__messages\" #scrollContainer>\n @for (msg of formattedMessages(); track trackById($index, msg)) {\n <div\n class=\"lc-chat__message\"\n [class.lc-chat__message--user]=\"msg.role === 'user'\"\n [class.lc-chat__message--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__message--system]=\"msg.role === 'system'\"\n >\n @if (showAvatars() && msg.role !== 'system') {\n <div class=\"lc-chat__avatar\">\n @if (msg.avatar) {\n <img [src]=\"msg.avatar\" [alt]=\"msg.name || msg.role\" class=\"lc-chat__avatar-img\" />\n } @else {\n <span class=\"lc-chat__avatar-fallback\" [class.lc-chat__avatar-fallback--agent]=\"msg.role === 'agent'\">\n {{ (msg.name || msg.role).charAt(0).toUpperCase() }}\n </span>\n }\n </div>\n }\n\n <div class=\"lc-chat__bubble\" [class.lc-chat__bubble--streaming]=\"msg.streaming\">\n @if (msg.name && msg.role !== 'user') {\n <div class=\"lc-chat__name\">{{ msg.name }}</div>\n }\n <div class=\"lc-chat__content\">{{ msg.content }}<span class=\"lc-chat__cursor\" [class.lc-chat__cursor--visible]=\"msg.streaming\"></span></div>\n @if (showTimestamps() && msg.timestamp) {\n <div class=\"lc-chat__time\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n </div>\n }\n\n @if (isStreaming() && !(formattedMessages().length && formattedMessages()[formattedMessages().length - 1].streaming)) {\n <div class=\"lc-chat__message lc-chat__message--agent\">\n @if (showAvatars()) {\n <div class=\"lc-chat__avatar\">\n <span class=\"lc-chat__avatar-fallback lc-chat__avatar-fallback--agent\">A</span>\n </div>\n }\n <div class=\"lc-chat__bubble\">\n <div class=\"lc-chat__typing\">\n <span></span><span></span><span></span>\n </div>\n </div>\n </div>\n }\n </div>\n\n <div class=\"lc-chat__input-area\">\n <textarea\n class=\"lc-chat__input\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n [disabled]=\"disabled()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n rows=\"1\"\n ></textarea>\n <button\n class=\"lc-chat__send-btn\"\n [disabled]=\"!inputValue().trim() || disabled()\"\n (click)=\"send()\"\n aria-label=\"Send\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M3 10l7-7m0 0l7 7m-7-7v14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" transform=\"rotate(90 10 10)\"/>\n </svg>\n </button>\n </div>\n</div>\n", styles: [".lc-chat{display:flex;flex-direction:column;height:100%;min-height:20rem;border:1px solid var(--color-neutral-200);border-radius:.5rem;overflow:hidden;background:var(--color-neutral-0, #fff);font-family:var(--typography-font-family, sans-serif)}[data-theme=dark] .lc-chat,:root[data-theme=dark] .lc-chat{border-color:var(--color-neutral-700);background:var(--color-neutral-900)}.lc-chat__header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-bottom:1px solid var(--color-neutral-200);background:var(--color-neutral-50)}[data-theme=dark] .lc-chat__header,:root[data-theme=dark] .lc-chat__header{border-color:var(--color-neutral-700);background:var(--color-neutral-800)}.lc-chat__title{font-size:.875rem;font-weight:600;color:var(--color-neutral-900)}[data-theme=dark] .lc-chat__title,:root[data-theme=dark] .lc-chat__title{color:var(--color-neutral-100)}.lc-chat__streaming-badge{font-size:.6875rem;padding:.125rem .5rem;background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-500);border-radius:1rem;font-weight:500;animation:pulse-badge 1.5s infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.6}}.lc-chat__messages{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.75rem}.lc-chat__message{display:flex;align-items:flex-start;gap:.5rem;max-width:85%}.lc-chat__message--user{align-self:flex-end;flex-direction:row-reverse}.lc-chat__message--agent{align-self:flex-start}.lc-chat__message--system{align-self:center;max-width:100%}.lc-chat__avatar{flex-shrink:0;width:2rem;height:2rem}.lc-chat__avatar-img{width:100%;height:100%;border-radius:50%;object-fit:cover}.lc-chat__avatar-fallback{display:flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:50%;background:var(--color-neutral-300);color:#fff;font-size:.75rem;font-weight:700}.lc-chat__avatar-fallback--agent{background:var(--color-primary-500)}.lc-chat__bubble{padding:.5rem .75rem;border-radius:1rem;font-size:.875rem;line-height:1.5;word-break:break-word}.lc-chat__message--user .lc-chat__bubble{background:var(--color-primary-500);color:#fff;border-bottom-right-radius:.25rem}.lc-chat__message--agent .lc-chat__bubble{background:var(--color-neutral-100);color:var(--color-neutral-900);border-bottom-left-radius:.25rem}[data-theme=dark] .lc-chat__message--agent .lc-chat__bubble,:root[data-theme=dark] .lc-chat__message--agent .lc-chat__bubble{background:var(--color-neutral-800);color:var(--color-neutral-100)}.lc-chat__message--system .lc-chat__bubble{background:transparent;color:var(--color-neutral-500);font-size:.75rem;text-align:center;padding:.25rem .5rem}.lc-chat__message--agent .lc-chat__bubble--streaming{border:1px solid color-mix(in srgb,var(--color-primary-500) 30%,transparent)}.lc-chat__name{font-size:.6875rem;font-weight:600;color:var(--color-primary-500);margin-bottom:.125rem}.lc-chat__content{white-space:pre-wrap}.lc-chat__cursor{display:none}.lc-chat__cursor--visible{display:inline-block;width:2px;height:1em;background:currentColor;margin-left:1px;vertical-align:text-bottom;animation:blink-cursor .8s step-end infinite}@keyframes blink-cursor{0%,to{opacity:1}50%{opacity:0}}.lc-chat__time{font-size:.625rem;color:var(--color-neutral-400);margin-top:.25rem}.lc-chat__message--user .lc-chat__time{color:#ffffffb3;text-align:right}.lc-chat__typing{display:flex;gap:.25rem;padding:.25rem 0}.lc-chat__typing span{width:.375rem;height:.375rem;border-radius:50%;background:var(--color-neutral-400);animation:typing-bounce 1.4s ease-in-out infinite}.lc-chat__typing span:nth-child(2){animation-delay:.2s}.lc-chat__typing span:nth-child(3){animation-delay:.4s}@keyframes typing-bounce{0%,60%,to{transform:translateY(0)}30%{transform:translateY(-.375rem)}}.lc-chat__input-area{display:flex;align-items:flex-end;gap:.5rem;padding:.75rem 1rem;border-top:1px solid var(--color-neutral-200);background:var(--color-neutral-50)}[data-theme=dark] .lc-chat__input-area,:root[data-theme=dark] .lc-chat__input-area{border-color:var(--color-neutral-700);background:var(--color-neutral-800)}.lc-chat__input{flex:1;resize:none;border:1px solid var(--color-neutral-300);border-radius:1.25rem;padding:.5rem .875rem;font-size:.875rem;font-family:inherit;line-height:1.4;outline:none;background:var(--color-neutral-0, #fff);color:var(--color-neutral-900);max-height:6rem;overflow-y:auto;transition:border-color .15s}.lc-chat__input:focus{border-color:var(--color-primary-500)}.lc-chat__input:disabled{opacity:.5;cursor:not-allowed}.lc-chat__input::placeholder{color:var(--color-neutral-400)}[data-theme=dark] .lc-chat__input,:root[data-theme=dark] .lc-chat__input{border-color:var(--color-neutral-600);background:var(--color-neutral-700);color:var(--color-neutral-100)}[data-theme=dark] .lc-chat__input::placeholder,:root[data-theme=dark] .lc-chat__input::placeholder{color:var(--color-neutral-500)}[data-theme=dark] .lc-chat__input:focus,:root[data-theme=dark] .lc-chat__input:focus{border-color:var(--color-primary-500)}.lc-chat__send-btn{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border:none;border-radius:50%;background:var(--color-primary-500);color:#fff;cursor:pointer;flex-shrink:0;transition:background .15s,opacity .15s}.lc-chat__send-btn:hover:not(:disabled){background:var(--color-primary-700)}.lc-chat__send-btn:disabled{opacity:.4;cursor:not-allowed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
10557
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: ChatComponent, isStandalone: true, selector: "lc-chat", inputs: { messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, isStreaming: { classPropertyName: "isStreaming", publicName: "isStreaming", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showAvatars: { classPropertyName: "showAvatars", publicName: "showAvatars", isSignal: true, isRequired: false, transformFunction: null }, showTimestamps: { classPropertyName: "showTimestamps", publicName: "showTimestamps", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { messageSend: "messageSend" }, queries: [{ propertyName: "messageTemplate", first: true, predicate: ["messageTemplate"], descendants: true }], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], ngImport: i0, template: "<div class=\"lc-chat\">\n @if (showHeader()) {\n <div class=\"lc-chat__header\">\n <span class=\"lc-chat__title\">{{ title() }}</span>\n @if (isStreaming()) {\n <span class=\"lc-chat__streaming-badge\">Streaming\u2026</span>\n }\n </div>\n }\n\n <div class=\"lc-chat__messages\" #scrollContainer>\n @for (msg of formattedMessages(); track trackById($index, msg)) {\n <div\n class=\"lc-chat__message\"\n [class.lc-chat__message--user]=\"msg.role === 'user'\"\n [class.lc-chat__message--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__message--system]=\"msg.role === 'system'\"\n >\n @if (showAvatars() && msg.role !== 'system') {\n <div class=\"lc-chat__avatar\">\n @if (msg.avatar) {\n <img [src]=\"msg.avatar\" [alt]=\"msg.name || msg.role\" class=\"lc-chat__avatar-img\" />\n } @else {\n <span class=\"lc-chat__avatar-fallback\" [class.lc-chat__avatar-fallback--agent]=\"msg.role === 'agent'\">\n {{ (msg.name || msg.role).charAt(0).toUpperCase() }}\n </span>\n }\n </div>\n }\n\n <div class=\"lc-chat__bubble\" [class.lc-chat__bubble--streaming]=\"msg.streaming\">\n @if (msg.name && msg.role !== 'user') {\n <div class=\"lc-chat__name\">{{ msg.name }}</div>\n }\n <div class=\"lc-chat__content\">\n @if (messageTemplate) {\n <ng-container *ngTemplateOutlet=\"messageTemplate; context: { $implicit: msg }\" />\n } @else {\n {{ msg.content }}\n }\n <span class=\"lc-chat__cursor\" [class.lc-chat__cursor--visible]=\"msg.streaming\"></span>\n </div>\n @if (showTimestamps() && msg.timestamp) {\n <div class=\"lc-chat__time\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n </div>\n }\n\n @if (isStreaming() && !(formattedMessages().length && formattedMessages()[formattedMessages().length - 1].streaming)) {\n <div class=\"lc-chat__message lc-chat__message--agent\">\n @if (showAvatars()) {\n <div class=\"lc-chat__avatar\">\n <span class=\"lc-chat__avatar-fallback lc-chat__avatar-fallback--agent\">A</span>\n </div>\n }\n <div class=\"lc-chat__bubble\">\n <div class=\"lc-chat__typing\">\n <span></span><span></span><span></span>\n </div>\n </div>\n </div>\n }\n </div>\n\n <div class=\"lc-chat__input-area\">\n <textarea\n class=\"lc-chat__input\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n [disabled]=\"disabled()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n rows=\"1\"\n ></textarea>\n <button\n class=\"lc-chat__send-btn\"\n [disabled]=\"!inputValue().trim() || disabled()\"\n (click)=\"send()\"\n aria-label=\"Send\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M3 10l7-7m0 0l7 7m-7-7v14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" transform=\"rotate(90 10 10)\"/>\n </svg>\n </button>\n </div>\n</div>\n", styles: [".lc-chat{display:flex;flex-direction:column;height:100%;min-height:20rem;border:1px solid var(--color-neutral-200);border-radius:.5rem;overflow:hidden;background:var(--color-neutral-0, #fff);font-family:var(--typography-font-family, sans-serif)}[data-theme=dark] .lc-chat,:root[data-theme=dark] .lc-chat{border-color:var(--color-neutral-700);background:var(--color-neutral-900)}.lc-chat__header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-bottom:1px solid var(--color-neutral-200);background:var(--color-neutral-50)}[data-theme=dark] .lc-chat__header,:root[data-theme=dark] .lc-chat__header{border-color:var(--color-neutral-700);background:var(--color-neutral-800)}.lc-chat__title{font-size:.875rem;font-weight:600;color:var(--color-neutral-900)}[data-theme=dark] .lc-chat__title,:root[data-theme=dark] .lc-chat__title{color:var(--color-neutral-100)}.lc-chat__streaming-badge{font-size:.6875rem;padding:.125rem .5rem;background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-500);border-radius:1rem;font-weight:500;animation:pulse-badge 1.5s infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.6}}.lc-chat__messages{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.75rem}.lc-chat__message{display:flex;align-items:flex-start;gap:.5rem;max-width:85%}.lc-chat__message--user{align-self:flex-end;flex-direction:row-reverse}.lc-chat__message--agent{align-self:flex-start}.lc-chat__message--system{align-self:center;max-width:100%}.lc-chat__avatar{flex-shrink:0;width:2rem;height:2rem}.lc-chat__avatar-img{width:100%;height:100%;border-radius:50%;object-fit:cover}.lc-chat__avatar-fallback{display:flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:50%;background:var(--color-neutral-300);color:#fff;font-size:.75rem;font-weight:700}.lc-chat__avatar-fallback--agent{background:var(--color-primary-500)}.lc-chat__bubble{padding:.5rem .75rem;border-radius:1rem;font-size:.875rem;line-height:1.5;word-break:break-word}.lc-chat__message--user .lc-chat__bubble{background:var(--color-primary-500);color:#fff;border-bottom-right-radius:.25rem}.lc-chat__message--agent .lc-chat__bubble{background:var(--color-neutral-100);color:var(--color-neutral-900);border-bottom-left-radius:.25rem}[data-theme=dark] .lc-chat__message--agent .lc-chat__bubble,:root[data-theme=dark] .lc-chat__message--agent .lc-chat__bubble{background:var(--color-neutral-800);color:var(--color-neutral-100)}.lc-chat__message--system .lc-chat__bubble{background:transparent;color:var(--color-neutral-500);font-size:.75rem;text-align:center;padding:.25rem .5rem}.lc-chat__message--agent .lc-chat__bubble--streaming{border:1px solid color-mix(in srgb,var(--color-primary-500) 30%,transparent)}.lc-chat__name{font-size:.6875rem;font-weight:600;color:var(--color-primary-500);margin-bottom:.125rem}.lc-chat__content{white-space:pre-wrap}.lc-chat__cursor{display:none}.lc-chat__cursor--visible{display:inline-block;width:2px;height:1em;background:currentColor;margin-left:1px;vertical-align:text-bottom;animation:blink-cursor .8s step-end infinite}@keyframes blink-cursor{0%,to{opacity:1}50%{opacity:0}}.lc-chat__time{font-size:.625rem;color:var(--color-neutral-400);margin-top:.25rem}.lc-chat__message--user .lc-chat__time{color:#ffffffb3;text-align:right}.lc-chat__typing{display:flex;gap:.25rem;padding:.25rem 0}.lc-chat__typing span{width:.375rem;height:.375rem;border-radius:50%;background:var(--color-neutral-400);animation:typing-bounce 1.4s ease-in-out infinite}.lc-chat__typing span:nth-child(2){animation-delay:.2s}.lc-chat__typing span:nth-child(3){animation-delay:.4s}@keyframes typing-bounce{0%,60%,to{transform:translateY(0)}30%{transform:translateY(-.375rem)}}.lc-chat__input-area{display:flex;align-items:flex-end;gap:.5rem;padding:.75rem 1rem;border-top:1px solid var(--color-neutral-200);background:var(--color-neutral-50)}[data-theme=dark] .lc-chat__input-area,:root[data-theme=dark] .lc-chat__input-area{border-color:var(--color-neutral-700);background:var(--color-neutral-800)}.lc-chat__input{flex:1;resize:none;border:1px solid var(--color-neutral-300);border-radius:1.25rem;padding:.5rem .875rem;font-size:.875rem;font-family:inherit;line-height:1.4;outline:none;background:var(--color-neutral-0, #fff);color:var(--color-neutral-900);max-height:6rem;overflow-y:auto;transition:border-color .15s}.lc-chat__input:focus{border-color:var(--color-primary-500)}.lc-chat__input:disabled{opacity:.5;cursor:not-allowed}.lc-chat__input::placeholder{color:var(--color-neutral-400)}[data-theme=dark] .lc-chat__input,:root[data-theme=dark] .lc-chat__input{border-color:var(--color-neutral-600);background:var(--color-neutral-700);color:var(--color-neutral-100)}[data-theme=dark] .lc-chat__input::placeholder,:root[data-theme=dark] .lc-chat__input::placeholder{color:var(--color-neutral-500)}[data-theme=dark] .lc-chat__input:focus,:root[data-theme=dark] .lc-chat__input:focus{border-color:var(--color-primary-500)}.lc-chat__send-btn{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border:none;border-radius:50%;background:var(--color-primary-500);color:#fff;cursor:pointer;flex-shrink:0;transition:background .15s,opacity .15s}.lc-chat__send-btn:hover:not(:disabled){background:var(--color-primary-700)}.lc-chat__send-btn:disabled{opacity:.4;cursor:not-allowed}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
10556
10558
  }
10557
10559
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ChatComponent, decorators: [{
10558
10560
  type: Component,
10559
- args: [{ selector: 'lc-chat', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"lc-chat\">\n @if (showHeader()) {\n <div class=\"lc-chat__header\">\n <span class=\"lc-chat__title\">{{ title() }}</span>\n @if (isStreaming()) {\n <span class=\"lc-chat__streaming-badge\">Streaming\u2026</span>\n }\n </div>\n }\n\n <div class=\"lc-chat__messages\" #scrollContainer>\n @for (msg of formattedMessages(); track trackById($index, msg)) {\n <div\n class=\"lc-chat__message\"\n [class.lc-chat__message--user]=\"msg.role === 'user'\"\n [class.lc-chat__message--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__message--system]=\"msg.role === 'system'\"\n >\n @if (showAvatars() && msg.role !== 'system') {\n <div class=\"lc-chat__avatar\">\n @if (msg.avatar) {\n <img [src]=\"msg.avatar\" [alt]=\"msg.name || msg.role\" class=\"lc-chat__avatar-img\" />\n } @else {\n <span class=\"lc-chat__avatar-fallback\" [class.lc-chat__avatar-fallback--agent]=\"msg.role === 'agent'\">\n {{ (msg.name || msg.role).charAt(0).toUpperCase() }}\n </span>\n }\n </div>\n }\n\n <div class=\"lc-chat__bubble\" [class.lc-chat__bubble--streaming]=\"msg.streaming\">\n @if (msg.name && msg.role !== 'user') {\n <div class=\"lc-chat__name\">{{ msg.name }}</div>\n }\n <div class=\"lc-chat__content\">{{ msg.content }}<span class=\"lc-chat__cursor\" [class.lc-chat__cursor--visible]=\"msg.streaming\"></span></div>\n @if (showTimestamps() && msg.timestamp) {\n <div class=\"lc-chat__time\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n </div>\n }\n\n @if (isStreaming() && !(formattedMessages().length && formattedMessages()[formattedMessages().length - 1].streaming)) {\n <div class=\"lc-chat__message lc-chat__message--agent\">\n @if (showAvatars()) {\n <div class=\"lc-chat__avatar\">\n <span class=\"lc-chat__avatar-fallback lc-chat__avatar-fallback--agent\">A</span>\n </div>\n }\n <div class=\"lc-chat__bubble\">\n <div class=\"lc-chat__typing\">\n <span></span><span></span><span></span>\n </div>\n </div>\n </div>\n }\n </div>\n\n <div class=\"lc-chat__input-area\">\n <textarea\n class=\"lc-chat__input\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n [disabled]=\"disabled()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n rows=\"1\"\n ></textarea>\n <button\n class=\"lc-chat__send-btn\"\n [disabled]=\"!inputValue().trim() || disabled()\"\n (click)=\"send()\"\n aria-label=\"Send\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M3 10l7-7m0 0l7 7m-7-7v14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" transform=\"rotate(90 10 10)\"/>\n </svg>\n </button>\n </div>\n</div>\n", styles: [".lc-chat{display:flex;flex-direction:column;height:100%;min-height:20rem;border:1px solid var(--color-neutral-200);border-radius:.5rem;overflow:hidden;background:var(--color-neutral-0, #fff);font-family:var(--typography-font-family, sans-serif)}[data-theme=dark] .lc-chat,:root[data-theme=dark] .lc-chat{border-color:var(--color-neutral-700);background:var(--color-neutral-900)}.lc-chat__header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-bottom:1px solid var(--color-neutral-200);background:var(--color-neutral-50)}[data-theme=dark] .lc-chat__header,:root[data-theme=dark] .lc-chat__header{border-color:var(--color-neutral-700);background:var(--color-neutral-800)}.lc-chat__title{font-size:.875rem;font-weight:600;color:var(--color-neutral-900)}[data-theme=dark] .lc-chat__title,:root[data-theme=dark] .lc-chat__title{color:var(--color-neutral-100)}.lc-chat__streaming-badge{font-size:.6875rem;padding:.125rem .5rem;background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-500);border-radius:1rem;font-weight:500;animation:pulse-badge 1.5s infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.6}}.lc-chat__messages{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.75rem}.lc-chat__message{display:flex;align-items:flex-start;gap:.5rem;max-width:85%}.lc-chat__message--user{align-self:flex-end;flex-direction:row-reverse}.lc-chat__message--agent{align-self:flex-start}.lc-chat__message--system{align-self:center;max-width:100%}.lc-chat__avatar{flex-shrink:0;width:2rem;height:2rem}.lc-chat__avatar-img{width:100%;height:100%;border-radius:50%;object-fit:cover}.lc-chat__avatar-fallback{display:flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:50%;background:var(--color-neutral-300);color:#fff;font-size:.75rem;font-weight:700}.lc-chat__avatar-fallback--agent{background:var(--color-primary-500)}.lc-chat__bubble{padding:.5rem .75rem;border-radius:1rem;font-size:.875rem;line-height:1.5;word-break:break-word}.lc-chat__message--user .lc-chat__bubble{background:var(--color-primary-500);color:#fff;border-bottom-right-radius:.25rem}.lc-chat__message--agent .lc-chat__bubble{background:var(--color-neutral-100);color:var(--color-neutral-900);border-bottom-left-radius:.25rem}[data-theme=dark] .lc-chat__message--agent .lc-chat__bubble,:root[data-theme=dark] .lc-chat__message--agent .lc-chat__bubble{background:var(--color-neutral-800);color:var(--color-neutral-100)}.lc-chat__message--system .lc-chat__bubble{background:transparent;color:var(--color-neutral-500);font-size:.75rem;text-align:center;padding:.25rem .5rem}.lc-chat__message--agent .lc-chat__bubble--streaming{border:1px solid color-mix(in srgb,var(--color-primary-500) 30%,transparent)}.lc-chat__name{font-size:.6875rem;font-weight:600;color:var(--color-primary-500);margin-bottom:.125rem}.lc-chat__content{white-space:pre-wrap}.lc-chat__cursor{display:none}.lc-chat__cursor--visible{display:inline-block;width:2px;height:1em;background:currentColor;margin-left:1px;vertical-align:text-bottom;animation:blink-cursor .8s step-end infinite}@keyframes blink-cursor{0%,to{opacity:1}50%{opacity:0}}.lc-chat__time{font-size:.625rem;color:var(--color-neutral-400);margin-top:.25rem}.lc-chat__message--user .lc-chat__time{color:#ffffffb3;text-align:right}.lc-chat__typing{display:flex;gap:.25rem;padding:.25rem 0}.lc-chat__typing span{width:.375rem;height:.375rem;border-radius:50%;background:var(--color-neutral-400);animation:typing-bounce 1.4s ease-in-out infinite}.lc-chat__typing span:nth-child(2){animation-delay:.2s}.lc-chat__typing span:nth-child(3){animation-delay:.4s}@keyframes typing-bounce{0%,60%,to{transform:translateY(0)}30%{transform:translateY(-.375rem)}}.lc-chat__input-area{display:flex;align-items:flex-end;gap:.5rem;padding:.75rem 1rem;border-top:1px solid var(--color-neutral-200);background:var(--color-neutral-50)}[data-theme=dark] .lc-chat__input-area,:root[data-theme=dark] .lc-chat__input-area{border-color:var(--color-neutral-700);background:var(--color-neutral-800)}.lc-chat__input{flex:1;resize:none;border:1px solid var(--color-neutral-300);border-radius:1.25rem;padding:.5rem .875rem;font-size:.875rem;font-family:inherit;line-height:1.4;outline:none;background:var(--color-neutral-0, #fff);color:var(--color-neutral-900);max-height:6rem;overflow-y:auto;transition:border-color .15s}.lc-chat__input:focus{border-color:var(--color-primary-500)}.lc-chat__input:disabled{opacity:.5;cursor:not-allowed}.lc-chat__input::placeholder{color:var(--color-neutral-400)}[data-theme=dark] .lc-chat__input,:root[data-theme=dark] .lc-chat__input{border-color:var(--color-neutral-600);background:var(--color-neutral-700);color:var(--color-neutral-100)}[data-theme=dark] .lc-chat__input::placeholder,:root[data-theme=dark] .lc-chat__input::placeholder{color:var(--color-neutral-500)}[data-theme=dark] .lc-chat__input:focus,:root[data-theme=dark] .lc-chat__input:focus{border-color:var(--color-primary-500)}.lc-chat__send-btn{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border:none;border-radius:50%;background:var(--color-primary-500);color:#fff;cursor:pointer;flex-shrink:0;transition:background .15s,opacity .15s}.lc-chat__send-btn:hover:not(:disabled){background:var(--color-primary-700)}.lc-chat__send-btn:disabled{opacity:.4;cursor:not-allowed}\n"] }]
10560
- }], propDecorators: { messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], isStreaming: [{ type: i0.Input, args: [{ isSignal: true, alias: "isStreaming", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showAvatars: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAvatars", required: false }] }], showTimestamps: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTimestamps", required: false }] }], messageSend: [{ type: i0.Output, args: ["messageSend"] }], scrollContainer: [{
10561
+ args: [{ selector: 'lc-chat', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"lc-chat\">\n @if (showHeader()) {\n <div class=\"lc-chat__header\">\n <span class=\"lc-chat__title\">{{ title() }}</span>\n @if (isStreaming()) {\n <span class=\"lc-chat__streaming-badge\">Streaming\u2026</span>\n }\n </div>\n }\n\n <div class=\"lc-chat__messages\" #scrollContainer>\n @for (msg of formattedMessages(); track trackById($index, msg)) {\n <div\n class=\"lc-chat__message\"\n [class.lc-chat__message--user]=\"msg.role === 'user'\"\n [class.lc-chat__message--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__message--system]=\"msg.role === 'system'\"\n >\n @if (showAvatars() && msg.role !== 'system') {\n <div class=\"lc-chat__avatar\">\n @if (msg.avatar) {\n <img [src]=\"msg.avatar\" [alt]=\"msg.name || msg.role\" class=\"lc-chat__avatar-img\" />\n } @else {\n <span class=\"lc-chat__avatar-fallback\" [class.lc-chat__avatar-fallback--agent]=\"msg.role === 'agent'\">\n {{ (msg.name || msg.role).charAt(0).toUpperCase() }}\n </span>\n }\n </div>\n }\n\n <div class=\"lc-chat__bubble\" [class.lc-chat__bubble--streaming]=\"msg.streaming\">\n @if (msg.name && msg.role !== 'user') {\n <div class=\"lc-chat__name\">{{ msg.name }}</div>\n }\n <div class=\"lc-chat__content\">\n @if (messageTemplate) {\n <ng-container *ngTemplateOutlet=\"messageTemplate; context: { $implicit: msg }\" />\n } @else {\n {{ msg.content }}\n }\n <span class=\"lc-chat__cursor\" [class.lc-chat__cursor--visible]=\"msg.streaming\"></span>\n </div>\n @if (showTimestamps() && msg.timestamp) {\n <div class=\"lc-chat__time\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n </div>\n }\n\n @if (isStreaming() && !(formattedMessages().length && formattedMessages()[formattedMessages().length - 1].streaming)) {\n <div class=\"lc-chat__message lc-chat__message--agent\">\n @if (showAvatars()) {\n <div class=\"lc-chat__avatar\">\n <span class=\"lc-chat__avatar-fallback lc-chat__avatar-fallback--agent\">A</span>\n </div>\n }\n <div class=\"lc-chat__bubble\">\n <div class=\"lc-chat__typing\">\n <span></span><span></span><span></span>\n </div>\n </div>\n </div>\n }\n </div>\n\n <div class=\"lc-chat__input-area\">\n <textarea\n class=\"lc-chat__input\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n [disabled]=\"disabled()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n rows=\"1\"\n ></textarea>\n <button\n class=\"lc-chat__send-btn\"\n [disabled]=\"!inputValue().trim() || disabled()\"\n (click)=\"send()\"\n aria-label=\"Send\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M3 10l7-7m0 0l7 7m-7-7v14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" transform=\"rotate(90 10 10)\"/>\n </svg>\n </button>\n </div>\n</div>\n", styles: [".lc-chat{display:flex;flex-direction:column;height:100%;min-height:20rem;border:1px solid var(--color-neutral-200);border-radius:.5rem;overflow:hidden;background:var(--color-neutral-0, #fff);font-family:var(--typography-font-family, sans-serif)}[data-theme=dark] .lc-chat,:root[data-theme=dark] .lc-chat{border-color:var(--color-neutral-700);background:var(--color-neutral-900)}.lc-chat__header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-bottom:1px solid var(--color-neutral-200);background:var(--color-neutral-50)}[data-theme=dark] .lc-chat__header,:root[data-theme=dark] .lc-chat__header{border-color:var(--color-neutral-700);background:var(--color-neutral-800)}.lc-chat__title{font-size:.875rem;font-weight:600;color:var(--color-neutral-900)}[data-theme=dark] .lc-chat__title,:root[data-theme=dark] .lc-chat__title{color:var(--color-neutral-100)}.lc-chat__streaming-badge{font-size:.6875rem;padding:.125rem .5rem;background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-500);border-radius:1rem;font-weight:500;animation:pulse-badge 1.5s infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.6}}.lc-chat__messages{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.75rem}.lc-chat__message{display:flex;align-items:flex-start;gap:.5rem;max-width:85%}.lc-chat__message--user{align-self:flex-end;flex-direction:row-reverse}.lc-chat__message--agent{align-self:flex-start}.lc-chat__message--system{align-self:center;max-width:100%}.lc-chat__avatar{flex-shrink:0;width:2rem;height:2rem}.lc-chat__avatar-img{width:100%;height:100%;border-radius:50%;object-fit:cover}.lc-chat__avatar-fallback{display:flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:50%;background:var(--color-neutral-300);color:#fff;font-size:.75rem;font-weight:700}.lc-chat__avatar-fallback--agent{background:var(--color-primary-500)}.lc-chat__bubble{padding:.5rem .75rem;border-radius:1rem;font-size:.875rem;line-height:1.5;word-break:break-word}.lc-chat__message--user .lc-chat__bubble{background:var(--color-primary-500);color:#fff;border-bottom-right-radius:.25rem}.lc-chat__message--agent .lc-chat__bubble{background:var(--color-neutral-100);color:var(--color-neutral-900);border-bottom-left-radius:.25rem}[data-theme=dark] .lc-chat__message--agent .lc-chat__bubble,:root[data-theme=dark] .lc-chat__message--agent .lc-chat__bubble{background:var(--color-neutral-800);color:var(--color-neutral-100)}.lc-chat__message--system .lc-chat__bubble{background:transparent;color:var(--color-neutral-500);font-size:.75rem;text-align:center;padding:.25rem .5rem}.lc-chat__message--agent .lc-chat__bubble--streaming{border:1px solid color-mix(in srgb,var(--color-primary-500) 30%,transparent)}.lc-chat__name{font-size:.6875rem;font-weight:600;color:var(--color-primary-500);margin-bottom:.125rem}.lc-chat__content{white-space:pre-wrap}.lc-chat__cursor{display:none}.lc-chat__cursor--visible{display:inline-block;width:2px;height:1em;background:currentColor;margin-left:1px;vertical-align:text-bottom;animation:blink-cursor .8s step-end infinite}@keyframes blink-cursor{0%,to{opacity:1}50%{opacity:0}}.lc-chat__time{font-size:.625rem;color:var(--color-neutral-400);margin-top:.25rem}.lc-chat__message--user .lc-chat__time{color:#ffffffb3;text-align:right}.lc-chat__typing{display:flex;gap:.25rem;padding:.25rem 0}.lc-chat__typing span{width:.375rem;height:.375rem;border-radius:50%;background:var(--color-neutral-400);animation:typing-bounce 1.4s ease-in-out infinite}.lc-chat__typing span:nth-child(2){animation-delay:.2s}.lc-chat__typing span:nth-child(3){animation-delay:.4s}@keyframes typing-bounce{0%,60%,to{transform:translateY(0)}30%{transform:translateY(-.375rem)}}.lc-chat__input-area{display:flex;align-items:flex-end;gap:.5rem;padding:.75rem 1rem;border-top:1px solid var(--color-neutral-200);background:var(--color-neutral-50)}[data-theme=dark] .lc-chat__input-area,:root[data-theme=dark] .lc-chat__input-area{border-color:var(--color-neutral-700);background:var(--color-neutral-800)}.lc-chat__input{flex:1;resize:none;border:1px solid var(--color-neutral-300);border-radius:1.25rem;padding:.5rem .875rem;font-size:.875rem;font-family:inherit;line-height:1.4;outline:none;background:var(--color-neutral-0, #fff);color:var(--color-neutral-900);max-height:6rem;overflow-y:auto;transition:border-color .15s}.lc-chat__input:focus{border-color:var(--color-primary-500)}.lc-chat__input:disabled{opacity:.5;cursor:not-allowed}.lc-chat__input::placeholder{color:var(--color-neutral-400)}[data-theme=dark] .lc-chat__input,:root[data-theme=dark] .lc-chat__input{border-color:var(--color-neutral-600);background:var(--color-neutral-700);color:var(--color-neutral-100)}[data-theme=dark] .lc-chat__input::placeholder,:root[data-theme=dark] .lc-chat__input::placeholder{color:var(--color-neutral-500)}[data-theme=dark] .lc-chat__input:focus,:root[data-theme=dark] .lc-chat__input:focus{border-color:var(--color-primary-500)}.lc-chat__send-btn{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border:none;border-radius:50%;background:var(--color-primary-500);color:#fff;cursor:pointer;flex-shrink:0;transition:background .15s,opacity .15s}.lc-chat__send-btn:hover:not(:disabled){background:var(--color-primary-700)}.lc-chat__send-btn:disabled{opacity:.4;cursor:not-allowed}\n"] }]
10562
+ }], propDecorators: { messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], isStreaming: [{ type: i0.Input, args: [{ isSignal: true, alias: "isStreaming", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showAvatars: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAvatars", required: false }] }], showTimestamps: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTimestamps", required: false }] }], messageSend: [{ type: i0.Output, args: ["messageSend"] }], messageTemplate: [{
10563
+ type: ContentChild,
10564
+ args: ['messageTemplate']
10565
+ }], scrollContainer: [{
10561
10566
  type: ViewChild,
10562
10567
  args: ['scrollContainer']
10563
10568
  }] } });
@@ -13130,11 +13135,11 @@ class MarkdownComponent {
13130
13135
  .replace(/>/g, '&gt;');
13131
13136
  }
13132
13137
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: MarkdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13133
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: MarkdownComponent, isStandalone: true, selector: "lc-markdown", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, linkTarget: { classPropertyName: "linkTarget", publicName: "linkTarget", isSignal: true, isRequired: false, transformFunction: null }, sanitize: { classPropertyName: "sanitize", publicName: "sanitize", isSignal: true, isRequired: false, transformFunction: null }, syntaxHighlight: { classPropertyName: "syntaxHighlight", publicName: "syntaxHighlight", isSignal: true, isRequired: false, transformFunction: null }, showHeadingAnchors: { classPropertyName: "showHeadingAnchors", publicName: "showHeadingAnchors", isSignal: true, isRequired: false, transformFunction: null }, baseUrl: { classPropertyName: "baseUrl", publicName: "baseUrl", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { linkClick: "linkClick", rendered: "rendered" }, ngImport: i0, template: "<div [class]=\"containerClasses()\" (click)=\"onLinkClick($event)\">\n @for (part of renderParts(); track part.index) {\n @if (part.type === 'html') {\n <div [innerHTML]=\"part.safeHtml\"></div>\n } @else {\n <lc-code-block\n [code]=\"part.code!\"\n [language]=\"$any(part.lang)\"\n [showLineNumbers]=\"true\"\n [showCopy]=\"true\"\n />\n }\n }\n</div>\n", styles: [".lc-markdown{color:var(--color-text, #111827);font-family:var(--font-family-sans);font-size:var(--font-size-base, 1rem);line-height:var(--line-height-relaxed, 1.75)}.lc-markdown h1,.lc-markdown h2,.lc-markdown h3,.lc-markdown h4,.lc-markdown h5,.lc-markdown h6{color:var(--color-text, #111827);font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-tight, 1.25);margin:1.5em 0 .5em}.lc-markdown h1:first-child,.lc-markdown h2:first-child,.lc-markdown h3:first-child,.lc-markdown h4:first-child,.lc-markdown h5:first-child,.lc-markdown h6:first-child{margin-top:0}.lc-markdown h1{font-size:2rem}.lc-markdown h2{font-size:1.5rem}.lc-markdown h3{font-size:1.25rem}.lc-markdown h4{font-size:1.125rem}.lc-markdown h5{font-size:1rem}.lc-markdown h6{font-size:.875rem}.lc-markdown p{margin:0 0 1em}.lc-markdown a{color:var(--color-primary-600, #2563eb);text-decoration:none}.lc-markdown a:hover{text-decoration:underline}.lc-markdown strong{font-weight:var(--font-weight-semibold, 600)}.lc-markdown code{background-color:var(--color-neutral-100, #f3f4f6);color:var(--color-neutral-800, #1f2937);padding:.125em .375em;border-radius:var(--radius-sm, .25rem);font-family:var(--font-family-mono, monospace);font-size:.875em}.lc-markdown pre{margin:1em 0;overflow-x:auto}.lc-markdown pre code{background:none;padding:0;border-radius:0}.lc-markdown blockquote{margin:1em 0;padding:.5em 1em;border-left:4px solid var(--color-primary-300, #93c5fd);background-color:var(--color-neutral-50, #f9fafb);color:var(--color-text-secondary, #4b5563)}.lc-markdown blockquote p{margin:0}.lc-markdown ul,.lc-markdown ol{margin:0 0 1em;padding-left:1.5em}.lc-markdown li{margin:.25em 0}.lc-markdown hr{border:none;border-top:1px solid var(--color-divider, #e5e7eb);margin:1.5em 0}.lc-markdown img{max-width:100%;height:auto;border-radius:var(--radius-md, .375rem)}.lc-markdown del{text-decoration:line-through;color:var(--color-text-secondary, #6b7280)}.lc-markdown__table{width:100%;border-collapse:collapse;margin:1em 0;font-size:var(--font-size-sm, .875rem)}.lc-markdown__table th,.lc-markdown__table td{padding:.5rem .75rem;border:1px solid var(--color-divider, #e5e7eb);text-align:left}.lc-markdown__table th{background-color:var(--color-neutral-50, #f9fafb);font-weight:var(--font-weight-semibold, 600)}.lc-markdown__table tr:hover td{background-color:var(--color-neutral-50, #f9fafb)}.lc-markdown__task{list-style:none;margin-left:-1.5em}.lc-markdown__task input[type=checkbox]{margin-right:.5em;vertical-align:middle}.lc-markdown__anchor{color:var(--color-neutral-400, #9ca3af);text-decoration:none;margin-right:.25em;opacity:0;transition:opacity .15s ease}h1:hover .lc-markdown__anchor,h2:hover .lc-markdown__anchor,h3:hover .lc-markdown__anchor,h4:hover .lc-markdown__anchor,h5:hover .lc-markdown__anchor,h6:hover .lc-markdown__anchor{opacity:1}.lc-markdown lc-code-block{display:block;margin:1em 0}.lc-markdown--compact{font-size:var(--font-size-sm, .875rem);line-height:var(--line-height-normal, 1.5)}.lc-markdown--compact h1{font-size:1.5rem}.lc-markdown--compact h2{font-size:1.25rem}.lc-markdown--compact h3{font-size:1.125rem}.lc-markdown--compact h4{font-size:1rem}.lc-markdown--compact h5,.lc-markdown--compact h6{font-size:.875rem}.lc-markdown--compact h1,.lc-markdown--compact h2,.lc-markdown--compact h3,.lc-markdown--compact h4,.lc-markdown--compact h5,.lc-markdown--compact h6{margin:1em 0 .25em}.lc-markdown--compact p{margin:0 0 .5em}.lc-markdown--compact blockquote{margin:.5em 0;padding:.25em .75em}.lc-markdown--compact ul,.lc-markdown--compact ol{margin:0 0 .5em}\n"], dependencies: [{ kind: "component", type: CodeBlockComponent, selector: "lc-code-block", inputs: ["code", "language", "filename", "showLineNumbers", "showCopy", "showHeader"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
13138
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: MarkdownComponent, isStandalone: true, selector: "lc-markdown", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, linkTarget: { classPropertyName: "linkTarget", publicName: "linkTarget", isSignal: true, isRequired: false, transformFunction: null }, sanitize: { classPropertyName: "sanitize", publicName: "sanitize", isSignal: true, isRequired: false, transformFunction: null }, syntaxHighlight: { classPropertyName: "syntaxHighlight", publicName: "syntaxHighlight", isSignal: true, isRequired: false, transformFunction: null }, showHeadingAnchors: { classPropertyName: "showHeadingAnchors", publicName: "showHeadingAnchors", isSignal: true, isRequired: false, transformFunction: null }, baseUrl: { classPropertyName: "baseUrl", publicName: "baseUrl", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { linkClick: "linkClick", rendered: "rendered" }, ngImport: i0, template: "<div [class]=\"containerClasses()\" (click)=\"onLinkClick($event)\">\n @for (part of renderParts(); track part.index) {\n @if (part.type === 'html') {\n <div [innerHTML]=\"part.safeHtml\"></div>\n } @else {\n <lc-code-block\n [code]=\"part.code!\"\n [language]=\"$any(part.lang)\"\n [showLineNumbers]=\"true\"\n [showCopy]=\"true\"\n />\n }\n }\n</div>\n", styles: [".lc-markdown{color:var(--color-text, #111827);font-family:var(--font-family-sans);font-size:var(--font-size-base, 1rem);line-height:var(--line-height-relaxed, 1.75)}.lc-markdown h1,.lc-markdown h2,.lc-markdown h3,.lc-markdown h4,.lc-markdown h5,.lc-markdown h6{color:var(--color-text, #111827);font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-tight, 1.25);margin:1.5em 0 .5em}.lc-markdown h1:first-child,.lc-markdown h2:first-child,.lc-markdown h3:first-child,.lc-markdown h4:first-child,.lc-markdown h5:first-child,.lc-markdown h6:first-child{margin-top:0}.lc-markdown h1{font-size:2rem}.lc-markdown h2{font-size:1.5rem}.lc-markdown h3{font-size:1.25rem}.lc-markdown h4{font-size:1.125rem}.lc-markdown h5{font-size:1rem}.lc-markdown h6{font-size:.875rem}.lc-markdown p{margin:0 0 1em}.lc-markdown a{color:var(--color-primary-600, #2563eb);text-decoration:none}.lc-markdown a:hover{text-decoration:underline}.lc-markdown strong{font-weight:var(--font-weight-semibold, 600)}.lc-markdown code{background-color:var(--color-neutral-100, #f3f4f6);color:var(--color-neutral-800, #1f2937);padding:.125em .375em;border-radius:var(--radius-sm, .25rem);font-family:var(--font-family-mono, monospace);font-size:.875em}.lc-markdown pre{margin:1em 0;overflow-x:auto}.lc-markdown pre code{background:none;padding:0;border-radius:0}.lc-markdown blockquote{margin:1em 0;padding:.5em 1em;border-left:4px solid var(--color-primary-300, #93c5fd);background-color:var(--color-neutral-50, #f9fafb);color:var(--color-text-secondary, #4b5563)}.lc-markdown blockquote p{margin:0}.lc-markdown ul,.lc-markdown ol{margin:0 0 1em;padding-left:1.5em}.lc-markdown ul{list-style:disc}.lc-markdown ol{list-style:decimal}.lc-markdown li{margin:.25em 0}.lc-markdown hr{border:none;border-top:1px solid var(--color-divider, #e5e7eb);margin:1.5em 0}.lc-markdown img{max-width:100%;height:auto;border-radius:var(--radius-md, .375rem)}.lc-markdown del{text-decoration:line-through;color:var(--color-text-secondary, #6b7280)}.lc-markdown__table{width:100%;border-collapse:collapse;margin:1em 0;font-size:var(--font-size-sm, .875rem)}.lc-markdown__table th,.lc-markdown__table td{padding:.5rem .75rem;border:1px solid var(--color-divider, #e5e7eb);text-align:left}.lc-markdown__table th{background-color:var(--color-neutral-50, #f9fafb);font-weight:var(--font-weight-semibold, 600)}.lc-markdown__table tr:hover td{background-color:var(--color-neutral-50, #f9fafb)}.lc-markdown__task{list-style:none;margin-left:-1.5em}.lc-markdown__task input[type=checkbox]{margin-right:.5em;vertical-align:middle}.lc-markdown__anchor{color:var(--color-neutral-400, #9ca3af);text-decoration:none;margin-right:.25em;opacity:0;transition:opacity .15s ease}h1:hover .lc-markdown__anchor,h2:hover .lc-markdown__anchor,h3:hover .lc-markdown__anchor,h4:hover .lc-markdown__anchor,h5:hover .lc-markdown__anchor,h6:hover .lc-markdown__anchor{opacity:1}.lc-markdown lc-code-block{display:block;margin:1em 0}.lc-markdown--compact{font-size:var(--font-size-sm, .875rem);line-height:var(--line-height-normal, 1.5)}.lc-markdown--compact h1{font-size:1.5rem}.lc-markdown--compact h2{font-size:1.25rem}.lc-markdown--compact h3{font-size:1.125rem}.lc-markdown--compact h4{font-size:1rem}.lc-markdown--compact h5,.lc-markdown--compact h6{font-size:.875rem}.lc-markdown--compact h1,.lc-markdown--compact h2,.lc-markdown--compact h3,.lc-markdown--compact h4,.lc-markdown--compact h5,.lc-markdown--compact h6{margin:1em 0 .25em}.lc-markdown--compact p{margin:0 0 .5em}.lc-markdown--compact blockquote{margin:.5em 0;padding:.25em .75em}.lc-markdown--compact ul,.lc-markdown--compact ol{margin:0 0 .5em}\n"], dependencies: [{ kind: "component", type: CodeBlockComponent, selector: "lc-code-block", inputs: ["code", "language", "filename", "showLineNumbers", "showCopy", "showHeader"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
13134
13139
  }
13135
13140
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: MarkdownComponent, decorators: [{
13136
13141
  type: Component,
13137
- args: [{ selector: 'lc-markdown', standalone: true, imports: [CodeBlockComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"containerClasses()\" (click)=\"onLinkClick($event)\">\n @for (part of renderParts(); track part.index) {\n @if (part.type === 'html') {\n <div [innerHTML]=\"part.safeHtml\"></div>\n } @else {\n <lc-code-block\n [code]=\"part.code!\"\n [language]=\"$any(part.lang)\"\n [showLineNumbers]=\"true\"\n [showCopy]=\"true\"\n />\n }\n }\n</div>\n", styles: [".lc-markdown{color:var(--color-text, #111827);font-family:var(--font-family-sans);font-size:var(--font-size-base, 1rem);line-height:var(--line-height-relaxed, 1.75)}.lc-markdown h1,.lc-markdown h2,.lc-markdown h3,.lc-markdown h4,.lc-markdown h5,.lc-markdown h6{color:var(--color-text, #111827);font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-tight, 1.25);margin:1.5em 0 .5em}.lc-markdown h1:first-child,.lc-markdown h2:first-child,.lc-markdown h3:first-child,.lc-markdown h4:first-child,.lc-markdown h5:first-child,.lc-markdown h6:first-child{margin-top:0}.lc-markdown h1{font-size:2rem}.lc-markdown h2{font-size:1.5rem}.lc-markdown h3{font-size:1.25rem}.lc-markdown h4{font-size:1.125rem}.lc-markdown h5{font-size:1rem}.lc-markdown h6{font-size:.875rem}.lc-markdown p{margin:0 0 1em}.lc-markdown a{color:var(--color-primary-600, #2563eb);text-decoration:none}.lc-markdown a:hover{text-decoration:underline}.lc-markdown strong{font-weight:var(--font-weight-semibold, 600)}.lc-markdown code{background-color:var(--color-neutral-100, #f3f4f6);color:var(--color-neutral-800, #1f2937);padding:.125em .375em;border-radius:var(--radius-sm, .25rem);font-family:var(--font-family-mono, monospace);font-size:.875em}.lc-markdown pre{margin:1em 0;overflow-x:auto}.lc-markdown pre code{background:none;padding:0;border-radius:0}.lc-markdown blockquote{margin:1em 0;padding:.5em 1em;border-left:4px solid var(--color-primary-300, #93c5fd);background-color:var(--color-neutral-50, #f9fafb);color:var(--color-text-secondary, #4b5563)}.lc-markdown blockquote p{margin:0}.lc-markdown ul,.lc-markdown ol{margin:0 0 1em;padding-left:1.5em}.lc-markdown li{margin:.25em 0}.lc-markdown hr{border:none;border-top:1px solid var(--color-divider, #e5e7eb);margin:1.5em 0}.lc-markdown img{max-width:100%;height:auto;border-radius:var(--radius-md, .375rem)}.lc-markdown del{text-decoration:line-through;color:var(--color-text-secondary, #6b7280)}.lc-markdown__table{width:100%;border-collapse:collapse;margin:1em 0;font-size:var(--font-size-sm, .875rem)}.lc-markdown__table th,.lc-markdown__table td{padding:.5rem .75rem;border:1px solid var(--color-divider, #e5e7eb);text-align:left}.lc-markdown__table th{background-color:var(--color-neutral-50, #f9fafb);font-weight:var(--font-weight-semibold, 600)}.lc-markdown__table tr:hover td{background-color:var(--color-neutral-50, #f9fafb)}.lc-markdown__task{list-style:none;margin-left:-1.5em}.lc-markdown__task input[type=checkbox]{margin-right:.5em;vertical-align:middle}.lc-markdown__anchor{color:var(--color-neutral-400, #9ca3af);text-decoration:none;margin-right:.25em;opacity:0;transition:opacity .15s ease}h1:hover .lc-markdown__anchor,h2:hover .lc-markdown__anchor,h3:hover .lc-markdown__anchor,h4:hover .lc-markdown__anchor,h5:hover .lc-markdown__anchor,h6:hover .lc-markdown__anchor{opacity:1}.lc-markdown lc-code-block{display:block;margin:1em 0}.lc-markdown--compact{font-size:var(--font-size-sm, .875rem);line-height:var(--line-height-normal, 1.5)}.lc-markdown--compact h1{font-size:1.5rem}.lc-markdown--compact h2{font-size:1.25rem}.lc-markdown--compact h3{font-size:1.125rem}.lc-markdown--compact h4{font-size:1rem}.lc-markdown--compact h5,.lc-markdown--compact h6{font-size:.875rem}.lc-markdown--compact h1,.lc-markdown--compact h2,.lc-markdown--compact h3,.lc-markdown--compact h4,.lc-markdown--compact h5,.lc-markdown--compact h6{margin:1em 0 .25em}.lc-markdown--compact p{margin:0 0 .5em}.lc-markdown--compact blockquote{margin:.5em 0;padding:.25em .75em}.lc-markdown--compact ul,.lc-markdown--compact ol{margin:0 0 .5em}\n"] }]
13142
+ args: [{ selector: 'lc-markdown', standalone: true, imports: [CodeBlockComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div [class]=\"containerClasses()\" (click)=\"onLinkClick($event)\">\n @for (part of renderParts(); track part.index) {\n @if (part.type === 'html') {\n <div [innerHTML]=\"part.safeHtml\"></div>\n } @else {\n <lc-code-block\n [code]=\"part.code!\"\n [language]=\"$any(part.lang)\"\n [showLineNumbers]=\"true\"\n [showCopy]=\"true\"\n />\n }\n }\n</div>\n", styles: [".lc-markdown{color:var(--color-text, #111827);font-family:var(--font-family-sans);font-size:var(--font-size-base, 1rem);line-height:var(--line-height-relaxed, 1.75)}.lc-markdown h1,.lc-markdown h2,.lc-markdown h3,.lc-markdown h4,.lc-markdown h5,.lc-markdown h6{color:var(--color-text, #111827);font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-tight, 1.25);margin:1.5em 0 .5em}.lc-markdown h1:first-child,.lc-markdown h2:first-child,.lc-markdown h3:first-child,.lc-markdown h4:first-child,.lc-markdown h5:first-child,.lc-markdown h6:first-child{margin-top:0}.lc-markdown h1{font-size:2rem}.lc-markdown h2{font-size:1.5rem}.lc-markdown h3{font-size:1.25rem}.lc-markdown h4{font-size:1.125rem}.lc-markdown h5{font-size:1rem}.lc-markdown h6{font-size:.875rem}.lc-markdown p{margin:0 0 1em}.lc-markdown a{color:var(--color-primary-600, #2563eb);text-decoration:none}.lc-markdown a:hover{text-decoration:underline}.lc-markdown strong{font-weight:var(--font-weight-semibold, 600)}.lc-markdown code{background-color:var(--color-neutral-100, #f3f4f6);color:var(--color-neutral-800, #1f2937);padding:.125em .375em;border-radius:var(--radius-sm, .25rem);font-family:var(--font-family-mono, monospace);font-size:.875em}.lc-markdown pre{margin:1em 0;overflow-x:auto}.lc-markdown pre code{background:none;padding:0;border-radius:0}.lc-markdown blockquote{margin:1em 0;padding:.5em 1em;border-left:4px solid var(--color-primary-300, #93c5fd);background-color:var(--color-neutral-50, #f9fafb);color:var(--color-text-secondary, #4b5563)}.lc-markdown blockquote p{margin:0}.lc-markdown ul,.lc-markdown ol{margin:0 0 1em;padding-left:1.5em}.lc-markdown ul{list-style:disc}.lc-markdown ol{list-style:decimal}.lc-markdown li{margin:.25em 0}.lc-markdown hr{border:none;border-top:1px solid var(--color-divider, #e5e7eb);margin:1.5em 0}.lc-markdown img{max-width:100%;height:auto;border-radius:var(--radius-md, .375rem)}.lc-markdown del{text-decoration:line-through;color:var(--color-text-secondary, #6b7280)}.lc-markdown__table{width:100%;border-collapse:collapse;margin:1em 0;font-size:var(--font-size-sm, .875rem)}.lc-markdown__table th,.lc-markdown__table td{padding:.5rem .75rem;border:1px solid var(--color-divider, #e5e7eb);text-align:left}.lc-markdown__table th{background-color:var(--color-neutral-50, #f9fafb);font-weight:var(--font-weight-semibold, 600)}.lc-markdown__table tr:hover td{background-color:var(--color-neutral-50, #f9fafb)}.lc-markdown__task{list-style:none;margin-left:-1.5em}.lc-markdown__task input[type=checkbox]{margin-right:.5em;vertical-align:middle}.lc-markdown__anchor{color:var(--color-neutral-400, #9ca3af);text-decoration:none;margin-right:.25em;opacity:0;transition:opacity .15s ease}h1:hover .lc-markdown__anchor,h2:hover .lc-markdown__anchor,h3:hover .lc-markdown__anchor,h4:hover .lc-markdown__anchor,h5:hover .lc-markdown__anchor,h6:hover .lc-markdown__anchor{opacity:1}.lc-markdown lc-code-block{display:block;margin:1em 0}.lc-markdown--compact{font-size:var(--font-size-sm, .875rem);line-height:var(--line-height-normal, 1.5)}.lc-markdown--compact h1{font-size:1.5rem}.lc-markdown--compact h2{font-size:1.25rem}.lc-markdown--compact h3{font-size:1.125rem}.lc-markdown--compact h4{font-size:1rem}.lc-markdown--compact h5,.lc-markdown--compact h6{font-size:.875rem}.lc-markdown--compact h1,.lc-markdown--compact h2,.lc-markdown--compact h3,.lc-markdown--compact h4,.lc-markdown--compact h5,.lc-markdown--compact h6{margin:1em 0 .25em}.lc-markdown--compact p{margin:0 0 .5em}.lc-markdown--compact blockquote{margin:.5em 0;padding:.25em .75em}.lc-markdown--compact ul,.lc-markdown--compact ol{margin:0 0 .5em}\n"] }]
13138
13143
  }], ctorParameters: () => [], propDecorators: { src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], linkTarget: [{ type: i0.Input, args: [{ isSignal: true, alias: "linkTarget", required: false }] }], sanitize: [{ type: i0.Input, args: [{ isSignal: true, alias: "sanitize", required: false }] }], syntaxHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "syntaxHighlight", required: false }] }], showHeadingAnchors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeadingAnchors", required: false }] }], baseUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "baseUrl", required: false }] }], linkClick: [{ type: i0.Output, args: ["linkClick"] }], rendered: [{ type: i0.Output, args: ["rendered"] }] } });
13139
13144
 
13140
13145
  /**
@@ -13410,11 +13415,11 @@ class LogViewerComponent {
13410
13415
  .replace(/>/g, '&gt;');
13411
13416
  }
13412
13417
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: LogViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13413
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: LogViewerComponent, isStandalone: true, selector: "lc-log-viewer", inputs: { lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, stream$: { classPropertyName: "stream$", publicName: "stream$", isSignal: true, isRequired: false, transformFunction: null }, maxLines: { classPropertyName: "maxLines", publicName: "maxLines", isSignal: true, isRequired: false, transformFunction: null }, autoScroll: { classPropertyName: "autoScroll", publicName: "autoScroll", isSignal: true, isRequired: false, transformFunction: null }, showTimestamps: { classPropertyName: "showTimestamps", publicName: "showTimestamps", isSignal: true, isRequired: false, transformFunction: null }, showLineNumbers: { classPropertyName: "showLineNumbers", publicName: "showLineNumbers", isSignal: true, isRequired: false, transformFunction: null }, ansiColors: { classPropertyName: "ansiColors", publicName: "ansiColors", isSignal: true, isRequired: false, transformFunction: null }, levelFilter: { classPropertyName: "levelFilter", publicName: "levelFilter", isSignal: true, isRequired: false, transformFunction: null }, searchQuery: { classPropertyName: "searchQuery", publicName: "searchQuery", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { lineClick: "lineClick", copyAll: "copyAll", scrollStateChange: "scrollStateChange" }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], ngImport: i0, template: "<div\n [class]=\"containerClasses()\"\n [style.height]=\"height()\"\n tabindex=\"0\"\n (keydown)=\"onKeydown($event)\"\n>\n <!-- Toolbar -->\n <div class=\"lc-log-viewer__toolbar\">\n <div class=\"lc-log-viewer__toolbar-left\">\n @if (stream$()) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n [class.lc-log-viewer__tool-btn--active]=\"paused()\"\n (click)=\"togglePause()\"\n [title]=\"paused() ? 'Resume' : 'Pause'\"\n >\n <lc-icon [name]=\"paused() ? 'play' : 'pause'\" size=\"xs\" />\n </button>\n }\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n (click)=\"clearBuffer()\"\n title=\"Clear\"\n >\n <lc-icon name=\"trash\" size=\"xs\" />\n </button>\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n (click)=\"onCopyAll()\"\n title=\"Copy all\"\n >\n <lc-icon name=\"clipboard-document\" size=\"xs\" />\n </button>\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n [class.lc-log-viewer__tool-btn--active]=\"showSearch()\"\n (click)=\"toggleSearch()\"\n title=\"Search (/)\"\n >\n <lc-icon name=\"magnifying-glass\" size=\"xs\" />\n </button>\n </div>\n\n <div class=\"lc-log-viewer__toolbar-right\">\n <!-- Level filter pills -->\n @if (levelCounts().error > 0) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__level-pill lc-log-viewer__level-pill--error\"\n [class.lc-log-viewer__level-pill--active]=\"internalLevelFilter().has('error')\"\n (click)=\"toggleLevelFilter('error')\"\n >\n {{ levelCounts().error }} errors\n </button>\n }\n @if (levelCounts().warn > 0) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__level-pill lc-log-viewer__level-pill--warn\"\n [class.lc-log-viewer__level-pill--active]=\"internalLevelFilter().has('warn')\"\n (click)=\"toggleLevelFilter('warn')\"\n >\n {{ levelCounts().warn }} warnings\n </button>\n }\n <span class=\"lc-log-viewer__line-count\">{{ filteredLines().length }} lines</span>\n </div>\n </div>\n\n <!-- Search bar -->\n @if (showSearch()) {\n <div class=\"lc-log-viewer__search\">\n <lc-icon name=\"magnifying-glass\" size=\"xs\" />\n <input\n type=\"text\"\n class=\"lc-log-viewer__search-input\"\n placeholder=\"Search logs...\"\n [value]=\"internalSearch()\"\n (input)=\"internalSearch.set($any($event.target).value)\"\n autofocus\n />\n </div>\n }\n\n <!-- Log content (virtualized) -->\n <div\n #scrollContainer\n class=\"lc-log-viewer__content\"\n >\n <div\n class=\"lc-log-viewer__spacer\"\n [style.height.px]=\"visibleRange().totalHeight\"\n >\n <div\n class=\"lc-log-viewer__window\"\n [style.transform]=\"'translateY(' + (visibleRange().start * LINE_HEIGHT) + 'px)'\"\n >\n @for (line of visibleLines(); track line._index) {\n <div\n class=\"lc-log-viewer__line\"\n [class.lc-log-viewer__line--debug]=\"line.level === 'debug'\"\n [class.lc-log-viewer__line--info]=\"line.level === 'info'\"\n [class.lc-log-viewer__line--warn]=\"line.level === 'warn'\"\n [class.lc-log-viewer__line--error]=\"line.level === 'error'\"\n (click)=\"onLineClick(line)\"\n >\n @if (showLineNumbers()) {\n <span class=\"lc-log-viewer__line-num\">{{ line._index + 1 }}</span>\n }\n @if (showTimestamps() && line.timestamp) {\n <span class=\"lc-log-viewer__timestamp\">{{ formatTimestamp(line.timestamp) }}</span>\n }\n @if (line.level) {\n <span class=\"lc-log-viewer__level\">{{ line.level.toUpperCase().padEnd(5) }}</span>\n }\n @if (line.source) {\n <span class=\"lc-log-viewer__source\">[{{ line.source }}]</span>\n }\n <span\n class=\"lc-log-viewer__text\"\n [innerHTML]=\"highlightSearch(parseAnsi(line.text))\"\n ></span>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Jump to bottom button -->\n @if (!atBottom()) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__jump-bottom\"\n (click)=\"scrollToBottom()\"\n >\n <lc-icon name=\"arrow-down\" size=\"xs\" />\n Jump to bottom\n </button>\n }\n</div>\n", styles: [".lc-log-viewer{display:flex;flex-direction:column;border:1px solid var(--color-divider, #e5e7eb);border-radius:var(--radius-md, .375rem);overflow:hidden;font-family:var(--font-family-mono, \"Menlo\", \"Monaco\", \"Courier New\", monospace);font-size:.8125rem;line-height:1}.lc-log-viewer:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-log-viewer--log{background-color:var(--color-background, #ffffff);color:var(--color-text, #111827)}.lc-log-viewer--terminal{background-color:#1e1e2e;color:#cdd6f4;border-color:#313244}.lc-log-viewer__toolbar{display:flex;align-items:center;justify-content:space-between;padding:.375rem .5rem;border-bottom:1px solid var(--color-divider, #e5e7eb);gap:.5rem;flex-shrink:0}.lc-log-viewer--terminal .lc-log-viewer__toolbar{border-bottom-color:#313244;background-color:#181825}.lc-log-viewer__toolbar-left,.lc-log-viewer__toolbar-right{display:flex;align-items:center;gap:.25rem}.lc-log-viewer__tool-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;border-radius:var(--radius-sm, .25rem);cursor:pointer;color:inherit;opacity:.7;transition:opacity .15s,background-color .15s}.lc-log-viewer__tool-btn:hover{opacity:1;background-color:#80808026}.lc-log-viewer__tool-btn--active{opacity:1;background-color:#80808033}.lc-log-viewer__level-pill{font-size:.6875rem;padding:.125rem .5rem;border-radius:9999px;border:none;cursor:pointer;font-family:var(--font-family-sans);transition:opacity .15s;opacity:.6}.lc-log-viewer__level-pill--active{opacity:1}.lc-log-viewer__level-pill--error{background-color:#fecaca;color:#991b1b}.lc-log-viewer--terminal .lc-log-viewer__level-pill--error{background-color:#45202a;color:#f38ba8}.lc-log-viewer__level-pill--warn{background-color:#fef3c7;color:#92400e}.lc-log-viewer--terminal .lc-log-viewer__level-pill--warn{background-color:#3d3520;color:#f9e2af}.lc-log-viewer__line-count{font-size:.6875rem;opacity:.5;font-family:var(--font-family-sans);padding:0 .25rem}.lc-log-viewer__search{display:flex;align-items:center;gap:.375rem;padding:.25rem .5rem;border-bottom:1px solid var(--color-divider, #e5e7eb);flex-shrink:0}.lc-log-viewer--terminal .lc-log-viewer__search{border-bottom-color:#313244;background-color:#181825}.lc-log-viewer__search-input{flex:1;background:transparent;border:none;outline:none;color:inherit;font-family:inherit;font-size:inherit}.lc-log-viewer__search-input::placeholder{opacity:.4}.lc-log-viewer__content{flex:1;overflow-y:auto;overflow-x:auto;position:relative;min-height:0}.lc-log-viewer__spacer{position:relative;width:100%}.lc-log-viewer__window{position:absolute;top:0;left:0;right:0}.lc-log-viewer__line{display:flex;align-items:baseline;gap:.625rem;padding:1px .75rem;height:22px;white-space:nowrap;cursor:pointer;transition:background-color .1s}.lc-log-viewer__line:hover{background-color:#80808014}.lc-log-viewer__line--debug{opacity:.6}.lc-log-viewer--log .lc-log-viewer__line--warn{background-color:#fffbeb}.lc-log-viewer--terminal .lc-log-viewer__line--warn{background-color:#f9e2af0d}.lc-log-viewer--log .lc-log-viewer__line--error{background-color:#fef2f2}.lc-log-viewer--terminal .lc-log-viewer__line--error{background-color:#f38ba814}.lc-log-viewer__line-num{color:inherit;opacity:.3;min-width:3ch;text-align:right;-webkit-user-select:none;user-select:none}.lc-log-viewer__timestamp{color:inherit;opacity:.5;min-width:12ch}.lc-log-viewer__level{min-width:5ch;font-weight:600}.lc-log-viewer__line--debug .lc-log-viewer__level{color:#9ca3af}.lc-log-viewer__line--info .lc-log-viewer__level{color:#3b82f6}.lc-log-viewer__line--warn .lc-log-viewer__level{color:#f59e0b}.lc-log-viewer__line--error .lc-log-viewer__level{color:#ef4444}.lc-log-viewer__line--debug .lc-log-viewer--terminal .lc-log-viewer__level{color:#6c7086}.lc-log-viewer__line--info .lc-log-viewer--terminal .lc-log-viewer__level{color:#89b4fa}.lc-log-viewer__line--warn .lc-log-viewer--terminal .lc-log-viewer__level{color:#f9e2af}.lc-log-viewer__line--error .lc-log-viewer--terminal .lc-log-viewer__level{color:#f38ba8}.lc-log-viewer__source{color:inherit;opacity:.5}.lc-log-viewer__text{flex:1;min-width:0}.lc-log-viewer__match{background-color:#fbbf2480;border-radius:2px;padding:0 1px}.lc-log-viewer--terminal .lc-log-viewer__match{background-color:#f9e2af40}.lc-log-viewer__jump-bottom{position:absolute;bottom:1rem;left:50%;transform:translate(-50%);display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border:1px solid var(--color-divider, #e5e7eb);border-radius:9999px;background-color:var(--color-background, #ffffff);color:var(--color-text, #111827);font-size:.75rem;font-family:var(--font-family-sans);cursor:pointer;box-shadow:0 2px 8px #00000026;z-index:10;transition:background-color .15s}.lc-log-viewer__jump-bottom:hover{background-color:var(--color-neutral-50, #f9fafb)}.lc-log-viewer--terminal .lc-log-viewer__jump-bottom{background-color:#313244;border-color:#45475a;color:#cdd6f4}.lc-log-viewer--terminal .lc-log-viewer__jump-bottom:hover{background-color:#45475a}.ansi-bold{font-weight:700}.ansi-italic{font-style:italic}.ansi-black{color:#1e1e2e}.ansi-red{color:#f38ba8}.ansi-green{color:#a6e3a1}.ansi-yellow{color:#f9e2af}.ansi-blue{color:#89b4fa}.ansi-magenta{color:#cba6f7}.ansi-cyan{color:#94e2d5}.ansi-white{color:#cdd6f4}.ansi-gray{color:#6c7086}.ansi-bright-red{color:#eba0ac}.ansi-bright-green{color:#a6e3a1}.ansi-bright-yellow{color:#f9e2af}.ansi-bright-blue{color:#89dceb}.ansi-bright-magenta{color:#f5c2e7}.ansi-bright-cyan{color:#94e2d5}.ansi-bright-white{color:#bac2de}.lc-log-viewer--log .ansi-black{color:#111827}.lc-log-viewer--log .ansi-red{color:#dc2626}.lc-log-viewer--log .ansi-green{color:#16a34a}.lc-log-viewer--log .ansi-yellow{color:#ca8a04}.lc-log-viewer--log .ansi-blue{color:#2563eb}.lc-log-viewer--log .ansi-magenta{color:#9333ea}.lc-log-viewer--log .ansi-cyan{color:#0891b2}.lc-log-viewer--log .ansi-white{color:#6b7280}.lc-log-viewer--log .ansi-gray{color:#9ca3af}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar{width:8px;height:8px}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-track{background:#181825}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-thumb{background:#45475a;border-radius:4px}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-thumb:hover{background:#585b70}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IconComponent, selector: "lc-icon", inputs: ["name", "variant", "size", "color", "ariaLabel", "decorative"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
13418
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: LogViewerComponent, isStandalone: true, selector: "lc-log-viewer", inputs: { lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, stream$: { classPropertyName: "stream$", publicName: "stream$", isSignal: true, isRequired: false, transformFunction: null }, maxLines: { classPropertyName: "maxLines", publicName: "maxLines", isSignal: true, isRequired: false, transformFunction: null }, autoScroll: { classPropertyName: "autoScroll", publicName: "autoScroll", isSignal: true, isRequired: false, transformFunction: null }, showTimestamps: { classPropertyName: "showTimestamps", publicName: "showTimestamps", isSignal: true, isRequired: false, transformFunction: null }, showLineNumbers: { classPropertyName: "showLineNumbers", publicName: "showLineNumbers", isSignal: true, isRequired: false, transformFunction: null }, ansiColors: { classPropertyName: "ansiColors", publicName: "ansiColors", isSignal: true, isRequired: false, transformFunction: null }, levelFilter: { classPropertyName: "levelFilter", publicName: "levelFilter", isSignal: true, isRequired: false, transformFunction: null }, searchQuery: { classPropertyName: "searchQuery", publicName: "searchQuery", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { lineClick: "lineClick", copyAll: "copyAll", scrollStateChange: "scrollStateChange" }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], ngImport: i0, template: "<div\n [class]=\"containerClasses()\"\n [style.height]=\"height()\"\n tabindex=\"0\"\n (keydown)=\"onKeydown($event)\"\n>\n <!-- Toolbar -->\n <div class=\"lc-log-viewer__toolbar\">\n <div class=\"lc-log-viewer__toolbar-left\">\n @if (stream$()) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n [class.lc-log-viewer__tool-btn--active]=\"paused()\"\n (click)=\"togglePause()\"\n [title]=\"paused() ? 'Resume' : 'Pause'\"\n >\n <lc-icon [name]=\"paused() ? 'play' : 'pause'\" size=\"xs\" />\n </button>\n }\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n (click)=\"clearBuffer()\"\n title=\"Clear\"\n >\n <lc-icon name=\"trash\" size=\"xs\" />\n </button>\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n (click)=\"onCopyAll()\"\n title=\"Copy all\"\n >\n <lc-icon name=\"clipboard-document\" size=\"xs\" />\n </button>\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n [class.lc-log-viewer__tool-btn--active]=\"showSearch()\"\n (click)=\"toggleSearch()\"\n title=\"Search (/)\"\n >\n <lc-icon name=\"magnifying-glass\" size=\"xs\" />\n </button>\n </div>\n\n <div class=\"lc-log-viewer__toolbar-right\">\n <!-- Level filter pills -->\n @if (levelCounts().error > 0) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__level-pill lc-log-viewer__level-pill--error\"\n [class.lc-log-viewer__level-pill--active]=\"internalLevelFilter().has('error')\"\n (click)=\"toggleLevelFilter('error')\"\n >\n {{ levelCounts().error }} errors\n </button>\n }\n @if (levelCounts().warn > 0) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__level-pill lc-log-viewer__level-pill--warn\"\n [class.lc-log-viewer__level-pill--active]=\"internalLevelFilter().has('warn')\"\n (click)=\"toggleLevelFilter('warn')\"\n >\n {{ levelCounts().warn }} warnings\n </button>\n }\n <span class=\"lc-log-viewer__line-count\">{{ filteredLines().length }} lines</span>\n </div>\n </div>\n\n <!-- Search bar -->\n @if (showSearch()) {\n <div class=\"lc-log-viewer__search\">\n <lc-icon name=\"magnifying-glass\" size=\"xs\" />\n <input\n type=\"text\"\n class=\"lc-log-viewer__search-input\"\n placeholder=\"Search logs...\"\n [value]=\"internalSearch()\"\n (input)=\"internalSearch.set($any($event.target).value)\"\n autofocus\n />\n </div>\n }\n\n <!-- Log content (virtualized) -->\n <div\n #scrollContainer\n class=\"lc-log-viewer__content\"\n >\n <div\n class=\"lc-log-viewer__spacer\"\n [style.height.px]=\"visibleRange().totalHeight\"\n >\n <div\n class=\"lc-log-viewer__window\"\n [style.transform]=\"'translateY(' + (visibleRange().start * LINE_HEIGHT) + 'px)'\"\n >\n @for (line of visibleLines(); track line._index) {\n <div\n class=\"lc-log-viewer__line\"\n [class.lc-log-viewer__line--debug]=\"line.level === 'debug'\"\n [class.lc-log-viewer__line--info]=\"line.level === 'info'\"\n [class.lc-log-viewer__line--warn]=\"line.level === 'warn'\"\n [class.lc-log-viewer__line--error]=\"line.level === 'error'\"\n (click)=\"onLineClick(line)\"\n >\n @if (showLineNumbers()) {\n <span class=\"lc-log-viewer__line-num\">{{ line._index + 1 }}</span>\n }\n @if (showTimestamps() && line.timestamp) {\n <span class=\"lc-log-viewer__timestamp\">{{ formatTimestamp(line.timestamp) }}</span>\n }\n @if (line.level) {\n <span class=\"lc-log-viewer__level\">{{ line.level.toUpperCase().padEnd(5) }}</span>\n }\n @if (line.source) {\n <span class=\"lc-log-viewer__source\">[{{ line.source }}]</span>\n }\n <span\n class=\"lc-log-viewer__text\"\n [innerHTML]=\"highlightSearch(parseAnsi(line.text))\"\n ></span>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Jump to bottom button -->\n @if (!atBottom()) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__jump-bottom\"\n (click)=\"scrollToBottom()\"\n >\n <lc-icon name=\"arrow-down\" size=\"xs\" />\n Jump to bottom\n </button>\n }\n</div>\n", styles: [".lc-log-viewer{display:flex;flex-direction:column;border:1px solid var(--color-divider, #e5e7eb);border-radius:var(--radius-md, .375rem);overflow:hidden;font-family:var(--font-family-mono, \"Menlo\", \"Monaco\", \"Courier New\", monospace);font-size:.8125rem;line-height:1}.lc-log-viewer:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-log-viewer--log{background-color:var(--color-background, #ffffff);color:var(--color-text, #111827)}.lc-log-viewer--terminal{background-color:#1e1e2e;color:#cdd6f4;border-color:#313244}.lc-log-viewer__toolbar{display:flex;align-items:center;justify-content:space-between;padding:.375rem .5rem;border-bottom:1px solid var(--color-divider, #e5e7eb);gap:.5rem;flex-shrink:0}.lc-log-viewer--terminal .lc-log-viewer__toolbar{border-bottom-color:#313244;background-color:#181825}.lc-log-viewer__toolbar-left,.lc-log-viewer__toolbar-right{display:flex;align-items:center;gap:.25rem}.lc-log-viewer__tool-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;border-radius:var(--radius-sm, .25rem);cursor:pointer;color:inherit;opacity:.7;transition:opacity .15s,background-color .15s}.lc-log-viewer__tool-btn:hover{opacity:1;background-color:#80808026}.lc-log-viewer__tool-btn--active{opacity:1;background-color:#80808033}.lc-log-viewer__level-pill{font-size:.6875rem;padding:.125rem .5rem;border-radius:9999px;border:none;cursor:pointer;font-family:var(--font-family-sans);transition:opacity .15s;opacity:.6}.lc-log-viewer__level-pill--active{opacity:1}.lc-log-viewer__level-pill--error{background-color:#fecaca;color:#991b1b}.lc-log-viewer--terminal .lc-log-viewer__level-pill--error{background-color:#45202a;color:#f38ba8}.lc-log-viewer__level-pill--warn{background-color:#fef3c7;color:#92400e}.lc-log-viewer--terminal .lc-log-viewer__level-pill--warn{background-color:#3d3520;color:#f9e2af}.lc-log-viewer__line-count{font-size:.6875rem;opacity:.5;font-family:var(--font-family-sans);padding:0 .25rem}.lc-log-viewer__search{display:flex;align-items:center;gap:.375rem;padding:.25rem .5rem;border-bottom:1px solid var(--color-divider, #e5e7eb);flex-shrink:0}.lc-log-viewer--terminal .lc-log-viewer__search{border-bottom-color:#313244;background-color:#181825}.lc-log-viewer__search-input{flex:1;background:transparent;border:none;outline:none;color:inherit;font-family:inherit;font-size:inherit}.lc-log-viewer__search-input::placeholder{opacity:.4}.lc-log-viewer__content{flex:1;overflow-y:auto;overflow-x:auto;position:relative;min-height:0}.lc-log-viewer__spacer{position:relative;width:100%}.lc-log-viewer__window{position:absolute;top:0;left:0;right:0}.lc-log-viewer__line{display:flex;align-items:baseline;gap:.625rem;padding:1px .75rem;height:22px;white-space:nowrap;cursor:pointer;transition:background-color .1s}.lc-log-viewer__line:hover{background-color:#80808014}.lc-log-viewer__line--debug{opacity:.6}.lc-log-viewer--log .lc-log-viewer__line--warn{background-color:#fffbeb}.lc-log-viewer--terminal .lc-log-viewer__line--warn{background-color:#f9e2af0d}.lc-log-viewer--log .lc-log-viewer__line--error{background-color:#fef2f2}.lc-log-viewer--terminal .lc-log-viewer__line--error{background-color:#f38ba814}.lc-log-viewer__line-num{color:inherit;opacity:.3;min-width:3ch;text-align:right;-webkit-user-select:none;user-select:none}.lc-log-viewer__timestamp{color:inherit;opacity:.5;min-width:12ch}.lc-log-viewer__level{min-width:5ch;font-weight:600}.lc-log-viewer__line--debug .lc-log-viewer__level{color:#9ca3af}.lc-log-viewer__line--info .lc-log-viewer__level{color:#3b82f6}.lc-log-viewer__line--warn .lc-log-viewer__level{color:#f59e0b}.lc-log-viewer__line--error .lc-log-viewer__level{color:#ef4444}.lc-log-viewer__line--debug .lc-log-viewer--terminal .lc-log-viewer__level{color:#6c7086}.lc-log-viewer__line--info .lc-log-viewer--terminal .lc-log-viewer__level{color:#89b4fa}.lc-log-viewer__line--warn .lc-log-viewer--terminal .lc-log-viewer__level{color:#f9e2af}.lc-log-viewer__line--error .lc-log-viewer--terminal .lc-log-viewer__level{color:#f38ba8}.lc-log-viewer__source{color:inherit;opacity:.5}.lc-log-viewer__text{flex:1;min-width:0}.lc-log-viewer__match{background-color:#fbbf2480;border-radius:2px;padding:0 1px}.lc-log-viewer--terminal .lc-log-viewer__match{background-color:#f9e2af40}.lc-log-viewer__jump-bottom{position:absolute;bottom:1rem;left:50%;transform:translate(-50%);display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border:1px solid var(--color-divider, #e5e7eb);border-radius:9999px;background-color:var(--color-background, #ffffff);color:var(--color-text, #111827);font-size:.75rem;font-family:var(--font-family-sans);cursor:pointer;box-shadow:0 2px 8px #00000026;z-index:10;transition:background-color .15s}.lc-log-viewer__jump-bottom:hover{background-color:var(--color-neutral-50, #f9fafb)}.lc-log-viewer--terminal .lc-log-viewer__jump-bottom{background-color:#313244;border-color:#45475a;color:#cdd6f4}.lc-log-viewer--terminal .lc-log-viewer__jump-bottom:hover{background-color:#45475a}.ansi-bold{font-weight:700}.ansi-italic{font-style:italic}.ansi-black{color:#1e1e2e}.ansi-red{color:#f38ba8}.ansi-green{color:#a6e3a1}.ansi-yellow{color:#f9e2af}.ansi-blue{color:#89b4fa}.ansi-magenta{color:#cba6f7}.ansi-cyan{color:#94e2d5}.ansi-white{color:#cdd6f4}.ansi-gray{color:#6c7086}.ansi-bright-red{color:#eba0ac}.ansi-bright-green{color:#a6e3a1}.ansi-bright-yellow{color:#f9e2af}.ansi-bright-blue{color:#89dceb}.ansi-bright-magenta{color:#f5c2e7}.ansi-bright-cyan{color:#94e2d5}.ansi-bright-white{color:#bac2de}.lc-log-viewer--log .ansi-black{color:#111827}.lc-log-viewer--log .ansi-red{color:#dc2626}.lc-log-viewer--log .ansi-green{color:#16a34a}.lc-log-viewer--log .ansi-yellow{color:#ca8a04}.lc-log-viewer--log .ansi-blue{color:#2563eb}.lc-log-viewer--log .ansi-magenta{color:#9333ea}.lc-log-viewer--log .ansi-cyan{color:#0891b2}.lc-log-viewer--log .ansi-white{color:#6b7280}.lc-log-viewer--log .ansi-gray{color:#9ca3af}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar{width:8px;height:8px}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-track{background:#181825}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-thumb{background:#45475a;border-radius:4px}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-thumb:hover{background:#585b70}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IconComponent, selector: "lc-icon", inputs: ["name", "variant", "size", "color", "ariaLabel", "decorative"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
13414
13419
  }
13415
13420
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: LogViewerComponent, decorators: [{
13416
13421
  type: Component,
13417
- args: [{ selector: 'lc-log-viewer', standalone: true, imports: [CommonModule, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n [class]=\"containerClasses()\"\n [style.height]=\"height()\"\n tabindex=\"0\"\n (keydown)=\"onKeydown($event)\"\n>\n <!-- Toolbar -->\n <div class=\"lc-log-viewer__toolbar\">\n <div class=\"lc-log-viewer__toolbar-left\">\n @if (stream$()) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n [class.lc-log-viewer__tool-btn--active]=\"paused()\"\n (click)=\"togglePause()\"\n [title]=\"paused() ? 'Resume' : 'Pause'\"\n >\n <lc-icon [name]=\"paused() ? 'play' : 'pause'\" size=\"xs\" />\n </button>\n }\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n (click)=\"clearBuffer()\"\n title=\"Clear\"\n >\n <lc-icon name=\"trash\" size=\"xs\" />\n </button>\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n (click)=\"onCopyAll()\"\n title=\"Copy all\"\n >\n <lc-icon name=\"clipboard-document\" size=\"xs\" />\n </button>\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n [class.lc-log-viewer__tool-btn--active]=\"showSearch()\"\n (click)=\"toggleSearch()\"\n title=\"Search (/)\"\n >\n <lc-icon name=\"magnifying-glass\" size=\"xs\" />\n </button>\n </div>\n\n <div class=\"lc-log-viewer__toolbar-right\">\n <!-- Level filter pills -->\n @if (levelCounts().error > 0) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__level-pill lc-log-viewer__level-pill--error\"\n [class.lc-log-viewer__level-pill--active]=\"internalLevelFilter().has('error')\"\n (click)=\"toggleLevelFilter('error')\"\n >\n {{ levelCounts().error }} errors\n </button>\n }\n @if (levelCounts().warn > 0) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__level-pill lc-log-viewer__level-pill--warn\"\n [class.lc-log-viewer__level-pill--active]=\"internalLevelFilter().has('warn')\"\n (click)=\"toggleLevelFilter('warn')\"\n >\n {{ levelCounts().warn }} warnings\n </button>\n }\n <span class=\"lc-log-viewer__line-count\">{{ filteredLines().length }} lines</span>\n </div>\n </div>\n\n <!-- Search bar -->\n @if (showSearch()) {\n <div class=\"lc-log-viewer__search\">\n <lc-icon name=\"magnifying-glass\" size=\"xs\" />\n <input\n type=\"text\"\n class=\"lc-log-viewer__search-input\"\n placeholder=\"Search logs...\"\n [value]=\"internalSearch()\"\n (input)=\"internalSearch.set($any($event.target).value)\"\n autofocus\n />\n </div>\n }\n\n <!-- Log content (virtualized) -->\n <div\n #scrollContainer\n class=\"lc-log-viewer__content\"\n >\n <div\n class=\"lc-log-viewer__spacer\"\n [style.height.px]=\"visibleRange().totalHeight\"\n >\n <div\n class=\"lc-log-viewer__window\"\n [style.transform]=\"'translateY(' + (visibleRange().start * LINE_HEIGHT) + 'px)'\"\n >\n @for (line of visibleLines(); track line._index) {\n <div\n class=\"lc-log-viewer__line\"\n [class.lc-log-viewer__line--debug]=\"line.level === 'debug'\"\n [class.lc-log-viewer__line--info]=\"line.level === 'info'\"\n [class.lc-log-viewer__line--warn]=\"line.level === 'warn'\"\n [class.lc-log-viewer__line--error]=\"line.level === 'error'\"\n (click)=\"onLineClick(line)\"\n >\n @if (showLineNumbers()) {\n <span class=\"lc-log-viewer__line-num\">{{ line._index + 1 }}</span>\n }\n @if (showTimestamps() && line.timestamp) {\n <span class=\"lc-log-viewer__timestamp\">{{ formatTimestamp(line.timestamp) }}</span>\n }\n @if (line.level) {\n <span class=\"lc-log-viewer__level\">{{ line.level.toUpperCase().padEnd(5) }}</span>\n }\n @if (line.source) {\n <span class=\"lc-log-viewer__source\">[{{ line.source }}]</span>\n }\n <span\n class=\"lc-log-viewer__text\"\n [innerHTML]=\"highlightSearch(parseAnsi(line.text))\"\n ></span>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Jump to bottom button -->\n @if (!atBottom()) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__jump-bottom\"\n (click)=\"scrollToBottom()\"\n >\n <lc-icon name=\"arrow-down\" size=\"xs\" />\n Jump to bottom\n </button>\n }\n</div>\n", styles: [".lc-log-viewer{display:flex;flex-direction:column;border:1px solid var(--color-divider, #e5e7eb);border-radius:var(--radius-md, .375rem);overflow:hidden;font-family:var(--font-family-mono, \"Menlo\", \"Monaco\", \"Courier New\", monospace);font-size:.8125rem;line-height:1}.lc-log-viewer:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-log-viewer--log{background-color:var(--color-background, #ffffff);color:var(--color-text, #111827)}.lc-log-viewer--terminal{background-color:#1e1e2e;color:#cdd6f4;border-color:#313244}.lc-log-viewer__toolbar{display:flex;align-items:center;justify-content:space-between;padding:.375rem .5rem;border-bottom:1px solid var(--color-divider, #e5e7eb);gap:.5rem;flex-shrink:0}.lc-log-viewer--terminal .lc-log-viewer__toolbar{border-bottom-color:#313244;background-color:#181825}.lc-log-viewer__toolbar-left,.lc-log-viewer__toolbar-right{display:flex;align-items:center;gap:.25rem}.lc-log-viewer__tool-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;border-radius:var(--radius-sm, .25rem);cursor:pointer;color:inherit;opacity:.7;transition:opacity .15s,background-color .15s}.lc-log-viewer__tool-btn:hover{opacity:1;background-color:#80808026}.lc-log-viewer__tool-btn--active{opacity:1;background-color:#80808033}.lc-log-viewer__level-pill{font-size:.6875rem;padding:.125rem .5rem;border-radius:9999px;border:none;cursor:pointer;font-family:var(--font-family-sans);transition:opacity .15s;opacity:.6}.lc-log-viewer__level-pill--active{opacity:1}.lc-log-viewer__level-pill--error{background-color:#fecaca;color:#991b1b}.lc-log-viewer--terminal .lc-log-viewer__level-pill--error{background-color:#45202a;color:#f38ba8}.lc-log-viewer__level-pill--warn{background-color:#fef3c7;color:#92400e}.lc-log-viewer--terminal .lc-log-viewer__level-pill--warn{background-color:#3d3520;color:#f9e2af}.lc-log-viewer__line-count{font-size:.6875rem;opacity:.5;font-family:var(--font-family-sans);padding:0 .25rem}.lc-log-viewer__search{display:flex;align-items:center;gap:.375rem;padding:.25rem .5rem;border-bottom:1px solid var(--color-divider, #e5e7eb);flex-shrink:0}.lc-log-viewer--terminal .lc-log-viewer__search{border-bottom-color:#313244;background-color:#181825}.lc-log-viewer__search-input{flex:1;background:transparent;border:none;outline:none;color:inherit;font-family:inherit;font-size:inherit}.lc-log-viewer__search-input::placeholder{opacity:.4}.lc-log-viewer__content{flex:1;overflow-y:auto;overflow-x:auto;position:relative;min-height:0}.lc-log-viewer__spacer{position:relative;width:100%}.lc-log-viewer__window{position:absolute;top:0;left:0;right:0}.lc-log-viewer__line{display:flex;align-items:baseline;gap:.625rem;padding:1px .75rem;height:22px;white-space:nowrap;cursor:pointer;transition:background-color .1s}.lc-log-viewer__line:hover{background-color:#80808014}.lc-log-viewer__line--debug{opacity:.6}.lc-log-viewer--log .lc-log-viewer__line--warn{background-color:#fffbeb}.lc-log-viewer--terminal .lc-log-viewer__line--warn{background-color:#f9e2af0d}.lc-log-viewer--log .lc-log-viewer__line--error{background-color:#fef2f2}.lc-log-viewer--terminal .lc-log-viewer__line--error{background-color:#f38ba814}.lc-log-viewer__line-num{color:inherit;opacity:.3;min-width:3ch;text-align:right;-webkit-user-select:none;user-select:none}.lc-log-viewer__timestamp{color:inherit;opacity:.5;min-width:12ch}.lc-log-viewer__level{min-width:5ch;font-weight:600}.lc-log-viewer__line--debug .lc-log-viewer__level{color:#9ca3af}.lc-log-viewer__line--info .lc-log-viewer__level{color:#3b82f6}.lc-log-viewer__line--warn .lc-log-viewer__level{color:#f59e0b}.lc-log-viewer__line--error .lc-log-viewer__level{color:#ef4444}.lc-log-viewer__line--debug .lc-log-viewer--terminal .lc-log-viewer__level{color:#6c7086}.lc-log-viewer__line--info .lc-log-viewer--terminal .lc-log-viewer__level{color:#89b4fa}.lc-log-viewer__line--warn .lc-log-viewer--terminal .lc-log-viewer__level{color:#f9e2af}.lc-log-viewer__line--error .lc-log-viewer--terminal .lc-log-viewer__level{color:#f38ba8}.lc-log-viewer__source{color:inherit;opacity:.5}.lc-log-viewer__text{flex:1;min-width:0}.lc-log-viewer__match{background-color:#fbbf2480;border-radius:2px;padding:0 1px}.lc-log-viewer--terminal .lc-log-viewer__match{background-color:#f9e2af40}.lc-log-viewer__jump-bottom{position:absolute;bottom:1rem;left:50%;transform:translate(-50%);display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border:1px solid var(--color-divider, #e5e7eb);border-radius:9999px;background-color:var(--color-background, #ffffff);color:var(--color-text, #111827);font-size:.75rem;font-family:var(--font-family-sans);cursor:pointer;box-shadow:0 2px 8px #00000026;z-index:10;transition:background-color .15s}.lc-log-viewer__jump-bottom:hover{background-color:var(--color-neutral-50, #f9fafb)}.lc-log-viewer--terminal .lc-log-viewer__jump-bottom{background-color:#313244;border-color:#45475a;color:#cdd6f4}.lc-log-viewer--terminal .lc-log-viewer__jump-bottom:hover{background-color:#45475a}.ansi-bold{font-weight:700}.ansi-italic{font-style:italic}.ansi-black{color:#1e1e2e}.ansi-red{color:#f38ba8}.ansi-green{color:#a6e3a1}.ansi-yellow{color:#f9e2af}.ansi-blue{color:#89b4fa}.ansi-magenta{color:#cba6f7}.ansi-cyan{color:#94e2d5}.ansi-white{color:#cdd6f4}.ansi-gray{color:#6c7086}.ansi-bright-red{color:#eba0ac}.ansi-bright-green{color:#a6e3a1}.ansi-bright-yellow{color:#f9e2af}.ansi-bright-blue{color:#89dceb}.ansi-bright-magenta{color:#f5c2e7}.ansi-bright-cyan{color:#94e2d5}.ansi-bright-white{color:#bac2de}.lc-log-viewer--log .ansi-black{color:#111827}.lc-log-viewer--log .ansi-red{color:#dc2626}.lc-log-viewer--log .ansi-green{color:#16a34a}.lc-log-viewer--log .ansi-yellow{color:#ca8a04}.lc-log-viewer--log .ansi-blue{color:#2563eb}.lc-log-viewer--log .ansi-magenta{color:#9333ea}.lc-log-viewer--log .ansi-cyan{color:#0891b2}.lc-log-viewer--log .ansi-white{color:#6b7280}.lc-log-viewer--log .ansi-gray{color:#9ca3af}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar{width:8px;height:8px}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-track{background:#181825}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-thumb{background:#45475a;border-radius:4px}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-thumb:hover{background:#585b70}\n"] }]
13422
+ args: [{ selector: 'lc-log-viewer', standalone: true, imports: [CommonModule, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n [class]=\"containerClasses()\"\n [style.height]=\"height()\"\n tabindex=\"0\"\n (keydown)=\"onKeydown($event)\"\n>\n <!-- Toolbar -->\n <div class=\"lc-log-viewer__toolbar\">\n <div class=\"lc-log-viewer__toolbar-left\">\n @if (stream$()) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n [class.lc-log-viewer__tool-btn--active]=\"paused()\"\n (click)=\"togglePause()\"\n [title]=\"paused() ? 'Resume' : 'Pause'\"\n >\n <lc-icon [name]=\"paused() ? 'play' : 'pause'\" size=\"xs\" />\n </button>\n }\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n (click)=\"clearBuffer()\"\n title=\"Clear\"\n >\n <lc-icon name=\"trash\" size=\"xs\" />\n </button>\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n (click)=\"onCopyAll()\"\n title=\"Copy all\"\n >\n <lc-icon name=\"clipboard-document\" size=\"xs\" />\n </button>\n <button\n type=\"button\"\n class=\"lc-log-viewer__tool-btn\"\n [class.lc-log-viewer__tool-btn--active]=\"showSearch()\"\n (click)=\"toggleSearch()\"\n title=\"Search (/)\"\n >\n <lc-icon name=\"magnifying-glass\" size=\"xs\" />\n </button>\n </div>\n\n <div class=\"lc-log-viewer__toolbar-right\">\n <!-- Level filter pills -->\n @if (levelCounts().error > 0) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__level-pill lc-log-viewer__level-pill--error\"\n [class.lc-log-viewer__level-pill--active]=\"internalLevelFilter().has('error')\"\n (click)=\"toggleLevelFilter('error')\"\n >\n {{ levelCounts().error }} errors\n </button>\n }\n @if (levelCounts().warn > 0) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__level-pill lc-log-viewer__level-pill--warn\"\n [class.lc-log-viewer__level-pill--active]=\"internalLevelFilter().has('warn')\"\n (click)=\"toggleLevelFilter('warn')\"\n >\n {{ levelCounts().warn }} warnings\n </button>\n }\n <span class=\"lc-log-viewer__line-count\">{{ filteredLines().length }} lines</span>\n </div>\n </div>\n\n <!-- Search bar -->\n @if (showSearch()) {\n <div class=\"lc-log-viewer__search\">\n <lc-icon name=\"magnifying-glass\" size=\"xs\" />\n <input\n type=\"text\"\n class=\"lc-log-viewer__search-input\"\n placeholder=\"Search logs...\"\n [value]=\"internalSearch()\"\n (input)=\"internalSearch.set($any($event.target).value)\"\n autofocus\n />\n </div>\n }\n\n <!-- Log content (virtualized) -->\n <div\n #scrollContainer\n class=\"lc-log-viewer__content\"\n >\n <div\n class=\"lc-log-viewer__spacer\"\n [style.height.px]=\"visibleRange().totalHeight\"\n >\n <div\n class=\"lc-log-viewer__window\"\n [style.transform]=\"'translateY(' + (visibleRange().start * LINE_HEIGHT) + 'px)'\"\n >\n @for (line of visibleLines(); track line._index) {\n <div\n class=\"lc-log-viewer__line\"\n [class.lc-log-viewer__line--debug]=\"line.level === 'debug'\"\n [class.lc-log-viewer__line--info]=\"line.level === 'info'\"\n [class.lc-log-viewer__line--warn]=\"line.level === 'warn'\"\n [class.lc-log-viewer__line--error]=\"line.level === 'error'\"\n (click)=\"onLineClick(line)\"\n >\n @if (showLineNumbers()) {\n <span class=\"lc-log-viewer__line-num\">{{ line._index + 1 }}</span>\n }\n @if (showTimestamps() && line.timestamp) {\n <span class=\"lc-log-viewer__timestamp\">{{ formatTimestamp(line.timestamp) }}</span>\n }\n @if (line.level) {\n <span class=\"lc-log-viewer__level\">{{ line.level.toUpperCase().padEnd(5) }}</span>\n }\n @if (line.source) {\n <span class=\"lc-log-viewer__source\">[{{ line.source }}]</span>\n }\n <span\n class=\"lc-log-viewer__text\"\n [innerHTML]=\"highlightSearch(parseAnsi(line.text))\"\n ></span>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Jump to bottom button -->\n @if (!atBottom()) {\n <button\n type=\"button\"\n class=\"lc-log-viewer__jump-bottom\"\n (click)=\"scrollToBottom()\"\n >\n <lc-icon name=\"arrow-down\" size=\"xs\" />\n Jump to bottom\n </button>\n }\n</div>\n", styles: [".lc-log-viewer{display:flex;flex-direction:column;border:1px solid var(--color-divider, #e5e7eb);border-radius:var(--radius-md, .375rem);overflow:hidden;font-family:var(--font-family-mono, \"Menlo\", \"Monaco\", \"Courier New\", monospace);font-size:.8125rem;line-height:1}.lc-log-viewer:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-log-viewer--log{background-color:var(--color-background, #ffffff);color:var(--color-text, #111827)}.lc-log-viewer--terminal{background-color:#1e1e2e;color:#cdd6f4;border-color:#313244}.lc-log-viewer__toolbar{display:flex;align-items:center;justify-content:space-between;padding:.375rem .5rem;border-bottom:1px solid var(--color-divider, #e5e7eb);gap:.5rem;flex-shrink:0}.lc-log-viewer--terminal .lc-log-viewer__toolbar{border-bottom-color:#313244;background-color:#181825}.lc-log-viewer__toolbar-left,.lc-log-viewer__toolbar-right{display:flex;align-items:center;gap:.25rem}.lc-log-viewer__tool-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;border-radius:var(--radius-sm, .25rem);cursor:pointer;color:inherit;opacity:.7;transition:opacity .15s,background-color .15s}.lc-log-viewer__tool-btn:hover{opacity:1;background-color:#80808026}.lc-log-viewer__tool-btn--active{opacity:1;background-color:#80808033}.lc-log-viewer__level-pill{font-size:.6875rem;padding:.125rem .5rem;border-radius:9999px;border:none;cursor:pointer;font-family:var(--font-family-sans);transition:opacity .15s;opacity:.6}.lc-log-viewer__level-pill--active{opacity:1}.lc-log-viewer__level-pill--error{background-color:#fecaca;color:#991b1b}.lc-log-viewer--terminal .lc-log-viewer__level-pill--error{background-color:#45202a;color:#f38ba8}.lc-log-viewer__level-pill--warn{background-color:#fef3c7;color:#92400e}.lc-log-viewer--terminal .lc-log-viewer__level-pill--warn{background-color:#3d3520;color:#f9e2af}.lc-log-viewer__line-count{font-size:.6875rem;opacity:.5;font-family:var(--font-family-sans);padding:0 .25rem}.lc-log-viewer__search{display:flex;align-items:center;gap:.375rem;padding:.25rem .5rem;border-bottom:1px solid var(--color-divider, #e5e7eb);flex-shrink:0}.lc-log-viewer--terminal .lc-log-viewer__search{border-bottom-color:#313244;background-color:#181825}.lc-log-viewer__search-input{flex:1;background:transparent;border:none;outline:none;color:inherit;font-family:inherit;font-size:inherit}.lc-log-viewer__search-input::placeholder{opacity:.4}.lc-log-viewer__content{flex:1;overflow-y:auto;overflow-x:auto;position:relative;min-height:0}.lc-log-viewer__spacer{position:relative;width:100%}.lc-log-viewer__window{position:absolute;top:0;left:0;right:0}.lc-log-viewer__line{display:flex;align-items:baseline;gap:.625rem;padding:1px .75rem;height:22px;white-space:nowrap;cursor:pointer;transition:background-color .1s}.lc-log-viewer__line:hover{background-color:#80808014}.lc-log-viewer__line--debug{opacity:.6}.lc-log-viewer--log .lc-log-viewer__line--warn{background-color:#fffbeb}.lc-log-viewer--terminal .lc-log-viewer__line--warn{background-color:#f9e2af0d}.lc-log-viewer--log .lc-log-viewer__line--error{background-color:#fef2f2}.lc-log-viewer--terminal .lc-log-viewer__line--error{background-color:#f38ba814}.lc-log-viewer__line-num{color:inherit;opacity:.3;min-width:3ch;text-align:right;-webkit-user-select:none;user-select:none}.lc-log-viewer__timestamp{color:inherit;opacity:.5;min-width:12ch}.lc-log-viewer__level{min-width:5ch;font-weight:600}.lc-log-viewer__line--debug .lc-log-viewer__level{color:#9ca3af}.lc-log-viewer__line--info .lc-log-viewer__level{color:#3b82f6}.lc-log-viewer__line--warn .lc-log-viewer__level{color:#f59e0b}.lc-log-viewer__line--error .lc-log-viewer__level{color:#ef4444}.lc-log-viewer__line--debug .lc-log-viewer--terminal .lc-log-viewer__level{color:#6c7086}.lc-log-viewer__line--info .lc-log-viewer--terminal .lc-log-viewer__level{color:#89b4fa}.lc-log-viewer__line--warn .lc-log-viewer--terminal .lc-log-viewer__level{color:#f9e2af}.lc-log-viewer__line--error .lc-log-viewer--terminal .lc-log-viewer__level{color:#f38ba8}.lc-log-viewer__source{color:inherit;opacity:.5}.lc-log-viewer__text{flex:1;min-width:0}.lc-log-viewer__match{background-color:#fbbf2480;border-radius:2px;padding:0 1px}.lc-log-viewer--terminal .lc-log-viewer__match{background-color:#f9e2af40}.lc-log-viewer__jump-bottom{position:absolute;bottom:1rem;left:50%;transform:translate(-50%);display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border:1px solid var(--color-divider, #e5e7eb);border-radius:9999px;background-color:var(--color-background, #ffffff);color:var(--color-text, #111827);font-size:.75rem;font-family:var(--font-family-sans);cursor:pointer;box-shadow:0 2px 8px #00000026;z-index:10;transition:background-color .15s}.lc-log-viewer__jump-bottom:hover{background-color:var(--color-neutral-50, #f9fafb)}.lc-log-viewer--terminal .lc-log-viewer__jump-bottom{background-color:#313244;border-color:#45475a;color:#cdd6f4}.lc-log-viewer--terminal .lc-log-viewer__jump-bottom:hover{background-color:#45475a}.ansi-bold{font-weight:700}.ansi-italic{font-style:italic}.ansi-black{color:#1e1e2e}.ansi-red{color:#f38ba8}.ansi-green{color:#a6e3a1}.ansi-yellow{color:#f9e2af}.ansi-blue{color:#89b4fa}.ansi-magenta{color:#cba6f7}.ansi-cyan{color:#94e2d5}.ansi-white{color:#cdd6f4}.ansi-gray{color:#6c7086}.ansi-bright-red{color:#eba0ac}.ansi-bright-green{color:#a6e3a1}.ansi-bright-yellow{color:#f9e2af}.ansi-bright-blue{color:#89dceb}.ansi-bright-magenta{color:#f5c2e7}.ansi-bright-cyan{color:#94e2d5}.ansi-bright-white{color:#bac2de}.lc-log-viewer--log .ansi-black{color:#111827}.lc-log-viewer--log .ansi-red{color:#dc2626}.lc-log-viewer--log .ansi-green{color:#16a34a}.lc-log-viewer--log .ansi-yellow{color:#ca8a04}.lc-log-viewer--log .ansi-blue{color:#2563eb}.lc-log-viewer--log .ansi-magenta{color:#9333ea}.lc-log-viewer--log .ansi-cyan{color:#0891b2}.lc-log-viewer--log .ansi-white{color:#6b7280}.lc-log-viewer--log .ansi-gray{color:#9ca3af}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar{width:8px;height:8px}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-track{background:#181825}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-thumb{background:#45475a;border-radius:4px}.lc-log-viewer--terminal .lc-log-viewer__content::-webkit-scrollbar-thumb:hover{background:#585b70}\n"] }]
13418
13423
  }], ctorParameters: () => [], propDecorators: { scrollContainer: [{
13419
13424
  type: ViewChild,
13420
13425
  args: ['scrollContainer']