mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	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:
		@@ -251,9 +251,9 @@ expect_stream_subject();
 | 
				
			|||||||
casper.then(check_narrow_title('frontend test - Zulip Dev - Zulip'));
 | 
					casper.then(check_narrow_title('frontend test - Zulip Dev - Zulip'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
casper.then(function () {
 | 
					casper.then(function () {
 | 
				
			||||||
    // This time, un-narrow by hitting the search 'x'
 | 
					    // Un-narrow by clicking "Zulip"
 | 
				
			||||||
    casper.test.info('Un-narrowing');
 | 
					    casper.test.info('Un-narrowing');
 | 
				
			||||||
    casper.click('#search_exit');
 | 
					    casper.click('.brand');
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
expect_home();
 | 
					expect_home();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ zrequire('search');
 | 
				
			|||||||
zrequire('search_pill');
 | 
					zrequire('search_pill');
 | 
				
			||||||
zrequire('Filter', 'js/filter');
 | 
					zrequire('Filter', 'js/filter');
 | 
				
			||||||
zrequire('search_pill_widget');
 | 
					zrequire('search_pill_widget');
 | 
				
			||||||
 | 
					zrequire('tab_bar');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const noop = () => {};
 | 
					const noop = () => {};
 | 
				
			||||||
const return_true = () => true;
 | 
					const return_true = () => true;
 | 
				
			||||||
@@ -38,13 +39,6 @@ run_test('update_button_visibility', () => {
 | 
				
			|||||||
    const search_query = $('#search_query');
 | 
					    const search_query = $('#search_query');
 | 
				
			||||||
    const search_button = $('.search_button');
 | 
					    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.is = return_true;
 | 
				
			||||||
    search_query.val('');
 | 
					    search_query.val('');
 | 
				
			||||||
    narrow_state.active = return_false;
 | 
					    narrow_state.active = return_false;
 | 
				
			||||||
@@ -237,7 +231,6 @@ run_test('initizalize', () => {
 | 
				
			|||||||
        search_query_box.is = return_true;
 | 
					        search_query_box.is = return_true;
 | 
				
			||||||
        func(ev);
 | 
					        func(ev);
 | 
				
			||||||
        assert(is_blurred);
 | 
					        assert(is_blurred);
 | 
				
			||||||
        assert(search_button.prop('disabled'));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        operators = [{
 | 
					        operators = [{
 | 
				
			||||||
            negated: false,
 | 
					            negated: false,
 | 
				
			||||||
@@ -268,7 +261,7 @@ run_test('initizalize', () => {
 | 
				
			|||||||
            search_query_box.val("test string");
 | 
					            search_query_box.val("test string");
 | 
				
			||||||
            narrow_state.search_string = () => 'ver';
 | 
					            narrow_state.search_string = () => 'ver';
 | 
				
			||||||
            callback();
 | 
					            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();
 | 
					    search.initialize();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    const search_exit_callback = $('#search_exit').get_on_handler('click');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    search_exit_callback();
 | 
					 | 
				
			||||||
    assert(is_deactivated);
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
run_test('initiate_search', () => {
 | 
					run_test('initiate_search', () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ set_global('page_params', {
 | 
				
			|||||||
    search_pills_enabled: false,
 | 
					    search_pills_enabled: false,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
zrequire('search');
 | 
					zrequire('search');
 | 
				
			||||||
 | 
					zrequire('tab_bar');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const noop = () => {};
 | 
					const noop = () => {};
 | 
				
			||||||
const return_true = () => true;
 | 
					const return_true = () => true;
 | 
				
			||||||
@@ -26,8 +27,6 @@ run_test('update_button_visibility', () => {
 | 
				
			|||||||
    search_query.val('');
 | 
					    search_query.val('');
 | 
				
			||||||
    narrow_state.active = return_false;
 | 
					    narrow_state.active = return_false;
 | 
				
			||||||
    search_button.prop('disabled', false);
 | 
					    search_button.prop('disabled', false);
 | 
				
			||||||
    search.update_button_visibility();
 | 
					 | 
				
			||||||
    assert(search_button.prop('disabled'));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    search_query.is = return_true;
 | 
					    search_query.is = return_true;
 | 
				
			||||||
    search_query.val('');
 | 
					    search_query.val('');
 | 
				
			||||||
@@ -213,7 +212,6 @@ run_test('initialize', () => {
 | 
				
			|||||||
        search_query_box.is = return_true;
 | 
					        search_query_box.is = return_true;
 | 
				
			||||||
        func(ev);
 | 
					        func(ev);
 | 
				
			||||||
        assert(is_blurred);
 | 
					        assert(is_blurred);
 | 
				
			||||||
        assert(search_button.prop('disabled'));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _setup('ver');
 | 
					        _setup('ver');
 | 
				
			||||||
        search.is_using_input_method = true;
 | 
					        search.is_using_input_method = true;
 | 
				
			||||||
@@ -239,7 +237,7 @@ run_test('initialize', () => {
 | 
				
			|||||||
            search_query_box.val("test string");
 | 
					            search_query_box.val("test string");
 | 
				
			||||||
            narrow_state.search_string = () => 'ver';
 | 
					            narrow_state.search_string = () => 'ver';
 | 
				
			||||||
            callback();
 | 
					            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;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (page_params.search_pills_enabled && $('#searchbox').has(':focus')) {
 | 
					        if ($('#searchbox').has(':focus')) {
 | 
				
			||||||
            $('#searchbox .pill').blur();
 | 
					            $("input:focus,textarea:focus").blur();
 | 
				
			||||||
            $('#searchbox #search_query').blur();
 | 
					            if (page_params.search_pills_enabled) {
 | 
				
			||||||
 | 
					                $('#searchbox .pill').blur();
 | 
				
			||||||
 | 
					                $('#searchbox #search_query').blur();
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                tab_bar.exit_search();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,8 +45,6 @@ function update_buttons_with_focus(focused) {
 | 
				
			|||||||
        || search_query_box.val()
 | 
					        || search_query_box.val()
 | 
				
			||||||
        || narrow_state.active()) {
 | 
					        || narrow_state.active()) {
 | 
				
			||||||
        $('.search_button').prop('disabled', false);
 | 
					        $('.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,
 | 
					    // Some of these functions don't actually need to be exported,
 | 
				
			||||||
    // but the code was moved here from elsewhere, and it would be
 | 
					    // but the code was moved here from elsewhere, and it would be
 | 
				
			||||||
    // more work to re-order everything and make them private.
 | 
					    // 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('focus', exports.focus_search);
 | 
				
			||||||
    search_query_box.on('blur', function () {
 | 
					    search_query_box.on('blur', function () {
 | 
				
			||||||
@@ -176,8 +173,6 @@ exports.initialize = function () {
 | 
				
			|||||||
        // really it would be OK if they did).
 | 
					        // really it would be OK if they did).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        setTimeout(function () {
 | 
					        setTimeout(function () {
 | 
				
			||||||
            const search_string = narrow_state.search_string();
 | 
					 | 
				
			||||||
            search_query_box.val(search_string);
 | 
					 | 
				
			||||||
            exports.update_button_visibility();
 | 
					            exports.update_button_visibility();
 | 
				
			||||||
        }, 100);
 | 
					        }, 100);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -204,6 +199,7 @@ exports.initiate_search = function () {
 | 
				
			|||||||
    if (page_params.search_pills_enabled) {
 | 
					    if (page_params.search_pills_enabled) {
 | 
				
			||||||
        $('#search_query').focus();
 | 
					        $('#search_query').focus();
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
					        tab_bar.open_search_bar_and_close_narrow_description();
 | 
				
			||||||
        $('#search_query').select();
 | 
					        $('#search_query').select();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -140,6 +140,12 @@ exports.update_stream_name = function (sub, new_name) {
 | 
				
			|||||||
    if (compose_state.stream_name() === old_name) {
 | 
					    if (compose_state.stream_name() === old_name) {
 | 
				
			||||||
        compose_state.stream_name(new_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) {
 | 
					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
 | 
					    // Update stream settings
 | 
				
			||||||
    stream_edit.update_stream_description(sub);
 | 
					    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) {
 | 
					exports.update_stream_privacy = function (sub, values) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,172 +1,138 @@
 | 
				
			|||||||
const render_tab_bar = require('../templates/tab_bar.hbs');
 | 
					const render_tab_bar = require('../templates/tab_bar.hbs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function make_tab(title, hash, data, extra_class, home) {
 | 
					function get_sub_count(current_stream) {
 | 
				
			||||||
    return {active: "inactive",
 | 
					    const sub_count = current_stream.subscriber_count;
 | 
				
			||||||
            cls: extra_class || "",
 | 
					    return sub_count;
 | 
				
			||||||
            title: title,
 | 
					 | 
				
			||||||
            hash: hash,
 | 
					 | 
				
			||||||
            data: data,
 | 
					 | 
				
			||||||
            home: home || false };
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function make_tab_data() {
 | 
					function get_formatted_sub_count(current_stream) {
 | 
				
			||||||
    const tabs = [];
 | 
					    let sub_count = get_sub_count(current_stream);
 | 
				
			||||||
    const filter = narrow_state.filter();
 | 
					    if (sub_count >= 1000) {
 | 
				
			||||||
 | 
					        // parseInt() is used to floor the value of division to an integer
 | 
				
			||||||
    function filtered_to_non_home_view_stream() {
 | 
					        sub_count = parseInt(sub_count / 1000, 10) + "k";
 | 
				
			||||||
        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);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return sub_count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function in_all() {
 | 
					function make_tab_data(filter) {
 | 
				
			||||||
        return filter !== undefined &&
 | 
					    const tab_data = {};
 | 
				
			||||||
               (filtered_to_non_home_view_stream() ||
 | 
					    if (filter === undefined) {
 | 
				
			||||||
                filter.has_operand("in", "all"));
 | 
					        return {
 | 
				
			||||||
 | 
					            title: 'All messages',
 | 
				
			||||||
 | 
					            icon: 'home',
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    tab_data.title = filter.get_title();
 | 
				
			||||||
    if (in_all()) {
 | 
					    tab_data.icon = filter.get_icon();
 | 
				
			||||||
        tabs.push(make_tab("All Messages", "#narrow/in/all", undefined, "root"));
 | 
					    if (tab_data.icon === 'hashtag' || tab_data.icon === 'lock') {
 | 
				
			||||||
    } else if (page_params.narrow !== undefined) {
 | 
					        const stream = filter.operands("stream")[0];
 | 
				
			||||||
        tabs.push(make_tab("Stream " + page_params.narrow_stream,
 | 
					        const current_stream  = stream_data.get_sub_by_name(stream);
 | 
				
			||||||
                           hash_util.operators_to_hash([page_params.narrow[0]]),
 | 
					        if (current_stream) {
 | 
				
			||||||
                           page_params.narrow_stream, 'stream'));
 | 
					            tab_data.rendered_narrow_description = current_stream.rendered_description;
 | 
				
			||||||
        if (page_params.narrow_topic !== undefined) {
 | 
					            tab_data.sub_count = get_sub_count(current_stream);
 | 
				
			||||||
            tabs.push(make_tab("Topic " + page_params.narrow_topic,
 | 
					            tab_data.formatted_sub_count = get_formatted_sub_count(current_stream);
 | 
				
			||||||
                               hash_util.operators_to_hash(page_params.narrow),
 | 
					            tab_data.stream_settings_link = "#streams/" + current_stream.stream_id + "/" + current_stream.name;
 | 
				
			||||||
                               null));
 | 
					        } 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.";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return tab_data;
 | 
				
			||||||
    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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exports.colorize_tab_bar = function () {
 | 
					exports.colorize_tab_bar = function () {
 | 
				
			||||||
    const stream_tab = $('#tab_list .stream');
 | 
					    const filter = narrow_state.filter();
 | 
				
			||||||
    if (stream_tab.length > 0) {
 | 
					    if (filter === undefined || !filter.has_operator('stream')) {return;}
 | 
				
			||||||
        let stream_name = stream_tab.data('name');
 | 
					    const color_for_stream = stream_data.get_color(filter.operands("stream")[0]);
 | 
				
			||||||
        if (stream_name === undefined) {
 | 
					    const stream_light = colorspace.getHexColor(colorspace.getDecimalColor(color_for_stream));
 | 
				
			||||||
            return;
 | 
					    $("#tab_list .fa-hashtag").css('color', stream_light);
 | 
				
			||||||
        }
 | 
					    $("#tab_list .fa-lock").css('color', stream_light);
 | 
				
			||||||
        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);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function build_tab_bar() {
 | 
					function display_tab_bar(tab_bar_data) {
 | 
				
			||||||
    const tabs = make_tab_data();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const tab_bar = $("#tab_bar");
 | 
					    const tab_bar = $("#tab_bar");
 | 
				
			||||||
    tab_bar.empty();
 | 
					    tab_bar.empty();
 | 
				
			||||||
 | 
					    const rendered = render_tab_bar(tab_bar_data);
 | 
				
			||||||
    tabs[tabs.length - 1].active = "active";
 | 
					 | 
				
			||||||
    const rendered =  render_tab_bar({tabs: tabs});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tab_bar.append(rendered);
 | 
					    tab_bar.append(rendered);
 | 
				
			||||||
    exports.colorize_tab_bar();
 | 
					    if (tab_bar_data.stream_settings_link) {
 | 
				
			||||||
 | 
					        exports.colorize_tab_bar();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    tab_bar.removeClass('notdisplayed');
 | 
					    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 () {
 | 
					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;
 | 
					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
 | 
					    /* 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. */
 | 
					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,
 | 
					    .message_header:not(.dark_background) a.stream_label:not(.dark_background):hover {
 | 
				
			||||||
    #tab_list li.stream:not(.dark_background) {
 | 
					        color: hsl(212, 28%, 18%);
 | 
				
			||||||
        color: hsl(212, 28%, 18%) !important;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* these are converting grey things to "new grey" */
 | 
					    /* 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-contents,
 | 
				
			||||||
    .message_header_private_message .message-header-contents,
 | 
					    .message_header_private_message .message-header-contents {
 | 
				
			||||||
    #tab_bar #tab_list li.active {
 | 
					 | 
				
			||||||
        background-color: hsla(0, 0%, 0%, 0.2);
 | 
					        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 {
 | 
					    .top-navbar-border {
 | 
				
			||||||
        border-color: hsla(0, 0%, 0%, 0.6);
 | 
					        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,
 | 
					    .overlay,
 | 
				
			||||||
    #subscription_overlay #stream-creation #stream_creation_form #stream_creating_indicator:not(:empty),
 | 
					    #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,
 | 
					    thead,
 | 
				
			||||||
    #searchbox,
 | 
					 | 
				
			||||||
    #searchbox_legacy,
 | 
					 | 
				
			||||||
    .drafts-container .drafts-header,
 | 
					    .drafts-container .drafts-header,
 | 
				
			||||||
    .nav > li > a:hover,
 | 
					    .nav > li > a:hover,
 | 
				
			||||||
    .subscriptions-container .subscriptions-header,
 | 
					    .subscriptions-container .subscriptions-header,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1372,6 +1372,7 @@ div.focused_table {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#tab_bar {
 | 
					#tab_bar {
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
    z-index: 2;
 | 
					    z-index: 2;
 | 
				
			||||||
    padding-top: 0px;
 | 
					    padding-top: 0px;
 | 
				
			||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
@@ -1379,97 +1380,161 @@ div.focused_table {
 | 
				
			|||||||
    float: left;
 | 
					    float: left;
 | 
				
			||||||
    letter-spacing: normal;
 | 
					    letter-spacing: normal;
 | 
				
			||||||
    height: 40px;
 | 
					    height: 40px;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    #tab_list {
 | 
					    #tab_list {
 | 
				
			||||||
        list-style: none;
 | 
					        display: flex;
 | 
				
			||||||
 | 
					        align-content: flex-start;
 | 
				
			||||||
 | 
					        flex-wrap: nowrap;
 | 
				
			||||||
        margin: 0px 0px 0px 0px;
 | 
					        margin: 0px 0px 0px 0px;
 | 
				
			||||||
        height: 40px;
 | 
					        height: 40px;
 | 
				
			||||||
        line-height: 40px;
 | 
					        line-height: 40px;
 | 
				
			||||||
        font-size: 16px;
 | 
					        font-size: 16px;
 | 
				
			||||||
        border: none;
 | 
					        border: none;
 | 
				
			||||||
        white-space: nowrap;
 | 
					        white-space: nowrap;
 | 
				
			||||||
 | 
					        width: calc(100% - 1px);
 | 
				
			||||||
        li {
 | 
					        cursor: default;
 | 
				
			||||||
 | 
					        .hidden {
 | 
				
			||||||
 | 
					            display: none;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        span {
 | 
				
			||||||
            white-space: nowrap;
 | 
					            white-space: nowrap;
 | 
				
			||||||
            list-style-type: none;
 | 
					            list-style-type: none;
 | 
				
			||||||
            display: inline-block;
 | 
					            display: inline-block;
 | 
				
			||||||
 | 
					            vertical-align: top;
 | 
				
			||||||
            position: relative;
 | 
					            position: relative;
 | 
				
			||||||
            font-weight: 300;
 | 
					            font-weight: 600;
 | 
				
			||||||
            background-color: hsl(0, 0%, 98%);
 | 
					            font-size: 16px;
 | 
				
			||||||
            margin: 0px;
 | 
					            line-height: 16px;
 | 
				
			||||||
            padding: 0px;
 | 
					            margin: 0 -4px 0 0;
 | 
				
			||||||
            text-overflow: ellipsis;
 | 
					            padding: 12px 6px;
 | 
				
			||||||
            padding: 0 5px;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        li.private_message a {
 | 
					            @media (max-width: 500px) {
 | 
				
			||||||
            color: hsl(0, 0%, 100%);
 | 
					                padding: 7px 3.5px; // based on having ~41.66% decrease
 | 
				
			||||||
        }
 | 
					            }
 | 
				
			||||||
 | 
					            &:not(.search_closed):not(.sub_count):not(.narrow_description) {
 | 
				
			||||||
        a {
 | 
					                flex-shrink: 1;
 | 
				
			||||||
            text-decoration: none;
 | 
					                overflow: hidden;
 | 
				
			||||||
            color: inherit;
 | 
					            }
 | 
				
			||||||
            border-color: inherit;
 | 
					            &:not(.stream) {
 | 
				
			||||||
            width: 100%;
 | 
					                text-overflow: ellipsis;
 | 
				
			||||||
            display: inline-block;
 | 
					            }
 | 
				
			||||||
            padding: 0px 5px;
 | 
					            i {
 | 
				
			||||||
            max-width: 150px;
 | 
					                margin-right: 3px;
 | 
				
			||||||
            white-space: nowrap;
 | 
					            }
 | 
				
			||||||
            overflow: hidden;
 | 
					            .fa {
 | 
				
			||||||
            text-overflow: ellipsis;
 | 
					                margin: 0px 3px 0px 5px;
 | 
				
			||||||
        }
 | 
					                .fa-envelope {
 | 
				
			||||||
 | 
					                    font-size: 14px;
 | 
				
			||||||
        li.active {
 | 
					                    margin: 0px 5px 0px 5px;
 | 
				
			||||||
            background-color: hsl(0, 0%, 88%);
 | 
					                }
 | 
				
			||||||
            max-width: 150px;
 | 
					                .fa-hashtag {
 | 
				
			||||||
            white-space: nowrap;
 | 
					                    font-size: 1.2rem;
 | 
				
			||||||
            overflow: hidden;
 | 
					                    // font-weight: 800;
 | 
				
			||||||
            text-overflow: ellipsis;
 | 
					                    margin: 0px 2px 0px 5px;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        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%);
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        li.inactive {
 | 
					        .stream {
 | 
				
			||||||
            border-width: 0px;
 | 
					            text-overflow: clip;
 | 
				
			||||||
            margin-right: -4px;
 | 
					            overflow: hidden;
 | 
				
			||||||
            font-size: 14px;
 | 
					            a {
 | 
				
			||||||
            &::before {
 | 
					                color: inherit;
 | 
				
			||||||
                left: 100%;
 | 
					                text-decoration: none;
 | 
				
			||||||
                top: 50%;
 | 
					                padding-right: 2px;
 | 
				
			||||||
                content: " ";
 | 
					 | 
				
			||||||
                height: 0px;
 | 
					 | 
				
			||||||
                width: 0px;
 | 
					 | 
				
			||||||
                position: absolute;
 | 
					 | 
				
			||||||
                pointer-events: none;
 | 
					 | 
				
			||||||
                z-index: 1;
 | 
					 | 
				
			||||||
                transform: scale(.9999);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        li.active.root {
 | 
					        .sub_count,
 | 
				
			||||||
            padding: 0px 10px;
 | 
					        .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%;
 | 
					    width: 100%;
 | 
				
			||||||
    height: 40px;
 | 
					    height: 40px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .navbar-search {
 | 
					    .navbar-search:not(.expanded) {
 | 
				
			||||||
        margin-top: 0px;
 | 
					        display: none;
 | 
				
			||||||
        width: auto;
 | 
					    }
 | 
				
			||||||
        float: none;
 | 
					
 | 
				
			||||||
 | 
					    .navbar-search.expanded {
 | 
				
			||||||
        overflow: hidden;
 | 
					        overflow: hidden;
 | 
				
			||||||
        height: 40px;
 | 
					        margin-top: 0px;
 | 
				
			||||||
 | 
					        right: 2;
 | 
				
			||||||
 | 
					        width: calc(100% - 2px);
 | 
				
			||||||
 | 
					        position: absolute;
 | 
				
			||||||
 | 
					        .search_button {
 | 
				
			||||||
 | 
					            display: inline;
 | 
				
			||||||
 | 
					            margin-right: 16px;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .input-append {
 | 
					    .input-append {
 | 
				
			||||||
@@ -1600,6 +1673,10 @@ div.focused_table {
 | 
				
			|||||||
            top: 10px;
 | 
					            top: 10px;
 | 
				
			||||||
            z-index: 5;
 | 
					            z-index: 5;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .fa-search:not(.deactivated) {
 | 
				
			||||||
 | 
					            cursor: pointer;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #search_query {
 | 
					    #search_query {
 | 
				
			||||||
@@ -1608,7 +1685,7 @@ div.focused_table {
 | 
				
			|||||||
        height: 40px;
 | 
					        height: 40px;
 | 
				
			||||||
        padding: 0px;
 | 
					        padding: 0px;
 | 
				
			||||||
        padding-left: 35px;
 | 
					        padding-left: 35px;
 | 
				
			||||||
        padding-right: 20px;
 | 
					        padding-right: 40px;
 | 
				
			||||||
        border: none;
 | 
					        border: none;
 | 
				
			||||||
        border-radius: 0px;
 | 
					        border-radius: 0px;
 | 
				
			||||||
        font-family: 'Source Sans Pro';
 | 
					        font-family: 'Source Sans Pro';
 | 
				
			||||||
@@ -1646,19 +1723,6 @@ div.focused_table {
 | 
				
			|||||||
        visibility: hidden;
 | 
					        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 {
 | 
					    #search_arrows {
 | 
				
			||||||
        /* Bootstrap wants font-size: 0 to eliminate space between
 | 
					        /* Bootstrap wants font-size: 0 to eliminate space between
 | 
				
			||||||
       the buttons.  We need to inherit the font size, so we
 | 
					       the buttons.  We need to inherit the font size, so we
 | 
				
			||||||
@@ -1701,7 +1765,7 @@ div.focused_table {
 | 
				
			|||||||
    left: 0px;
 | 
					    left: 0px;
 | 
				
			||||||
    text-align: center;
 | 
					    text-align: center;
 | 
				
			||||||
    vertical-align: middle;
 | 
					    vertical-align: middle;
 | 
				
			||||||
    border-right: 2px solid hsl(204, 20%, 74%);
 | 
					    // border-right: 2px solid hsl(204, 20%, 74%);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#streamlist-toggle-button {
 | 
					#streamlist-toggle-button {
 | 
				
			||||||
@@ -2515,17 +2579,10 @@ div.topic_edit_spinner .loading_indicator_spinner {
 | 
				
			|||||||
        width: 30px;
 | 
					        width: 30px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #top_navbar.rightside-userlist .navbar-search {
 | 
					 | 
				
			||||||
        margin-right: 100px;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #top_navbar.rightside-userlist #navbar-buttons {
 | 
					    #top_navbar.rightside-userlist #navbar-buttons {
 | 
				
			||||||
        margin-right: 41px;
 | 
					        margin-right: 41px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .navbar-search {
 | 
					 | 
				
			||||||
        margin-right: 60px;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .nav .dropdown-menu {
 | 
					    .nav .dropdown-menu {
 | 
				
			||||||
        min-width: 180px;
 | 
					        min-width: 180px;
 | 
				
			||||||
@@ -2539,6 +2596,25 @@ div.topic_edit_spinner .loading_indicator_spinner {
 | 
				
			|||||||
    .column-middle {
 | 
					    .column-middle {
 | 
				
			||||||
        margin-right: 7px;
 | 
					        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) {
 | 
					@media (max-width: 775px) {
 | 
				
			||||||
@@ -2604,17 +2680,34 @@ div.topic_edit_spinner .loading_indicator_spinner {
 | 
				
			|||||||
        display: block;
 | 
					        display: block;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #searchbox,
 | 
					    .top-navbar-border {
 | 
				
			||||||
    #searchbox_legacy {
 | 
					        margin-left: 40px;
 | 
				
			||||||
        margin-left: 42px;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #top_navbar.rightside-userlist .navbar-search {
 | 
					    .top-navbar-border {
 | 
				
			||||||
        margin-right: 127px;
 | 
					        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 {
 | 
					    .search_closed .fa-search {
 | 
				
			||||||
        margin-right: 81px;
 | 
					        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;
 | 
					        margin-top: 10px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .search_closed .fa-search {
 | 
				
			||||||
 | 
					        top: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #streamlist-toggle,
 | 
					    #streamlist-toggle,
 | 
				
			||||||
    #navbar-buttons,
 | 
					    #navbar-buttons,
 | 
				
			||||||
    .navbar-search,
 | 
					    .navbar-search,
 | 
				
			||||||
@@ -2665,10 +2762,6 @@ div.topic_edit_spinner .loading_indicator_spinner {
 | 
				
			|||||||
        top: -5px;
 | 
					        top: -5px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #top_navbar.rightside-userlist .navbar-search {
 | 
					 | 
				
			||||||
        margin-right: 115px;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #searchbox,
 | 
					    #searchbox,
 | 
				
			||||||
    #searchbox_legacy {
 | 
					    #searchbox_legacy {
 | 
				
			||||||
        .input-append .fa-search {
 | 
					        .input-append .fa-search {
 | 
				
			||||||
@@ -2677,7 +2770,7 @@ div.topic_edit_spinner .loading_indicator_spinner {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        .search_button,
 | 
					        .search_button,
 | 
				
			||||||
        .search_button[disabled]:hover {
 | 
					        .search_button[disabled]:hover {
 | 
				
			||||||
            top: 2px;
 | 
					            top: 0px;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,19 +1,19 @@
 | 
				
			|||||||
<ul id="tab_list">
 | 
					<span id="tab_list">
 | 
				
			||||||
    {{#each tabs}}
 | 
					    <span {{#if stream_settings_link}}class="stream"{{/if}} {{#if data}}data-name="{{data}}"{{/if}}>
 | 
				
			||||||
    <li class="{{active}} {{cls}}" {{#if data}}data-name="{{data}}"{{/if}}>
 | 
					 | 
				
			||||||
        {{#if icon}}
 | 
					        {{#if icon}}
 | 
				
			||||||
        <i class="fa fa-angle-right" aria-hidden="true"></i>
 | 
					        <i class="fa fa-{{icon}}" aria-hidden="true"></i>
 | 
				
			||||||
        {{/if}}
 | 
					        {{/if}}
 | 
				
			||||||
        {{! Most tabs are links, but some are not since we don't have a narrow for them (e.g. Search) }}
 | 
					        {{#if stream_settings_link}}
 | 
				
			||||||
        {{#if hash}}
 | 
					        <a href="{{stream_settings_link}}">{{title}}</a>
 | 
				
			||||||
            <a href="{{hash}}">{{title}}</a>
 | 
					 | 
				
			||||||
        {{else}}
 | 
					        {{else}}
 | 
				
			||||||
            {{#if home}}
 | 
					        {{title}}
 | 
				
			||||||
            <i class="fa fa-home" aria-hidden="true"></i>
 | 
					 | 
				
			||||||
            {{else}}
 | 
					 | 
				
			||||||
            {{title}}
 | 
					 | 
				
			||||||
            {{/if}}
 | 
					 | 
				
			||||||
        {{/if}}
 | 
					        {{/if}}
 | 
				
			||||||
    </li>
 | 
					    </span>
 | 
				
			||||||
    {{/each}}
 | 
					    {{#if sub_count}}
 | 
				
			||||||
</ul>
 | 
					    <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>
 | 
					                        <span id="streamlist-toggle-unreadcount">0</span>
 | 
				
			||||||
                    </a>
 | 
					                    </a>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="top-navbar-border">
 | 
					                <div class="top-navbar-border top-navbar-container">
 | 
				
			||||||
                    {% if search_pills_enabled %}
 | 
					                    {% if search_pills_enabled %}
 | 
				
			||||||
                    <div id="searchbox">
 | 
					                    <div id="searchbox">
 | 
				
			||||||
                        <div id="tab_bar" class="notdisplayed">
 | 
					                        <div id="tab_bar" class="notdisplayed">
 | 
				
			||||||
                        </div>
 | 
					                        </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">
 | 
					                        <form id="searchbox_form" class="form-search navbar-search">
 | 
				
			||||||
                            <div id="search_arrows" class="pill-container input-append">
 | 
					                            <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') }}"
 | 
					                                <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">
 | 
					                            <div id="search_arrows" class="input-append">
 | 
				
			||||||
                                <input class="search-query input-block-level" id="search_query" type="text" placeholder="{{ _('Search') }}"
 | 
					                                <input class="search-query input-block-level" id="search_query" type="text" placeholder="{{ _('Search') }}"
 | 
				
			||||||
                                  autocomplete="off" aria-label="{{ _('Search') }}" title="{{ _('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" aria-label="{{ _('Exit search') }}"><i class="fa fa-remove" aria-hidden="true"></i></button>
 | 
				
			||||||
                                <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>
 | 
					                                <span class="search_icon search_open" ><i class="fa fa-search" aria-hidden="true"></i></span>
 | 
				
			||||||
                                <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>
 | 
					 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
                        </form>
 | 
					                        </form>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user