diff --git a/app/assets/javascripts/discourse/app/components/search-menu-panel.hbs b/app/assets/javascripts/discourse/app/components/search-menu-panel.hbs
new file mode 100644
index 00000000000..51d562c165e
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/components/search-menu-panel.hbs
@@ -0,0 +1,7 @@
+
+
+
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/search-menu-panel.js b/app/assets/javascripts/discourse/app/components/search-menu-panel.js
new file mode 100644
index 00000000000..f6d907485a4
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/components/search-menu-panel.js
@@ -0,0 +1,11 @@
+import Component from "@glimmer/component";
+import { inject as service } from "@ember/service";
+
+export default class SearchMenuPanel extends Component {
+ @service site;
+ get animationClass() {
+ return this.site.mobileView || this.site.narrowDesktopView
+ ? "slide-in"
+ : "drop-down";
+ }
+}
diff --git a/app/assets/javascripts/discourse/app/components/search-menu.hbs b/app/assets/javascripts/discourse/app/components/search-menu.hbs
index fbb0cc04ae5..ce806cafe0a 100644
--- a/app/assets/javascripts/discourse/app/components/search-menu.hbs
+++ b/app/assets/javascripts/discourse/app/components/search-menu.hbs
@@ -1,23 +1,83 @@
-
-
-
\ No newline at end of file
+
+
+
+ {{#if @inlineResults}}
+
+ {{else if this.displayMenuPanelResults}}
+
+
+
+ {{/if}}
+
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/search-menu.js b/app/assets/javascripts/discourse/app/components/search-menu.js
index 49cd6e296c7..e979d51d0d4 100644
--- a/app/assets/javascripts/discourse/app/components/search-menu.js
+++ b/app/assets/javascripts/discourse/app/components/search-menu.js
@@ -22,7 +22,6 @@ const CATEGORY_SLUG_REGEXP = /(\#[a-zA-Z0-9\-:]*)$/gi;
const USERNAME_REGEXP = /(\@[a-zA-Z0-9\-\_]*)$/gi;
const SUGGESTIONS_REGEXP = /(in:|status:|order:|:)([a-zA-Z]*)$/gi;
export const SEARCH_INPUT_ID = "search-term";
-export const SEARCH_BUTTON_ID = "search-button";
export const MODIFIER_REGEXP = /.*(\#|\@|:).*$/gi;
export const DEFAULT_TYPE_FILTER = "exclude_topics";
@@ -30,16 +29,11 @@ export function focusSearchInput() {
document.getElementById(SEARCH_INPUT_ID).focus();
}
-export function focusSearchButton() {
- document.getElementById(SEARCH_BUTTON_ID).focus();
-}
-
export default class SearchMenu extends Component {
@service search;
@service currentUser;
@service siteSettings;
@service appEvents;
- @service site;
@tracked loading = false;
@tracked results = {};
@@ -50,13 +44,42 @@ export default class SearchMenu extends Component {
@tracked suggestionKeyword = false;
@tracked suggestionResults = [];
@tracked invalidTerm = false;
+ @tracked menuPanelOpen = false;
+
_debouncer = null;
_activeSearch = null;
- get animationClass() {
- return this.site.mobileView || this.site.narrowDesktopView
- ? "slide-in"
- : "drop-down";
+ @bind
+ setupEventListeners() {
+ document.addEventListener("mousedown", this.onDocumentPress, true);
+ document.addEventListener("touchend", this.onDocumentPress, {
+ capture: true,
+ passive: true,
+ });
+ }
+
+ willDestroy() {
+ document.removeEventListener("mousedown", this.onDocumentPress);
+ document.removeEventListener("touchend", this.onDocumentPress);
+
+ super.willDestroy(...arguments);
+ }
+
+ @bind
+ onDocumentPress(event) {
+ if (!event.target.closest(".search-menu-container.menu-panel-results")) {
+ this.menuPanelOpen = false;
+ }
+ }
+
+ get classNames() {
+ const classes = ["search-menu-container"];
+
+ if (!this.args.inlineResults) {
+ classes.push("menu-panel-results");
+ }
+
+ return classes.join(" ");
}
get includesTopics() {
@@ -71,6 +94,23 @@ export default class SearchMenu extends Component {
return false;
}
+ @action
+ close() {
+ if (this.args?.closeSearchMenu) {
+ return this.args.closeSearchMenu();
+ }
+
+ // We want to blur the active element (search input) when in stand-alone mode
+ // so that when we focus on the search input again, the menu panel pops up
+ document.activeElement.blur();
+ this.menuPanelOpen = false;
+ }
+
+ @action
+ open() {
+ this.menuPanelOpen = true;
+ }
+
@bind
fullSearchUrl(opts) {
let url = "/search";
@@ -95,6 +135,18 @@ export default class SearchMenu extends Component {
return getURL(url);
}
+ get advancedSearchButtonHref() {
+ return this.fullSearchUrl({ expanded: true });
+ }
+
+ get displayMenuPanelResults() {
+ if (this.args.inlineResults) {
+ return false;
+ }
+
+ return this.menuPanelOpen;
+ }
+
@bind
clearSearch(e) {
e.stopPropagation();
diff --git a/app/assets/javascripts/discourse/app/components/search-menu/menu-panel-contents.hbs b/app/assets/javascripts/discourse/app/components/search-menu/menu-panel-contents.hbs
deleted file mode 100644
index 9caee2bb218..00000000000
--- a/app/assets/javascripts/discourse/app/components/search-menu/menu-panel-contents.hbs
+++ /dev/null
@@ -1,63 +0,0 @@
-
- {{#if @suggestionKeyword}}
-
- {{else if this.termTooShort}}
-
{{i18n "search.too_short"}}
- {{else if this.noTopicResults}}
-
{{i18n "search.no_results"}}
- {{else if this.renderInitialOptions}}
-
- {{else}}
- {{#if @searchTopics}}
- {{! render results after a search has been performed }}
- {{#if this.resultTypesWithComponent}}
-
-
- {{/if}}
+{{#if (and this.search.inTopicContext (not @searchTopics))}}
+
+{{else if (not @loading)}}
+
+ {{#if @suggestionKeyword}}
+
+ {{else if this.termTooShort}}
+
{{i18n "search.too_short"}}
+ {{else if this.noTopicResults}}
+
{{i18n "search.no_results"}}
+ {{else if this.renderInitialOptions}}
+
{{else}}
- {{#unless @inPMInboxContext}}
- {{! render the first couple suggestions before a search has been performed}}
-
+ {{#if @searchTopics}}
+ {{! render results after a search has been performed }}
{{#if this.resultTypesWithComponent}}
+
{{/if}}
- {{/unless}}
+ {{else}}
+ {{#unless @inPMInboxContext}}
+ {{! render the first couple suggestions before a search has been performed}}
+
+ {{#if this.resultTypesWithComponent}}
+
+ {{/if}}
+ {{/unless}}
+ {{/if}}
{{/if}}
- {{/if}}
-
\ No newline at end of file
+
+{{/if}}
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/search-menu/results/assistant-item.js b/app/assets/javascripts/discourse/app/components/search-menu/results/assistant-item.js
index 4008f1a33a8..4c4e994ae10 100644
--- a/app/assets/javascripts/discourse/app/components/search-menu/results/assistant-item.js
+++ b/app/assets/javascripts/discourse/app/components/search-menu/results/assistant-item.js
@@ -3,10 +3,7 @@ import getURL from "discourse-common/lib/get-url";
import { inject as service } from "@ember/service";
import { action } from "@ember/object";
import { debounce } from "discourse-common/utils/decorators";
-import {
- focusSearchButton,
- focusSearchInput,
-} from "discourse/components/search-menu";
+import { focusSearchInput } from "discourse/components/search-menu";
export default class AssistantItem extends Component {
@service search;
@@ -65,7 +62,6 @@ export default class AssistantItem extends Component {
}
if (e.key === "Escape") {
- focusSearchButton();
this.args.closeSearchMenu();
e.preventDefault();
return false;
diff --git a/app/assets/javascripts/discourse/app/components/search-menu/results/more-link.hbs b/app/assets/javascripts/discourse/app/components/search-menu/results/more-link.hbs
index a035c876406..72cccafbc1d 100644
--- a/app/assets/javascripts/discourse/app/components/search-menu/results/more-link.hbs
+++ b/app/assets/javascripts/discourse/app/components/search-menu/results/more-link.hbs
@@ -2,7 +2,11 @@
{{! template-lint-disable no-invalid-interactive }}