class SearchController extends Controller
{
- protected $searchRunner;
+ protected SearchRunner $searchRunner;
public function __construct(SearchRunner $searchRunner)
{
--- /dev/null
+/**
+ * @extends {Component}
+ */
+import {htmlToDom} from "../services/dom";
+
+class GlobalSearch {
+
+ setup() {
+ this.input = this.$refs.input;
+ this.suggestions = this.$refs.suggestions;
+ this.suggestionResultsWrap = this.$refs.suggestionResults;
+
+ this.setupListeners();
+ }
+
+ setupListeners() {
+ this.input.addEventListener('input', () => {
+ const value = this.input.value;
+ if (value.length > 0) {
+ this.updateSuggestions(value);
+ } else {
+ this.hideSuggestions();
+ }
+ });
+ }
+
+ async updateSuggestions(search) {
+ const {data: results} = await window.$http.get('/ajax/search/entities', {term: search, count: 5});
+ const resultDom = htmlToDom(results);
+
+ const childrenToTrim = Array.from(resultDom.children).slice(9);
+ for (const child of childrenToTrim) {
+ child.remove();
+ }
+
+ this.suggestions.style.display = 'block';
+ this.suggestionResultsWrap.innerHTML = '';
+ this.suggestionResultsWrap.append(resultDom);
+ }
+
+ hideSuggestions() {
+ this.suggestions.style.display = null;
+ this.suggestionResultsWrap.innerHTML = '';
+ }
+}
+
+export default GlobalSearch;
\ No newline at end of file
import userSelect from "./user-select.js"
import webhookEvents from "./webhook-events";
import wysiwygEditor from "./wysiwyg-editor.js"
+import globalSearch from "./global-search";
const componentMapping = {
"add-remove-rows": addRemoveRows,
"entity-selector-popup": entitySelectorPopup,
"event-emit-select": eventEmitSelect,
"expand-toggle": expandToggle,
+ "global-search": globalSearch,
"header-mobile-toggle": headerMobileToggle,
"homepage-control": homepageControl,
"image-manager": imageManager,
.card-title a {
line-height: 1;
}
-.card-footer-link {
+.card-footer-link, button.card-footer-link {
display: block;
padding: $-s $-m;
line-height: 1;
border-top: 1px solid;
+ width: 100%;
+ text-align: left;
@include lightDark(border-color, #DDD, #555);
border-radius: 0 0 3px 3px;
font-size: 0.9em;
border: 1px solid #b4b4b4;
box-shadow: 0 1px 1px rgba(0, 0, 0, .2), 0 2px 0 0 rgba(255, 255, 255, .7) inset;
color: #333;
+}
+
+.global-search-suggestions {
+ display: none;
+ position: absolute;
+ top: -$-s;
+ left: 0;
+ right: 0;
+ z-index: -1;
+ margin-left: -$-xxl;
+ margin-right: -$-xxl;
+ padding-top: 56px;
+ border-radius: 3px;
+ box-shadow: $bs-hover;
+ .entity-item-snippet p {
+ display: none;
+ }
+ .entity-item-snippet {
+ font-size: .8rem;
+ }
+ .entity-list-item-name {
+ font-size: .9rem;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ overflow: hidden;
+ }
}
\ No newline at end of file
.search-box {
max-width: 100%;
position: relative;
- button {
+ button[tabindex="-1"] {
background-color: transparent;
border: none;
@include lightDark(color, #666, #AAA);
border: 1px solid rgba(255, 255, 255, 0.4);
}
}
- button {
- z-index: 1;
- left: 16px;
- top: 10px;
- color: #FFF;
- opacity: 0.6;
- @include lightDark(color, rgba(255, 255, 255, 0.8), #AAA);
- @include rtl {
- left: auto;
- right: 16px;
- }
- svg {
- margin-block-end: 0;
- }
- }
input::placeholder {
color: #FFF;
opacity: 0.6;
@include between($l, $xl) {
max-width: 200px;
}
- &:focus-within button {
+ &:focus-within #header-search-box-button {
opacity: 1;
}
}
+#header-search-box-button {
+ z-index: 1;
+ left: 16px;
+ top: 10px;
+ color: #FFF;
+ opacity: 0.6;
+ @include lightDark(color, rgba(255, 255, 255, 0.8), #AAA);
+ @include rtl {
+ left: auto;
+ right: 16px;
+ }
+ svg {
+ margin-block-end: 0;
+ }
+}
.logo {
display: inline-flex;
<div class="flex-container-column items-center justify-center hide-under-l">
@if (hasAppAccess())
- <form action="{{ url('/search') }}" method="GET" class="search-box" role="search">
+ <form component="global-search" action="{{ url('/search') }}" method="GET" class="search-box" role="search">
<button id="header-search-box-button" type="submit" aria-label="{{ trans('common.search') }}" tabindex="-1">@icon('search') </button>
- <input id="header-search-box-input" type="text" name="term"
+ <input id="header-search-box-input"
+ refs="global-search@input"
+ type="text"
+ name="term"
data-shortcut="global_search"
aria-label="{{ trans('common.search') }}" placeholder="{{ trans('common.search') }}"
- value="{{ isset($searchTerm) ? $searchTerm : '' }}">
+ value="{{ $searchTerm ?? '' }}">
+ <div refs="global-search@suggestions" class="global-search-suggestions card">
+ <div refs="global-search@suggestion-results" class="px-m"></div>
+ <button class="text-button card-footer-link" type="submit">{{ trans('common.view_all') }}</button>
+ </div>
</form>
@endif
</div>