navbar: Improve structure & styling for top navbar.

This updates the logged-in top navbar to display the stream/message
name, number of users, and description. It also replaces the search
bar with a search icon that expands into a full-width search bar.

Co-authored-by: Max Nussenbaum <max@maxnuss.com>

Fixes: #164.
Fixes: #5198.
This commit is contained in:
YashRE42 2020-02-03 21:31:11 +05:30 committed by Tim Abbott
parent 5fdb8989e5
commit eb4a2b9d4e
11 changed files with 379 additions and 318 deletions

View File

@ -251,9 +251,9 @@ expect_stream_subject();
casper.then(check_narrow_title('frontend test - Zulip Dev - Zulip'));
casper.then(function () {
// This time, un-narrow by hitting the search 'x'
// Un-narrow by clicking "Zulip"
casper.test.info('Un-narrowing');
casper.click('#search_exit');
casper.click('.brand');
});
expect_home();

View File

@ -5,6 +5,7 @@ zrequire('search');
zrequire('search_pill');
zrequire('Filter', 'js/filter');
zrequire('search_pill_widget');
zrequire('tab_bar');
const noop = () => {};
const return_true = () => true;
@ -38,13 +39,6 @@ run_test('update_button_visibility', () => {
const search_query = $('#search_query');
const search_button = $('.search_button');
search_query.is = return_false;
search_query.val('');
narrow_state.active = return_false;
search_button.prop('disabled', false);
search.update_button_visibility();
assert(search_button.prop('disabled'));
search_query.is = return_true;
search_query.val('');
narrow_state.active = return_false;
@ -237,7 +231,6 @@ run_test('initizalize', () => {
search_query_box.is = return_true;
func(ev);
assert(is_blurred);
assert(search_button.prop('disabled'));
operators = [{
negated: false,
@ -268,7 +261,7 @@ run_test('initizalize', () => {
search_query_box.val("test string");
narrow_state.search_string = () => 'ver';
callback();
assert.equal(search_query_box.val(), 'ver');
assert.equal(search_query_box.val(), 'test string');
}
};
@ -284,17 +277,7 @@ run_test('initizalize', () => {
}
};
let is_deactivated;
narrow.deactivate = () => {
is_deactivated = true;
};
search.initialize();
const search_exit_callback = $('#search_exit').get_on_handler('click');
search_exit_callback();
assert(is_deactivated);
});
run_test('initiate_search', () => {

View File

@ -2,6 +2,7 @@ set_global('page_params', {
search_pills_enabled: false,
});
zrequire('search');
zrequire('tab_bar');
const noop = () => {};
const return_true = () => true;
@ -26,8 +27,6 @@ run_test('update_button_visibility', () => {
search_query.val('');
narrow_state.active = return_false;
search_button.prop('disabled', false);
search.update_button_visibility();
assert(search_button.prop('disabled'));
search_query.is = return_true;
search_query.val('');
@ -213,7 +212,6 @@ run_test('initialize', () => {
search_query_box.is = return_true;
func(ev);
assert(is_blurred);
assert(search_button.prop('disabled'));
_setup('ver');
search.is_using_input_method = true;
@ -239,7 +237,7 @@ run_test('initialize', () => {
search_query_box.val("test string");
narrow_state.search_string = () => 'ver';
callback();
assert.equal(search_query_box.val(), 'ver');
assert.equal(search_query_box.val(), 'test string');
}
};

View File

@ -231,9 +231,14 @@ exports.process_escape_key = function (e) {
return true;
}
if (page_params.search_pills_enabled && $('#searchbox').has(':focus')) {
if ($('#searchbox').has(':focus')) {
$("input:focus,textarea:focus").blur();
if (page_params.search_pills_enabled) {
$('#searchbox .pill').blur();
$('#searchbox #search_query').blur();
} else {
tab_bar.exit_search();
}
return true;
}

View File

@ -45,8 +45,6 @@ function update_buttons_with_focus(focused) {
|| search_query_box.val()
|| narrow_state.active()) {
$('.search_button').prop('disabled', false);
} else {
$('.search_button').prop('disabled', true);
}
}
@ -156,7 +154,6 @@ exports.initialize = function () {
// Some of these functions don't actually need to be exported,
// but the code was moved here from elsewhere, and it would be
// more work to re-order everything and make them private.
$('#search_exit').on('click', narrow.deactivate);
search_query_box.on('focus', exports.focus_search);
search_query_box.on('blur', function () {
@ -176,8 +173,6 @@ exports.initialize = function () {
// really it would be OK if they did).
setTimeout(function () {
const search_string = narrow_state.search_string();
search_query_box.val(search_string);
exports.update_button_visibility();
}, 100);
});
@ -204,6 +199,7 @@ exports.initiate_search = function () {
if (page_params.search_pills_enabled) {
$('#search_query').focus();
} else {
tab_bar.open_search_bar_and_close_narrow_description();
$('#search_query').select();
}
};

View File

@ -140,6 +140,12 @@ exports.update_stream_name = function (sub, new_name) {
if (compose_state.stream_name() === old_name) {
compose_state.stream_name(new_name);
}
// Update navbar stream name if needed
const filter = narrow_state.filter();
if (filter && filter.operands("stream")[0] === old_name) {
tab_bar.update_stream_name(new_name);
}
};
exports.update_stream_description = function (sub, description, rendered_description) {
@ -152,6 +158,12 @@ exports.update_stream_description = function (sub, description, rendered_descrip
// Update stream settings
stream_edit.update_stream_description(sub);
// Update navbar stream description if needed
const filter = narrow_state.filter();
if (filter && filter.operands("stream")[0] === sub.name) {
tab_bar.update_stream_description(sub.rendered_description);
}
};
exports.update_stream_privacy = function (sub, values) {

View File

@ -1,172 +1,138 @@
const render_tab_bar = require('../templates/tab_bar.hbs');
function make_tab(title, hash, data, extra_class, home) {
return {active: "inactive",
cls: extra_class || "",
title: title,
hash: hash,
data: data,
home: home || false };
function get_sub_count(current_stream) {
const sub_count = current_stream.subscriber_count;
return sub_count;
}
function make_tab_data() {
const tabs = [];
const filter = narrow_state.filter();
function filtered_to_non_home_view_stream() {
if (!filter.has_operator('stream')) {
return false;
function get_formatted_sub_count(current_stream) {
let sub_count = get_sub_count(current_stream);
if (sub_count >= 1000) {
// parseInt() is used to floor the value of division to an integer
sub_count = parseInt(sub_count / 1000, 10) + "k";
}
const stream_name = filter.operands('stream')[0];
const stream_id = stream_data.get_stream_id(stream_name);
if (!stream_id) {
return true;
return sub_count;
}
return stream_data.is_muted(stream_id);
function make_tab_data(filter) {
const tab_data = {};
if (filter === undefined) {
return {
title: 'All messages',
icon: 'home',
};
}
function in_all() {
return filter !== undefined &&
(filtered_to_non_home_view_stream() ||
filter.has_operand("in", "all"));
}
if (in_all()) {
tabs.push(make_tab("All Messages", "#narrow/in/all", undefined, "root"));
} else if (page_params.narrow !== undefined) {
tabs.push(make_tab("Stream " + page_params.narrow_stream,
hash_util.operators_to_hash([page_params.narrow[0]]),
page_params.narrow_stream, 'stream'));
if (page_params.narrow_topic !== undefined) {
tabs.push(make_tab("Topic " + page_params.narrow_topic,
hash_util.operators_to_hash(page_params.narrow),
null));
tab_data.title = filter.get_title();
tab_data.icon = filter.get_icon();
if (tab_data.icon === 'hashtag' || tab_data.icon === 'lock') {
const stream = filter.operands("stream")[0];
const current_stream = stream_data.get_sub_by_name(stream);
if (current_stream) {
tab_data.rendered_narrow_description = current_stream.rendered_description;
tab_data.sub_count = get_sub_count(current_stream);
tab_data.formatted_sub_count = get_formatted_sub_count(current_stream);
tab_data.stream_settings_link = "#streams/" + current_stream.stream_id + "/" + current_stream.name;
} else {
tab_data.title = 'Unknown Stream';
tab_data.sub_count = '0';
tab_data.formatted_sub_count = '0';
tab_data.rendered_narrow_description = "This stream does not exist or is private.";
}
}
if (narrow_state.active() && narrow_state.operators().length > 0) {
let stream;
const ops = narrow_state.operators();
// Second breadcrumb item
let hashed = hash_util.operators_to_hash(ops.slice(0, 1));
if (filter.has_operator("stream")) {
stream = filter.operands("stream")[0];
tabs.push(make_tab(stream, hashed, stream, 'stream'));
} else if (filter.has_operator("pm-with") ||
filter.has_operand("is", "private")) {
tabs.push(make_tab("Private Messages", '#narrow/is/private',
undefined, 'private_message '));
if (filter.has_operator("pm-with")) {
const emails = filter.operands("pm-with")[0].split(',');
const names = emails.map(email => {
if (!people.get_by_email(email)) {
return email;
}
return people.get_by_email(email).full_name;
});
tabs.push(make_tab(names.join(', '), hashed));
}
} else if (filter.has_operator("group-pm-with")) {
tabs.push(make_tab("Group Private", '#narrow/group-pm-with',
undefined, 'private_message '));
} else if (filter.has_operand("is", "starred")) {
tabs.push(make_tab("Starred", hashed));
} else if (filter.has_operand("streams", "public")) {
tabs.push(make_tab("Public Streams", hashed));
} else if (filter.has_operator("near")) {
tabs.push(make_tab("Near " + filter.operands("near")[0], hashed));
} else if (filter.has_operator("id")) {
tabs.push(make_tab("ID " + filter.operands("id")[0], hashed));
} else if (filter.has_operand("is", "mentioned")) {
tabs.push(make_tab("Mentions", hashed));
} else if (filter.has_operator("sender")) {
let sender = filter.operands("sender")[0];
if (people.get_by_email(sender)) {
sender = people.get_by_email(sender).full_name;
}
tabs.push(make_tab("Sent by " + sender, hashed));
} else if (filter.has_operator("search")) {
// Search is not a clickable link, since we don't have
// a search narrow
tabs.push(make_tab("Search results", false));
}
// Third breadcrumb item for stream-topic naarrows
if (filter.has_operator("stream") &&
filter.has_operator("topic")) {
const topic = filter.operands("topic")[0];
hashed = hash_util.operators_to_hash(ops.slice(0, 2));
tabs.push(make_tab(topic, hashed, null));
}
}
if (tabs.length === 0) {
tabs.push(make_tab('All messages', "#", "home", "root", true));
}
// Last tab is not a link
tabs[tabs.length - 1].hash = null;
return tabs;
return tab_data;
}
exports.colorize_tab_bar = function () {
const stream_tab = $('#tab_list .stream');
if (stream_tab.length > 0) {
let stream_name = stream_tab.data('name');
if (stream_name === undefined) {
return;
}
stream_name = stream_name.toString();
const color_for_stream = stream_data.get_color(stream_name);
const stream_dark = stream_color.get_color_class(color_for_stream);
const stream_light = colorspace.getHexColor(
colorspace.getLighterColor(
colorspace.getDecimalColor(color_for_stream), 0.2));
if (stream_tab.hasClass("stream")) {
stream_tab.css('background-color', color_for_stream);
if (stream_tab.hasClass("inactive")) {
stream_tab.hover (
function () {
$(this).css('background-color', stream_light);
}, function () {
$(this).css('background-color', color_for_stream);
}
);
}
stream_tab.removeClass(stream_color.color_classes);
stream_tab.addClass(stream_dark);
}
}
const filter = narrow_state.filter();
if (filter === undefined || !filter.has_operator('stream')) {return;}
const color_for_stream = stream_data.get_color(filter.operands("stream")[0]);
const stream_light = colorspace.getHexColor(colorspace.getDecimalColor(color_for_stream));
$("#tab_list .fa-hashtag").css('color', stream_light);
$("#tab_list .fa-lock").css('color', stream_light);
};
function build_tab_bar() {
const tabs = make_tab_data();
function display_tab_bar(tab_bar_data) {
const tab_bar = $("#tab_bar");
tab_bar.empty();
tabs[tabs.length - 1].active = "active";
const rendered = render_tab_bar({tabs: tabs});
const rendered = render_tab_bar(tab_bar_data);
tab_bar.append(rendered);
if (tab_bar_data.stream_settings_link) {
exports.colorize_tab_bar();
}
tab_bar.removeClass('notdisplayed');
}
function build_tab_bar(filter) {
// This makes sure we don't waste time appending tab_bar on a template where it's never used
if (filter && !filter.is_common_narrow()) {
exports.open_search_bar_and_close_narrow_description();
} else {
const tab_bar_data = make_tab_data(filter);
display_tab_bar(tab_bar_data);
$(".search_closed").on("click", function (e) {
exports.open_search_bar_and_close_narrow_description();
$('#search_query').select();
e.preventDefault();
e.stopPropagation();
});
exports.close_search_bar_and_open_narrow_description();
}
}
exports.exit_search = function () {
const filter = narrow_state.filter();
if (!filter || filter.is_common_narrow()) {
// for common narrows, we change the UI (and don't redirect)
exports.close_search_bar_and_open_narrow_description();
} else {
// for "searching narrows", we redirect
window.location.replace(filter.generate_redirect_url());
}
};
exports.update_stream_name = function (new_name) {
const stream_name = $(".stream a");
if (stream_name !== undefined) {
stream_name.text(new_name);
}
};
exports.update_stream_description = function () {
// TODO: Implement this properly. Really, this and update_stream
// name should just do a full rerender of the tab_tab component;
// they're rare events and that rendering is cheap.
// TODO: Do similar rerenders for stream privacy or subscriber
// count changes.
return;
};
exports.initialize = function () {
build_tab_bar();
const filter = narrow_state.filter();
build_tab_bar(filter);
// register navbar click handlers
$('#search_exit').on("click", function (e) {
tab_bar.exit_search();
e.preventDefault();
e.stopPropagation();
});
$(".search_open").on("click", function (e) {
$('#search_query').typeahead('lookup').focus();
e.preventDefault();
e.stopPropagation();
});
};
exports.open_search_bar_and_close_narrow_description = function () {
$(".navbar-search").addClass("expanded");
$("#tab_list").addClass("hidden");
};
exports.close_search_bar_and_open_narrow_description = function () {
$(".navbar-search").removeClass("expanded");
$("#tab_list").removeClass("hidden");
};
window.tab_bar = exports;

View File

@ -83,9 +83,8 @@ body.night-mode {
/* do not turn the .message_header .stream_label text dark on hover because they're
on a dark background, and don't change the dark labels dark either. */
.message_header:not(.dark_background) a.stream_label:not(.dark_background):hover,
#tab_list li.stream:not(.dark_background) {
color: hsl(212, 28%, 18%) !important;
.message_header:not(.dark_background) a.stream_label:not(.dark_background):hover {
color: hsl(212, 28%, 18%);
}
/* these are converting grey things to "new grey" */
@ -204,8 +203,7 @@ on a dark background, and don't change the dark labels dark either. */
}
.message-header-contents,
.message_header_private_message .message-header-contents,
#tab_bar #tab_list li.active {
.message_header_private_message .message-header-contents {
background-color: hsla(0, 0%, 0%, 0.2);
}
@ -226,6 +224,19 @@ on a dark background, and don't change the dark labels dark either. */
.top-navbar-border {
border-color: hsla(0, 0%, 0%, 0.6);
}
#tab_bar #tab_list li.sub_count::before {
background: hsla(0, 0%, 100%, 0.5);
}
#tab_bar #tab_list li.sub_count::after {
background: hsla(0, 0%, 100%, 0.5);
}
#searchbox_legacy {
#tab_bar #tab_list li.sub_count,
#tab_bar #tab_list li.narrow_description {
color: hsla(0, 0%, 90%, 1);
}
}
.overlay,
#subscription_overlay #stream-creation #stream_creation_form #stream_creating_indicator:not(:empty),
@ -354,8 +365,6 @@ on a dark background, and don't change the dark labels dark either. */
}
thead,
#searchbox,
#searchbox_legacy,
.drafts-container .drafts-header,
.nav > li > a:hover,
.subscriptions-container .subscriptions-header,

View File

@ -1372,6 +1372,7 @@ div.focused_table {
}
#tab_bar {
width: 100%;
z-index: 2;
padding-top: 0px;
overflow: hidden;
@ -1379,97 +1380,161 @@ div.focused_table {
float: left;
letter-spacing: normal;
height: 40px;
#tab_list {
list-style: none;
display: flex;
align-content: flex-start;
flex-wrap: nowrap;
margin: 0px 0px 0px 0px;
height: 40px;
line-height: 40px;
font-size: 16px;
border: none;
white-space: nowrap;
li {
width: calc(100% - 1px);
cursor: default;
.hidden {
display: none;
}
span {
white-space: nowrap;
list-style-type: none;
display: inline-block;
vertical-align: top;
position: relative;
font-weight: 300;
background-color: hsl(0, 0%, 98%);
margin: 0px;
padding: 0px;
font-weight: 600;
font-size: 16px;
line-height: 16px;
margin: 0 -4px 0 0;
padding: 12px 6px;
@media (max-width: 500px) {
padding: 7px 3.5px; // based on having ~41.66% decrease
}
&:not(.search_closed):not(.sub_count):not(.narrow_description) {
flex-shrink: 1;
overflow: hidden;
}
&:not(.stream) {
text-overflow: ellipsis;
padding: 0 5px;
}
li.private_message a {
color: hsl(0, 0%, 100%);
}
i {
margin-right: 3px;
}
.fa {
margin: 0px 3px 0px 5px;
.fa-envelope {
font-size: 14px;
margin: 0px 5px 0px 5px;
}
.fa-hashtag {
font-size: 1.2rem;
// font-weight: 800;
margin: 0px 2px 0px 5px;
}
}
}
.stream {
text-overflow: clip;
overflow: hidden;
a {
text-decoration: none;
color: inherit;
border-color: inherit;
width: 100%;
display: inline-block;
padding: 0px 5px;
max-width: 150px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
li.active {
background-color: hsl(0, 0%, 88%);
max-width: 150px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
li.private_message {
border-top-color: hsla(0, 0%, 0%, 0.0);
border-right-color: hsla(0, 0%, 0%, 0.0);
border-bottom-color: hsla(0, 0%, 0%, 0.0);
background-color: hsl(0, 0%, 27%);
border-left-color: hsl(0, 0%, 27%);
color: hsl(0, 0%, 100%);
border-width: 0px;
}
.root {
border-color: hsl(0, 0%, 88%);
background-color: hsl(0, 0%, 88%);
margin: 0px;
a {
color: hsl(0, 0%, 52%);
text-decoration: none;
padding-right: 2px;
}
}
.sub_count,
.narrow_description {
background: none;
font-size: 14px;
color: hsl(0, 0%, 40%);
font-weight: 400;
line-height: 20px;
}
.sub_count {
margin-left: 10px;
margin-right: 10px;
.fa.fa-user-o {
margin-left: 0px;
}
&::before {
content: "";
position: absolute;
left: -5px;
top: 25%;
width: 1px;
height: 50%;
background: hsl(0, 0%, 88%);
@media (max-width: 500px) {
top: 10%;
}
}
&::after {
content: "";
position: absolute;
right: -5px;
top: 25%;
width: 1px;
height: 50%;
background: hsl(0, 0%, 88%);
@media (max-width: 500px) {
top: 10%;
}
}
}
.narrow_description {
// the actual value of flex shrink does not matter, it is the
// ratio of this value to other flex items that determines the
// behavior while shrinking, here the other item has the .stream
// class and a flex of 1, so the value here *is* the ratio, and
// is chosen such that the narrow description shrinks to close
// before the stream name must begin to shrink
flex-shrink: 100;
overflow: hidden;
white-space: nowrap;
margin: 0;
.emoji {
margin: 0;
padding: 0;
}
padding: 12px 0px;
padding-left: 2px;
@media (max-width: 500px) {
padding: 7px 0;
padding-left: 2px;
}
}
.search_closed {
flex: 0; // makes sure search icon is always visible
margin-left: auto; // aligns search icon to right end of box
margin-right: 40px; // 27 = 15 (gets icon inside border) + 25 (margin against border)
cursor: pointer;
font-size: 20px;
padding: 12px 0px 0px 0px;
@media (max-width: 500px) {
padding: 5px 0px 0px 0px;
}
}
}
}
.search_icon {
color: hsl(0, 0%, 80%);
text-decoration: none;
width: 0;
height: 0;
padding-top: 12px;
padding-left: 50px;
&:hover {
color: hsl(0, 0%, 0%);
}
}
}
li.inactive {
border-width: 0px;
margin-right: -4px;
font-size: 14px;
&::before {
left: 100%;
top: 50%;
content: " ";
height: 0px;
width: 0px;
position: absolute;
pointer-events: none;
z-index: 1;
transform: scale(.9999);
}
}
li.active.root {
padding: 0px 10px;
}
text-decoration: none;
}
}
@ -1580,12 +1645,20 @@ div.focused_table {
width: 100%;
height: 40px;
.navbar-search {
margin-top: 0px;
width: auto;
float: none;
.navbar-search:not(.expanded) {
display: none;
}
.navbar-search.expanded {
overflow: hidden;
height: 40px;
margin-top: 0px;
right: 2;
width: calc(100% - 2px);
position: absolute;
.search_button {
display: inline;
margin-right: 16px;
}
}
.input-append {
@ -1600,6 +1673,10 @@ div.focused_table {
top: 10px;
z-index: 5;
}
.fa-search:not(.deactivated) {
cursor: pointer;
}
}
#search_query {
@ -1608,7 +1685,7 @@ div.focused_table {
height: 40px;
padding: 0px;
padding-left: 35px;
padding-right: 20px;
padding-right: 40px;
border: none;
border-radius: 0px;
font-family: 'Source Sans Pro';
@ -1646,19 +1723,6 @@ div.focused_table {
visibility: hidden;
}
.search_icon {
color: hsl(0, 0%, 80%);
text-decoration: none;
display: block;
width: 1px;
height: 1px;
}
.search_icon:hover {
color: hsl(0, 0%, 0%);
text-decoration: none;
}
#search_arrows {
/* Bootstrap wants font-size: 0 to eliminate space between
the buttons. We need to inherit the font size, so we
@ -1701,7 +1765,7 @@ div.focused_table {
left: 0px;
text-align: center;
vertical-align: middle;
border-right: 2px solid hsl(204, 20%, 74%);
// border-right: 2px solid hsl(204, 20%, 74%);
}
#streamlist-toggle-button {
@ -2515,17 +2579,10 @@ div.topic_edit_spinner .loading_indicator_spinner {
width: 30px;
}
#top_navbar.rightside-userlist .navbar-search {
margin-right: 100px;
}
#top_navbar.rightside-userlist #navbar-buttons {
margin-right: 41px;
}
.navbar-search {
margin-right: 60px;
}
.nav .dropdown-menu {
min-width: 180px;
@ -2539,6 +2596,25 @@ div.topic_edit_spinner .loading_indicator_spinner {
.column-middle {
margin-right: 7px;
}
.top-navbar-container,
#searchbox_legacy .navbar-search.expanded {
width: calc(100% - 91px);
}
.search_closed .fa-search {
right: 115px;
}
#top_navbar:not(.rightside-userlist) {
.search_closed .fa-search {
right: 72px;
}
.top-navbar-border,
#searchbox_legacy .navbar-search.expanded {
width: calc(100% - 50px);
}
}
}
@media (max-width: 775px) {
@ -2604,17 +2680,34 @@ div.topic_edit_spinner .loading_indicator_spinner {
display: block;
}
#searchbox,
#searchbox_legacy {
margin-left: 42px;
.top-navbar-border {
margin-left: 40px;
}
#top_navbar.rightside-userlist .navbar-search {
margin-right: 127px;
.top-navbar-border {
width: calc(100% - 116px);
}
// todo: Figure out why this has to be different
// from above at this width and resolve it
// #searchbox_legacy .navbar-search.expanded,
#searchbox_legacy .navbar-search.expanded {
width: calc(100% - 131px);
}
.navbar-search {
margin-right: 81px;
.search_closed .fa-search {
right: 115px;
}
#top_navbar:not(.rightside-userlist) {
// .search_closed .fa-search {
// right: 115px;
// }
.top-navbar-border {
width: calc(100% - 75px);
}
#searchbox_legacy .navbar-search.expanded {
width: calc(100% - 90px);
}
}
}
@ -2636,6 +2729,10 @@ div.topic_edit_spinner .loading_indicator_spinner {
margin-top: 10px;
}
.search_closed .fa-search {
top: 5px;
}
#streamlist-toggle,
#navbar-buttons,
.navbar-search,
@ -2665,10 +2762,6 @@ div.topic_edit_spinner .loading_indicator_spinner {
top: -5px;
}
#top_navbar.rightside-userlist .navbar-search {
margin-right: 115px;
}
#searchbox,
#searchbox_legacy {
.input-append .fa-search {
@ -2677,7 +2770,7 @@ div.topic_edit_spinner .loading_indicator_spinner {
.search_button,
.search_button[disabled]:hover {
top: 2px;
top: 0px;
}
}

View File

@ -1,19 +1,19 @@
<ul id="tab_list">
{{#each tabs}}
<li class="{{active}} {{cls}}" {{#if data}}data-name="{{data}}"{{/if}}>
<span id="tab_list">
<span {{#if stream_settings_link}}class="stream"{{/if}} {{#if data}}data-name="{{data}}"{{/if}}>
{{#if icon}}
<i class="fa fa-angle-right" aria-hidden="true"></i>
<i class="fa fa-{{icon}}" aria-hidden="true"></i>
{{/if}}
{{! Most tabs are links, but some are not since we don't have a narrow for them (e.g. Search) }}
{{#if hash}}
<a href="{{hash}}">{{title}}</a>
{{else}}
{{#if home}}
<i class="fa fa-home" aria-hidden="true"></i>
{{#if stream_settings_link}}
<a href="{{stream_settings_link}}">{{title}}</a>
{{else}}
{{title}}
{{/if}}
</span>
{{#if sub_count}}
<span class="sub_count" data-toggle="tooltip" title="{{sub_count}} users are subscribed to #{{title}}"><i class="fa fa-user-o"></i>{{formatted_sub_count}}</span>
{{/if}}
</li>
{{/each}}
</ul>
{{#if rendered_narrow_description}}
<span class="narrow_description rendered_markdown" data-toggle="tooltip" title="{{rendered_narrow_description}}">{{rendered_markdown rendered_narrow_description}}</span>
{{/if}}
<span class="search_icon search_closed" ><i class="fa fa-search" aria-hidden="true"></i></span>
</span>

View File

@ -12,12 +12,12 @@
<span id="streamlist-toggle-unreadcount">0</span>
</a>
</div>
<div class="top-navbar-border">
<div class="top-navbar-border top-navbar-container">
{% if search_pills_enabled %}
<div id="searchbox">
<div id="tab_bar" class="notdisplayed">
</div>
<a class="search_icon" href="#search-operators" data-overlay-trigger="search-operators" title="{{ _('Search help') }}"><i class="fa fa-search" aria-hidden="true"></i></a>
<span class="search_icon" ><i class="fa fa-search" aria-hidden="true"></i></span>
<form id="searchbox_form" class="form-search navbar-search">
<div id="search_arrows" class="pill-container input-append">
<div contenteditable="true" class="input search-query input-block-level" id="search_query" type="text" placeholder="{{ _('Search') }}"
@ -35,9 +35,8 @@
<div id="search_arrows" class="input-append">
<input class="search-query input-block-level" id="search_query" type="text" placeholder="{{ _('Search') }}"
autocomplete="off" aria-label="{{ _('Search') }}" title="{{ _('Search') }} (/)"/>
{# Start the button off disabled since there is no active search #}
<button class="btn search_button" type="button" id="search_exit" disabled="disabled" aria-label="{{ _('Exit search') }}"><i class="fa fa-remove" aria-hidden="true"></i></button>
<a class="search_icon" href="#search-operators" data-overlay-trigger="search-operators" title="{{ _('Search help') }}"><i class="fa fa-search" aria-hidden="true"></i></a>
<button class="btn search_button" type="button" id="search_exit" aria-label="{{ _('Exit search') }}"><i class="fa fa-remove" aria-hidden="true"></i></button>
<span class="search_icon search_open" ><i class="fa fa-search" aria-hidden="true"></i></span>
</div>
</form>
</div>