mirror of https://github.com/zulip/zulip.git
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:
parent
5fdb8989e5
commit
eb4a2b9d4e
|
@ -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();
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -231,9 +231,14 @@ exports.process_escape_key = function (e) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (page_params.search_pills_enabled && $('#searchbox').has(':focus')) {
|
||||
$('#searchbox .pill').blur();
|
||||
$('#searchbox #search_query').blur();
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
const stream_name = filter.operands('stream')[0];
|
||||
const stream_id = stream_data.get_stream_id(stream_name);
|
||||
if (!stream_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return stream_data.is_muted(stream_id);
|
||||
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";
|
||||
}
|
||||
return sub_count;
|
||||
}
|
||||
|
||||
function in_all() {
|
||||
return filter !== undefined &&
|
||||
(filtered_to_non_home_view_stream() ||
|
||||
filter.has_operand("in", "all"));
|
||||
function make_tab_data(filter) {
|
||||
const tab_data = {};
|
||||
if (filter === undefined) {
|
||||
return {
|
||||
title: 'All messages',
|
||||
icon: 'home',
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
exports.colorize_tab_bar();
|
||||
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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
text-overflow: ellipsis;
|
||||
padding: 0 5px;
|
||||
}
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
margin: 0 -4px 0 0;
|
||||
padding: 12px 6px;
|
||||
|
||||
li.private_message a {
|
||||
color: hsl(0, 0%, 100%);
|
||||
}
|
||||
|
||||
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%);
|
||||
padding-right: 2px;
|
||||
&:hover {
|
||||
color: hsl(0, 0%, 0%);
|
||||
@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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
.stream {
|
||||
text-overflow: clip;
|
||||
overflow: hidden;
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
padding-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
li.active.root {
|
||||
padding: 0px 10px;
|
||||
.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%);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
{{#if stream_settings_link}}
|
||||
<a href="{{stream_settings_link}}">{{title}}</a>
|
||||
{{else}}
|
||||
{{#if home}}
|
||||
<i class="fa fa-home" aria-hidden="true"></i>
|
||||
{{else}}
|
||||
{{title}}
|
||||
{{/if}}
|
||||
{{title}}
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</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}}
|
||||
{{#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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue