FEATURE: revamps search-menu layout (#6543)

FEATURE: revamps search-menu layout (#6543)

diff --git a/app/assets/javascripts/discourse/lib/search.js.es6 b/app/assets/javascripts/discourse/lib/search.js.es6
index 405ec5f..c886eb0 100644
--- a/app/assets/javascripts/discourse/lib/search.js.es6
+++ b/app/assets/javascripts/discourse/lib/search.js.es6
@@ -9,24 +9,13 @@ import Post from "discourse/models/post";
 import Topic from "discourse/models/topic";
 
 export function translateResults(results, opts) {
-  if (!opts) opts = {};
+  opts = opts || {};
 
-  // Topics might not be included
-  if (!results.topics) {
-    results.topics = [];
-  }
-  if (!results.users) {
-    results.users = [];
-  }
-  if (!results.posts) {
-    results.posts = [];
-  }
-  if (!results.categories) {
-    results.categories = [];
-  }
-  if (!results.tags) {
-    results.tags = [];
-  }
+  results.topics = results.topics || [];
+  results.users = results.users || [];
+  results.posts = results.posts || [];
+  results.categories = results.categories || [];
+  results.tags = results.tags || [];
 
   const topicMap = {};
   results.topics = results.topics.map(function(topic) {
@@ -45,8 +34,7 @@ export function translateResults(results, opts) {
   });
 
   results.users = results.users.map(function(user) {
-    user = User.create(user);
-    return user;
+    return User.create(user);
   });
 
   results.categories = results.categories
@@ -57,7 +45,7 @@ export function translateResults(results, opts) {
 
   results.tags = results.tags
     .map(function(tag) {
-      let tagName = Handlebars.Utils.escapeExpression(tag.name);
+      const tagName = Handlebars.Utils.escapeExpression(tag.name);
       return Ember.Object.create({
         id: tagName,
         url: Discourse.getURL("/tags/" + tagName)
@@ -65,31 +53,31 @@ export function translateResults(results, opts) {
     })
     .compact();
 
-  const r = results.grouped_search_result;
   results.resultTypes = [];
 
   // TODO: consider refactoring front end to take a better structure
-  if (r) {
+  const groupedSearchResult = results.grouped_search_result;
+  if (groupedSearchResult) {
     [
       ["topic", "posts"],
-      ["user", "users"],
       ["category", "categories"],
-      ["tag", "tags"]
+      ["tag", "tags"],
+      ["user", "users"]
     ].forEach(function(pair) {
-      const type = pair[0],
-        name = pair[1];
+      const type = pair[0];
+      const name = pair[1];
       if (results[name].length > 0) {
-        var result = {
+        const componentName =
+          opts.searchContext &&
+          opts.searchContext.type === "topic" &&
+          type === "topic"
+            ? "post"
+            : type;
+        const result = {
           results: results[name],
-          componentName:
-            "search-result-" +
-            (opts.searchContext &&
-            opts.searchContext.type === "topic" &&
-            type === "topic"
-              ? "post"
-              : type),
+          componentName: `search-result-${componentName}`,
           type,
-          more: r["more_" + name]
+          more: groupedSearchResult[`more_${name}`]
         };
 
         if (result.more && name === "posts" && opts.fullSearchUrl) {
@@ -103,10 +91,10 @@ export function translateResults(results, opts) {
   }
 
   const noResults = !!(
-    results.topics.length === 0 &&
-    results.posts.length === 0 &&
-    results.users.length === 0 &&
-    results.categories.length === 0
+    !results.topics.length &&
+    !results.posts.length &&
+    !results.users.length &&
+    !results.categories.length
   );
 
   return noResults ? null : Em.Object.create(results);
diff --git a/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6 b/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6
index ddf3768..19d6420 100644
--- a/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6
+++ b/app/assets/javascripts/discourse/widgets/search-menu-results.js.es6
@@ -3,7 +3,6 @@ import { dateNode } from "discourse/helpers/node";
 import RawHtml from "discourse/widgets/raw-html";
 import { createWidget } from "discourse/widgets/widget";
 import { h } from "virtual-dom";
-import { iconNode } from "discourse-common/lib/icon-library";
 import highlightText from "discourse/lib/highlight-text";
 import { escapeExpression, formatUsername } from "discourse/lib/utilities";
 
@@ -20,6 +19,8 @@ class Highlighted extends RawHtml {
 
 function createSearchResult({ type, linkField, builder }) {
   return createWidget(`search-result-${type}`, {
+    tagName: "ul.list",
+
     html(attrs) {
       return attrs.results.map(r => {
         let searchResultId;
@@ -31,7 +32,7 @@ function createSearchResult({ type, linkField, builder }) {
         }
 
         return h(
-          "li",
+          "li.item",
           this.attach("link", {
             href: r.get(linkField),
             contents: () => builder.call(this, r, attrs.term),
@@ -54,7 +55,7 @@ function postResult(result, link, term) {
     html.push(
       h("span.blurb", [
         dateNode(result.created_at),
-        " - ",
+        h("span", " - "),
         new Highlighted(result.blurb, term)
       ])
     );
@@ -64,19 +65,50 @@ function postResult(result, link, term) {
 }
 
 createSearchResult({
+  type: "tag",
+  linkField: "url",
+  builder(t) {
+    const tag = escapeExpression(t.get("id"));
+    return h(
+      "a",
+      {
+        attributes: { href: t.get("url") },
+        className: `widget-link search-link tag-${tag} discourse-tag ${
+          Discourse.SiteSettings.tag_style
+        }`
+      },
+      tag
+    );
+  }
+});
+
+createSearchResult({
+  type: "category",
+  linkField: "url",
+  builder(c) {
+    return this.attach("category-link", { category: c, link: false });
+  }
+});
+
+createSearchResult({
   type: "user",
   linkField: "path",
   builder(u) {
-    return [
+    const userTitles = [h("span.username", formatUsername(u.username))];
+
+    if (u.name) {
+      userTitles.push(h("span.name", u.name));
+    }
+
+    const userResultContents = [
       avatarImg("small", {
         template: u.avatar_template,
         username: u.username
       }),
-      " ",
-      h("span.user-results", h("b", formatUsername(u.username))),
-      " ",
-      h("span.user-results", u.name ? u.name : "")
+      h("div.user-titles", userTitles)
     ];
+
+    return h("div.user-result", userResultContents);
   }
 });
 
@@ -111,32 +143,6 @@ createSearchResult({
   }
 });
 
-createSearchResult({
-  type: "category",
-  linkField: "url",
-  builder(c) {
-    return this.attach("category-link", { category: c, link: false });
-  }
-});
-
-createSearchResult({
-  type: "tag",
-  linkField: "url",
-  builder(t) {
-    const tag = escapeExpression(t.get("id"));
-    return h(
-      "a",
-      {
-        attributes: { href: t.get("url") },
-        className: `tag-${tag} discourse-tag ${
-          Discourse.SiteSettings.tag_style
-        }`
-      },
-      tag
-    );
-  }
-});
-
 createWidget("search-menu-results", {
   tagName: "div.results",
 
@@ -151,12 +157,26 @@ createWidget("search-menu-results", {
 
     const results = attrs.results;
     const resultTypes = results.resultTypes || [];
-    return resultTypes.map(rt => {
+
+    const mainResultsContent = [];
+    const classificationContents = [];
+    const otherContents = [];
+    const assignContainer = (type, node) => {
+      if (["topic"].includes(type)) {
+        mainResultsContent.push(node);
+      } else if (["category", "tag"].includes(type)) {
+        classificationContents.push(node);
+      } else {
+        otherContents.push(node);
+      }
+    };
+
+    resultTypes.forEach(rt => {
       const more = [];
 
       const moreArgs = {
         className: "filter",
-        contents: () => [I18n.t("show_more"), " ", iconNode("chevron-down")]
+        contents: () => [I18n.t("more"), "..."]
       };
 
       if (rt.moreUrl) {
@@ -176,22 +196,54 @@ createWidget("search-menu-results", {
         );
       }
 
-      let resultNode = [

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

GitHub sha: 11ee07093c939940f8d09c36211d0f2d0aa8ca56

This commit has been mentioned on Discourse Meta. There might be relevant details there: