popovers: Add stream-info-popover when channel pill is clicked.

Shows a stream info popover whenever a channel pill is clicked (such
as in the pill widgets for adding subscribers to a channel or
invitations). The stream info popover contains channel icon and name,
channel description and a link to channel settings.

Fixes #30567.
This commit is contained in:
opmkumar 2024-09-10 22:00:14 +05:30 committed by Tim Abbott
parent 5ecdf56336
commit 719518baba
10 changed files with 110 additions and 3 deletions

View File

@ -236,6 +236,7 @@ EXEMPT_FILES = make_set(
"web/src/spoilers.ts",
"web/src/starred_messages_ui.ts",
"web/src/state_data.ts",
"web/src/stream_card_popover.ts",
"web/src/stream_color.ts",
"web/src/stream_color_events.ts",
"web/src/stream_create.js",

View File

@ -21,6 +21,7 @@ type PopoverName =
| "left_sidebar_recent_view_popover"
| "top_left_sidebar"
| "message_actions"
| "stream_card_popover"
| "stream_settings"
| "topics_menu"
| "send_later"
@ -38,6 +39,7 @@ export const popover_instances: Record<PopoverName, tippy.Instance | null> = {
left_sidebar_recent_view_popover: null,
top_left_sidebar: null,
message_actions: null,
stream_card_popover: null,
stream_settings: null,
topics_menu: null,
send_later: null,

View File

@ -0,0 +1,66 @@
import $ from "jquery";
import assert from "minimalistic-assert";
import render_stream_card_popover from "../templates/popovers/stream_card_popover.hbs";
import * as browser_history from "./browser_history";
import * as hash_util from "./hash_util";
import * as modals from "./modals";
import * as popover_menus from "./popover_menus";
import {current_user} from "./state_data";
import * as stream_data from "./stream_data";
import * as sub_store from "./sub_store";
import * as ui_util from "./ui_util";
let stream_id: number | undefined;
export function initialize(): void {
popover_menus.register_popover_menu(".pill[data-stream-id]", {
theme: "popover-menu",
placement: "right",
onShow(instance) {
popover_menus.popover_instances.stream_card_popover = instance;
popover_menus.on_show_prep(instance);
const $elt = $(instance.reference);
const stream_id_str = $elt.attr("data-stream-id");
assert(stream_id_str !== undefined);
stream_id = Number.parseInt(stream_id_str, 10);
instance.setContent(
ui_util.parse_html(
render_stream_card_popover({
stream: {
...sub_store.get(stream_id),
},
}),
),
);
},
onMount(instance) {
const $popper = $(instance.popper);
// Stream settings
$popper.on("click", ".open_stream_settings", () => {
assert(stream_id !== undefined);
const sub = sub_store.get(stream_id);
assert(sub !== undefined);
popover_menus.hide_current_popover_if_visible(instance);
// modals.close_active_if_any() is mainly used to handle navigation to channel settings
// using the popover that is opened when clicking on channel pills in the invite user modal.
modals.close_active_if_any();
const can_change_name_description = current_user.is_admin;
const can_change_stream_permissions = stream_data.can_change_permissions(sub);
let stream_edit_hash = hash_util.channels_settings_edit_url(sub, "general");
if (!can_change_stream_permissions && !can_change_name_description) {
stream_edit_hash = hash_util.channels_settings_edit_url(sub, "personal");
}
browser_history.go_to_location(stream_edit_hash);
});
},
onHidden(instance) {
instance.destroy();
popover_menus.popover_instances.stream_card_popover = null;
},
});
}

View File

@ -96,6 +96,7 @@ export function generate_pill_html(item: StreamPill): string {
has_stream: true,
stream,
display_value: get_display_value_from_item(item),
stream_id: item.stream_id,
});
}

View File

