@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,
|
|
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()
|
|
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,
|
|
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=\"
|
|
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
|
|
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
|
-
|
|
5988
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
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
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
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) {
|