UX: Better topic search experience (#14625)

UX: Better topic search experience (#14625)

diff --git a/app/assets/javascripts/discourse/app/lib/search.js b/app/assets/javascripts/discourse/app/lib/search.js
index 5df67d4..9f2b3f3 100644
--- a/app/assets/javascripts/discourse/app/lib/search.js
+++ b/app/assets/javascripts/discourse/app/lib/search.js
@@ -117,7 +117,7 @@ function translateGroupedSearchResults(results, opts) {
       const name = pair[1];
       if (results[name].length > 0) {
         const componentName =
-          opts.showPosts && type === "topic" ? "post" : type;
+          opts.searchContext && type === "topic" ? "post" : type;
 
         const result = {
           results: results[name],
@@ -154,8 +154,12 @@ export function searchForTerm(term, opts) {
     data.restrict_to_archetype = opts.restrictToArchetype;
   }
 
-  if (term.includes("topic:")) {
-    opts.showPosts = true;
+  if (opts.searchContext) {
+    data.search_context = {
+      type: opts.searchContext.type,
+      id: opts.searchContext.id,
+      name: opts.searchContext.name,
+    };
   }
 
   let ajaxPromise = ajax("/search/query", { data });
diff --git a/app/assets/javascripts/discourse/app/widgets/header.js b/app/assets/javascripts/discourse/app/widgets/header.js
index afe4821..db23ceb 100644
--- a/app/assets/javascripts/discourse/app/widgets/header.js
+++ b/app/assets/javascripts/discourse/app/widgets/header.js
@@ -4,10 +4,10 @@ import { addExtraUserClasses } from "discourse/helpers/user-avatar";
 import { ajax } from "discourse/lib/ajax";
 import { avatarImg } from "discourse/widgets/post";
 import { createWidget } from "discourse/widgets/widget";
-import { get } from "@ember/object";
 import getURL from "discourse-common/lib/get-url";
 import { h } from "virtual-dom";
 import { iconNode } from "discourse-common/lib/icon-library";
+import putCursorAtEnd from "discourse/lib/put-cursor-at-end";
 import { schedule } from "@ember/runloop";
 import { scrollTop } from "discourse/mixins/scroll-top";
 import { wantsNewWindow } from "discourse/lib/intercept-click";
@@ -321,8 +321,6 @@ createWidget("header-cloak", {
   scheduleRerender() {},
 });
 
-const forceContextEnabled = ["category", "user", "private_messages", "tag"];
-
 let additionalPanels = [];
 export function attachAdditionalPanel(name, toggle, transformAttrs) {
   additionalPanels.push({ name, toggle, transformAttrs });
@@ -339,6 +337,7 @@ export default createWidget("header", {
       hamburgerVisible: false,
       userVisible: false,
       ringBackdrop: true,
+      inTopicContext: false,
     };
 
     if (this.site.mobileView) {
@@ -366,21 +365,10 @@ export default createWidget("header", {
       const panels = [this.attach("header-buttons", attrs), headerIcons];
 
       if (state.searchVisible) {
-        const contextType = this.searchContextType();
-
-        if (state.searchContextType !== contextType) {
-          state.contextEnabled = undefined;
-          state.searchContextType = contextType;
-        }
-
-        if (state.contextEnabled === undefined) {
-          if (forceContextEnabled.includes(contextType)) {
-            state.contextEnabled = true;
-          }
-        }
-
         panels.push(
-          this.attach("search-menu", { contextEnabled: state.contextEnabled })
+          this.attach("search-menu", {
+            inTopicContext: state.inTopicContext,
+          })
         );
       } else if (state.hamburgerVisible) {
         panels.push(this.attach("hamburger-menu"));
@@ -477,11 +465,9 @@ export default createWidget("header", {
     this.updateHighlight();
 
     if (this.state.searchVisible) {
-      schedule("afterRender", () => {
-        const searchInput = document.querySelector("#search-term");
-        searchInput.focus();
-        searchInput.select();
-      });
+      this.focusSearchInput();
+    } else {
+      this.state.inTopicContext = false;
     }
   },
 
@@ -537,8 +523,7 @@ export default createWidget("header", {
 
   togglePageSearch() {
     const { state } = this;
-
-    state.contextEnabled = false;
+    state.inTopicContext = false;
 
     const currentPath = this.router.get("_router.currentPath");
     const blocklist = [/^discovery\.categories/];
@@ -565,7 +550,7 @@ export default createWidget("header", {
     }
 
     if (showSearch) {
-      state.contextEnabled = true;
+      state.inTopicContext = true;
       this.toggleSearchMenu();
       return false;
     }
@@ -573,13 +558,6 @@ export default createWidget("header", {
     return true;
   },
 
-  searchMenuContextChanged(value) {
-    this.state.contextType = this.register
-      .lookup("search-service:main")
-      .get("contextType");
-    this.state.contextEnabled = value;
-  },
-
   domClean() {
     const { state } = this;
 
@@ -637,10 +615,6 @@ export default createWidget("header", {
         this.toggleHamburger();
         break;
       case "page-search":
-        let contextType = this.searchContextType();
-        if (contextType === "topic") {
-          this.state.searchContextType = contextType;
-        }
         if (!this.togglePageSearch()) {
           msg.event.preventDefault();
           msg.event.stopPropagation();
@@ -649,13 +623,21 @@ export default createWidget("header", {
     }
   },
 
-  searchContextType() {
-    const service = this.register.lookup("search-service:main");
-    if (service) {
-      const ctx = service.get("searchContext");
-      if (ctx) {
-        return get(ctx, "type");
-      }
+  focusSearchInput() {
+    if (this.state.searchVisible) {
+      schedule("afterRender", () => {
+        putCursorAtEnd(document.querySelector("#search-term"));
+      });
     }
   },
+
+  setTopicContext() {
+    this.state.inTopicContext = true;
+    this.focusSearchInput();
+  },
+
+  clearContext() {
+    this.state.inTopicContext = false;
+    this.focusSearchInput();
+  },
 });
diff --git a/app/assets/javascripts/discourse/app/widgets/search-menu-results.js b/app/assets/javascripts/discourse/app/widgets/search-menu-results.js
index 364fee7..3aaf475 100644
--- a/app/assets/javascripts/discourse/app/widgets/search-menu-results.js
+++ b/app/assets/javascripts/discourse/app/widgets/search-menu-results.js
@@ -11,10 +11,7 @@ import { h } from "virtual-dom";
 import highlightSearch from "discourse/lib/highlight-search";
 import { iconNode } from "discourse-common/lib/icon-library";
 import renderTag from "discourse/lib/render-tag";
-import {
-  MODIFIER_REGEXP,
-  TOPIC_REPLACE_REGEXP,
-} from "discourse/widgets/search-menu";
+import { MODIFIER_REGEXP } from "discourse/widgets/search-menu";
 
 const suggestionShortcuts = [
   "in:title",
@@ -79,9 +76,7 @@ resetQuickSearchRandomTips();
 class Highlighted extends RawHtml {
   constructor(html, term) {
     super({ html: `<span>${html}</span>` });
-    if (term) {
-      this.term = term.replace(TOPIC_REPLACE_REGEXP, "");
-    }
+    this.term = term;
   }
 
   decorate($html) {
@@ -296,9 +291,7 @@ createWidget("search-menu-results", {
     }
 
     if (!term) {
-      return this.attach("search-menu-initial-options", {
-        term,
-      });
+      return this.attach("search-menu-initial-options", { term });
     }
 
     const resultTypes = results.resultTypes || [];
@@ -483,15 +476,15 @@ createWidget("search-menu-initial-options", {
 
     if (attrs.term || ctx) {
       if (ctx) {
-        const term = attrs.term ? `${attrs.term} ` : "";
-
+        const term = attrs.term || "";
         switch (ctx.type) {
           case "topic":
             content.push(
               this.attach("search-menu-assistant-item", {
-                slug: `${term}topic:${ctx.id}`,
+                slug: term,
+                setTopicContext: true,
                 label: [
-                  h("span", term),
+                  h("span", `${term} `),
                   h("span.label-suffix", I18n.t("search.in_this_topic")),
                 ],
               })
@@ -501,7 +494,7 @@ createWidget("search-menu-initial-options", {
           case "private_messages":
             content.push(

[... diff too long, it was truncated ...]

GitHub sha: 073e5ccd839b675e555182686a52fb51661efe1f

This commit appears in #14625 which was approved by jjaffeux. It was merged by pmusaraj.