@ah-oh/ao-workspaces-design-system 0.0.48 → 0.0.50

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.
@@ -9,7 +9,7 @@ import { ReactiveFormsModule, NG_VALUE_ACCESSOR, FormsModule, FormControl, Valid
9
9
  import * as phosphorIcons from '@ng-icons/phosphor-icons/regular';
10
10
  import { phosphorLockSimple, phosphorWarning, phosphorCaretDown, phosphorSquare, phosphorCheckSquare, phosphorMinusSquare, phosphorCaretLeft, phosphorCaretRight, phosphorCalendarBlank, phosphorDotsThreeVertical, phosphorPlus, phosphorTrash, phosphorDatabase, phosphorMagnifyingGlass, phosphorFunnel, phosphorArrowsDownUp, phosphorCaretUp, phosphorPencilSimple, phosphorEye, phosphorArrowClockwise, phosphorArrowCounterClockwise, phosphorMinus, phosphorLink, phosphorCodeBlock, phosphorQuotes, phosphorListNumbers, phosphorListBullets, phosphorTextHThree, phosphorTextHTwo, phosphorTextHOne, phosphorCode, phosphorTextStrikethrough, phosphorTextItalic, phosphorTextB, phosphorCheck, phosphorX, phosphorSparkle, phosphorMicrophone, phosphorArrowRight, phosphorBell, phosphorBookOpenText, phosphorTestTube, phosphorPaperPlaneRight, phosphorClockCounterClockwise, phosphorSignOut, phosphorRobot, phosphorPuzzlePiece, phosphorGearSix, phosphorPenNib, phosphorTreeStructure, phosphorSquaresFour } from '@ng-icons/phosphor-icons/regular';
11
11
  import { takeUntilDestroyed, toSignal, toObservable } from '@angular/core/rxjs-interop';
12
- import { Subject, debounceTime, BehaviorSubject, map as map$1, catchError, of, tap, takeUntil, firstValueFrom, filter as filter$1, distinctUntilChanged, switchMap, timer, fromEvent } from 'rxjs';
12
+ import { Subject, debounceTime, BehaviorSubject, map as map$1, catchError, of, tap, takeUntil, throttleTime, asyncScheduler, switchMap, firstValueFrom, filter as filter$1, distinctUntilChanged, timer, fromEvent } from 'rxjs';
13
13
  import { Editor } from '@tiptap/core';
14
14
  import Link from '@tiptap/extension-link';
15
15
  import Placeholder from '@tiptap/extension-placeholder';
@@ -21,7 +21,7 @@ import { Product, AccessRole } from '@ah-oh/ao-workspaces-types';
21
21
  import * as i1$1 from '@angular/router';
22
22
  import { NavigationEnd, Router } from '@angular/router';
23
23
  import RecordRTC from 'recordrtc';
24
- import { filter, map, throttleTime } from 'rxjs/operators';
24
+ import { filter, map, throttleTime as throttleTime$1 } from 'rxjs/operators';
25
25
  import { ENTER, COMMA } from '@angular/cdk/keycodes';
26
26
  import { MarkdownComponent } from 'ngx-markdown';
27
27
  import { CdkMenu, CdkMenuItem } from '@angular/cdk/menu';
@@ -2916,6 +2916,7 @@ class AiSearchComponent {
2916
2916
  loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
2917
2917
  error = input(null, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
2918
2918
  panelOpen = model(false, ...(ngDevMode ? [{ debugName: "panelOpen" }] : /* istanbul ignore next */ []));
2919
+ voiceLanguage = input('de-DE', ...(ngDevMode ? [{ debugName: "voiceLanguage" }] : /* istanbul ignore next */ []));
2919
2920
  submit = output();
2920
2921
  voiceStart = output();
2921
2922
  queryChange = output();
@@ -2930,7 +2931,13 @@ class AiSearchComponent {
2930
2931
  caretRightIcon = phosphorCaretRight;
2931
2932
  arrowRightIcon = phosphorArrowRight;
2932
2933
  closeIcon = phosphorX;
2934
+ isVoiceRecording = signal(false, ...(ngDevMode ? [{ debugName: "isVoiceRecording" }] : /* istanbul ignore next */ []));
2935
+ voiceError = signal(null, ...(ngDevMode ? [{ debugName: "voiceError" }] : /* istanbul ignore next */ []));
2936
+ voiceButtonLabel = computed(() => this.isVoiceRecording() ? 'Voice input stoppen' : 'Voice input starten', ...(ngDevMode ? [{ debugName: "voiceButtonLabel" }] : /* istanbul ignore next */ []));
2937
+ effectiveError = computed(() => this.voiceError() ?? this.error(), ...(ngDevMode ? [{ debugName: "effectiveError" }] : /* istanbul ignore next */ []));
2933
2938
  searchInput = viewChild('searchInput', ...(ngDevMode ? [{ debugName: "searchInput" }] : /* istanbul ignore next */ []));
2939
+ speechRecognition = null;
2940
+ currentVoiceTranscript = '';
2934
2941
  hasAnyResults = computed(() => this.resultGroups().length > 0 ||
2935
2942
  this.aiSuggestions().length > 0 ||
2936
2943
  this.pageSuggestion() !== null, ...(ngDevMode ? [{ debugName: "hasAnyResults" }] : /* istanbul ignore next */ []));
@@ -2943,10 +2950,13 @@ class AiSearchComponent {
2943
2950
  return this.placeholder();
2944
2951
  }, ...(ngDevMode ? [{ debugName: "effectivePlaceholder" }] : /* istanbul ignore next */ []));
2945
2952
  hasPanelContent = computed(() => {
2953
+ if (this.effectiveError() !== null) {
2954
+ return true;
2955
+ }
2946
2956
  if (this.value().length === 0) {
2947
2957
  return this.showRecommendedFilters();
2948
2958
  }
2949
- return this.hasAnyResults() || this.loading() || this.error() !== null;
2959
+ return this.hasAnyResults() || this.loading();
2950
2960
  }, ...(ngDevMode ? [{ debugName: "hasPanelContent" }] : /* istanbul ignore next */ []));
2951
2961
  onDocumentClick(event) {
2952
2962
  if (!this.panelOpen()) {
@@ -2963,6 +2973,7 @@ class AiSearchComponent {
2963
2973
  onInput(event) {
2964
2974
  const inputEl = event.target;
2965
2975
  const next = inputEl.value;
2976
+ this.voiceError.set(null);
2966
2977
  this.value.set(next);
2967
2978
  this.panelOpen.set(true);
2968
2979
  this.queryChange.emit(next);
@@ -2984,7 +2995,15 @@ class AiSearchComponent {
2984
2995
  }
2985
2996
  }
2986
2997
  onVoiceClick() {
2998
+ if (this.disabled()) {
2999
+ return;
3000
+ }
3001
+ if (this.isVoiceRecording()) {
3002
+ this.stopVoiceRecognition();
3003
+ return;
3004
+ }
2987
3005
  this.voiceStart.emit();
3006
+ this.startVoiceRecognition();
2988
3007
  }
2989
3008
  onFilterClick(filter) {
2990
3009
  this.activeFilter.set(filter);
@@ -3020,12 +3039,90 @@ class AiSearchComponent {
3020
3039
  }
3021
3040
  const escaped = this.escapeHtml(text);
3022
3041
  const pattern = new RegExp(this.escapeRegex(query), 'gi');
3023
- const highlighted = escaped.replace(pattern, (match) => `<mark class="ai-search__hl">${match}</mark>`);
3042
+ const highlighted = escaped.replace(pattern, match => `<mark class="ai-search__hl">${match}</mark>`);
3024
3043
  return this.sanitizer.bypassSecurityTrustHtml(highlighted);
3025
3044
  }
3026
3045
  focus() {
3027
3046
  this.searchInput()?.nativeElement.focus();
3028
3047
  }
3048
+ startVoiceRecognition() {
3049
+ const Recognition = this.getSpeechRecognitionFactory();
3050
+ if (Recognition === null) {
3051
+ this.showVoiceError('Spracheingabe wird von diesem Browser nicht unterstützt');
3052
+ return;
3053
+ }
3054
+ try {
3055
+ const recognition = new Recognition();
3056
+ this.currentVoiceTranscript = '';
3057
+ recognition.continuous = false;
3058
+ recognition.interimResults = true;
3059
+ recognition.lang = this.voiceLanguage();
3060
+ recognition.onresult = (event) => this.handleVoiceResult(event);
3061
+ recognition.onerror = (event) => this.handleVoiceError(event);
3062
+ recognition.onend = () => this.handleVoiceEnd();
3063
+ this.speechRecognition = recognition;
3064
+ this.isVoiceRecording.set(true);
3065
+ this.voiceError.set(null);
3066
+ recognition.start();
3067
+ }
3068
+ catch (err) {
3069
+ console.warn('[AiSearch] voice input failed', err);
3070
+ this.showVoiceError('Spracheingabe konnte nicht gestartet werden');
3071
+ }
3072
+ }
3073
+ stopVoiceRecognition() {
3074
+ this.speechRecognition?.stop();
3075
+ }
3076
+ handleVoiceResult(event) {
3077
+ const transcript = this.getTranscript(event);
3078
+ if (!transcript) {
3079
+ return;
3080
+ }
3081
+ this.currentVoiceTranscript = transcript;
3082
+ this.value.set(transcript);
3083
+ this.panelOpen.set(true);
3084
+ this.voiceError.set(null);
3085
+ this.queryChange.emit(transcript);
3086
+ }
3087
+ handleVoiceError(event) {
3088
+ if (event.error === 'no-speech') {
3089
+ this.showVoiceError('Keine Sprache erkannt');
3090
+ return;
3091
+ }
3092
+ this.showVoiceError('Spracheingabe fehlgeschlagen');
3093
+ }
3094
+ handleVoiceEnd() {
3095
+ const query = this.currentVoiceTranscript.trim();
3096
+ this.isVoiceRecording.set(false);
3097
+ this.speechRecognition = null;
3098
+ this.currentVoiceTranscript = '';
3099
+ if (!query) {
3100
+ return;
3101
+ }
3102
+ this.submit.emit({ query, isVoiceInput: true, filter: this.activeFilter() });
3103
+ this.panelOpen.set(false);
3104
+ }
3105
+ getTranscript(event) {
3106
+ const parts = [];
3107
+ for (let i = 0; i < event.results.length; i++) {
3108
+ const result = event.results.item(i);
3109
+ if (result.length > 0) {
3110
+ parts.push(result.item(0).transcript);
3111
+ }
3112
+ }
3113
+ return parts.join(' ').trim();
3114
+ }
3115
+ getSpeechRecognitionFactory() {
3116
+ const scope = globalThis;
3117
+ return scope.SpeechRecognition ?? scope.webkitSpeechRecognition ?? null;
3118
+ }
3119
+ showVoiceError(message) {
3120
+ this.isVoiceRecording.set(false);
3121
+ this.currentVoiceTranscript = '';
3122
+ this.speechRecognition = null;
3123
+ this.voiceError.set(message);
3124
+ this.panelOpen.set(true);
3125
+ }
3029
3126
  clearActiveFilter() {
3030
3127
  if (this.activeFilter() === null) {
3031
3128
  return;
@@ -3045,14 +3142,14 @@ class AiSearchComponent {
3045
3142
  return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
3046
3143
  }
3047
3144
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: AiSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3048
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: AiSearchComponent, isStandalone: true, selector: "ao-ai-search", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, recommendedFilters: { classPropertyName: "recommendedFilters", publicName: "recommendedFilters", isSignal: true, isRequired: false, transformFunction: null }, activeFilter: { classPropertyName: "activeFilter", publicName: "activeFilter", isSignal: true, isRequired: false, transformFunction: null }, resultGroups: { classPropertyName: "resultGroups", publicName: "resultGroups", isSignal: true, isRequired: false, transformFunction: null }, pageSuggestion: { classPropertyName: "pageSuggestion", publicName: "pageSuggestion", isSignal: true, isRequired: false, transformFunction: null }, aiSuggestions: { classPropertyName: "aiSuggestions", publicName: "aiSuggestions", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, panelOpen: { classPropertyName: "panelOpen", publicName: "panelOpen", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", activeFilter: "activeFilterChange", panelOpen: "panelOpenChange", submit: "submit", voiceStart: "voiceStart", queryChange: "queryChange", filterSelect: "filterSelect", filterClear: "filterClear", resultSelect: "resultSelect", aiSuggestionSelect: "aiSuggestionSelect", pageSuggestionSelect: "pageSuggestionSelect", viewAllClick: "viewAllClick" }, host: { listeners: { "document:click": "onDocumentClick($event)" }, classAttribute: "ao-ai-search" }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ai-search\" [class.ai-search--open]=\"panelOpen() && hasPanelContent()\">\n <ao-icon [svg]=\"sparkleIcon\" size=\"sm\" class=\"ai-search__icon-left\" />\n @if (activeFilter(); as f) {\n <span class=\"ai-search__active-chip\" role=\"status\">\n <span class=\"ai-search__active-chip-label\">{{ f.label }}</span>\n <button\n type=\"button\"\n class=\"ai-search__active-chip-remove\"\n [disabled]=\"disabled()\"\n (click)=\"onChipRemove($event)\"\n [attr.aria-label]=\"'Filter ' + f.label + ' entfernen'\"\n >\n <ao-icon [svg]=\"closeIcon\" size=\"xs\" />\n </button>\n </span>\n }\n <input\n #searchInput\n type=\"text\"\n class=\"ai-search__input\"\n [placeholder]=\"effectivePlaceholder()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n (focus)=\"onFocus()\"\n (input)=\"onInput($event)\"\n (keydown.enter)=\"onEnter()\"\n (keydown.escape)=\"onEscape()\"\n (keydown.backspace)=\"onBackspace($event)\"\n aria-label=\"AI Search\"\n autocomplete=\"off\"\n />\n <button\n type=\"button\"\n class=\"ai-search__voice-btn\"\n [disabled]=\"disabled()\"\n (click)=\"onVoiceClick()\"\n aria-label=\"Voice input\"\n >\n <ao-icon [svg]=\"micIcon\" size=\"sm\" />\n </button>\n</div>\n\n@if (panelOpen() && hasPanelContent()) {\n <div class=\"ai-search__panel\" role=\"listbox\">\n @if (value().length === 0) {\n @if (showRecommendedFilters()) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">Empfohlene Filter</h4>\n <div class=\"ai-search__filter-chips\">\n @for (f of recommendedFilters(); track f.id) {\n <button\n type=\"button\"\n class=\"ai-search__filter-chip\"\n (click)=\"onFilterClick(f)\"\n >\n {{ f.label }}\n </button>\n }\n </div>\n </div>\n }\n } @else {\n @if (error(); as msg) {\n <div class=\"ai-search__panel-section ai-search__status ai-search__status--error\">\n {{ msg }}\n </div>\n } @else if (loading() && !hasAnyResults()) {\n <div class=\"ai-search__panel-section ai-search__status\">\n <span class=\"ai-search__spinner\" aria-hidden=\"true\"></span>\n Suche l\u00E4uft\u2026\n </div>\n }\n @if (pageSuggestion(); as p) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">Pfad</h4>\n <button\n type=\"button\"\n class=\"ai-search__path-row\"\n (click)=\"onPathClick(p)\"\n >\n @for (crumb of p.breadcrumb; track crumb; let last = $last) {\n <span class=\"ai-search__path-crumb\">{{ crumb }}</span>\n @if (!last) {\n <ao-icon [svg]=\"caretRightIcon\" size=\"sm\" class=\"ai-search__path-sep\" />\n }\n }\n </button>\n </div>\n }\n @for (group of resultGroups(); track group.type) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">{{ group.label }}</h4>\n @for (r of group.results; track r.id) {\n <button\n type=\"button\"\n class=\"ai-search__result-row\"\n (click)=\"onResultClick(r)\"\n >\n <span class=\"ai-search__result-primary\" [innerHTML]=\"highlight(r.primary)\"></span>\n </button>\n }\n </div>\n }\n @if (aiSuggestions().length) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">KI-Vorschl\u00E4ge</h4>\n @for (r of aiSuggestions(); track r.id) {\n <button\n type=\"button\"\n class=\"ai-search__ai-row\"\n (click)=\"onAiSuggestionClick(r)\"\n >\n <ao-icon [svg]=\"sparkleIcon\" size=\"sm\" class=\"ai-search__ai-icon\" />\n <span [innerHTML]=\"highlight(r.primary)\"></span>\n </button>\n }\n </div>\n }\n @if (hasAnyResults()) {\n <button\n type=\"button\"\n class=\"ai-search__view-all\"\n (click)=\"onViewAll()\"\n >\n <span>Alle Ergebnisse anzeigen</span>\n <ao-icon [svg]=\"arrowRightIcon\" size=\"sm\" />\n </button>\n }\n }\n </div>\n}\n", styles: [":host{display:inline-block;position:relative}.ai-search{display:flex;align-items:center;gap:10px;width:400px;height:35px;padding:0 10px 0 15px;border:1px solid #223cff;background-color:#fff;border-radius:9999px;position:relative;z-index:2}.ai-search__icon-left{color:#223cff;flex-shrink:0}.ai-search__active-chip{display:inline-flex;align-items:center;gap:5px;height:23px;padding:0 5px 0 10px;background-color:#223cff14;color:#223cff;border:1px solid #223cff;border-radius:9999px;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;flex-shrink:0;max-width:50%}.ai-search__active-chip-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}.ai-search__active-chip-remove{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;padding:0;border:none;border-radius:50%;background-color:transparent;color:inherit;cursor:pointer;flex-shrink:0}.ai-search__active-chip-remove:hover:not(:disabled){background-color:#00000014}.ai-search__active-chip-remove:focus-visible{outline:3px solid #223cff;outline-offset:1px}.ai-search__active-chip-remove:disabled{cursor:not-allowed;opacity:.5}.ai-search__input{flex:1;height:100%;padding:0;border:none;background:transparent;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__input::placeholder{color:#212121}.ai-search__input:focus{outline:none}.ai-search__input:disabled{cursor:not-allowed}.ai-search__voice-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;border-radius:50%;background-color:transparent;color:#212121;cursor:pointer;transition:color .2s ease;flex-shrink:0}.ai-search__voice-btn:hover:not(:disabled){color:#223cff}.ai-search__voice-btn:focus-visible{outline:3px solid #223cff;outline-offset:2px}.ai-search__voice-btn:disabled{opacity:.5;cursor:not-allowed}.ai-search__panel{position:absolute;top:45px;left:0;width:400px;max-height:70vh;overflow-y:auto;background-color:#fff;border:1px solid #e9e9e9;border-radius:5px;box-shadow:0 4px 16px #2121211a;z-index:10}.ai-search__panel-section{padding:15px 0;border-bottom:1px solid #e9e9e9}.ai-search__panel-section:last-of-type{border-bottom:none}.ai-search__section-title{margin:0 0 10px;padding:0 15px;font-size:12px;line-height:18px;letter-spacing:0;color:#909090;font-weight:500}.ai-search__filter-chips{display:flex;flex-direction:column;align-items:flex-start;gap:10px;padding:0 15px}.ai-search__filter-chip{display:inline-flex;align-items:center;padding:5px 15px;border:1px solid #e9e9e9;background-color:#fff;color:#212121;cursor:pointer;border-radius:9999px;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;transition:background-color .15s ease,border-color .15s ease}.ai-search__filter-chip:hover{background-color:#f3f3f3;border-color:#909090}.ai-search__filter-chip:focus-visible{outline:3px solid #223cff;outline-offset:2px}.ai-search__path-row,.ai-search__result-row,.ai-search__ai-row{display:flex;align-items:center;width:100%;padding:10px 15px;border:none;background:transparent;text-align:left;cursor:pointer;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;color:#212121}.ai-search__path-row:hover,.ai-search__result-row:hover,.ai-search__ai-row:hover{background-color:#f3f3f3}.ai-search__path-row:focus-visible,.ai-search__result-row:focus-visible,.ai-search__ai-row:focus-visible{outline:3px solid #223cff;outline-offset:-2px}.ai-search__path-row{gap:10px}.ai-search__path-sep{color:#909090}.ai-search__result-row{display:block;width:100%}.ai-search__result-primary{display:block;width:100%;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-search__ai-row{gap:10px}.ai-search__ai-icon{color:#223cff;flex-shrink:0}.ai-search__hl{background-color:#fff59d;color:inherit;padding:0;border-radius:2px}.ai-search__status{display:flex;align-items:center;gap:10px;padding:15px;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__spinner{display:inline-block;width:14px;height:14px;border:2px solid #e9e9e9;border-top-color:#223cff;border-radius:50%;animation:ao-ai-search-spin .8s linear infinite}@keyframes ao-ai-search-spin{to{transform:rotate(360deg)}}.ai-search__view-all{display:flex;align-items:center;justify-content:space-between;width:100%;padding:15px;border:none;border-top:1px solid #e9e9e9;background:transparent;cursor:pointer;text-align:left;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__view-all:hover{background-color:#f3f3f3}.ai-search__view-all:focus-visible{outline:3px solid #223cff;outline-offset:-2px}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "ao-icon", inputs: ["svg", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3145
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: AiSearchComponent, isStandalone: true, selector: "ao-ai-search", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, recommendedFilters: { classPropertyName: "recommendedFilters", publicName: "recommendedFilters", isSignal: true, isRequired: false, transformFunction: null }, activeFilter: { classPropertyName: "activeFilter", publicName: "activeFilter", isSignal: true, isRequired: false, transformFunction: null }, resultGroups: { classPropertyName: "resultGroups", publicName: "resultGroups", isSignal: true, isRequired: false, transformFunction: null }, pageSuggestion: { classPropertyName: "pageSuggestion", publicName: "pageSuggestion", isSignal: true, isRequired: false, transformFunction: null }, aiSuggestions: { classPropertyName: "aiSuggestions", publicName: "aiSuggestions", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, panelOpen: { classPropertyName: "panelOpen", publicName: "panelOpen", isSignal: true, isRequired: false, transformFunction: null }, voiceLanguage: { classPropertyName: "voiceLanguage", publicName: "voiceLanguage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", activeFilter: "activeFilterChange", panelOpen: "panelOpenChange", submit: "submit", voiceStart: "voiceStart", queryChange: "queryChange", filterSelect: "filterSelect", filterClear: "filterClear", resultSelect: "resultSelect", aiSuggestionSelect: "aiSuggestionSelect", pageSuggestionSelect: "pageSuggestionSelect", viewAllClick: "viewAllClick" }, host: { listeners: { "document:click": "onDocumentClick($event)" }, classAttribute: "ao-ai-search" }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ai-search\" [class.ai-search--open]=\"panelOpen() && hasPanelContent()\">\n <ao-icon [svg]=\"sparkleIcon\" size=\"sm\" class=\"ai-search__icon-left\" />\n @if (activeFilter(); as f) {\n <span class=\"ai-search__active-chip\" role=\"status\">\n <span class=\"ai-search__active-chip-label\">{{ f.label }}</span>\n <button\n type=\"button\"\n class=\"ai-search__active-chip-remove\"\n [disabled]=\"disabled()\"\n (click)=\"onChipRemove($event)\"\n [attr.aria-label]=\"'Filter ' + f.label + ' entfernen'\"\n >\n <ao-icon [svg]=\"closeIcon\" size=\"xs\" />\n </button>\n </span>\n }\n <input\n #searchInput\n type=\"text\"\n class=\"ai-search__input\"\n [placeholder]=\"effectivePlaceholder()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n (focus)=\"onFocus()\"\n (input)=\"onInput($event)\"\n (keydown.enter)=\"onEnter()\"\n (keydown.escape)=\"onEscape()\"\n (keydown.backspace)=\"onBackspace($event)\"\n aria-label=\"AI Search\"\n autocomplete=\"off\"\n />\n <button\n type=\"button\"\n class=\"ai-search__voice-btn\"\n [class.ai-search__voice-btn--recording]=\"isVoiceRecording()\"\n [disabled]=\"disabled()\"\n (click)=\"onVoiceClick()\"\n [attr.aria-label]=\"voiceButtonLabel()\"\n [attr.aria-pressed]=\"isVoiceRecording()\"\n >\n <ao-icon [svg]=\"micIcon\" size=\"sm\" />\n </button>\n</div>\n\n@if (panelOpen() && hasPanelContent()) {\n <div class=\"ai-search__panel\" role=\"listbox\">\n @if (effectiveError(); as msg) {\n <div class=\"ai-search__panel-section ai-search__status ai-search__status--error\">\n {{ msg }}\n </div>\n } @else if (value().length === 0) {\n @if (showRecommendedFilters()) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">Empfohlene Filter</h4>\n <div class=\"ai-search__filter-chips\">\n @for (f of recommendedFilters(); track f.id) {\n <button type=\"button\" class=\"ai-search__filter-chip\" (click)=\"onFilterClick(f)\">\n {{ f.label }}\n </button>\n }\n </div>\n </div>\n }\n } @else {\n @if (loading() && !hasAnyResults()) {\n <div class=\"ai-search__panel-section ai-search__status\">\n <span class=\"ai-search__spinner\" aria-hidden=\"true\"></span>\n Suche l\u00E4uft\u2026\n </div>\n }\n @if (pageSuggestion(); as p) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">Pfad</h4>\n <button type=\"button\" class=\"ai-search__path-row\" (click)=\"onPathClick(p)\">\n @for (crumb of p.breadcrumb; track crumb; let last = $last) {\n <span class=\"ai-search__path-crumb\">{{ crumb }}</span>\n @if (!last) {\n <ao-icon [svg]=\"caretRightIcon\" size=\"sm\" class=\"ai-search__path-sep\" />\n }\n }\n </button>\n </div>\n }\n @for (group of resultGroups(); track group.type) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">{{ group.label }}</h4>\n @for (r of group.results; track r.id) {\n <button type=\"button\" class=\"ai-search__result-row\" (click)=\"onResultClick(r)\">\n <span class=\"ai-search__result-primary\" [innerHTML]=\"highlight(r.primary)\"></span>\n </button>\n }\n </div>\n }\n @if (aiSuggestions().length) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">KI-Vorschl\u00E4ge</h4>\n @for (r of aiSuggestions(); track r.id) {\n <button type=\"button\" class=\"ai-search__ai-row\" (click)=\"onAiSuggestionClick(r)\">\n <ao-icon [svg]=\"sparkleIcon\" size=\"sm\" class=\"ai-search__ai-icon\" />\n <span [innerHTML]=\"highlight(r.primary)\"></span>\n </button>\n }\n </div>\n }\n @if (hasAnyResults()) {\n <button type=\"button\" class=\"ai-search__view-all\" (click)=\"onViewAll()\">\n <span>Alle Ergebnisse anzeigen</span>\n <ao-icon [svg]=\"arrowRightIcon\" size=\"sm\" />\n </button>\n }\n }\n </div>\n}\n", styles: [":host{display:inline-block;position:relative}.ai-search{display:flex;align-items:center;gap:10px;width:400px;height:35px;padding:0 10px 0 15px;border:1px solid #223cff;background-color:#fff;border-radius:9999px;position:relative;z-index:2}.ai-search__icon-left{color:#223cff;flex-shrink:0}.ai-search__active-chip{display:inline-flex;align-items:center;gap:5px;height:23px;padding:0 5px 0 10px;background-color:#223cff14;color:#223cff;border:1px solid #223cff;border-radius:9999px;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;flex-shrink:0;max-width:50%}.ai-search__active-chip-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}.ai-search__active-chip-remove{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;padding:0;border:none;border-radius:50%;background-color:transparent;color:inherit;cursor:pointer;flex-shrink:0}.ai-search__active-chip-remove:hover:not(:disabled){background-color:#00000014}.ai-search__active-chip-remove:focus-visible{outline:3px solid #223cff;outline-offset:1px}.ai-search__active-chip-remove:disabled{cursor:not-allowed;opacity:.5}.ai-search__input{flex:1;height:100%;padding:0;border:none;background:transparent;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__input::placeholder{color:#212121}.ai-search__input:focus{outline:none}.ai-search__input:disabled{cursor:not-allowed}.ai-search__voice-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;border-radius:50%;background-color:transparent;color:#212121;cursor:pointer;transition:color .2s ease;flex-shrink:0}.ai-search__voice-btn:hover:not(:disabled){color:#223cff}.ai-search__voice-btn--recording{color:#223cff;background-color:#223cff14}.ai-search__voice-btn:focus-visible{outline:3px solid #223cff;outline-offset:2px}.ai-search__voice-btn:disabled{opacity:.5;cursor:not-allowed}.ai-search__panel{position:absolute;top:45px;left:0;width:400px;max-height:70vh;overflow-y:auto;background-color:#fff;border:1px solid #e9e9e9;border-radius:5px;box-shadow:0 4px 16px #2121211a;z-index:10}.ai-search__panel-section{padding:15px 0;border-bottom:1px solid #e9e9e9}.ai-search__panel-section:last-of-type{border-bottom:none}.ai-search__section-title{margin:0 0 10px;padding:0 15px;font-size:12px;line-height:18px;letter-spacing:0;color:#909090;font-weight:500}.ai-search__filter-chips{display:flex;flex-direction:column;align-items:flex-start;gap:10px;padding:0 15px}.ai-search__filter-chip{display:inline-flex;align-items:center;padding:5px 15px;border:1px solid #e9e9e9;background-color:#fff;color:#212121;cursor:pointer;border-radius:9999px;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;transition:background-color .15s ease,border-color .15s ease}.ai-search__filter-chip:hover{background-color:#f3f3f3;border-color:#909090}.ai-search__filter-chip:focus-visible{outline:3px solid #223cff;outline-offset:2px}.ai-search__path-row,.ai-search__result-row,.ai-search__ai-row{display:flex;align-items:center;width:100%;padding:10px 15px;border:none;background:transparent;text-align:left;cursor:pointer;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;color:#212121}.ai-search__path-row:hover,.ai-search__result-row:hover,.ai-search__ai-row:hover{background-color:#f3f3f3}.ai-search__path-row:focus-visible,.ai-search__result-row:focus-visible,.ai-search__ai-row:focus-visible{outline:3px solid #223cff;outline-offset:-2px}.ai-search__path-row{gap:10px}.ai-search__path-sep{color:#909090}.ai-search__result-row{display:block;width:100%}.ai-search__result-primary{display:block;width:100%;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-search__ai-row{gap:10px}.ai-search__ai-icon{color:#223cff;flex-shrink:0}.ai-search__hl{background-color:#fff59d;color:inherit;padding:0;border-radius:2px}.ai-search__status{display:flex;align-items:center;gap:10px;padding:15px;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__status--error{color:#ff004d}.ai-search__spinner{display:inline-block;width:14px;height:14px;border:2px solid #e9e9e9;border-top-color:#223cff;border-radius:50%;animation:ao-ai-search-spin .8s linear infinite}@keyframes ao-ai-search-spin{to{transform:rotate(360deg)}}.ai-search__view-all{display:flex;align-items:center;justify-content:space-between;width:100%;padding:15px;border:none;border-top:1px solid #e9e9e9;background:transparent;cursor:pointer;text-align:left;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__view-all:hover{background-color:#f3f3f3}.ai-search__view-all:focus-visible{outline:3px solid #223cff;outline-offset:-2px}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "ao-icon", inputs: ["svg", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3049
3146
  }
3050
3147
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: AiSearchComponent, decorators: [{
3051
3148
  type: Component,
3052
3149
  args: [{ selector: 'ao-ai-search', imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
3053
3150
  class: 'ao-ai-search',
3054
- }, template: "<div class=\"ai-search\" [class.ai-search--open]=\"panelOpen() && hasPanelContent()\">\n <ao-icon [svg]=\"sparkleIcon\" size=\"sm\" class=\"ai-search__icon-left\" />\n @if (activeFilter(); as f) {\n <span class=\"ai-search__active-chip\" role=\"status\">\n <span class=\"ai-search__active-chip-label\">{{ f.label }}</span>\n <button\n type=\"button\"\n class=\"ai-search__active-chip-remove\"\n [disabled]=\"disabled()\"\n (click)=\"onChipRemove($event)\"\n [attr.aria-label]=\"'Filter ' + f.label + ' entfernen'\"\n >\n <ao-icon [svg]=\"closeIcon\" size=\"xs\" />\n </button>\n </span>\n }\n <input\n #searchInput\n type=\"text\"\n class=\"ai-search__input\"\n [placeholder]=\"effectivePlaceholder()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n (focus)=\"onFocus()\"\n (input)=\"onInput($event)\"\n (keydown.enter)=\"onEnter()\"\n (keydown.escape)=\"onEscape()\"\n (keydown.backspace)=\"onBackspace($event)\"\n aria-label=\"AI Search\"\n autocomplete=\"off\"\n />\n <button\n type=\"button\"\n class=\"ai-search__voice-btn\"\n [disabled]=\"disabled()\"\n (click)=\"onVoiceClick()\"\n aria-label=\"Voice input\"\n >\n <ao-icon [svg]=\"micIcon\" size=\"sm\" />\n </button>\n</div>\n\n@if (panelOpen() && hasPanelContent()) {\n <div class=\"ai-search__panel\" role=\"listbox\">\n @if (value().length === 0) {\n @if (showRecommendedFilters()) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">Empfohlene Filter</h4>\n <div class=\"ai-search__filter-chips\">\n @for (f of recommendedFilters(); track f.id) {\n <button\n type=\"button\"\n class=\"ai-search__filter-chip\"\n (click)=\"onFilterClick(f)\"\n >\n {{ f.label }}\n </button>\n }\n </div>\n </div>\n }\n } @else {\n @if (error(); as msg) {\n <div class=\"ai-search__panel-section ai-search__status ai-search__status--error\">\n {{ msg }}\n </div>\n } @else if (loading() && !hasAnyResults()) {\n <div class=\"ai-search__panel-section ai-search__status\">\n <span class=\"ai-search__spinner\" aria-hidden=\"true\"></span>\n Suche l\u00E4uft\u2026\n </div>\n }\n @if (pageSuggestion(); as p) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">Pfad</h4>\n <button\n type=\"button\"\n class=\"ai-search__path-row\"\n (click)=\"onPathClick(p)\"\n >\n @for (crumb of p.breadcrumb; track crumb; let last = $last) {\n <span class=\"ai-search__path-crumb\">{{ crumb }}</span>\n @if (!last) {\n <ao-icon [svg]=\"caretRightIcon\" size=\"sm\" class=\"ai-search__path-sep\" />\n }\n }\n </button>\n </div>\n }\n @for (group of resultGroups(); track group.type) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">{{ group.label }}</h4>\n @for (r of group.results; track r.id) {\n <button\n type=\"button\"\n class=\"ai-search__result-row\"\n (click)=\"onResultClick(r)\"\n >\n <span class=\"ai-search__result-primary\" [innerHTML]=\"highlight(r.primary)\"></span>\n </button>\n }\n </div>\n }\n @if (aiSuggestions().length) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">KI-Vorschl\u00E4ge</h4>\n @for (r of aiSuggestions(); track r.id) {\n <button\n type=\"button\"\n class=\"ai-search__ai-row\"\n (click)=\"onAiSuggestionClick(r)\"\n >\n <ao-icon [svg]=\"sparkleIcon\" size=\"sm\" class=\"ai-search__ai-icon\" />\n <span [innerHTML]=\"highlight(r.primary)\"></span>\n </button>\n }\n </div>\n }\n @if (hasAnyResults()) {\n <button\n type=\"button\"\n class=\"ai-search__view-all\"\n (click)=\"onViewAll()\"\n >\n <span>Alle Ergebnisse anzeigen</span>\n <ao-icon [svg]=\"arrowRightIcon\" size=\"sm\" />\n </button>\n }\n }\n </div>\n}\n", styles: [":host{display:inline-block;position:relative}.ai-search{display:flex;align-items:center;gap:10px;width:400px;height:35px;padding:0 10px 0 15px;border:1px solid #223cff;background-color:#fff;border-radius:9999px;position:relative;z-index:2}.ai-search__icon-left{color:#223cff;flex-shrink:0}.ai-search__active-chip{display:inline-flex;align-items:center;gap:5px;height:23px;padding:0 5px 0 10px;background-color:#223cff14;color:#223cff;border:1px solid #223cff;border-radius:9999px;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;flex-shrink:0;max-width:50%}.ai-search__active-chip-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}.ai-search__active-chip-remove{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;padding:0;border:none;border-radius:50%;background-color:transparent;color:inherit;cursor:pointer;flex-shrink:0}.ai-search__active-chip-remove:hover:not(:disabled){background-color:#00000014}.ai-search__active-chip-remove:focus-visible{outline:3px solid #223cff;outline-offset:1px}.ai-search__active-chip-remove:disabled{cursor:not-allowed;opacity:.5}.ai-search__input{flex:1;height:100%;padding:0;border:none;background:transparent;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__input::placeholder{color:#212121}.ai-search__input:focus{outline:none}.ai-search__input:disabled{cursor:not-allowed}.ai-search__voice-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;border-radius:50%;background-color:transparent;color:#212121;cursor:pointer;transition:color .2s ease;flex-shrink:0}.ai-search__voice-btn:hover:not(:disabled){color:#223cff}.ai-search__voice-btn:focus-visible{outline:3px solid #223cff;outline-offset:2px}.ai-search__voice-btn:disabled{opacity:.5;cursor:not-allowed}.ai-search__panel{position:absolute;top:45px;left:0;width:400px;max-height:70vh;overflow-y:auto;background-color:#fff;border:1px solid #e9e9e9;border-radius:5px;box-shadow:0 4px 16px #2121211a;z-index:10}.ai-search__panel-section{padding:15px 0;border-bottom:1px solid #e9e9e9}.ai-search__panel-section:last-of-type{border-bottom:none}.ai-search__section-title{margin:0 0 10px;padding:0 15px;font-size:12px;line-height:18px;letter-spacing:0;color:#909090;font-weight:500}.ai-search__filter-chips{display:flex;flex-direction:column;align-items:flex-start;gap:10px;padding:0 15px}.ai-search__filter-chip{display:inline-flex;align-items:center;padding:5px 15px;border:1px solid #e9e9e9;background-color:#fff;color:#212121;cursor:pointer;border-radius:9999px;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;transition:background-color .15s ease,border-color .15s ease}.ai-search__filter-chip:hover{background-color:#f3f3f3;border-color:#909090}.ai-search__filter-chip:focus-visible{outline:3px solid #223cff;outline-offset:2px}.ai-search__path-row,.ai-search__result-row,.ai-search__ai-row{display:flex;align-items:center;width:100%;padding:10px 15px;border:none;background:transparent;text-align:left;cursor:pointer;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;color:#212121}.ai-search__path-row:hover,.ai-search__result-row:hover,.ai-search__ai-row:hover{background-color:#f3f3f3}.ai-search__path-row:focus-visible,.ai-search__result-row:focus-visible,.ai-search__ai-row:focus-visible{outline:3px solid #223cff;outline-offset:-2px}.ai-search__path-row{gap:10px}.ai-search__path-sep{color:#909090}.ai-search__result-row{display:block;width:100%}.ai-search__result-primary{display:block;width:100%;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-search__ai-row{gap:10px}.ai-search__ai-icon{color:#223cff;flex-shrink:0}.ai-search__hl{background-color:#fff59d;color:inherit;padding:0;border-radius:2px}.ai-search__status{display:flex;align-items:center;gap:10px;padding:15px;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__spinner{display:inline-block;width:14px;height:14px;border:2px solid #e9e9e9;border-top-color:#223cff;border-radius:50%;animation:ao-ai-search-spin .8s linear infinite}@keyframes ao-ai-search-spin{to{transform:rotate(360deg)}}.ai-search__view-all{display:flex;align-items:center;justify-content:space-between;width:100%;padding:15px;border:none;border-top:1px solid #e9e9e9;background:transparent;cursor:pointer;text-align:left;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__view-all:hover{background-color:#f3f3f3}.ai-search__view-all:focus-visible{outline:3px solid #223cff;outline-offset:-2px}\n"] }]
3055
- }], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], recommendedFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "recommendedFilters", required: false }] }], activeFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeFilter", required: false }] }, { type: i0.Output, args: ["activeFilterChange"] }], resultGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "resultGroups", required: false }] }], pageSuggestion: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSuggestion", required: false }] }], aiSuggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiSuggestions", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], panelOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelOpen", required: false }] }, { type: i0.Output, args: ["panelOpenChange"] }], submit: [{ type: i0.Output, args: ["submit"] }], voiceStart: [{ type: i0.Output, args: ["voiceStart"] }], queryChange: [{ type: i0.Output, args: ["queryChange"] }], filterSelect: [{ type: i0.Output, args: ["filterSelect"] }], filterClear: [{ type: i0.Output, args: ["filterClear"] }], resultSelect: [{ type: i0.Output, args: ["resultSelect"] }], aiSuggestionSelect: [{ type: i0.Output, args: ["aiSuggestionSelect"] }], pageSuggestionSelect: [{ type: i0.Output, args: ["pageSuggestionSelect"] }], viewAllClick: [{ type: i0.Output, args: ["viewAllClick"] }], searchInput: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }], onDocumentClick: [{
3151
+ }, template: "<div class=\"ai-search\" [class.ai-search--open]=\"panelOpen() && hasPanelContent()\">\n <ao-icon [svg]=\"sparkleIcon\" size=\"sm\" class=\"ai-search__icon-left\" />\n @if (activeFilter(); as f) {\n <span class=\"ai-search__active-chip\" role=\"status\">\n <span class=\"ai-search__active-chip-label\">{{ f.label }}</span>\n <button\n type=\"button\"\n class=\"ai-search__active-chip-remove\"\n [disabled]=\"disabled()\"\n (click)=\"onChipRemove($event)\"\n [attr.aria-label]=\"'Filter ' + f.label + ' entfernen'\"\n >\n <ao-icon [svg]=\"closeIcon\" size=\"xs\" />\n </button>\n </span>\n }\n <input\n #searchInput\n type=\"text\"\n class=\"ai-search__input\"\n [placeholder]=\"effectivePlaceholder()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n (focus)=\"onFocus()\"\n (input)=\"onInput($event)\"\n (keydown.enter)=\"onEnter()\"\n (keydown.escape)=\"onEscape()\"\n (keydown.backspace)=\"onBackspace($event)\"\n aria-label=\"AI Search\"\n autocomplete=\"off\"\n />\n <button\n type=\"button\"\n class=\"ai-search__voice-btn\"\n [class.ai-search__voice-btn--recording]=\"isVoiceRecording()\"\n [disabled]=\"disabled()\"\n (click)=\"onVoiceClick()\"\n [attr.aria-label]=\"voiceButtonLabel()\"\n [attr.aria-pressed]=\"isVoiceRecording()\"\n >\n <ao-icon [svg]=\"micIcon\" size=\"sm\" />\n </button>\n</div>\n\n@if (panelOpen() && hasPanelContent()) {\n <div class=\"ai-search__panel\" role=\"listbox\">\n @if (effectiveError(); as msg) {\n <div class=\"ai-search__panel-section ai-search__status ai-search__status--error\">\n {{ msg }}\n </div>\n } @else if (value().length === 0) {\n @if (showRecommendedFilters()) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">Empfohlene Filter</h4>\n <div class=\"ai-search__filter-chips\">\n @for (f of recommendedFilters(); track f.id) {\n <button type=\"button\" class=\"ai-search__filter-chip\" (click)=\"onFilterClick(f)\">\n {{ f.label }}\n </button>\n }\n </div>\n </div>\n }\n } @else {\n @if (loading() && !hasAnyResults()) {\n <div class=\"ai-search__panel-section ai-search__status\">\n <span class=\"ai-search__spinner\" aria-hidden=\"true\"></span>\n Suche l\u00E4uft\u2026\n </div>\n }\n @if (pageSuggestion(); as p) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">Pfad</h4>\n <button type=\"button\" class=\"ai-search__path-row\" (click)=\"onPathClick(p)\">\n @for (crumb of p.breadcrumb; track crumb; let last = $last) {\n <span class=\"ai-search__path-crumb\">{{ crumb }}</span>\n @if (!last) {\n <ao-icon [svg]=\"caretRightIcon\" size=\"sm\" class=\"ai-search__path-sep\" />\n }\n }\n </button>\n </div>\n }\n @for (group of resultGroups(); track group.type) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">{{ group.label }}</h4>\n @for (r of group.results; track r.id) {\n <button type=\"button\" class=\"ai-search__result-row\" (click)=\"onResultClick(r)\">\n <span class=\"ai-search__result-primary\" [innerHTML]=\"highlight(r.primary)\"></span>\n </button>\n }\n </div>\n }\n @if (aiSuggestions().length) {\n <div class=\"ai-search__panel-section\">\n <h4 class=\"ai-search__section-title\">KI-Vorschl\u00E4ge</h4>\n @for (r of aiSuggestions(); track r.id) {\n <button type=\"button\" class=\"ai-search__ai-row\" (click)=\"onAiSuggestionClick(r)\">\n <ao-icon [svg]=\"sparkleIcon\" size=\"sm\" class=\"ai-search__ai-icon\" />\n <span [innerHTML]=\"highlight(r.primary)\"></span>\n </button>\n }\n </div>\n }\n @if (hasAnyResults()) {\n <button type=\"button\" class=\"ai-search__view-all\" (click)=\"onViewAll()\">\n <span>Alle Ergebnisse anzeigen</span>\n <ao-icon [svg]=\"arrowRightIcon\" size=\"sm\" />\n </button>\n }\n }\n </div>\n}\n", styles: [":host{display:inline-block;position:relative}.ai-search{display:flex;align-items:center;gap:10px;width:400px;height:35px;padding:0 10px 0 15px;border:1px solid #223cff;background-color:#fff;border-radius:9999px;position:relative;z-index:2}.ai-search__icon-left{color:#223cff;flex-shrink:0}.ai-search__active-chip{display:inline-flex;align-items:center;gap:5px;height:23px;padding:0 5px 0 10px;background-color:#223cff14;color:#223cff;border:1px solid #223cff;border-radius:9999px;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;flex-shrink:0;max-width:50%}.ai-search__active-chip-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}.ai-search__active-chip-remove{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;padding:0;border:none;border-radius:50%;background-color:transparent;color:inherit;cursor:pointer;flex-shrink:0}.ai-search__active-chip-remove:hover:not(:disabled){background-color:#00000014}.ai-search__active-chip-remove:focus-visible{outline:3px solid #223cff;outline-offset:1px}.ai-search__active-chip-remove:disabled{cursor:not-allowed;opacity:.5}.ai-search__input{flex:1;height:100%;padding:0;border:none;background:transparent;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__input::placeholder{color:#212121}.ai-search__input:focus{outline:none}.ai-search__input:disabled{cursor:not-allowed}.ai-search__voice-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;border-radius:50%;background-color:transparent;color:#212121;cursor:pointer;transition:color .2s ease;flex-shrink:0}.ai-search__voice-btn:hover:not(:disabled){color:#223cff}.ai-search__voice-btn--recording{color:#223cff;background-color:#223cff14}.ai-search__voice-btn:focus-visible{outline:3px solid #223cff;outline-offset:2px}.ai-search__voice-btn:disabled{opacity:.5;cursor:not-allowed}.ai-search__panel{position:absolute;top:45px;left:0;width:400px;max-height:70vh;overflow-y:auto;background-color:#fff;border:1px solid #e9e9e9;border-radius:5px;box-shadow:0 4px 16px #2121211a;z-index:10}.ai-search__panel-section{padding:15px 0;border-bottom:1px solid #e9e9e9}.ai-search__panel-section:last-of-type{border-bottom:none}.ai-search__section-title{margin:0 0 10px;padding:0 15px;font-size:12px;line-height:18px;letter-spacing:0;color:#909090;font-weight:500}.ai-search__filter-chips{display:flex;flex-direction:column;align-items:flex-start;gap:10px;padding:0 15px}.ai-search__filter-chip{display:inline-flex;align-items:center;padding:5px 15px;border:1px solid #e9e9e9;background-color:#fff;color:#212121;cursor:pointer;border-radius:9999px;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;transition:background-color .15s ease,border-color .15s ease}.ai-search__filter-chip:hover{background-color:#f3f3f3;border-color:#909090}.ai-search__filter-chip:focus-visible{outline:3px solid #223cff;outline-offset:2px}.ai-search__path-row,.ai-search__result-row,.ai-search__ai-row{display:flex;align-items:center;width:100%;padding:10px 15px;border:none;background:transparent;text-align:left;cursor:pointer;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0;color:#212121}.ai-search__path-row:hover,.ai-search__result-row:hover,.ai-search__ai-row:hover{background-color:#f3f3f3}.ai-search__path-row:focus-visible,.ai-search__result-row:focus-visible,.ai-search__ai-row:focus-visible{outline:3px solid #223cff;outline-offset:-2px}.ai-search__path-row{gap:10px}.ai-search__path-sep{color:#909090}.ai-search__result-row{display:block;width:100%}.ai-search__result-primary{display:block;width:100%;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-search__ai-row{gap:10px}.ai-search__ai-icon{color:#223cff;flex-shrink:0}.ai-search__hl{background-color:#fff59d;color:inherit;padding:0;border-radius:2px}.ai-search__status{display:flex;align-items:center;gap:10px;padding:15px;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__status--error{color:#ff004d}.ai-search__spinner{display:inline-block;width:14px;height:14px;border:2px solid #e9e9e9;border-top-color:#223cff;border-radius:50%;animation:ao-ai-search-spin .8s linear infinite}@keyframes ao-ai-search-spin{to{transform:rotate(360deg)}}.ai-search__view-all{display:flex;align-items:center;justify-content:space-between;width:100%;padding:15px;border:none;border-top:1px solid #e9e9e9;background:transparent;cursor:pointer;text-align:left;color:#212121;font-size:13px;font-weight:400;line-height:19.5px;letter-spacing:0}.ai-search__view-all:hover{background-color:#f3f3f3}.ai-search__view-all:focus-visible{outline:3px solid #223cff;outline-offset:-2px}\n"] }]
3152
+ }], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], recommendedFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "recommendedFilters", required: false }] }], activeFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeFilter", required: false }] }, { type: i0.Output, args: ["activeFilterChange"] }], resultGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "resultGroups", required: false }] }], pageSuggestion: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSuggestion", required: false }] }], aiSuggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiSuggestions", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], panelOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelOpen", required: false }] }, { type: i0.Output, args: ["panelOpenChange"] }], voiceLanguage: [{ type: i0.Input, args: [{ isSignal: true, alias: "voiceLanguage", required: false }] }], submit: [{ type: i0.Output, args: ["submit"] }], voiceStart: [{ type: i0.Output, args: ["voiceStart"] }], queryChange: [{ type: i0.Output, args: ["queryChange"] }], filterSelect: [{ type: i0.Output, args: ["filterSelect"] }], filterClear: [{ type: i0.Output, args: ["filterClear"] }], resultSelect: [{ type: i0.Output, args: ["resultSelect"] }], aiSuggestionSelect: [{ type: i0.Output, args: ["aiSuggestionSelect"] }], pageSuggestionSelect: [{ type: i0.Output, args: ["pageSuggestionSelect"] }], viewAllClick: [{ type: i0.Output, args: ["viewAllClick"] }], searchInput: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }], onDocumentClick: [{
3056
3153
  type: HostListener,
3057
3154
  args: ['document:click', ['$event']]
3058
3155
  }] } });
