left_sidebar: Add menu to change channel folder setting in left sidebar.

Earlier, you could change setting to show/hide channel folders in
left sidebar from setting overlay.

This commit adds an menu option to toggle channel folders setting in
the left sidebar. The menu is hidden if there are no subscribed
channels with channel folder.

Fixes #35574.
This commit is contained in:
Pratik Chanda
2025-08-05 18:53:48 +05:30
committed by Tim Abbott
parent 35896244d7
commit 8711730e6b
8 changed files with 115 additions and 4 deletions

View File

@@ -65,6 +65,7 @@ EXEMPT_FILES = make_set(
"web/src/browser_history.ts",
"web/src/buddy_list.ts",
"web/src/buttons.ts",
"web/src/channel_folders_popover.ts",
"web/src/channel_folders_ui.ts",
"web/src/click_handlers.ts",
"web/src/color_picker_popover.ts",

View File

@@ -0,0 +1,54 @@
import $ from "jquery";
import assert from "minimalistic-assert";
import type * as tippy from "tippy.js";
import render_left_sidebar_channels_folder_setting_popover from "../templates/popovers/left_sidebar/left_sidebar_channels_folder_setting_popover.hbs";
import * as channel from "./channel.ts";
import * as popover_menus from "./popover_menus.ts";
import {parse_html} from "./ui_util.ts";
import {user_settings} from "./user_settings.ts";
function do_change_show_channel_folders(instance: tippy.Instance): void {
const show_channel_folders = user_settings.web_left_sidebar_show_channel_folders;
const data = {
web_left_sidebar_show_channel_folders: JSON.stringify(!show_channel_folders),
};
void channel.patch({
url: "/json/settings",
data,
});
popover_menus.hide_current_popover_if_visible(instance);
}
export function initialize(): void {
popover_menus.register_popover_menu("#left-sidebar-search .channel-folders-sidebar-menu-icon", {
...popover_menus.left_sidebar_tippy_options,
theme: "popover-menu",
onMount(instance) {
const $popper = $(instance.popper);
assert(instance.reference instanceof HTMLElement);
$popper.one("click", "#left_sidebar_channel_folders", () => {
do_change_show_channel_folders(instance);
});
},
onShow(instance) {
const show_channel_folders = user_settings.web_left_sidebar_show_channel_folders;
// Assuming that the instance can be shown, track and
// prep the instance for showing
popover_menus.popover_instances.show_channels_sidebar = instance;
instance.setContent(
parse_html(
render_left_sidebar_channels_folder_setting_popover({show_channel_folders}),
),
);
popover_menus.on_show_prep(instance);
return undefined;
},
onHidden(instance) {
instance.destroy();
popover_menus.popover_instances.show_channels_sidebar = null;
},
});
}

View File

@@ -32,7 +32,8 @@ type PopoverName =
| "help_menu"
| "buddy_list"
| "stream_actions_popover"
| "color_picker_popover";
| "color_picker_popover"
| "show_channels_sidebar";
export const popover_instances: Record<PopoverName, tippy.Instance | null> = {
compose_control_buttons: null,
@@ -54,6 +55,7 @@ export const popover_instances: Record<PopoverName, tippy.Instance | null> = {
buddy_list: null,
stream_actions_popover: null,
color_picker_popover: null,
show_channels_sidebar: null,
};
// Font size in em for popover derived from popover font size being

View File

@@ -284,6 +284,17 @@ export function update_unread_counts_visibility(): void {
// `update_section_unread_count`, since they depend on unread counts.
}
function maybe_change_channel_folders_option_visibility(): void {
const $channel_folders_sidebar_option = $(
"#left-sidebar-search .channel-folders-sidebar-menu-icon",
);
if (channel_folders.user_has_folders()) {
$channel_folders_sidebar_option.show();
} else {
$channel_folders_sidebar_option.hide();
}
}
export function build_stream_list(force_rerender: boolean): void {
// The stream list in the left sidebar contains 3 sections:
// pinned, normal, and dormant streams, with headings above them
@@ -303,6 +314,8 @@ export function build_stream_list(force_rerender: boolean): void {
return;
}
maybe_change_channel_folders_option_visibility();
function add_sidebar_li(stream_id: number, $list: JQuery, inactive_or_muted = false): void {
const sidebar_row = stream_sidebar.get_row(stream_id);
assert(sidebar_row !== undefined);

View File

@@ -22,6 +22,7 @@ import * as blueslip from "./blueslip.ts";
import * as bot_data from "./bot_data.ts";
import * as channel from "./channel.ts";
import * as channel_folders from "./channel_folders.ts";
import * as channel_folders_popover from "./channel_folders_popover.ts";
import * as click_handlers from "./click_handlers.ts";
import * as color_picker_popover from "./color_picker_popover.ts";
import * as common from "./common.ts";
@@ -587,6 +588,7 @@ export async function initialize_everything(state_data) {
stream_popover.initialize();
color_picker_popover.initialize();
add_stream_options_popover.initialize();
channel_folders_popover.initialize();
click_handlers.initialize();
scheduled_messages_overlay_ui.initialize();
compose_paste.initialize({

View File

@@ -55,7 +55,8 @@
.add-stream-icon-container {
grid-area: add-channel;
display: grid;
margin: 2px 0;
/* 2px right margin here to match the new topic margin-right */
margin: 2px 1px 2px 0;
border-radius: 3px;
.add_stream_icon {
@@ -331,8 +332,10 @@
#left-sidebar-search {
display: grid;
grid-template-areas: "filter-container add-channel";
grid-template-columns: minmax(0, 1fr) var(--left-sidebar-header-icon-width);
grid-template-areas: "filter-container add-channel channel-folders-option";
grid-template-columns:
minmax(0, 1fr) var(--left-sidebar-header-icon-width)
auto;
position: sticky;
top: 0;
/* Must be more than .stream-list-subsection-header */
@@ -340,6 +343,27 @@
background: var(--color-background);
/* Must be padding not margin so that the sticky headers don't show behind it */
padding: 0 var(--left-sidebar-right-margin) 3px 5px;
.channel-folders-sidebar-menu-icon {
grid-area: channel-folders-option;
display: grid;
/* width excluding left & right margin */
width: calc(var(--left-sidebar-vdots-width) - 3px);
cursor: pointer;
place-items: center center;
border-radius: 3px;
margin: 2px 2px 2px 1px;
color: var(--color-vdots-visible);
& i.zulip-icon {
font-size: 1.0625em;
}
&:hover {
color: var(--color-vdots-hover);
background-color: var(--color-background-sidebar-action-hover);
}
}
}
.stream-list-subsection-header {

View File

@@ -8,6 +8,7 @@
<span id="add_streams_tooltip" class="add-stream-icon-container hidden-for-spectators">
<i id="streams_inline_icon" class="add_stream_icon zulip-icon zulip-icon-square-plus" aria-hidden="true" ></i>
</span>
<span class="sidebar-menu-icon channel-folders-sidebar-menu-icon hidden-for-spectators"><i class="zulip-icon zulip-icon-more-vertical" aria-label="{{t 'Show channel folders'}}"></i></span>
</div>
<ul id="left-sidebar-empty-list-message" class="hidden">
{{> empty_list_widget_for_list

View File

@@ -0,0 +1,14 @@
<div class="popover-menu" data-simplebar data-simplebar-tab-index="-1">
<ul role="menu" class="popover-menu-list">
<li role="none" class="link-item popover-menu-list-item">
<a role="menuitem" id="left_sidebar_channel_folders" class="popover-menu-link" tabindex="0">
<i class="popover-menu-icon zulip-icon zulip-icon-folder" aria-hidden="true"></i>
{{#if show_channel_folders}}
<span class="popover-menu-label">{{t "Don't group channels by folder" }}</span>
{{else}}
<span class="popover-menu-label">{{t "Group channels by folder" }}</span>
{{/if}}
</a>
</li>
</ul>
</div>