mirror of
https://github.com/zulip/zulip.git
synced 2026-06-03 21:01:43 +08:00
parent
fe9a8b7cdb
commit
4fbc8daf66
@ -1249,6 +1249,7 @@ function render_channel_view(channel_id: number): void {
|
||||
channel_view_topic_widget = new InboxTopicListWidget(
|
||||
$("#inbox-list"),
|
||||
channel_id,
|
||||
false,
|
||||
(topic_names: string[]) => filter_topics_in_channel(channel_id, topic_names),
|
||||
);
|
||||
channel_view_topic_widget.build();
|
||||
|
||||
@ -76,12 +76,10 @@ export let update_dom_with_unread_counts = function (
|
||||
const $mentioned_li = $(".top_left_mentions");
|
||||
const $home_view_li = $(".selected-home-view");
|
||||
const $condensed_view_li = $(".top_left_condensed_unread_marker");
|
||||
const $back_to_streams = $("#topics_header");
|
||||
|
||||
ui_util.update_unread_count_in_dom($mentioned_li, counts.mentioned_message_count);
|
||||
ui_util.update_unread_count_in_dom($home_view_li, counts.home_unread_messages);
|
||||
ui_util.update_unread_count_in_dom($condensed_view_li, counts.home_unread_messages);
|
||||
ui_util.update_unread_count_in_dom($back_to_streams, counts.stream_unread_messages);
|
||||
|
||||
if (!skip_animations) {
|
||||
animate_unread_changes($mentioned_li, counts.mentioned_message_count, last_mention_count);
|
||||
|
||||
@ -341,8 +341,8 @@ function zoom_in(): void {
|
||||
pre_search_scroll_position = 0;
|
||||
ui_util.disable_left_sidebar_search();
|
||||
update_private_messages();
|
||||
$("#left-sidebar").removeClass("zoom-out").addClass("zoom-in");
|
||||
$("#streams_list").hide();
|
||||
$("#left-sidebar").addClass("zoom-in");
|
||||
$("#left-sidebar").addClass("zoom-in-conversations");
|
||||
$("#direct-messages-modal").toggleClass("no-display", false);
|
||||
|
||||
const $filter = $(".direct-messages-list-filter").expectOne();
|
||||
@ -356,8 +356,8 @@ function zoom_out(): void {
|
||||
zoomed = false;
|
||||
ui_util.enable_left_sidebar_search();
|
||||
clear_search();
|
||||
$("#left-sidebar").removeClass("zoom-in").addClass("zoom-out");
|
||||
$("#streams_list").show();
|
||||
$("#left-sidebar").removeClass("zoom-in");
|
||||
$("#left-sidebar").removeClass("zoom-in-conversations");
|
||||
$("#direct-messages-modal").toggleClass("no-display", true);
|
||||
}
|
||||
|
||||
@ -391,11 +391,7 @@ export function initialize(): void {
|
||||
}
|
||||
});
|
||||
|
||||
$("#left-sidebar").on("click", ".left-sidebar-modal-close-area", (e) => {
|
||||
if ($("#direct-messages-modal.no-display").length > 0) {
|
||||
// This can happen when zooming out of a topics modal
|
||||
return;
|
||||
}
|
||||
$("body").on("click", ".zoom-in-conversations .left-sidebar-modal-close-area", (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ import * as compose_actions from "./compose_actions.ts";
|
||||
import type {Filter} from "./filter.ts";
|
||||
import * as hash_util from "./hash_util.ts";
|
||||
import {$t} from "./i18n.ts";
|
||||
import * as keydown_util from "./keydown_util.ts";
|
||||
import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area.ts";
|
||||
import {localstorage} from "./localstorage.ts";
|
||||
import * as mouse_drag from "./mouse_drag.ts";
|
||||
@ -73,10 +74,14 @@ function zoom_in(): void {
|
||||
const stream_id = topic_list.active_stream_id();
|
||||
assert(stream_id !== undefined);
|
||||
|
||||
$("#direct-messages-modal").toggleClass("no-display", true);
|
||||
popovers.hide_all();
|
||||
pm_list.close();
|
||||
topic_list.zoom_in();
|
||||
zoom_in_topics(stream_id);
|
||||
topic_list.zoom_in(get_stream_li(stream_id)!);
|
||||
$("#left-sidebar").addClass("zoom-in");
|
||||
$("#left-sidebar").addClass("zoom-in-topics");
|
||||
$("#left-sidebar-modal").addClass("zoom-in-topics");
|
||||
}
|
||||
|
||||
export function set_pending_stream_list_rerender(value: boolean): void {
|
||||
@ -600,7 +605,16 @@ export function rewire_set_sections_states(value: typeof set_sections_states): v
|
||||
set_sections_states = value;
|
||||
}
|
||||
|
||||
export function get_stream_li(stream_id: number): JQuery | undefined {
|
||||
export function get_stream_li(stream_id: number, override_zoomed_in?: boolean): JQuery | undefined {
|
||||
const for_zoomed = override_zoomed_in ?? zoomed_in;
|
||||
if (for_zoomed) {
|
||||
assert(zoomed_in_row !== undefined);
|
||||
if (zoomed_in_row.sub.stream_id !== stream_id) {
|
||||
return undefined;
|
||||
}
|
||||
return zoomed_in_row.$list_item;
|
||||
}
|
||||
|
||||
const row = stream_sidebar.get_row(stream_id);
|
||||
if (!row) {
|
||||
// Not all streams are in the sidebar, so we don't report
|
||||
@ -655,9 +669,9 @@ class StreamSidebarRow {
|
||||
sub: StreamSubscription;
|
||||
$list_item: JQuery;
|
||||
|
||||
constructor(sub: StreamSubscription) {
|
||||
constructor(sub: StreamSubscription, for_modal = false) {
|
||||
this.sub = sub;
|
||||
this.$list_item = build_stream_sidebar_li(sub);
|
||||
this.$list_item = build_stream_sidebar_li(sub, for_modal);
|
||||
this.update_unread_count();
|
||||
}
|
||||
|
||||
@ -702,32 +716,27 @@ class StreamSidebarRow {
|
||||
}
|
||||
}
|
||||
|
||||
let zoomed_in_row: StreamSidebarRow | undefined;
|
||||
export function zoom_in_topics(stream_id: number): void {
|
||||
// This only does stream-related tasks related to zooming
|
||||
// in to more topics, which is basically hiding all the
|
||||
// other streams.
|
||||
// This only does channel-related tasks related to zooming
|
||||
// in to more topics, which is creating the sidebar row
|
||||
// and setting up the channel's more topics modal.
|
||||
const sub = sub_store.get(stream_id);
|
||||
assert(sub !== undefined);
|
||||
|
||||
$("#streams_list").expectOne().removeClass("zoom-out").addClass("zoom-in");
|
||||
|
||||
$("#stream_filters li.narrow-filter").each(function () {
|
||||
const $elt = $(this);
|
||||
|
||||
if (stream_id_for_elt($elt) === stream_id) {
|
||||
$elt.toggleClass("hide", false);
|
||||
// Add search box for topics list.
|
||||
$elt.children("div.bottom_left_row").append($(render_filter_topics()));
|
||||
topic_list.setup_topic_search_typeahead();
|
||||
} else {
|
||||
$elt.toggleClass("hide", true);
|
||||
}
|
||||
});
|
||||
zoomed_in_row = new StreamSidebarRow(sub, true);
|
||||
$("#more-topics-modal").replaceWith(zoomed_in_row.$list_item);
|
||||
$("#more-topics-modal").find("div.bottom_left_row").append($(render_filter_topics()));
|
||||
topic_list.setup_topic_search_typeahead();
|
||||
}
|
||||
|
||||
export function zoom_out_topics(): void {
|
||||
$("#streams_list").expectOne().removeClass("zoom-in").addClass("zoom-out");
|
||||
$("#left-sidebar").removeClass("zoom-in");
|
||||
$("#left-sidebar").removeClass("zoom-in-topics");
|
||||
$("#left-sidebar-modal").removeClass("zoom-in-topics");
|
||||
$("#stream_filters li.narrow-filter").toggleClass("hide", false);
|
||||
// Remove search box for topics list from DOM.
|
||||
$(".filter-topics").remove();
|
||||
$("#more-topics-modal").empty();
|
||||
zoomed_in_row = undefined;
|
||||
}
|
||||
|
||||
export function set_in_home_view(stream_id: number, in_home: boolean): void {
|
||||
@ -744,7 +753,7 @@ export function set_in_home_view(stream_id: number, in_home: boolean): void {
|
||||
}
|
||||
}
|
||||
|
||||
function build_stream_sidebar_li(sub: StreamSubscription): JQuery {
|
||||
function build_stream_sidebar_li(sub: StreamSubscription, for_modal = false): JQuery {
|
||||
const name = sub.name;
|
||||
const is_muted = stream_data.is_muted(sub.stream_id);
|
||||
const can_post_messages = stream_data.can_post_messages_in_stream(sub);
|
||||
@ -763,6 +772,7 @@ function build_stream_sidebar_li(sub: StreamSubscription): JQuery {
|
||||
sub.stream_id,
|
||||
),
|
||||
is_empty_topic_only_channel: stream_data.is_empty_topic_only_channel(sub.stream_id),
|
||||
for_modal,
|
||||
};
|
||||
const $list_item = $(render_stream_sidebar_row(args));
|
||||
return $list_item;
|
||||
@ -808,7 +818,10 @@ function set_stream_unread_count(
|
||||
stream_has_any_unmuted_unread_mention: boolean,
|
||||
stream_has_only_muted_unread_mentions: boolean,
|
||||
): void {
|
||||
const $stream_li = get_stream_li(stream_id);
|
||||
// Update the unread count for the regular stream list, even if we're
|
||||
// currently zoomed in, so that it has the correct number when we zoom
|
||||
// out.
|
||||
const $stream_li = get_stream_li(stream_id, false);
|
||||
if (!$stream_li) {
|
||||
// This can happen for legitimate reasons, but we warn
|
||||
// just in case.
|
||||
@ -822,6 +835,23 @@ function set_stream_unread_count(
|
||||
stream_has_any_unmuted_unread_mention,
|
||||
stream_has_only_muted_unread_mentions,
|
||||
);
|
||||
|
||||
if (zoomed_in) {
|
||||
const $stream_li = get_stream_li(stream_id);
|
||||
if (!$stream_li) {
|
||||
// This can happen for legitimate reasons, but we warn
|
||||
// just in case.
|
||||
blueslip.warn("stream id no longer in sidebar: " + stream_id);
|
||||
return;
|
||||
}
|
||||
update_count_in_dom(
|
||||
$stream_li,
|
||||
count,
|
||||
stream_has_any_unread_mention_messages,
|
||||
stream_has_any_unmuted_unread_mention,
|
||||
stream_has_only_muted_unread_mentions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export let update_streams_sidebar = (force_rerender = false): void => {
|
||||
@ -1134,7 +1164,7 @@ export function update_stream_sidebar_for_narrow(filter: Filter): JQuery | undef
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!info.topic_selected) {
|
||||
if (!info.topic_selected && !zoomed_in) {
|
||||
$stream_li.addClass("active-filter");
|
||||
}
|
||||
|
||||
@ -1176,13 +1206,15 @@ export function handle_narrow_activated(
|
||||
change_hash: boolean,
|
||||
show_more_topics: boolean,
|
||||
): void {
|
||||
// Zoom out, if needed, so that get_stream_li returns the correct
|
||||
// value when calling update_stream_sidebar_for_narrow.
|
||||
if (!change_hash && is_zoomed_in() && !show_more_topics) {
|
||||
zoom_out();
|
||||
}
|
||||
|
||||
const $stream_li = update_stream_sidebar_for_narrow(filter);
|
||||
if ($stream_li && !change_hash) {
|
||||
if (!is_zoomed_in() && show_more_topics) {
|
||||
zoom_in();
|
||||
} else if (is_zoomed_in() && !show_more_topics) {
|
||||
zoom_out();
|
||||
}
|
||||
if ($stream_li && !change_hash && !is_zoomed_in() && show_more_topics) {
|
||||
zoom_in();
|
||||
}
|
||||
|
||||
scroll_stream_into_view();
|
||||
@ -1227,7 +1259,19 @@ export function initialize({
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$(".show-all-streams").on("click", (e) => {
|
||||
$("body").on("click", ".zoom-in-topics .left-sidebar-modal-close-area", (e) => {
|
||||
zoom_out();
|
||||
browser_history.update_current_history_state_data({show_more_topics: false});
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$("body").on("keydown", ".zoom-in-topics .left-sidebar-modal-close-area", (e) => {
|
||||
if (!keydown_util.is_enter_event(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
zoom_out();
|
||||
browser_history.update_current_history_state_data({show_more_topics: false});
|
||||
|
||||
@ -1237,41 +1281,47 @@ export function initialize({
|
||||
}
|
||||
|
||||
export function initialize_tippy_tooltips(): void {
|
||||
tippy.delegate("body", {
|
||||
target: "#stream_filters li .subscription_block .stream-name",
|
||||
delay: LONG_HOVER_DELAY,
|
||||
onShow(instance) {
|
||||
// check for "Go to channel feed" tooltip conditions first.
|
||||
const stream_id = stream_id_for_elt($(instance.reference).parents("li.narrow-filter"));
|
||||
const current_narrow_stream_id = narrow_state.stream_id();
|
||||
const current_topic = narrow_state.topic();
|
||||
if (current_narrow_stream_id === stream_id && current_topic !== undefined) {
|
||||
if (
|
||||
user_settings.web_channel_default_view ===
|
||||
web_channel_default_view_values.list_of_topics.code
|
||||
) {
|
||||
instance.setContent(
|
||||
ui_util.parse_html(render_go_to_channel_list_of_topics_tooltip()),
|
||||
);
|
||||
} else {
|
||||
instance.setContent(ui_util.parse_html(render_go_to_channel_feed_tooltip()));
|
||||
for (const parent_class of ["#stream_filters li", "#left-sidebar-modal"]) {
|
||||
tippy.delegate("body", {
|
||||
target: `${parent_class} .subscription_block .stream-name`,
|
||||
delay: LONG_HOVER_DELAY,
|
||||
onShow(instance) {
|
||||
// check for "Go to channel feed" tooltip conditions first.
|
||||
const stream_id = stream_id_for_elt(
|
||||
$(instance.reference).parents("li.narrow-filter"),
|
||||
);
|
||||
const current_narrow_stream_id = narrow_state.stream_id();
|
||||
const current_topic = narrow_state.topic();
|
||||
if (current_narrow_stream_id === stream_id && current_topic !== undefined) {
|
||||
if (
|
||||
user_settings.web_channel_default_view ===
|
||||
web_channel_default_view_values.list_of_topics.code
|
||||
) {
|
||||
instance.setContent(
|
||||
ui_util.parse_html(render_go_to_channel_list_of_topics_tooltip()),
|
||||
);
|
||||
} else {
|
||||
instance.setContent(
|
||||
ui_util.parse_html(render_go_to_channel_feed_tooltip()),
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
// Then check for truncation
|
||||
const stream_name_element = instance.reference;
|
||||
assert(stream_name_element instanceof HTMLElement);
|
||||
// Then check for truncation
|
||||
const stream_name_element = instance.reference;
|
||||
assert(stream_name_element instanceof HTMLElement);
|
||||
|
||||
if (stream_name_element.offsetWidth < stream_name_element.scrollWidth) {
|
||||
const stream_name = stream_name_element.textContent ?? "";
|
||||
instance.setContent(stream_name);
|
||||
return undefined;
|
||||
}
|
||||
if (stream_name_element.offsetWidth < stream_name_element.scrollWidth) {
|
||||
const stream_name = stream_name_element.textContent ?? "";
|
||||
instance.setContent(stream_name);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
appendTo: () => document.body,
|
||||
});
|
||||
return false;
|
||||
},
|
||||
appendTo: () => document.body,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function on_sidebar_channel_click(
|
||||
@ -1405,28 +1455,36 @@ export function set_event_handlers({
|
||||
on_sidebar_channel_click(stream_id, e, show_channel_feed);
|
||||
});
|
||||
|
||||
$("#stream_filters").on(
|
||||
function on_click_new_topic(element: HTMLElement, e: JQuery.ClickEvent): void {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
const stream_id = Number.parseInt(element.getAttribute("data-stream-id")!, 10);
|
||||
let trigger = "clear topic button";
|
||||
let topic = "";
|
||||
|
||||
if ($(e.target).closest(".zoomed-new-topic").length > 0) {
|
||||
trigger = "zoomed new topic";
|
||||
topic = $("#topic_filter_query").text().trim().slice(0, realm.max_topic_length);
|
||||
}
|
||||
|
||||
compose_actions.start({
|
||||
message_type: "stream",
|
||||
stream_id,
|
||||
topic,
|
||||
trigger,
|
||||
keep_composebox_empty: true,
|
||||
});
|
||||
}
|
||||
|
||||
$("#stream_filters").on("click", ".channel-new-topic-button", function (this: HTMLElement, e) {
|
||||
on_click_new_topic(this, e);
|
||||
});
|
||||
|
||||
$("#left-sidebar-modal").on(
|
||||
"click",
|
||||
".channel-new-topic-button, .zoomed-new-topic",
|
||||
"#more-topics-modal .channel-new-topic-button, #more-topics-modal .zoomed-new-topic",
|
||||
function (this: HTMLElement, e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
const stream_id = Number.parseInt(this.getAttribute("data-stream-id")!, 10);
|
||||
let trigger = "clear topic button";
|
||||
let topic = "";
|
||||
|
||||
if ($(e.target).closest(".zoomed-new-topic").length > 0) {
|
||||
trigger = "zoomed new topic";
|
||||
topic = $("#topic_filter_query").text().trim().slice(0, realm.max_topic_length);
|
||||
}
|
||||
|
||||
compose_actions.start({
|
||||
message_type: "stream",
|
||||
stream_id,
|
||||
topic,
|
||||
trigger,
|
||||
keep_composebox_empty: true,
|
||||
});
|
||||
on_click_new_topic(this, e);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@ -1220,19 +1220,30 @@ export async function build_move_topic_to_stream_popover(
|
||||
}
|
||||
|
||||
export function initialize(): void {
|
||||
$("#stream_filters").on("click", ".stream-sidebar-menu-icon", function (this: HTMLElement, e) {
|
||||
function on_sidebar_menu_icon_click(element: HTMLElement, e: JQuery.ClickEvent): void {
|
||||
e.preventDefault();
|
||||
const $stream_li = $(this).parents("li");
|
||||
const $stream_li = $(element).parents("li");
|
||||
const stream_id = elem_to_stream_id($stream_li);
|
||||
|
||||
build_stream_popover({
|
||||
elt: this,
|
||||
elt: element,
|
||||
stream_id,
|
||||
});
|
||||
|
||||
e.stopPropagation();
|
||||
}
|
||||
$("#stream_filters").on("click", ".stream-sidebar-menu-icon", function (this: HTMLElement, e) {
|
||||
on_sidebar_menu_icon_click(this, e);
|
||||
});
|
||||
|
||||
$("#left-sidebar-modal").on(
|
||||
"click",
|
||||
"#more-topics-modal .stream-sidebar-menu-icon",
|
||||
function (this: HTMLElement, e) {
|
||||
on_sidebar_menu_icon_click(this, e);
|
||||
},
|
||||
);
|
||||
|
||||
$("body").on("click", ".inbox-stream-menu", function (this: HTMLElement, e) {
|
||||
const stream_id = Number.parseInt($(this).attr("data-stream-id")!, 10);
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ import * as vdom from "./vdom.ts";
|
||||
one for now, but we may eventually allow multiple streams to be
|
||||
expanded. */
|
||||
const active_widgets = new Map<number, LeftSidebarTopicListWidget>();
|
||||
let zoomed_in_widget: LeftSidebarTopicListWidget | undefined;
|
||||
export let topic_filter_pill_widget: TopicFilterPillWidget | null = null;
|
||||
export let topic_state_typeahead: Typeahead<TopicFilterPill> | undefined;
|
||||
|
||||
@ -45,6 +46,9 @@ export function update(): void {
|
||||
for (const widget of active_widgets.values()) {
|
||||
widget.build();
|
||||
}
|
||||
if (zoomed_in_widget) {
|
||||
zoomed_in_widget.build();
|
||||
}
|
||||
}
|
||||
|
||||
export function update_widget_for_stream(stream_id: number): void {
|
||||
@ -54,6 +58,10 @@ export function update_widget_for_stream(stream_id: number): void {
|
||||
return;
|
||||
}
|
||||
widget.build();
|
||||
|
||||
if (zoomed_in_widget?.my_stream_id === stream_id) {
|
||||
zoomed_in_widget.build();
|
||||
}
|
||||
}
|
||||
|
||||
export function clear(): void {
|
||||
@ -67,6 +75,12 @@ export function clear(): void {
|
||||
active_widgets.clear();
|
||||
}
|
||||
|
||||
export function clear_zoomed(): void {
|
||||
popover_menus.get_topic_menu_popover()?.hide();
|
||||
topic_filter_pill_widget?.clear(true);
|
||||
zoomed_in_widget?.remove();
|
||||
}
|
||||
|
||||
export function close(): void {
|
||||
clear();
|
||||
if (zoomed) {
|
||||
@ -83,14 +97,13 @@ export function zoom_out(): void {
|
||||
zoomed = false;
|
||||
ui_util.enable_left_sidebar_search();
|
||||
|
||||
const stream_ids = [...active_widgets.keys()];
|
||||
|
||||
if (stream_ids.length !== 1 || stream_ids[0] === undefined) {
|
||||
blueslip.error("Unexpected number of topic lists to zoom out.");
|
||||
const stream_id = zoomed_in_widget?.my_stream_id;
|
||||
if (stream_id === undefined) {
|
||||
blueslip.error("Expected a topic list to zoom out.");
|
||||
return;
|
||||
}
|
||||
zoomed_in_widget = undefined;
|
||||
|
||||
const stream_id = stream_ids[0];
|
||||
const widget = active_widgets.get(stream_id);
|
||||
assert(widget !== undefined);
|
||||
const $stream_li = widget.get_stream_li();
|
||||
@ -274,26 +287,28 @@ export class TopicListWidget {
|
||||
prior_dom: vdom.Tag<ListInfoNodeOptions> | undefined = undefined;
|
||||
$stream_li: JQuery;
|
||||
my_stream_id: number;
|
||||
for_modal: boolean;
|
||||
filter_topics: (topic_names: string[]) => string[];
|
||||
|
||||
constructor(
|
||||
$stream_li: JQuery,
|
||||
my_stream_id: number,
|
||||
for_modal: boolean,
|
||||
filter_topics: (topic_names: string[]) => string[],
|
||||
) {
|
||||
this.$stream_li = $stream_li;
|
||||
this.my_stream_id = my_stream_id;
|
||||
this.for_modal = for_modal;
|
||||
this.filter_topics = filter_topics;
|
||||
}
|
||||
|
||||
build_list(
|
||||
spinner: boolean,
|
||||
formatter: (conversation: TopicInfo) => ListInfoNode,
|
||||
is_zoomed: boolean,
|
||||
): vdom.Tag<ListInfoNodeOptions> {
|
||||
const list_info = topic_list_data.get_list_info(
|
||||
this.my_stream_id,
|
||||
is_zoomed,
|
||||
this.for_modal,
|
||||
this.filter_topics,
|
||||
);
|
||||
|
||||
@ -328,7 +343,7 @@ export class TopicListWidget {
|
||||
list_info.more_topics_unread_count_muted,
|
||||
),
|
||||
);
|
||||
} else if (is_zoomed && stream_data.can_post_messages_in_stream(stream)) {
|
||||
} else if (this.for_modal && stream_data.can_post_messages_in_stream(stream)) {
|
||||
nodes.push(new_topic(this.my_stream_id));
|
||||
}
|
||||
|
||||
@ -353,16 +368,17 @@ export class TopicListWidget {
|
||||
this.prior_dom = undefined;
|
||||
}
|
||||
|
||||
build(
|
||||
spinner = false,
|
||||
formatter: (conversation: TopicInfo) => ListInfoNode,
|
||||
is_zoomed: boolean,
|
||||
): void {
|
||||
const new_dom = this.build_list(spinner, formatter, is_zoomed);
|
||||
|
||||
build(spinner = false, formatter: (conversation: TopicInfo) => ListInfoNode): void {
|
||||
const new_dom = this.build_list(spinner, formatter);
|
||||
const replace_content = (html: string): void => {
|
||||
this.remove();
|
||||
this.$stream_li.append($(html));
|
||||
if (this.for_modal && this.$stream_li.find(".simplebar-content").length > 0) {
|
||||
this.$stream_li.find(".simplebar-content").append($(html));
|
||||
} else if (this.for_modal) {
|
||||
this.$stream_li.find(".topic-list-scroll-container").append($(html));
|
||||
} else {
|
||||
this.$stream_li.append($(html));
|
||||
}
|
||||
};
|
||||
|
||||
const find = (): JQuery => this.$stream_li.find(`.${this.topic_list_class_name}`);
|
||||
@ -393,15 +409,14 @@ function filter_topics_left_sidebar(topic_names: string[]): string[] {
|
||||
}
|
||||
|
||||
export class LeftSidebarTopicListWidget extends TopicListWidget {
|
||||
constructor($stream_li: JQuery, my_stream_id: number) {
|
||||
super($stream_li, my_stream_id, filter_topics_left_sidebar);
|
||||
constructor($stream_li: JQuery, my_stream_id: number, for_modal: boolean) {
|
||||
super($stream_li, my_stream_id, for_modal, filter_topics_left_sidebar);
|
||||
}
|
||||
|
||||
override build(spinner = false): void {
|
||||
const is_zoomed = zoomed;
|
||||
const formatter = keyed_topic_li;
|
||||
|
||||
super.build(spinner, formatter, is_zoomed);
|
||||
super.build(spinner, formatter);
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,6 +436,10 @@ export function clear_topic_search(e: JQuery.Event): void {
|
||||
}
|
||||
|
||||
export function active_stream_id(): number | undefined {
|
||||
if (zoomed) {
|
||||
return zoomed_in_widget?.my_stream_id;
|
||||
}
|
||||
|
||||
const stream_ids = [...active_widgets.keys()];
|
||||
|
||||
if (stream_ids.length !== 1) {
|
||||
@ -431,6 +450,10 @@ export function active_stream_id(): number | undefined {
|
||||
}
|
||||
|
||||
export function get_stream_li(): JQuery | undefined {
|
||||
if (zoomed) {
|
||||
return zoomed_in_widget?.get_stream_li();
|
||||
}
|
||||
|
||||
const widgets = [...active_widgets.values()];
|
||||
|
||||
if (widgets.length !== 1 || widgets[0] === undefined) {
|
||||
@ -442,6 +465,16 @@ export function get_stream_li(): JQuery | undefined {
|
||||
}
|
||||
|
||||
export function rebuild_left_sidebar($stream_li: JQuery, stream_id: number): void {
|
||||
if (zoomed) {
|
||||
if (zoomed_in_widget?.my_stream_id !== stream_id) {
|
||||
clear_zoomed();
|
||||
zoomed_in_widget = new LeftSidebarTopicListWidget($stream_li, stream_id, true);
|
||||
}
|
||||
zoomed_in_widget.build();
|
||||
return;
|
||||
}
|
||||
|
||||
zoomed_in_widget?.remove();
|
||||
const active_widget = active_widgets.get(stream_id);
|
||||
|
||||
if (active_widget) {
|
||||
@ -450,51 +483,58 @@ export function rebuild_left_sidebar($stream_li: JQuery, stream_id: number): voi
|
||||
}
|
||||
|
||||
clear();
|
||||
const widget = new LeftSidebarTopicListWidget($stream_li, stream_id);
|
||||
const widget = new LeftSidebarTopicListWidget($stream_li, stream_id, false);
|
||||
widget.build();
|
||||
|
||||
active_widgets.set(stream_id, widget);
|
||||
}
|
||||
|
||||
export function left_sidebar_scroll_zoomed_in_topic_into_view(): void {
|
||||
const $selected_topic = $(".topic-list .topic-list-item.active-sub-filter");
|
||||
const $scroll_container = zoomed
|
||||
? $("#more-topics-modal .topic-list-scroll-container")
|
||||
: $("#left_sidebar_scroll_container");
|
||||
const $selected_topic = $scroll_container.find(".topic-list-item.active-sub-filter");
|
||||
if ($selected_topic.length === 0) {
|
||||
// If we don't have a selected topic, scroll to top.
|
||||
scroll_util.get_scroll_element($("#left_sidebar_scroll_container")).scrollTop(0);
|
||||
scroll_util.get_scroll_element($scroll_container).scrollTop(0);
|
||||
return;
|
||||
}
|
||||
const $container = $("#left_sidebar_scroll_container");
|
||||
let sticky_header_height = 0;
|
||||
if (zoomed) {
|
||||
const stream_header_height =
|
||||
$(
|
||||
"#streams_list.zoom-in .narrow-filter.stream-expanded > .bottom_left_row",
|
||||
).outerHeight(true) ?? 0;
|
||||
const topic_header_height =
|
||||
$("#streams_list.zoom-in #topics_header").outerHeight(true) ?? 0;
|
||||
sticky_header_height += stream_header_height + topic_header_height;
|
||||
}
|
||||
const channel_folder_header_height =
|
||||
$selected_topic
|
||||
.closest(".stream-list-section-container")
|
||||
.find(".stream-list-subsection-header")
|
||||
.outerHeight(true) ?? 0;
|
||||
sticky_header_height += channel_folder_header_height;
|
||||
const $topic_list = $selected_topic.closest(".topic-list");
|
||||
const topic_list_height = $topic_list.outerHeight(true) ?? 0;
|
||||
const available_topic_height = ($container.height() ?? 0) - sticky_header_height;
|
||||
scroll_util.scroll_element_into_container($selected_topic, $scroll_container, 0);
|
||||
} else {
|
||||
const direct_message_header_height =
|
||||
$("#direct-messages-section-header").outerHeight(true) ?? 0;
|
||||
const direct_message_divider_height =
|
||||
$(".direct-message-section-bottom-divider-container").outerHeight(true) ?? 0;
|
||||
const channel_folder_header_height =
|
||||
$selected_topic
|
||||
.closest(".stream-list-section-container")
|
||||
.find(".stream-list-subsection-header")
|
||||
.outerHeight(true) ?? 0;
|
||||
const sticky_header_height =
|
||||
direct_message_header_height +
|
||||
direct_message_divider_height +
|
||||
channel_folder_header_height;
|
||||
|
||||
let $scroll_target = $selected_topic;
|
||||
if (topic_list_height <= available_topic_height) {
|
||||
$scroll_target = $topic_list;
|
||||
const $channel_section = $selected_topic.closest(".stream-expanded");
|
||||
const channel_section_height = $channel_section.outerHeight(true) ?? 0;
|
||||
const available_topic_height = ($scroll_container.height() ?? 0) - sticky_header_height;
|
||||
|
||||
let $scroll_target = $selected_topic;
|
||||
if (channel_section_height <= available_topic_height) {
|
||||
$scroll_target = $channel_section;
|
||||
}
|
||||
scroll_util.scroll_element_into_container(
|
||||
$scroll_target,
|
||||
$scroll_container,
|
||||
sticky_header_height,
|
||||
);
|
||||
}
|
||||
scroll_util.scroll_element_into_container($scroll_target, $container, sticky_header_height);
|
||||
}
|
||||
|
||||
// For zooming, we only do topic-list stuff here...let stream_list
|
||||
// handle hiding/showing the non-narrowed streams
|
||||
export function zoom_in(): void {
|
||||
zoomed = true;
|
||||
export function zoom_in($stream_li: JQuery): void {
|
||||
previous_search_term = "";
|
||||
pre_search_scroll_position = 0;
|
||||
ui_util.disable_left_sidebar_search();
|
||||
@ -505,8 +545,10 @@ export function zoom_in(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
const active_widget = active_widgets.get(stream_id);
|
||||
assert(active_widget !== undefined);
|
||||
zoomed = true;
|
||||
zoomed_in_widget = new LeftSidebarTopicListWidget($stream_li, stream_id, true);
|
||||
const spinner = true;
|
||||
zoomed_in_widget.build(spinner);
|
||||
|
||||
function on_success(): void {
|
||||
if (!active_widgets.has(stream_id!)) {
|
||||
@ -523,19 +565,14 @@ export function zoom_in(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
active_widget!.build();
|
||||
if (zoomed) {
|
||||
// It is fine to force scroll here even if user has scrolled to a different
|
||||
// position since we just added some topics to the list which moved user
|
||||
// to a different position anyway.
|
||||
left_sidebar_scroll_zoomed_in_topic_into_view();
|
||||
topic_state_typeahead?.lookup(true);
|
||||
}
|
||||
rebuild_left_sidebar($stream_li, stream_id!);
|
||||
// It is fine to force scroll here even if user has scrolled to a different
|
||||
// position since we just added some topics to the list which moved user
|
||||
// to a different position anyway.
|
||||
left_sidebar_scroll_zoomed_in_topic_into_view();
|
||||
topic_state_typeahead?.lookup(true);
|
||||
}
|
||||
|
||||
const spinner = true;
|
||||
active_widget.build(spinner);
|
||||
|
||||
stream_topic_history_util.get_server_history(stream_id, on_success);
|
||||
left_sidebar_scroll_zoomed_in_topic_into_view();
|
||||
}
|
||||
@ -667,12 +704,8 @@ export function setup_topic_search_typeahead(): void {
|
||||
});
|
||||
|
||||
topic_filter_pill_widget.onPillRemove(() => {
|
||||
const stream_id = active_stream_id();
|
||||
if (stream_id !== undefined) {
|
||||
const widget = active_widgets.get(stream_id);
|
||||
if (widget) {
|
||||
widget.build();
|
||||
}
|
||||
if (zoomed_in_widget) {
|
||||
zoomed_in_widget.build();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -682,7 +715,7 @@ export function initialize({
|
||||
}: {
|
||||
on_topic_click: (stream_id: number, topic: string) => void;
|
||||
}): void {
|
||||
$("#stream_filters").on("click", ".topic-box", (e) => {
|
||||
function on_topic_box_click(e: JQuery.ClickEvent): void {
|
||||
const $target = $(e.target);
|
||||
if (e.metaKey || e.ctrlKey || e.shiftKey) {
|
||||
return;
|
||||
@ -720,7 +753,9 @@ export function initialize({
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
$("#more-topics-modal").on("click", ".topic-box", on_topic_box_click);
|
||||
$("#stream_filters").on("click", ".topic-box", on_topic_box_click);
|
||||
|
||||
$("body").on("input", "#left-sidebar-filter-topic-input", (): void => {
|
||||
const stream_id = active_stream_id();
|
||||
@ -730,11 +765,10 @@ export function initialize({
|
||||
const is_previous_search_term_empty = previous_search_term === "";
|
||||
previous_search_term = search_term;
|
||||
|
||||
const widget = active_widgets.get(stream_id)!;
|
||||
const left_sidebar_scroll_container = scroll_util.get_left_sidebar_scroll_container();
|
||||
if (search_term === "") {
|
||||
requestAnimationFrame(() => {
|
||||
widget.build();
|
||||
zoomed_in_widget!.build();
|
||||
// Restore previous scroll position.
|
||||
left_sidebar_scroll_container.scrollTop(pre_search_scroll_position);
|
||||
});
|
||||
@ -757,7 +791,7 @@ export function initialize({
|
||||
pre_search_scroll_position = left_sidebar_scroll_container.scrollTop()!;
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
widget.build();
|
||||
zoomed_in_widget!.build();
|
||||
// Always scroll to top when there is a search term present.
|
||||
left_sidebar_scroll_container.scrollTop(0);
|
||||
});
|
||||
|
||||
@ -86,7 +86,7 @@ export function initialize(): void {
|
||||
});
|
||||
|
||||
popover_menus.register_popover_menu(
|
||||
"#stream_filters .topic-sidebar-menu-icon, .inbox-row .inbox-topic-menu, .recipient-row-topic-menu, .recent_view_focusable .visibility-status-icon",
|
||||
"#stream_filters .topic-sidebar-menu-icon, #more-topics-modal .topic-sidebar-menu-icon, .inbox-row .inbox-topic-menu, .recipient-row-topic-menu, .recent_view_focusable .visibility-status-icon",
|
||||
{
|
||||
...popover_menus.left_sidebar_tippy_options,
|
||||
onShow(instance) {
|
||||
|
||||
@ -107,12 +107,6 @@
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.zoom-in {
|
||||
#topics_header {
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
}
|
||||
|
||||
#recent_view_table {
|
||||
.zulip-icon-user {
|
||||
opacity: 0.7;
|
||||
|
||||
@ -245,13 +245,16 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#left-sidebar-modal-content #direct-messages-modal {
|
||||
#left-sidebar-modal-content #direct-messages-modal,
|
||||
#left-sidebar-modal-content #more-topics-modal {
|
||||
display: grid;
|
||||
grid-template:
|
||||
"section-header" minmax(0, max-content)
|
||||
"conversation-list" minmax(0, 1fr) / minmax(0, 1fr);
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
#left-sidebar-modal-content #direct-messages-modal {
|
||||
#direct-messages-modal-section-header,
|
||||
.dm-list {
|
||||
margin-right: var(--left-sidebar-right-margin);
|
||||
@ -327,12 +330,17 @@
|
||||
}
|
||||
|
||||
#direct-messages-section-header {
|
||||
grid-template-columns:
|
||||
0 var(--left-sidebar-header-icon-toggle-width) 0 minmax(0, 1fr)
|
||||
minmax(0, max-content) minmax(0, max-content) var(
|
||||
--left-sidebar-vdots-width
|
||||
)
|
||||
0;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
/* This extends the general pattern of left sidebar rows, but includes a
|
||||
second grid row for placing filter boxes. */
|
||||
grid-template-areas:
|
||||
"starting-offset starting-anchor-element icon-content-gap row-content controls markers-and-unreads ending-anchor-element ending-offset"
|
||||
"filter-container filter-container filter-container filter-container filter-container filter-container filter-container filter-container";
|
||||
grid-template-rows: var(--line-height-sidebar-row-prominent) minmax(
|
||||
0,
|
||||
max-content
|
||||
);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-background-hover-narrow-filter);
|
||||
@ -849,10 +857,10 @@
|
||||
.narrow-filter
|
||||
.topic-list
|
||||
.bottom_left_row:has(a.topic-box:focus-visible),
|
||||
#more-topics-modal .bottom_left_row:has(a.topic-box:focus-visible),
|
||||
#direct-messages-list .dm-list .bottom_left_row:has(a.dm-box:focus-visible),
|
||||
#modal-direct-messages-list .bottom_left_row:has(a.dm-box:focus-visible),
|
||||
#show-more-direct-messages:has(a.dm-name:focus-visible),
|
||||
#topics_header .show-all-streams:focus-visible,
|
||||
#subscribe-to-more-streams:has(.subscribe-more-link:focus-visible),
|
||||
#login-to-more-streams:has(.subscribe-more-link:focus-visible) {
|
||||
outline: 2px solid var(--color-outline-focus);
|
||||
@ -965,7 +973,10 @@ ul.filters {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#more-topics-modal .topic-list,
|
||||
ul.filters {
|
||||
.sidebar-topic-action-heading {
|
||||
&:focus {
|
||||
color: var(--color-text-sidebar-action-heading);
|
||||
@ -1503,32 +1514,10 @@ li.active-sub-filter {
|
||||
}
|
||||
}
|
||||
|
||||
#direct-messages-section-header,
|
||||
#topics_header {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
/* This extends the general pattern of left sidebar rows, but includes a
|
||||
second grid row for placing filter boxes. */
|
||||
grid-template-areas:
|
||||
"starting-offset starting-anchor-element icon-content-gap row-content controls markers-and-unreads ending-anchor-element ending-offset"
|
||||
"filter-container filter-container filter-container filter-container filter-container filter-container filter-container filter-container";
|
||||
grid-template-rows: var(--line-height-sidebar-row-prominent) minmax(
|
||||
0,
|
||||
max-content
|
||||
);
|
||||
}
|
||||
|
||||
.left-sidebar-filter-input-container {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
grid-area: filter-container;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template:
|
||||
"starting-offset filter-input ending-offset" minmax(0, max-content)
|
||||
/ calc(
|
||||
var(--left-sidebar-toggle-width-offset) -
|
||||
var(--input-icon-starting-offset)
|
||||
)
|
||||
minmax(0, 1fr) 0;
|
||||
|
||||
.filter-input,
|
||||
.filter-topics {
|
||||
@ -1558,6 +1547,35 @@ li.active-sub-filter {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#views-label-container.showing-condensed-navigation,
|
||||
.left-sidebar.zoom-in #views-label-container {
|
||||
/* Use a next-sibling combinator (+) to use CSS to show and hide
|
||||
filter rows as needed, based on the narrow. */
|
||||
+ #left-sidebar-navigation-list {
|
||||
/* In the condensed state, we don't want to generate
|
||||
auto rows, or there will be a footprint where the
|
||||
expanded nav sits. */
|
||||
grid-auto-rows: unset;
|
||||
/* When the navigation area is condensed, hide all
|
||||
the rows in the full navigation list... */
|
||||
& .top_left_row {
|
||||
display: none;
|
||||
}
|
||||
/* ...except when there is an active filter in place:
|
||||
that row should still be shown. */
|
||||
& .top_left_row.top-left-active-filter {
|
||||
display: grid;
|
||||
/* In the absence of auto rows in the condensed state,
|
||||
we set an explicit height on the active filter. */
|
||||
height: var(--line-height-sidebar-row);
|
||||
}
|
||||
}
|
||||
|
||||
.zulip-icon-heading-triangle-right {
|
||||
rotate: 0deg;
|
||||
}
|
||||
}
|
||||
|
||||
#views-label-container {
|
||||
margin-right: var(--left-sidebar-right-margin);
|
||||
grid-template-columns:
|
||||
@ -1580,30 +1598,6 @@ li.active-sub-filter {
|
||||
}
|
||||
}
|
||||
|
||||
/* Use a next-sibling combinator (+) to use CSS to show and hide
|
||||
filter rows as needed, based on the narrow. */
|
||||
&.showing-condensed-navigation {
|
||||
+ #left-sidebar-navigation-list {
|
||||
/* In the condensed state, we don't want to generate
|
||||
auto rows, or there will be a footprint where the
|
||||
expanded nav sits. */
|
||||
grid-auto-rows: unset;
|
||||
/* When the navigation area is condensed, hide all
|
||||
the rows in the full navigation list... */
|
||||
& .top_left_row {
|
||||
display: none;
|
||||
}
|
||||
/* ...except when there is an active filter in place:
|
||||
that row should still be shown. */
|
||||
& .top_left_row.top-left-active-filter {
|
||||
display: grid;
|
||||
/* In the absence of auto rows in the condensed state,
|
||||
we set an explicit height on the active filter. */
|
||||
height: var(--line-height-sidebar-row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the cursor: pointer property of Views label for the spectators. */
|
||||
&.remove-pointer-for-spectator {
|
||||
cursor: default;
|
||||
@ -1955,6 +1949,22 @@ li.active-sub-filter {
|
||||
align-self: baseline;
|
||||
}
|
||||
|
||||
#more-topics-modal .topic-box {
|
||||
grid-template:
|
||||
"starting-offset starting-anchor-element icon-content-gap row-content controls markers-and-unreads ending-anchor-element ending-offset"
|
||||
var(--line-height-sidebar-row-prominent)
|
||||
". . . row-content . . . . "
|
||||
auto
|
||||
/ var(--input-icon-starting-offset) var(
|
||||
--left-sidebar-icon-column-width
|
||||
)
|
||||
var(--left-sidebar-icon-content-gap) minmax(0, 1fr) minmax(
|
||||
0,
|
||||
max-content
|
||||
)
|
||||
minmax(0, max-content) var(--left-sidebar-vdots-width) 0;
|
||||
}
|
||||
|
||||
.zoomed-new-topic {
|
||||
display: grid;
|
||||
grid-template:
|
||||
@ -2197,9 +2207,9 @@ ul.topic-list:has(.show-more-topics)::after {
|
||||
}
|
||||
|
||||
/* The grouping border should not be shown
|
||||
on zoomed-in views. */
|
||||
.zoom-in .topic-list.topic-list-has-topics::before,
|
||||
.zoom-in .topic-list.topic-list-has-topics::after {
|
||||
in the more topics modal. */
|
||||
#more-topics-modal .topic-list.topic-list-has-topics::before,
|
||||
#more-topics-modal .topic-list.topic-list-has-topics::after {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
@ -2262,62 +2272,6 @@ li.topic-list-item {
|
||||
}
|
||||
}
|
||||
|
||||
#streams_list.zoom-out #topics_header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#topics_header {
|
||||
display: grid;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
grid-template-columns:
|
||||
[topics-content-area-start] var(--left-sidebar-toggle-width-offset)
|
||||
0 0 minmax(0, 1fr) 0
|
||||
max-content 0 var(--left-sidebar-vdots-width)
|
||||
[topics-content-area-end] var(--left-sidebar-right-margin);
|
||||
grid-template-rows:
|
||||
[topics-content-area-start] var(--line-height-sidebar-row-prominent)
|
||||
[topics-content-area-end] 0;
|
||||
padding-top: var(--left-sidebar-sections-vertical-gutter);
|
||||
color: hsl(0deg 0% 43%);
|
||||
background-color: var(--color-background);
|
||||
/* With quiet unreads, we want the BACK TO CHANNELS
|
||||
and unread count to share a common baseline. */
|
||||
line-height: var(--line-height-sidebar-row);
|
||||
align-items: baseline;
|
||||
|
||||
.show-all-streams {
|
||||
grid-area: topics-content-area;
|
||||
padding-left: var(--left-sidebar-toggle-width-offset);
|
||||
border-radius: 4px;
|
||||
font-size: var(--font-size-sidebar-action-heading);
|
||||
font-weight: var(--font-weight-sidebar-action-heading);
|
||||
font-variant: var(--font-variant-sidebar-action-heading);
|
||||
text-transform: var(--text-transform-sidebar-action-heading);
|
||||
color: var(--color-text-sidebar-action-heading);
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
|
||||
&:hover {
|
||||
background-color: var(
|
||||
--color-background-sidebar-action-heading-hover
|
||||
);
|
||||
box-shadow: inset 0 0 0 1px var(--color-shadow-sidebar-row-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.unread_count {
|
||||
grid-area: markers-and-unreads;
|
||||
/* Extra margin for unreads. */
|
||||
margin-right: var(--left-sidebar-unread-offset);
|
||||
|
||||
&:empty {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.zero_count {
|
||||
visibility: hidden;
|
||||
}
|
||||
@ -2326,63 +2280,38 @@ li.topic-list-item {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.zoom-in {
|
||||
.narrow-filter.hide {
|
||||
display: none;
|
||||
}
|
||||
#more-topics-modal > .channel-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
padding-bottom: 1px;
|
||||
background-color: var(--color-background);
|
||||
|
||||
.narrow-filter > .bottom_left_row {
|
||||
position: sticky;
|
||||
/* We need to hold the space where the BACK TO CHANNELS
|
||||
line sits, so the channel info doesn't run over the
|
||||
top of it when scrolling down. These are the same
|
||||
variables for setting the space on the BACK TO CHANNELS
|
||||
grid row plus its top padding: */
|
||||
top: calc(
|
||||
var(--line-height-sidebar-row-prominent) +
|
||||
var(--left-sidebar-sections-vertical-gutter)
|
||||
);
|
||||
z-index: 2;
|
||||
padding-bottom: 1px;
|
||||
&:hover {
|
||||
/* Prevent hover styles set on other rows. */
|
||||
box-shadow: none;
|
||||
background-color: var(--color-background);
|
||||
|
||||
&:hover {
|
||||
/* Prevent hover styles set on other rows. */
|
||||
box-shadow: none;
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
|
||||
/* We avoid putting the box-shadow around both
|
||||
the channel row and the filter input it contains,
|
||||
as there is no hover effect on channel rows when
|
||||
zoomed in, making a preserve-the-hover-outline
|
||||
effect here moot. */
|
||||
&:has(.left_sidebar_menu_icon_visible) {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* When zooming in on a channel that's serving as an
|
||||
active filter, keep the background colors in line
|
||||
with the active-narrow-filter colors. */
|
||||
.narrow-filter.active-filter > .bottom_left_row {
|
||||
background-color: var(--color-background-active-narrow-filter);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-background-active-narrow-filter);
|
||||
}
|
||||
/* We avoid putting the box-shadow around both
|
||||
the channel row and the filter input it contains,
|
||||
as there is no hover effect on channel rows when
|
||||
zoomed in, making a preserve-the-hover-outline
|
||||
effect here moot. */
|
||||
&:has(.left_sidebar_menu_icon_visible) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#subscribe-to-more-streams,
|
||||
#login-to-more-streams,
|
||||
.show-more-topics {
|
||||
display: none;
|
||||
.subscription_block:focus-visible {
|
||||
outline: 2px solid var(--color-outline-focus);
|
||||
border-radius: 4px;
|
||||
background-color: var(--color-background-hover-narrow-filter);
|
||||
}
|
||||
}
|
||||
|
||||
.zoom-in-hide,
|
||||
#left-sidebar-search.zoom-in-hide {
|
||||
display: none;
|
||||
}
|
||||
#more-topics-modal .bottom_left_row:last-of-type {
|
||||
/* Needed for the scroll container to not cut off the hover border */
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.top_left_row.hidden-by-filters {
|
||||
@ -2408,12 +2337,6 @@ li.topic-list-item {
|
||||
}
|
||||
}
|
||||
|
||||
#left-sidebar.zoom-out #left-sidebar-modal {
|
||||
/* Hidden instead of display: none so that we scroll to the
|
||||
correct height more easily as it becomes visible again */
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#left-sidebar.zoom-in {
|
||||
#left_sidebar_scroll_container {
|
||||
/* Hidden instead of display: none so that we scroll to the
|
||||
@ -2426,18 +2349,95 @@ li.topic-list-item {
|
||||
}
|
||||
}
|
||||
|
||||
#left-sidebar.zoom-in #left-sidebar-modal {
|
||||
/* Show the DM header when zoomed into topics, visible behind
|
||||
the back button area */
|
||||
#left-sidebar.zoom-in-topics #direct-messages-section-header {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#left-sidebar-modal {
|
||||
/* Hidden instead of display: none so that we scroll to the
|
||||
correct height more easily as it becomes visible again */
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* The two modals have different top paddings */
|
||||
#left-sidebar.zoom-in-conversations #left-sidebar-modal {
|
||||
.left-sidebar-modal-close-area {
|
||||
padding-top: var(--left-sidebar-modal-close-area-padding-top);
|
||||
}
|
||||
|
||||
#left-sidebar-modal-content {
|
||||
height: calc(
|
||||
100dvh - var(--navbar-fixed-height) -
|
||||
var(--left-sidebar-modal-close-area-padding-top) -
|
||||
var(--left-sidebar-modal-close-area-height)
|
||||
);
|
||||
box-shadow:
|
||||
0 -0.2em 0.75em 0 var(--color-left-sidebar-inner-box-shadow),
|
||||
0 -2.5em 1em 0 var(--color-left-sidebar-middle-box-shadow),
|
||||
0 -4em 1em 0 var(--color-left-sidebar-outer-box-shadow);
|
||||
}
|
||||
|
||||
.left-sidebar-modal-close-area:focus-visible + #left-sidebar-modal-content,
|
||||
.left-sidebar-modal-close-area:hover + #left-sidebar-modal-content {
|
||||
box-shadow:
|
||||
0 -0.2em 0.75em 0 var(--color-left-sidebar-inner-box-shadow),
|
||||
0 -2.5em 1em 0 var(--color-left-sidebar-middle-box-shadow-hover),
|
||||
0 -4em 1em 0 var(--color-left-sidebar-outer-box-shadow-hover);
|
||||
}
|
||||
}
|
||||
|
||||
/* The topic menu leaves space to see the DM section by padding the sidebar
|
||||
row height to the close section's upper padding. */
|
||||
#left-sidebar.zoom-in-topics #left-sidebar-modal {
|
||||
.left-sidebar-modal-close-area {
|
||||
padding-top: calc(
|
||||
var(--left-sidebar-modal-close-area-padding-top) +
|
||||
var(--line-height-sidebar-row-prominent)
|
||||
);
|
||||
}
|
||||
|
||||
#left-sidebar-modal-content {
|
||||
height: calc(
|
||||
100dvh - var(--navbar-fixed-height) -
|
||||
var(--left-sidebar-modal-close-area-padding-top) -
|
||||
var(--left-sidebar-modal-close-area-height) -
|
||||
var(--line-height-sidebar-row-prominent)
|
||||
);
|
||||
box-shadow:
|
||||
0 -0.2em 0.75em 0 var(--color-left-sidebar-inner-box-shadow),
|
||||
0 -2.5em 1em 0 var(--color-left-sidebar-middle-box-shadow),
|
||||
0 -5.5em 1em 0 var(--color-left-sidebar-outer-box-shadow);
|
||||
}
|
||||
|
||||
.left-sidebar-modal-close-area:focus-visible + #left-sidebar-modal-content,
|
||||
.left-sidebar-modal-close-area:hover + #left-sidebar-modal-content {
|
||||
box-shadow:
|
||||
0 -0.2em 0.75em 0 var(--color-left-sidebar-inner-box-shadow),
|
||||
0 -2.5em 1em 0 var(--color-left-sidebar-middle-box-shadow-hover),
|
||||
0 -5.5em 1em 0 var(--color-left-sidebar-outer-box-shadow-hover);
|
||||
}
|
||||
}
|
||||
|
||||
@container app (width <= $cq_ml_min) {
|
||||
.left-sidebar-modal-close-area .zulip-icon-close {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
#left-sidebar.zoom-in-topics #left-sidebar-modal,
|
||||
#left-sidebar.zoom-in-conversations #left-sidebar-modal {
|
||||
position: absolute;
|
||||
visibility: visible;
|
||||
left: 0;
|
||||
top: var(--navbar-fixed-height);
|
||||
width: var(--left-sidebar-width);
|
||||
color: var(--color-left-sidebar-navigation-icon);
|
||||
|
||||
.left-sidebar-modal-close-area {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: var(--left-sidebar-modal-close-area-height);
|
||||
padding-top: var(--left-sidebar-modal-close-area-padding-top);
|
||||
display: flex;
|
||||
margin: 0 10px;
|
||||
justify-content: space-between;
|
||||
@ -2456,44 +2456,70 @@ li.topic-list-item {
|
||||
}
|
||||
}
|
||||
|
||||
#direct-messages-modal-section-header {
|
||||
grid-area: section-header;
|
||||
#direct-messages-modal-section-header,
|
||||
.channel-header {
|
||||
margin-top: 5px;
|
||||
grid-area: section-header;
|
||||
}
|
||||
|
||||
.modal-direct-messages-list {
|
||||
.modal-direct-messages-list,
|
||||
.topic-list-scroll-container {
|
||||
grid-area: conversation-list;
|
||||
}
|
||||
|
||||
.channel-header {
|
||||
/* Override the usual hover behavior for the first row (topic name and search bar)
|
||||
and its popover. */
|
||||
box-shadow: none;
|
||||
background-color: var(--color-background);
|
||||
/* For the scrollbar */
|
||||
margin-right: var(--left-sidebar-right-margin);
|
||||
}
|
||||
|
||||
#left-sidebar-modal-content {
|
||||
padding: 0 0 5px 5px;
|
||||
background: var(--color-background);
|
||||
border-radius: 6px 6px 0 0;
|
||||
height: calc(
|
||||
100dvh - var(--navbar-fixed-height) -
|
||||
var(--left-sidebar-modal-close-area-padding-top) -
|
||||
var(--left-sidebar-modal-close-area-height)
|
||||
);
|
||||
box-shadow:
|
||||
0 -0.2em 0.75em 0 var(--color-left-sidebar-inner-box-shadow),
|
||||
0 -2.5em 1em 0 var(--color-left-sidebar-middle-box-shadow),
|
||||
0 -4em 1em 0 var(--color-left-sidebar-outer-box-shadow);
|
||||
}
|
||||
|
||||
.left-sidebar-modal-close-area:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.left-sidebar-modal-close-area:focus-visible + #left-sidebar-modal-content,
|
||||
.left-sidebar-modal-close-area:hover + #left-sidebar-modal-content {
|
||||
box-shadow:
|
||||
0 -0.2em 0.75em 0 var(--color-left-sidebar-inner-box-shadow),
|
||||
0 -2.5em 1em 0 var(--color-left-sidebar-middle-box-shadow-hover),
|
||||
0 -4em 1em 0 var(--color-left-sidebar-outer-box-shadow-hover);
|
||||
/* Remove extra left spacing */
|
||||
.subscription_block {
|
||||
grid-template-columns:
|
||||
0.5em var(--left-sidebar-icon-column-width) var(
|
||||
--left-sidebar-icon-content-gap
|
||||
)
|
||||
minmax(0, 1fr) minmax(0, max-content) minmax(0, max-content) var(
|
||||
--left-sidebar-vdots-width
|
||||
)
|
||||
0;
|
||||
}
|
||||
|
||||
.left-sidebar-filter-input-container {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
.topic-list {
|
||||
margin-bottom: var(--left-sidebar-bottom-scrolling-buffer);
|
||||
}
|
||||
|
||||
.topic-list-item {
|
||||
padding-right: 0;
|
||||
margin-right: var(--left-sidebar-right-margin);
|
||||
}
|
||||
|
||||
/* Override default margin when in the modal. */
|
||||
.topic-list,
|
||||
.topic-list-item {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* Always show the new topic button and header menu icon for the modal view. */
|
||||
.channel-new-topic-button {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.channel-header .sidebar-menu-icon {
|
||||
display: flex;
|
||||
color: var(--color-vdots-visible);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1843,7 +1843,9 @@ body:not(.spectator-view) {
|
||||
}
|
||||
|
||||
.app-main .column-right.expanded .right-sidebar,
|
||||
.app-main .column-left.expanded .left-sidebar {
|
||||
.app-main .column-left.expanded .left-sidebar,
|
||||
.app-main #left-sidebar.zoom-in-topics #left-sidebar-modal,
|
||||
.app-main #left-sidebar.zoom-in-conversations #left-sidebar-modal {
|
||||
width: 100vw;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<div class="left-sidebar zoom-out" id="left-sidebar" role="navigation">
|
||||
<div id="left-sidebar-search" class="zoom-in-hide">
|
||||
<div class="left-sidebar" id="left-sidebar" role="navigation">
|
||||
<div id="left-sidebar-search">
|
||||
<div class="input-wrapper-for-tooltip tippy-zulip-delayed-tooltip" data-tooltip-template-id="filter-left-sidebar-tooltip-template">
|
||||
{{#> components/input_wrapper input_type="filter-input" custom_classes="left-sidebar-search-section" icon="search" input_button_icon="close"}}
|
||||
<input type="text" class="input-element left-sidebar-search-input" autocomplete="off" placeholder="{{t 'Filter left sidebar' }}" />
|
||||
@ -59,10 +59,7 @@
|
||||
<div class="direct-message-section-bottom-divider-container">
|
||||
<hr class="direct-message-section-bottom-divider"/>
|
||||
</div>
|
||||
<div id="streams_list" class="zoom-out">
|
||||
<div id="topics_header">
|
||||
<a class="show-all-streams trigger-click-on-enter" tabindex="0">{{t 'Back to channels' }}</a> <span class="unread_count quiet-count"></span>
|
||||
</div>
|
||||
<div id="streams_list">
|
||||
<div id="stream-filters-container">
|
||||
<ul id="stream_filters" class="filters"></ul>
|
||||
{{#unless is_guest }}
|
||||
@ -108,7 +105,7 @@
|
||||
</div>
|
||||
<div id="modal-direct-messages-list" class="scrolling_list" data-simplebar data-simplebar-tab-index="-1"></div>
|
||||
</div>
|
||||
{{!-- TODO: Put "more topics modal here --}}
|
||||
<div id="more-topics-modal"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<div class="stream-list-toggle-inactive-or-muted-channels bottom_left_row zoom-in-hide">
|
||||
<div class="stream-list-toggle-inactive-or-muted-channels bottom_left_row">
|
||||
<div class="show-inactive-or-muted-channels sidebar-topic-action-heading">
|
||||
<i class="zulip-icon zulip-icon-expand" aria-hidden="true"></i>
|
||||
<div class="stream-list-toggle-inactive-or-muted-channels-text">
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<div id="stream-list-{{id}}-container" data-section-id="{{id}}" class="stream-list-section-container">
|
||||
<div class="stream-list-subsection-header zoom-in-hide">
|
||||
<div class="stream-list-subsection-header">
|
||||
<i class="stream-list-section-toggle zulip-icon zulip-icon-heading-triangle-right rotate-icon-down" aria-hidden="true"></i>
|
||||
<h4 class="left-sidebar-title">
|
||||
{{section_title}}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{{! Stream sidebar rows }}
|
||||
|
||||
<li class="narrow-filter{{#if is_muted}} out_of_home_view{{/if}}" data-stream-id="{{id}}">
|
||||
<div class="bottom_left_row">
|
||||
<li {{#if for_modal}}id="more-topics-modal" {{/if}}class="narrow-filter{{#if is_muted}} out_of_home_view{{/if}}" data-stream-id="{{id}}">
|
||||
<div class="bottom_left_row channel-header">
|
||||
<a href="{{url}}" class="subscription_block selectable_sidebar_block" draggable="false">
|
||||
|
||||
<span class="stream-privacy-original-color-{{id}} stream-privacy filter-icon" style="color: {{color}}">
|
||||
@ -29,4 +28,5 @@
|
||||
<span class="sidebar-menu-icon stream-sidebar-menu-icon"><i class="zulip-icon zulip-icon-more-vertical" aria-hidden="true"></i></span>
|
||||
</a>
|
||||
</div>
|
||||
{{#if for_modal}}<div class="topic-list-scroll-container" data-simplebar data-simplebar-tab-index="-1"></div>{{/if}}
|
||||
</li>
|
||||
|
||||
@ -126,8 +126,6 @@ run_test("update_count_in_dom", () => {
|
||||
|
||||
make_elem($(".top_left_reminders"), "<reminders-count>");
|
||||
|
||||
make_elem($("#topics_header"), "<topics-count>");
|
||||
|
||||
left_sidebar_navigation_area.update_dom_with_unread_counts(counts, false);
|
||||
left_sidebar_navigation_area.update_starred_count(444, false);
|
||||
left_sidebar_navigation_area.update_scheduled_messages_row();
|
||||
@ -141,7 +139,6 @@ run_test("update_count_in_dom", () => {
|
||||
assert.equal($("<reminders-count>").text(), "1");
|
||||
assert.ok(!$(".top_left_scheduled_messages").hasClass("hidden-by-filters"));
|
||||
assert.ok(!$(".top_left_reminders").hasClass("hidden-by-filters"));
|
||||
assert.equal($("<topics-count>").text(), "666");
|
||||
|
||||
counts.mentioned_message_count = 0;
|
||||
message_reminder.set_reminders_by_id_for_testing(new Map());
|
||||
|
||||
@ -379,47 +379,9 @@ function initialize_stream_data() {
|
||||
stream_list.build_stream_list();
|
||||
}
|
||||
|
||||
function elem($obj) {
|
||||
return {to_$: () => $obj, classList: $obj[0].classList};
|
||||
}
|
||||
|
||||
test_ui("zoom_in_and_zoom_out", ({mock_template}) => {
|
||||
topic_list.setup_topic_search_typeahead = noop;
|
||||
|
||||
const $stream_li1 = $.create("stream1 stub");
|
||||
const $stream_li2 = $.create("stream2 stub");
|
||||
|
||||
$stream_li1.attr("data-stream-id", "42");
|
||||
$stream_li1.hide();
|
||||
$stream_li2.attr("data-stream-id", "99");
|
||||
|
||||
$.set_results("#stream_filters li.narrow-filter", [elem($stream_li1), elem($stream_li2)]);
|
||||
|
||||
mock_template("filter_topics.hbs", false, () => "<filter-topics-stub>");
|
||||
let filter_topics_appended = false;
|
||||
const $bottom_left_row = $.create("bottom-left-row-stub");
|
||||
$bottom_left_row.set_matches("div.bottom_left_row", true);
|
||||
$stream_li1.set_children($bottom_left_row);
|
||||
$bottom_left_row[0].append = (element) => {
|
||||
assert.equal(element, $("<filter-topics-stub>")[0]);
|
||||
filter_topics_appended = true;
|
||||
};
|
||||
stream_list.zoom_in_topics(42);
|
||||
|
||||
assert.ok(!$stream_li1.hasClass("hide"));
|
||||
assert.ok($stream_li2.hasClass("hide"));
|
||||
assert.ok($("#streams_list").hasClass("zoom-in"));
|
||||
assert.ok(filter_topics_appended);
|
||||
|
||||
$(".filter-topics")[0].remove = () => {
|
||||
filter_topics_appended = false;
|
||||
};
|
||||
stream_list.zoom_out_topics({$stream_li: $stream_li1});
|
||||
|
||||
assert.ok(!$stream_li1.hasClass("hide"));
|
||||
assert.ok(!$stream_li2.hasClass("hide"));
|
||||
assert.ok($("#streams_list").hasClass("zoom-out"));
|
||||
assert.ok(!filter_topics_appended);
|
||||
test_ui("zoom_in_and_zoom_out", () => {
|
||||
// TODO(evy): write new tests for this, if we want, though it would involve a lot of
|
||||
// jquery wrangling.
|
||||
});
|
||||
|
||||
test_ui("narrowing", ({override_rewire}) => {
|
||||
@ -623,6 +585,7 @@ test_ui("rename_stream", ({mock_template, override, override_rewire}) => {
|
||||
invite_only: false,
|
||||
is_web_public: false,
|
||||
color: payload.color,
|
||||
for_modal: false,
|
||||
pin_to_top: true,
|
||||
can_post_messages: true,
|
||||
is_empty_topic_only_channel: false,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user