@@ -5898,7 +5995,7 @@ class TopNavComponent {
5898
5995
  }
5899
5996
  }
5900
5997
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: TopNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5901
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: TopNavComponent, isStandalone: true, selector: "ao-top-nav", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, activeItemId: { classPropertyName: "activeItemId", publicName: "activeItemId", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, showNotifications: { classPropertyName: "showNotifications", publicName: "showNotifications", isSignal: true, isRequired: false, transformFunction: null }, notificationCount: { classPropertyName: "notificationCount", publicName: "notificationCount", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, showTools: { classPropertyName: "showTools", publicName: "showTools", isSignal: true, isRequired: false, transformFunction: null }, recommendedFilters: { classPropertyName: "recommendedFilters", publicName: "recommendedFilters", isSignal: true, isRequired: false, transformFunction: null }, activeFilter: { classPropertyName: "activeFilter", publicName: "activeFilter", isSignal: true, isRequired: false, transformFunction: null }, resultGroups: { classPropertyName: "resultGroups", publicName: "resultGroups", isSignal: true, isRequired: false, transformFunction: null }, pageSuggestion: { classPropertyName: "pageSuggestion", publicName: "pageSuggestion", isSignal: true, isRequired: false, transformFunction: null }, aiSuggestions: { classPropertyName: "aiSuggestions", publicName: "aiSuggestions", isSignal: true, isRequired: false, transformFunction: null }, searchLoading: { classPropertyName: "searchLoading", publicName: "searchLoading", isSignal: true, isRequired: false, transformFunction: null }, searchError: { classPropertyName: "searchError", publicName: "searchError", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeItemId: "activeItemIdChange", activeFilter: "activeFilterChange", itemClick: "itemClick", itemChange: "itemChange", searchSubmit: "searchSubmit", searchQueryChange: "searchQueryChange", searchResultSelect: "searchResultSelect", searchAiSuggestionSelect: "searchAiSuggestionSelect", searchPageSuggestionSelect: "searchPageSuggestionSelect", searchFilterSelect: "searchFilterSelect", searchFilterClear: "searchFilterClear", searchViewAll: "searchViewAll", notificationClick: "notificationClick" }, host: { classAttribute: "ao-top-nav" }, viewQueries: [{ propertyName: "navItems", predicate: ["navItem"], descendants: true, isSignal: true }], ngImport: i0, template: "<nav class=\"top-nav-outer\" role=\"navigation\" aria-label=\"Main navigation\">\n <div class=\"top-nav\">\n <div class=\"top-nav__list-wrapper\">\n <ul class=\"top-nav__list\" role=\"menubar\">\n @for (item of items(); track item.id) {\n <li role=\"none\">\n <a\n #navItem\n class=\"top-nav__item\"\n [class.top-nav__item--active]=\"item.id === activeItemId()\"\n [class.top-nav__item--disabled]=\"item.disabled\"\n [attr.href]=\"item.route ?? null\"\n [attr.aria-current]=\"item.id === activeItemId() ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled || null\"\n [attr.tabindex]=\"item.disabled ? -1 : 0\"\n role=\"menuitem\"\n (click)=\"$event.preventDefault(); onItemClick(item)\"\n (keydown)=\"onKeydown($event, item)\"\n >\n @if (item.icon) {\n <ao-icon [svg]=\"item.icon\" size=\"sm\" />\n }\n {{ item.label }}\n </a>\n </li>\n }\n </ul>\n @if (showIndicator()) {\n <span\n class=\"top-nav__indicator\"\n [style.left]=\"indicatorStyle().left\"\n [style.width]=\"indicatorStyle().width\"\n ></span>\n }\n </div>\n\n <div class=\"top-nav__actions\">\n @if (showSearch()) {\n <ao-ai-search\n [placeholder]=\"searchPlaceholder()\"\n [(value)]=\"searchValue\"\n [recommendedFilters]=\"recommendedFilters()\"\n [(activeFilter)]=\"activeFilter\"\n [resultGroups]=\"resultGroups()\"\n [pageSuggestion]=\"pageSuggestion()\"\n [aiSuggestions]=\"aiSuggestions()\"\n [loading]=\"searchLoading()\"\n [error]=\"searchError()\"\n (submit)=\"onSearchSubmit($event)\"\n (queryChange)=\"searchQueryChange.emit($event)\"\n (resultSelect)=\"searchResultSelect.emit($event)\"\n (aiSuggestionSelect)=\"searchAiSuggestionSelect.emit($event)\"\n (pageSuggestionSelect)=\"searchPageSuggestionSelect.emit($event)\"\n (filterSelect)=\"searchFilterSelect.emit($event)\"\n (filterClear)=\"searchFilterClear.emit()\"\n (viewAllClick)=\"searchViewAll.emit($event)\"\n />\n }\n @if (showTools()) {\n <ao-nav-tools />\n }\n @if (showNotifications()) {\n <ao-notification-button\n [count]=\"notificationCount()\"\n (buttonClick)=\"onNotificationClick()\"\n />\n }\n </div>\n </div>\n</nav>\n", styles: [":host{display:block;height:50px;background-color:#fff;border-bottom:1px solid #e9e9e9;padding-left:70px}.top-nav-outer{max-width:1640px;width:calc(100% - 96px);margin:auto;height:100%}@media(max-width:1279px){.top-nav-outer{width:calc(100% - 64px)}}@media(max-width:599px){.top-nav-outer{width:calc(100% - 32px)}}.top-nav{display:flex;align-items:center;justify-content:space-between;height:100%}.top-nav__list-wrapper{position:relative;height:100%}.top-nav__list{display:flex;align-items:center;gap:30px;list-style:none;margin:0;padding:0;height:100%}.top-nav__item{display:flex;align-items:center;gap:5px;height:100%;padding:0;border:none;background:transparent;color:#212121;text-decoration:none;cursor:pointer;transition:color .2s ease;font-size:13px;font-weight:700;line-height:19.5px;letter-spacing:0}.top-nav__item:hover:not(.top-nav__item--disabled){color:#ff004d}.top-nav__item:focus-visible{outline:3px solid #ff004d;outline-offset:-3px}.top-nav__item--active{color:#ff004d}.top-nav__item--disabled{color:#909090;cursor:not-allowed}.top-nav__indicator{position:absolute;bottom:0;height:3px;background-color:#ff004d;transition:left .3s cubic-bezier(.4,0,.2,1),width .3s cubic-bezier(.4,0,.2,1)}.top-nav__actions{display:flex;align-items:center;gap:20px}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "ao-icon", inputs: ["svg", "size"] }, { kind: "component", type: AiSearchComponent, selector: "ao-ai-search", inputs: ["placeholder", "value", "disabled", "recommendedFilters", "activeFilter", "resultGroups", "pageSuggestion", "aiSuggestions", "loading", "error", "panelOpen"], outputs: ["valueChange", "activeFilterChange", "panelOpenChange", "submit", "voiceStart", "queryChange", "filterSelect", "filterClear", "resultSelect", "aiSuggestionSelect", "pageSuggestionSelect", "viewAllClick"] }, { kind: "component", type: NotificationButtonComponent, selector: "ao-notification-button", inputs: ["count", "maxCount", "disabled"], outputs: ["buttonClick"] }, { kind: "component", type: NavToolsComponent, selector: "ao-nav-tools", inputs: ["activeCompany", "companySearch"], outputs: ["changeCompany"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5998
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: TopNavComponent, isStandalone: true, selector: "ao-top-nav", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, activeItemId: { classPropertyName: "activeItemId", publicName: "activeItemId", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, showNotifications: { classPropertyName: "showNotifications", publicName: "showNotifications", isSignal: true, isRequired: false, transformFunction: null }, notificationCount: { classPropertyName: "notificationCount", publicName: "notificationCount", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, showTools: { classPropertyName: "showTools", publicName: "showTools", isSignal: true, isRequired: false, transformFunction: null }, recommendedFilters: { classPropertyName: "recommendedFilters", publicName: "recommendedFilters", isSignal: true, isRequired: false, transformFunction: null }, activeFilter: { classPropertyName: "activeFilter", publicName: "activeFilter", isSignal: true, isRequired: false, transformFunction: null }, resultGroups: { classPropertyName: "resultGroups", publicName: "resultGroups", isSignal: true, isRequired: false, transformFunction: null }, pageSuggestion: { classPropertyName: "pageSuggestion", publicName: "pageSuggestion", isSignal: true, isRequired: false, transformFunction: null }, aiSuggestions: { classPropertyName: "aiSuggestions", publicName: "aiSuggestions", isSignal: true, isRequired: false, transformFunction: null }, searchLoading: { classPropertyName: "searchLoading", publicName: "searchLoading", isSignal: true, isRequired: false, transformFunction: null }, searchError: { classPropertyName: "searchError", publicName: "searchError", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeItemId: "activeItemIdChange", activeFilter: "activeFilterChange", itemClick: "itemClick", itemChange: "itemChange", searchSubmit: "searchSubmit", searchQueryChange: "searchQueryChange", searchResultSelect: "searchResultSelect", searchAiSuggestionSelect: "searchAiSuggestionSelect", searchPageSuggestionSelect: "searchPageSuggestionSelect", searchFilterSelect: "searchFilterSelect", searchFilterClear: "searchFilterClear", searchViewAll: "searchViewAll", notificationClick: "notificationClick" }, host: { classAttribute: "ao-top-nav" }, viewQueries: [{ propertyName: "navItems", predicate: ["navItem"], descendants: true, isSignal: true }], ngImport: i0, template: "<nav class=\"top-nav-outer\" role=\"navigation\" aria-label=\"Main navigation\">\n <div class=\"top-nav\">\n <div class=\"top-nav__list-wrapper\">\n <ul class=\"top-nav__list\" role=\"menubar\">\n @for (item of items(); track item.id) {\n <li role=\"none\">\n <a\n #navItem\n class=\"top-nav__item\"\n [class.top-nav__item--active]=\"item.id === activeItemId()\"\n [class.top-nav__item--disabled]=\"item.disabled\"\n [attr.href]=\"item.route ?? null\"\n [attr.aria-current]=\"item.id === activeItemId() ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled || null\"\n [attr.tabindex]=\"item.disabled ? -1 : 0\"\n role=\"menuitem\"\n (click)=\"$event.preventDefault(); onItemClick(item)\"\n (keydown)=\"onKeydown($event, item)\"\n >\n @if (item.icon) {\n <ao-icon [svg]=\"item.icon\" size=\"sm\" />\n }\n {{ item.label }}\n </a>\n </li>\n }\n </ul>\n @if (showIndicator()) {\n <span\n class=\"top-nav__indicator\"\n [style.left]=\"indicatorStyle().left\"\n [style.width]=\"indicatorStyle().width\"\n ></span>\n }\n </div>\n\n <div class=\"top-nav__actions\">\n @if (showSearch()) {\n <ao-ai-search\n [placeholder]=\"searchPlaceholder()\"\n [(value)]=\"searchValue\"\n [recommendedFilters]=\"recommendedFilters()\"\n [(activeFilter)]=\"activeFilter\"\n [resultGroups]=\"resultGroups()\"\n [pageSuggestion]=\"pageSuggestion()\"\n [aiSuggestions]=\"aiSuggestions()\"\n [loading]=\"searchLoading()\"\n [error]=\"searchError()\"\n (submit)=\"onSearchSubmit($event)\"\n (queryChange)=\"searchQueryChange.emit($event)\"\n (resultSelect)=\"searchResultSelect.emit($event)\"\n (aiSuggestionSelect)=\"searchAiSuggestionSelect.emit($event)\"\n (pageSuggestionSelect)=\"searchPageSuggestionSelect.emit($event)\"\n (filterSelect)=\"searchFilterSelect.emit($event)\"\n (filterClear)=\"searchFilterClear.emit()\"\n (viewAllClick)=\"searchViewAll.emit($event)\"\n />\n }\n @if (showTools()) {\n <ao-nav-tools />\n }\n @if (showNotifications()) {\n <ao-notification-button\n [count]=\"notificationCount()\"\n (buttonClick)=\"onNotificationClick()\"\n />\n }\n </div>\n </div>\n</nav>\n", styles: [":host{display:block;height:50px;background-color:#fff;border-bottom:1px solid #e9e9e9;padding-left:70px}.top-nav-outer{max-width:1640px;width:calc(100% - 96px);margin:auto;height:100%}@media(max-width:1279px){.top-nav-outer{width:calc(100% - 64px)}}@media(max-width:599px){.top-nav-outer{width:calc(100% - 32px)}}.top-nav{display:flex;align-items:center;justify-content:space-between;height:100%}.top-nav__list-wrapper{position:relative;height:100%}.top-nav__list{display:flex;align-items:center;gap:30px;list-style:none;margin:0;padding:0;height:100%}.top-nav__item{display:flex;align-items:center;gap:5px;height:100%;padding:0;border:none;background:transparent;color:#212121;text-decoration:none;cursor:pointer;transition:color .2s ease;font-size:13px;font-weight:700;line-height:19.5px;letter-spacing:0}.top-nav__item:hover:not(.top-nav__item--disabled){color:#ff004d}.top-nav__item:focus-visible{outline:3px solid #ff004d;outline-offset:-3px}.top-nav__item--active{color:#ff004d}.top-nav__item--disabled{color:#909090;cursor:not-allowed}.top-nav__indicator{position:absolute;bottom:0;height:3px;background-color:#ff004d;transition:left .3s cubic-bezier(.4,0,.2,1),width .3s cubic-bezier(.4,0,.2,1)}.top-nav__actions{display:flex;align-items:center;gap:20px}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "ao-icon", inputs: ["svg", "size"] }, { kind: "component", type: AiSearchComponent, selector: "ao-ai-search", inputs: ["placeholder", "value", "disabled", "recommendedFilters", "activeFilter", "resultGroups", "pageSuggestion", "aiSuggestions", "loading", "error", "panelOpen", "voiceLanguage"], outputs: ["valueChange", "activeFilterChange", "panelOpenChange", "submit", "voiceStart", "queryChange", "filterSelect", "filterClear", "resultSelect", "aiSuggestionSelect", "pageSuggestionSelect", "viewAllClick"] }, { kind: "component", type: NotificationButtonComponent, selector: "ao-notification-button", inputs: ["count", "maxCount", "disabled"], outputs: ["buttonClick"] }, { kind: "component", type: NavToolsComponent, selector: "ao-nav-tools", inputs: ["activeCompany", "companySearch"], outputs: ["changeCompany"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5902
5999
  }
5903
6000
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: TopNavComponent, decorators: [{
5904
6001
  type: Component,
@@ -5972,7 +6069,7 @@ const ROBIN_SEARCH_APP_NAME = new InjectionToken('ROBIN_SEARCH_APP_NAME', {
5972
6069
  providedIn: 'root',
5973
6070
  factory: () => 'unknown',
5974
6071
  });
5975
- const QUICK_DEBOUNCE_MS = 200;
6072
+ const QUICK_THROTTLE_MS = 200;
5976
6073
  class RobinSearchService {
5977
6074
  http = inject(HttpClient);
5978
6075
  baseUrl = inject(ROBIN_API_BASE_URL);
@@ -5984,8 +6081,12 @@ class RobinSearchService {
5984
6081
  resultGroups = signal([], ...(ngDevMode ? [{ debugName: "resultGroups" }] : /* istanbul ignore next */ []));
5985
6082
  pageSuggestion = signal(null, ...(ngDevMode ? [{ debugName: "pageSuggestion" }] : /* istanbul ignore next */ []));
5986
6083
  aiSuggestions = signal([], ...(ngDevMode ? [{ debugName: "aiSuggestions" }] : /* istanbul ignore next */ []));
5987
- debounceHandle = null;
5988
- requestSeq = 0;
6084
+ quickSearchInput$ = new Subject();
6085
+ constructor() {
6086
+ this.quickSearchInput$
6087
+ .pipe(throttleTime(QUICK_THROTTLE_MS, asyncScheduler, { leading: true, trailing: true }), switchMap(({ query, type }) => this.fetchQuickSearch(query, type)))
6088
+ .subscribe((outcome) => this.applyQuickSearchOutcome(outcome));
6089
+ }
5989
6090
  async loadRecommendedFilters() {
5990
6091
  try {
5991
6092
  const params = new HttpParams().set('appName', this.appName);
@@ -5999,9 +6100,6 @@ class RobinSearchService {
5999
6100
  }
6000
6101
  search(query, type) {
6001
6102
  this.query.set(query);
6002
- if (this.debounceHandle !== null) {
6003
- clearTimeout(this.debounceHandle);
6004
- }
6005
6103
  if (!query.trim()) {
6006
6104
  this.resultGroups.set([]);
6007
6105
  this.pageSuggestion.set(null);
@@ -6011,9 +6109,7 @@ class RobinSearchService {
6011
6109
  return;
6012
6110
  }
6013
6111
  this.loading.set(true);
6014
- this.debounceHandle = setTimeout(() => {
6015
- void this.runQuickSearch(query, type);
6016
- }, QUICK_DEBOUNCE_MS);
6112
+ this.quickSearchInput$.next({ query, type });
6017
6113
  }
6018
6114
  async loadFull(query, type, date) {
6019
6115
  let params = new HttpParams().set('q', query).set('appName', this.appName);
@@ -6041,35 +6137,35 @@ class RobinSearchService {
6041
6137
  this.loading.set(false);
6042
6138
  }
6043
6139
  }
6044
- async runQuickSearch(query, type) {
6045
- const seq = ++this.requestSeq;
6140
+ fetchQuickSearch(query, type) {
6046
6141
  let params = new HttpParams().set('q', query).set('appName', this.appName);
6047
6142
  if (type)
6048
6143
  params = params.set('type', type);
6049
- try {
6050
- const payload = await firstValueFrom(this.http.get(this.url('/search/quick'), { params }));
6051
- if (seq !== this.requestSeq)
6052
- return;
6053
- const safe = payload ?? {};
6054
- this.resultGroups.set(safe.groups ?? []);
6055
- this.pageSuggestion.set(safe.pageSuggestion ?? null);
6056
- this.aiSuggestions.set(safe.aiSuggestions ?? []);
6057
- this.error.set(null);
6058
- }
6059
- catch (err) {
6060
- if (seq !== this.requestSeq)
6061
- return;
6144
+ return this.http
6145
+ .get(this.url('/search/quick'), { params })
6146
+ .pipe(map$1((payload) => ({ query, payload, failed: false })), catchError((err) => {
6062
6147
  console.warn('[RobinSearch] quickSearch failed', err);
6148
+ return of({ query, payload: null, failed: true });
6149
+ }));
6150
+ }
6151
+ applyQuickSearchOutcome(outcome) {
6152
+ if (this.query() !== outcome.query) {
6153
+ return;
6154
+ }
6155
+ if (outcome.failed) {
6063
6156
  this.error.set('Suche fehlgeschlagen');
6064
6157
  this.resultGroups.set([]);
6065
6158
  this.pageSuggestion.set(null);
6066
6159
  this.aiSuggestions.set([]);
6067
6160
  }
6068
- finally {
6069
- if (seq === this.requestSeq) {
6070
- this.loading.set(false);
6071
- }
6161
+ else {
6162
+ const safe = outcome.payload ?? {};
6163
+ this.resultGroups.set(safe.groups ?? []);
6164
+ this.pageSuggestion.set(safe.pageSuggestion ?? null);
6165
+ this.aiSuggestions.set(safe.aiSuggestions ?? []);
6166
+ this.error.set(null);
6072
6167
  }
6168
+ this.loading.set(false);
6073
6169
  }
6074
6170
  url(path) {
6075
6171
  return `${this.baseUrl}${path}`;
@@ -6080,7 +6176,7 @@ class RobinSearchService {
6080
6176
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RobinSearchService, decorators: [{
6081
6177
  type: Injectable,
6082
6178
  args: [{ providedIn: 'root' }]
6083
- }] });
6179
+ }], ctorParameters: () => [] });
6084
6180
 
6085
6181
  class LogoMenuComponent {
6086
6182
  workspaceNavbarService = inject(WorkspaceNavbarService);
@@ -7185,7 +7281,7 @@ class WorkspaceNavbarComponent {
7185
7281
  ngAfterViewInit() {
7186
7282
  if (isPlatformBrowser(this.platformId)) {
7187
7283
  fromEvent(window, 'scroll', { passive: true })
7188
- .pipe(throttleTime(50), takeUntilDestroyed(this.destroyRef))
7284
+ .pipe(throttleTime$1(50), takeUntilDestroyed(this.destroyRef))
7189
7285
  .subscribe(() => {
7190
7286
  const scrollY = window.scrollY ?? window.pageYOffset ?? 0;
7191
7287
  if (scrollY <= this.scrollThreshold) {