FEATURE: revamps search-menu layout (#6543)

This commit is contained in:
Joffrey JAFFEUX 2018-10-30 15:44:49 +01:00 committed by Kris
parent e32993f96c
commit 11ee07093c
4 changed files with 325 additions and 191 deletions

View File

@ -9,24 +9,13 @@ import Post from "discourse/models/post";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
export function translateResults(results, opts) { export function translateResults(results, opts) {
if (!opts) opts = {}; opts = opts || {};
// Topics might not be included results.topics = results.topics || [];
if (!results.topics) { results.users = results.users || [];
results.topics = []; results.posts = results.posts || [];
} results.categories = results.categories || [];
if (!results.users) { results.tags = results.tags || [];
results.users = [];
}
if (!results.posts) {
results.posts = [];
}
if (!results.categories) {
results.categories = [];
}
if (!results.tags) {
results.tags = [];
}
const topicMap = {}; const topicMap = {};
results.topics = results.topics.map(function(topic) { results.topics = results.topics.map(function(topic) {
@ -45,8 +34,7 @@ export function translateResults(results, opts) {
}); });
results.users = results.users.map(function(user) { results.users = results.users.map(function(user) {
user = User.create(user); return User.create(user);
return user;
}); });
results.categories = results.categories results.categories = results.categories
@ -57,7 +45,7 @@ export function translateResults(results, opts) {
results.tags = results.tags results.tags = results.tags
.map(function(tag) { .map(function(tag) {
let tagName = Handlebars.Utils.escapeExpression(tag.name); const tagName = Handlebars.Utils.escapeExpression(tag.name);
return Ember.Object.create({ return Ember.Object.create({
id: tagName, id: tagName,
url: Discourse.getURL("/tags/" + tagName) url: Discourse.getURL("/tags/" + tagName)
@ -65,31 +53,31 @@ export function translateResults(results, opts) {
}) })
.compact(); .compact();
const r = results.grouped_search_result;
results.resultTypes = []; results.resultTypes = [];
// TODO: consider refactoring front end to take a better structure // TODO: consider refactoring front end to take a better structure
if (r) { const groupedSearchResult = results.grouped_search_result;
if (groupedSearchResult) {
[ [
["topic", "posts"], ["topic", "posts"],
["user", "users"],
["category", "categories"], ["category", "categories"],
["tag", "tags"] ["tag", "tags"],
["user", "users"]
].forEach(function(pair) { ].forEach(function(pair) {
const type = pair[0], const type = pair[0];
name = pair[1]; const name = pair[1];
if (results[name].length > 0) { if (results[name].length > 0) {
var result = { const componentName =
opts.searchContext &&
opts.searchContext.type === "topic" &&
type === "topic"
? "post"
: type;
const result = {
results: results[name], results: results[name],
componentName: componentName: `search-result-${componentName}`,
"search-result-" +
(opts.searchContext &&
opts.searchContext.type === "topic" &&
type === "topic"
? "post"
: type),
type, type,
more: r["more_" + name] more: groupedSearchResult[`more_${name}`]
}; };
if (result.more && name === "posts" && opts.fullSearchUrl) { if (result.more && name === "posts" && opts.fullSearchUrl) {
@ -103,10 +91,10 @@ export function translateResults(results, opts) {
} }
const noResults = !!( const noResults = !!(
results.topics.length === 0 && !results.topics.length &&
results.posts.length === 0 && !results.posts.length &&
results.users.length === 0 && !results.users.length &&
results.categories.length === 0 !results.categories.length
); );
return noResults ? null : Em.Object.create(results); return noResults ? null : Em.Object.create(results);

View File

@ -3,7 +3,6 @@ import { dateNode } from "discourse/helpers/node";
import RawHtml from "discourse/widgets/raw-html"; import RawHtml from "discourse/widgets/raw-html";
import { createWidget } from "discourse/widgets/widget"; import { createWidget } from "discourse/widgets/widget";
import { h } from "virtual-dom"; import { h } from "virtual-dom";
import { iconNode } from "discourse-common/lib/icon-library";
import highlightText from "discourse/lib/highlight-text"; import highlightText from "discourse/lib/highlight-text";
import { escapeExpression, formatUsername } from "discourse/lib/utilities"; import { escapeExpression, formatUsername } from "discourse/lib/utilities";
@ -20,6 +19,8 @@ class Highlighted extends RawHtml {
function createSearchResult({ type, linkField, builder }) { function createSearchResult({ type, linkField, builder }) {
return createWidget(`search-result-${type}`, { return createWidget(`search-result-${type}`, {
tagName: "ul.list",
html(attrs) { html(attrs) {
return attrs.results.map(r => { return attrs.results.map(r => {
let searchResultId; let searchResultId;
@ -31,7 +32,7 @@ function createSearchResult({ type, linkField, builder }) {
} }
return h( return h(
"li", "li.item",
this.attach("link", { this.attach("link", {
href: r.get(linkField), href: r.get(linkField),
contents: () => builder.call(this, r, attrs.term), contents: () => builder.call(this, r, attrs.term),
@ -54,7 +55,7 @@ function postResult(result, link, term) {
html.push( html.push(
h("span.blurb", [ h("span.blurb", [
dateNode(result.created_at), dateNode(result.created_at),
" - ", h("span", " - "),
new Highlighted(result.blurb, term) new Highlighted(result.blurb, term)
]) ])
); );
@ -63,20 +64,51 @@ function postResult(result, link, term) {
return html; return html;
} }
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({ createSearchResult({
type: "user", type: "user",
linkField: "path", linkField: "path",
builder(u) { 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", { avatarImg("small", {
template: u.avatar_template, template: u.avatar_template,
username: u.username username: u.username
}), }),
" ", h("div.user-titles", userTitles)
h("span.user-results", h("b", formatUsername(u.username))),
" ",
h("span.user-results", u.name ? u.name : "")
]; ];
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", { createWidget("search-menu-results", {
tagName: "div.results", tagName: "div.results",
@ -151,12 +157,26 @@ createWidget("search-menu-results", {
const results = attrs.results; const results = attrs.results;
const resultTypes = results.resultTypes || []; 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 more = [];
const moreArgs = { const moreArgs = {
className: "filter", className: "filter",
contents: () => [I18n.t("show_more"), " ", iconNode("chevron-down")] contents: () => [I18n.t("more"), "..."]
}; };
if (rt.moreUrl) { if (rt.moreUrl) {
@ -176,22 +196,54 @@ createWidget("search-menu-results", {
); );
} }
let resultNode = [ const resultNodeContents = [
h( this.attach(rt.componentName, {
"ul", searchContextEnabled: attrs.searchContextEnabled,
this.attach(rt.componentName, { searchLogId: attrs.results.grouped_search_result.search_log_id,
searchContextEnabled: attrs.searchContextEnabled, results: rt.results,
searchLogId: attrs.results.grouped_search_result.search_log_id, term: attrs.term
results: rt.results, })
term: attrs.term
})
)
]; ];
if (more.length) { if (more.length) {
resultNode.push(h("div.no-results", more)); resultNodeContents.push(h("div.show-more", more));
} }
return resultNode; assignContainer(
rt.type,
h(`div.${rt.componentName}`, resultNodeContents)
);
}); });
const content = [];
if (mainResultsContent.length) {
content.push(h("div.main-results", mainResultsContent));
}
if (classificationContents.length || otherContents.length) {
const secondaryResultsContent = [];
if (classificationContents.length) {
secondaryResultsContent.push(
h("div.classification-results", classificationContents)
);
}
if (otherContents.length) {
secondaryResultsContent.push(h("div.other-results", otherContents));
}
content.push(
h(
`div.secondary-results${
mainResultsContent.length ? "" : ".no-main-results"
}`,
secondaryResultsContent
)
);
}
return content;
} }
}); });

View File

@ -131,110 +131,6 @@
} }
} }
.search-menu {
.search-input {
position: relative;
}
.search-context .show-help {
float: right;
}
.heading {
padding: 5px 0 5px 5px;
.filter {
padding: 0 5px;
}
}
input[type="text"] {
margin: 0.5em 3px;
box-sizing: border-box;
width: calc(100% - 6px);
height: 32px;
}
.search-context {
padding: 0 5px;
label {
margin-bottom: 0;
}
}
.searching {
position: absolute;
top: 1.15em;
right: 1em;
.spinner {
width: 10px;
height: 10px;
border-width: 2px;
margin: 0;
}
}
// I am ghetto using this to display "Show More".. be warned
.no-results {
padding: 5px;
text-align: center;
}
.filter {
padding: 0;
&:hover {
background: transparent;
}
}
.search-link {
.badge-category-parent {
line-height: $line-height-small;
}
.topic-title {
margin-right: 6px;
}
.topic-statuses {
float: none;
display: inline-block;
color: dark-light-choose($primary-medium, $secondary-medium);
margin: 0;
.fa {
margin: 0;
}
}
}
li:not(.category):not(.heading) {
font-size: $font-0;
line-height: $line-height-medium;
.fa {
font-size: inherit;
}
a {
&:not(.discourse-tag) {
display: block;
padding: 5px;
}
transition: all linear 0.15s;
.user-results {
color: dark-light-choose($primary-high, $secondary-low);
}
}
&:hover a:not(.badge-notification) {
background-color: $highlight-medium;
}
button {
margin-left: 5px;
}
}
}
.user-menu { .user-menu {
.notifications { .notifications {
width: 100%; width: 100%;

View File

@ -0,0 +1,198 @@
.search-menu {
.search-input {
position: relative;
}
.search-context .show-help {
float: right;
}
.heading {
padding: 5px 0 5px 5px;
.filter {
padding: 0 5px;
}
}
input[type="text"] {
margin: 0.5em 3px;
box-sizing: border-box;
width: calc(100% - 6px);
height: 32px;
}
.search-context {
padding: 0 5px;
label {
margin-bottom: 0;
}
}
.search-context + .results {
margin-top: 5px;
}
.results {
display: flex;
flex-direction: row;
.list {
.item {
.blurb {
// https://css-tricks.com/snippets/css/prevent-long-urls-from-breaking-out-of-container/
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-all;
word-break: break-word;
-ms-hyphens: auto;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
}
}
.main-results {
display: flex;
flex: 1;
}
.main-results + .secondary-results {
border-left: 1px solid $primary-low;
margin-left: 1em;
padding-left: 1em;
max-width: 33%;
}
.secondary-results {
display: flex;
flex-direction: column;
flex: 1;
.classification-results {
border-bottom: 1px solid $primary-low;
margin-bottom: 1em;
padding-bottom: 1em;
}
.search-result-category {
}
.search-result-tag {
.list {
.item {
display: inline-flex;
.widget-link.search-link {
display: inline;
font-size: $font-0;
padding: 5px;
}
}
}
}
.search-result-user {
.user-result {
display: flex;
flex-direction: row;
align-items: center;
.avatar {
margin-right: 0.5em;
display: block;
min-width: 25px;
}
.user-titles {
display: flex;
flex-direction: column;
overflow: auto;
.username,
.name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.username {
color: dark-light-choose($primary-high, $secondary-low);
font-size: $font-0;
font-weight: 700;
}
.name {
color: dark-light-choose($primary-high, $secondary-low);
font-size: $font-down-1;
margin-top: 0.25em;
}
}
}
}
&.no-main-results .search-result-user {
.user-titles {
flex-direction: row;
align-items: center;
.name {
margin: 0 0 0 0.25em;
font-size: $font-0;
}
}
}
}
.show-more {
padding: 5px;
}
}
.searching {
position: absolute;
top: 1.15em;
right: 1em;
.spinner {
width: 10px;
height: 10px;
border-width: 2px;
margin: 0;
}
}
.no-results {
padding: 5px;
}
.filter {
padding: 0;
&:hover {
background: transparent;
}
}
.search-link {
.badge-category-parent {
line-height: $line-height-small;
}
.topic-title {
margin-right: 0.25em;
}
.topic-statuses {
float: none;
display: inline-block;
color: dark-light-choose($primary-medium, $secondary-medium);
margin: 0;
.fa {
margin: 0;
}
}
}
}