@ -115,6 +115,7 @@ import * as spoilers from "./spoilers";
import * as starred_messages from "./starred_messages";
import * as starred_messages_ui from "./starred_messages_ui";
import {current_user, realm, set_current_user, set_realm, state_data_schema} from "./state_data";
import * as stream_card_popover from "./stream_card_popover";
import * as stream_data from "./stream_data";
import * as stream_edit from "./stream_edit";
import * as stream_edit_subscribers from "./stream_edit_subscribers";
@ -533,6 +534,7 @@ export function initialize_everything(state_data) {
stream_edit_subscribers.initialize();
stream_data.initialize(state_data.stream_data);
user_group_edit_members.initialize();
stream_card_popover.initialize();
pm_conversations.recent.initialize(state_data.pm_conversations);
user_topics.initialize(state_data.user_topics);
muted_users.initialize(state_data.muted_users);

View File

@ -281,6 +281,7 @@
--user-group-info-popover-min-width: 16.4285em; /* 230px / 14px em */
--topic-actions-popover-min-width: 200px;
--user-card-popover-min-width: 200px;
--stream-card-popover-min-width: 16.4285em;
/* Information density and typography values */
/* The legacy values here are updated via JavaScript */

View File

@ -246,7 +246,8 @@
z-index: 106;
}
#stream-actions-menu-popover {
#stream-actions-menu-popover,
#stream-card-popover {
.popover-stream-name {
font-weight: 600;
color: var(--color-text-popover-menu);
@ -265,6 +266,10 @@
margin: 0 !important;
}
.popover-stream-info-menu-description {
color: var(--color-text-popover-menu);
}
.colorpicker-container {
display: none;
margin-right: 10px;
@ -1336,6 +1341,12 @@ ul.popover-group-menu-member-list {
}
}
#stream-card-popover {
.simplebar-content {
min-width: var(--stream-card-popover-min-width);
}
}
.personal-menu-clear-status {
display: flex;
align-items: center;

View File

@ -1,4 +1,4 @@
<div class='pill {{#if deactivated}} deactivated-pill {{/if}}'{{#if user_id}}data-user-id="{{user_id}}"{{/if}}{{#if group_id}}data-user-group-id="{{group_id}}"{{/if}} tabindex=0>
<div class='pill {{#if deactivated}} deactivated-pill {{/if}}'{{#if user_id}}data-user-id="{{user_id}}"{{/if}}{{#if group_id}}data-user-group-id="{{group_id}}"{{/if}}{{#if stream_id}}data-stream-id="{{stream_id}}"{{/if}} tabindex=0>
{{#if has_image}}
<img class="pill-image" src="{{img_src}}" />
{{/if}}

View File

@ -0,0 +1,23 @@
<div class="popover-menu" id="stream-card-popover" data-simplebar data-simplebar-tab-index="-1">
<ul role="menu" class="popover-menu-list">
<li role="none" class="popover-stream-header text-item popover-menu-list-item">
<span class="stream-privacy-original-color-{{stream.stream_id}} stream-privacy filter-icon" style="color: {{stream.color}}">
{{> ../stream_privacy
invite_only=stream.invite_only
is_web_public=stream.is_web_public }}
</span>
<span class="popover-stream-name">{{stream.name}}</span>
</li>
<li role="none" class="popover-stream-info-menu-description text-item popover-menu-list-item">
{{> ../stream_settings/stream_description
rendered_description=stream.rendered_description}}
</li>
<li role="separator" class="popover-menu-separator hidden-for-spectators"></li>
<li role="none" class="link-item popover-menu-list-item hidden-for-spectators">
<a role="menuitem" class="open_stream_settings popover-menu-link" tabindex="0">
<i class="popover-menu-icon zulip-icon zulip-icon-gear" aria-hidden="true"></i>
<span class="popover-menu-label">{{t "Channel settings" }}</span>
</a>
</li>
</ul>
</div>

View File

@ -118,7 +118,7 @@ run_test("get_stream_ids", () => {
run_test("generate_pill_html", () => {
assert.deepEqual(
stream_pill.generate_pill_html(denmark_pill),
"<div class='pill ' tabindex=0>\n" +
"<div class='pill 'data-stream-id=\"101\" tabindex=0>\n" +
' <span class="pill-label">\n' +
' <span class="pill-value">\n' +
'<i class="zulip-icon zulip-icon-hashtag stream-privacy-type-icon" aria-hidden="true"></i> translated: Denmark: 3 users\n' +