settings: Use grid and flex for the two-pane settings overlay.

Instead of changing the height of the button subheader depending
on the width of the modal, which was fiddly and error prone, we now
let grid determine the height of the button subheader, and determine
the height of the body through javascript resize calculations.
This commit is contained in:
evykassirer
2025-03-17 14:49:04 -07:00
committed by Tim Abbott
parent e66431f128
commit 236e595438
12 changed files with 242 additions and 211 deletions

View File

@@ -16,6 +16,12 @@ const mc = 849; // Middle column as wide as it appears after the `sm` breakpoint
// Base em unit for container_breakpoints conversion
const base_em_px = 16;
// Used for main settings overlay and stream/subscription settings overlay
// measured as the width of the overlay itself, not the width of the full
// screen. 800px is the breakpoint at the 14px legacy font size, scaled with
// em to user-chosen font-size.
const settings_overlay_sidebar_collapse_breakpoint = 800;
export const media_breakpoints = {
xs_min: xs + "px",
sm_min: sm + "px",
@@ -27,11 +33,8 @@ export const media_breakpoints = {
mm_min: mm + "px",
ms_min: ms + "px",
short_navbar_cutoff_height: "600px",
// Used for main settings overlay and stream/subscription settings overlay
// measured as the width of the overlay itself, not the width of the full
// screen. 800px is the breakpoint at the 14px legacy font size, scaled with
// em to user-chosen font-size.
settings_overlay_sidebar_collapse_breakpoint: 800 / 14 + "em",
settings_overlay_sidebar_collapse_breakpoint:
settings_overlay_sidebar_collapse_breakpoint / 14 + "em",
};
export const container_breakpoints = {
@@ -54,4 +57,5 @@ export const media_breakpoints_num = {
ml,
mm,
ms,
settings_overlay_sidebar_collapse_breakpoint,
};

View File

@@ -7,6 +7,7 @@ import * as compose_state from "./compose_state.ts";
import * as compose_ui from "./compose_ui.ts";
import {media_breakpoints_num} from "./css_variables.ts";
import * as message_viewport from "./message_viewport.ts";
import {user_settings} from "./user_settings.ts";
function get_bottom_whitespace_height(): number {
return message_viewport.height() * 0.4;
@@ -87,6 +88,10 @@ function height_of($element: JQuery): number {
return $element.get(0)!.getBoundingClientRect().height;
}
function width_of($element: JQuery): number {
return $element.get(0)!.getBoundingClientRect().width;
}
export function reset_compose_message_max_height(bottom_whitespace_height?: number): void {
// If the compose-box is open, we set the `max-height` property of
// `compose-textarea` and `preview-textarea`, so that the
@@ -218,18 +223,53 @@ function resize_navbar_alerts(): void {
}
}
// On narrow screens, the `right` panel is absolutely positioned, so its
// height doesn't change the height of `left` and vice versa. Here we
// first let subheaders on both sides attain their natural height as
// per the content and then make both of them equal by setting the
// height of subheader which is smaller to the height of subheader that
// has larger height.
// This feels a bit hacky and a cleaner solution would be nice to find.
export function resize_settings_overlay_subheader_for_narrow_screens($container: JQuery): void {
const breakpoint_em =
(media_breakpoints_num.settings_overlay_sidebar_collapse_breakpoint / 14) *
user_settings.web_font_size_px;
const $left_subheader = $container.find(".two-pane-settings-subheader .left");
const $right_subheader = $container.find(".two-pane-settings-subheader .right");
if (width_of($container.find(".two-pane-settings-overlay")) > breakpoint_em) {
$left_subheader.css("height", "");
$right_subheader.css("height", "");
return;
}
$left_subheader.css("height", "");
$right_subheader.css("height", "");
const left_subheader_height = height_of($left_subheader);
const right_subheader_height = height_of($right_subheader);
if (left_subheader_height < right_subheader_height) {
$left_subheader.css("height", right_subheader_height);
} else {
$right_subheader.css("height", left_subheader_height);
}
}
export function resize_settings_overlay($container: JQuery): void {
if ($container.find(".two-pane-settings-overlay.show").length === 0) {
return;
}
resize_settings_overlay_subheader_for_narrow_screens($container);
$container
.find(".two-pane-settings-left-simplebar-container")
.css(
"height",
height_of($container.find(".two-pane-settings-container")) -
height_of($container.find(".two-pane-settings-header")) -
height_of($container.find(".two-pane-settings-overlay .display-type")) -
height_of($container.find(".two-pane-settings-subheader")) -
height_of($container.find(".two-pane-settings-search")),
);
@@ -239,7 +279,7 @@ export function resize_settings_overlay($container: JQuery): void {
"height",
height_of($container.find(".two-pane-settings-container")) -
height_of($container.find(".two-pane-settings-header")) -
height_of($container.find(".two-pane-settings-overlay .display-type")),
height_of($container.find(".two-pane-settings-subheader")),
);
}
@@ -254,7 +294,7 @@ export function resize_settings_creation_overlay($container: JQuery): void {
"height",
height_of($container.find(".two-pane-settings-container")) -
height_of($container.find(".two-pane-settings-header")) -
height_of($container.find(".display-type")) -
height_of($container.find(".two-pane-settings-subheader")) -
height_of($container.find(".settings-sticky-footer")),
);
}

View File

@@ -14,7 +14,6 @@ import * as keydown_util from "./keydown_util.ts";
import * as loading from "./loading.ts";
import * as onboarding_steps from "./onboarding_steps.ts";
import {page_params} from "./page_params.ts";
import * as resize from "./resize.ts";
import * as settings_components from "./settings_components.ts";
import * as settings_config from "./settings_config.ts";
import * as settings_data from "./settings_data.ts";
@@ -484,7 +483,6 @@ export function show_new_stream_modal(): void {
$("#stream-creation").removeClass("hide");
$(".right .settings").hide();
stream_ui_updates.hide_or_disable_stream_privacy_options_if_required($("#stream-creation"));
resize.resize_settings_creation_overlay($("#channels_overlay_container"));
stream_create_subscribers.build_widgets();

View File

@@ -13,6 +13,7 @@ import {$t, $t_html} from "./i18n.ts";
import * as loading from "./loading.ts";
import * as overlays from "./overlays.ts";
import * as peer_data from "./peer_data.ts";
import * as resize from "./resize.ts";
import * as settings_data from "./settings_data.ts";
import {current_user} from "./state_data.ts";
import * as stream_data from "./stream_data.ts";
@@ -42,11 +43,13 @@ export const show_subs_pane = {
$("#subscription_overlay .stream-info-title").text(
$t({defaultMessage: "Channel settings"}),
);
resize.resize_settings_overlay($("#channels_overlay_container"));
},
settings(sub: StreamSubscription): void {
$(".settings, #stream-creation").hide();
$(".settings").show();
set_right_panel_title(sub);
resize.resize_settings_overlay($("#channels_overlay_container"));
},
create_stream(
container_name = "configure_channel_settings",
@@ -76,6 +79,8 @@ export const show_subs_pane = {
$(`.${CSS.escape(container_name)}`).show();
$(".nothing-selected, .settings, #stream-creation").hide();
$("#stream-creation").show();
resize.resize_settings_overlay($("#channels_overlay_container"));
resize.resize_settings_creation_overlay($("#channels_overlay_container"));
},
};

View File

@@ -979,7 +979,6 @@ export function change_state(
if (section === "new") {
do_open_create_stream(folder_id);
show_right_section();
resize.resize_settings_creation_overlay($("#channels_overlay_container"));
return;
}
@@ -1205,6 +1204,9 @@ export function initialize(): void {
$("#channels_overlay_container").on("click", ".fa-chevron-left", () => {
$(".right").removeClass("show");
$("#channels_overlay_container .two-pane-settings-header").removeClass("slide-left");
resize.resize_settings_overlay_subheader_for_narrow_screens(
$("#channels_overlay_container"),
);
});
$("#channels_overlay_container").on("click", "#preview-stream-button", () => {

View File

@@ -3,6 +3,7 @@ import $ from "jquery";
import {$t_html} from "./i18n.ts";
import * as people from "./people.ts";
import type {User} from "./people.ts";
import * as resize from "./resize.ts";
import * as user_groups from "./user_groups.ts";
import type {UserGroup} from "./user_groups.ts";
import * as user_sort from "./user_sort.ts";
@@ -27,6 +28,7 @@ export const show_user_group_settings_pane = {
$t_html({defaultMessage: "User group settings"}),
);
$("#groups_overlay .deactivated-user-group-icon-right").hide();
resize.resize_settings_overlay($("#groups_overlay_container"));
},
settings(group: UserGroup) {
$("#groups_overlay .nothing-selected, #user-group-creation").hide();
@@ -39,6 +41,7 @@ export const show_user_group_settings_pane = {
} else {
$("#groups_overlay .deactivated-user-group-icon-right").hide();
}
resize.resize_settings_overlay($("#groups_overlay_container"));
},
create_user_group(container_name = "configure_user_group_settings", group_name?: string) {
$(".user_group_creation").hide();
@@ -57,6 +60,8 @@ export const show_user_group_settings_pane = {
reset_active_group_id();
$("#user-group-creation").show();
$("#groups_overlay .deactivated-user-group-icon-right").hide();
resize.resize_settings_overlay($("#groups_overlay_container"));
resize.resize_settings_creation_overlay($("#groups_overlay_container"));
},
};

View File

@@ -9,7 +9,6 @@ import * as group_permission_settings from "./group_permission_settings.ts";
import {$t, $t_html} from "./i18n.ts";
import * as keydown_util from "./keydown_util.ts";
import * as loading from "./loading.ts";
import * as resize from "./resize.ts";
import * as settings_components from "./settings_components.ts";
import * as settings_data from "./settings_data.ts";
import {realm} from "./state_data.ts";
@@ -184,7 +183,6 @@ function clear_error_display(): void {
export function show_new_user_group_modal(): void {
$("#user-group-creation").removeClass("hide");
$(".right .settings").hide();
resize.resize_settings_creation_overlay($("#groups_overlay_container"));
user_group_create_members.build_widgets();

View File

@@ -1546,7 +1546,6 @@ export function change_state(
if (section === "new") {
do_open_create_user_group();
redraw_user_group_list();
resize.resize_settings_creation_overlay($("#groups_overlay_container"));
return;
}
@@ -2156,6 +2155,7 @@ export function initialize(): void {
$("#groups_overlay_container").on("click", ".fa-chevron-left", () => {
$(".right").removeClass("show");
$("#groups_overlay_container .two-pane-settings-header").removeClass("slide-left");
resize.resize_settings_overlay_subheader_for_narrow_screens($("#groups_overlay_container"));
});
$("#groups_overlay_container").on(

View File

@@ -67,6 +67,7 @@
}
#add_new_user_group {
margin-left: auto;
height: var(--settings-overlay-header-button-height);
}
@@ -77,7 +78,7 @@
border-radius: 5px;
background-color: var(--color-background-settings-plus-button);
color: var(--color-text-settings-plus-button);
margin: 0 0 0 5px;
margin: 0;
height: 100%;
width: var(--settings-overlay-header-button-height);
display: flex;
@@ -364,34 +365,48 @@ h4.user_group_setting_subsection_title {
}
}
/* Subheader styles. These aren't in a separate subheader div yet,
so we add `.overlay-container` for now to apppease the linter in
differentiating from the main container styles below. */
.two-pane-settings-container.overlay-container {
.list-toggler-container {
align-items: center;
padding: 0 8px;
border-bottom: 1px solid var(--color-border-modal-bar);
display: flex;
justify-content: space-between;
height: var(--settings-overlay-subheader-height);
.two-pane-settings-container .two-pane-settings-subheader {
display: flex;
align-items: center;
border-bottom: 1px solid var(--color-border-modal-bar);
grid-area: settings-overlay-subheader;
.left {
align-self: start;
}
.stream_sorter_toggle {
.left,
.right {
display: flex;
justify-content: center;
}
.list-toggler-container {
flex-wrap: wrap;
padding: 8px;
display: flex;
justify-content: end;
flex-grow: 1;
gap: 5px;
}
.tab-switcher.stream_sorter_toggle {
margin-left: auto;
}
.tab-switcher,
#add_new_subscription {
margin: 0;
height: var(--settings-overlay-header-button-height);
}
.display-type {
height: var(--settings-overlay-subheader-height);
display: flex;
justify-content: center;
align-items: center;
font-weight: 600;
border-bottom: 1px solid var(--color-border-modal-bar);
padding: 10px;
overflow: hidden;
& a {
color: inherit;
@@ -446,69 +461,20 @@ h4.user_group_setting_subsection_title {
}
}
#subscription_overlay .two-pane-settings-container {
container: subscriptions / inline-size;
}
/* There's an awkward width of modal that is wider than the
breakpoint that collapses the left pane, but still narrow
enough that the sort buttons need a second row to be visible
without overlapping other UI. Note that for 16px and larger
font sizes, we always show two rows of buttons.
We also show two rows of buttons on particularly narrow
screens where there's only one panel and the overlay doesn't
have enough space for all the buttons. */
@container settings-overlay (
((width >= $settings_overlay_sidebar_collapse_breakpoint) and (width < calc(80em + 80px)))
or ((width < $settings_overlay_sidebar_collapse_breakpoint) and (width <= 36em))
) {
#subscription_overlay .two-pane-settings-container {
.left {
.list-toggler-container {
height: 5em;
justify-content: end;
flex-wrap: wrap;
}
.tab-switcher {
margin-right: 0;
}
.tab-switcher:first-child {
/* This forces the other buttons to the next row */
width: 100%;
display: flex;
justify-content: end;
}
}
.right .display-type {
height: 5em;
}
.streams-list {
/* Calculated from several heights and padding/margin measurements
in .list-toggler-container and .stream_filter, with some added
fiddling to see what worked best at 12px - 20px font sizes.
Notably this height is shorter than the similar calculation
below because the toggler is taller.
When we redesign this area we should make this less brittle. */
height: calc(100% - 5.4em - 40px);
}
#stream_settings {
height: calc(100% - 5em);
}
}
}
.two-pane-settings-container {
position: relative;
display: grid;
grid-template:
"settings-overlay-header " var(--settings-overlay-header-height)
"settings-overlay-subheader" minmax(
var(--settings-overlay-subheader-height),
max-content
)
"settings-overlay-body " minmax(0, 1fr) / 100%;
height: 95%;
border-radius: 4px;
padding: 0;
width: 97%;
position: relative;
overflow: hidden;
max-width: 1200px;
max-height: var(--overlay-container-max-height);
@@ -524,7 +490,7 @@ h4.user_group_setting_subsection_title {
}
.two-pane-settings-header {
height: var(--settings-overlay-header-height);
grid-area: settings-overlay-header;
display: flex;
align-items: center;
justify-content: space-between;
@@ -547,12 +513,8 @@ h4.user_group_setting_subsection_title {
cursor: pointer;
}
.left,
.right {
position: relative;
display: inline-block;
vertical-align: top;
margin: 0 -2px;
.two-pane-settings-body {
display: flex;
}
.left .no-streams-to-show,
@@ -605,11 +567,12 @@ h4.user_group_setting_subsection_title {
.left {
width: 40%;
border-right: 1px solid var(--color-border-modal-bar);
}
.right {
width: calc(60% + 1px);
border-left: 1px solid var(--color-border-modal-bar);
box-sizing: border-box;
.nothing-selected .create_stream_button,
.nothing-selected .create_user_group_button {
@@ -982,10 +945,6 @@ h4.user_group_setting_subsection_title {
.settings-sticky-footer {
display: flex;
justify-content: space-between;
position: absolute;
bottom: 0;
/* Subtract 15px padding on either side. */
width: calc(100% - 30px);
padding: 9px 15px;
text-align: right;
background-color: var(--color-background-modal-bar);
@@ -1440,16 +1399,20 @@ div.settings-radio-input-parent {
max-width: 95%;
}
.two-pane-settings-container .left .list-toggler-container {
flex-wrap: wrap;
}
#groups_overlay .group_settings_header,
#subscription_overlay .stream_settings_header {
flex-wrap: wrap;
}
}
/* This ensures the left-border is tall enough. We can't keep this style for
narrow screens because `right` is absolutely positioned on narrow screens. */
@container settings-overlay (width >= $settings_overlay_sidebar_collapse_breakpoint) {
.two-pane-settings-container .right {
height: 100%;
}
}
/* We should eventually consolidate some of these styles with the styles
in settings.css, using shared classnames. */
@container settings-overlay (width < $settings_overlay_sidebar_collapse_breakpoint) {
@@ -1466,14 +1429,9 @@ div.settings-radio-input-parent {
}
}
.two-pane-settings-overlay .left,
.two-pane-settings-overlay .right {
position: absolute;
display: block;
margin: 0;
.two-pane-settings-overlay .left {
overflow: hidden;
width: 100%;
border: none;
}
.two-pane-settings-overlay .right {
@@ -1482,6 +1440,7 @@ div.settings-radio-input-parent {
transition: transform 0.3s ease;
background-color: var(--color-background-modal);
z-index: 10;
width: 100%;
&.show {
transform: translateX(0%);

View File

@@ -8,78 +8,86 @@
<span class="exit-sign">&times;</span>
</div>
</div>
<div class="left">
<div class="list-toggler-container">
<div id="add_new_subscription">
{{#if can_create_streams}}
<button class="create_stream_button two-pane-settings-plus-button tippy-zulip-delayed-tooltip" data-tooltip-template-id="create-new-stream-tooltip-template" data-tippy-placement="bottom">
<i class="create_button_plus_sign zulip-icon zulip-icon-square-plus" aria-hidden="true"></i>
</button>
{{/if}}
<div class="float-clear"></div>
</div>
</div>
<div class="input-append stream_name_search_section two-pane-settings-search" id="stream_filter">
<input type="text" name="stream_name" id="search_stream_name" class="filter_text_input" autocomplete="off"
placeholder="{{t 'Filter' }}" value=""/>
<button type="button" class="clear_search_button" id="clear_search_stream_name">
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
<div class="stream_settings_filter_container {{#unless realm_has_archived_channels}}hide_filter{{/unless}}">
{{> ../dropdown_widget widget_name="stream_settings_filter"}}
</div>
</div>
<div class="no-streams-to-show">
<div class="subscribed_streams_tab_empty_text">
<span class="settings-empty-option-text">
{{t 'You are not subscribed to any channels.'}}
{{#if can_view_all_streams}}
<a href="#channels/all">{{t 'View all channels'}}</a>
{{/if}}
</span>
</div>
<div class="not_subscribed_streams_tab_empty_text">
<span class="settings-empty-option-text">
{{t 'No channels to show.'}}
<a href="#channels/all">{{t 'View all channels'}}</a>
</span>
</div>
<div class="no_stream_match_filter_empty_text">
<span class="settings-empty-option-text">
{{t 'No channels match your filter.'}}
</span>
</div>
<div class="all_streams_tab_empty_text">
<span class="settings-empty-option-text">
{{t 'There are no channels you can view in this organization.'}}
<div class="two-pane-settings-subheader">
<div class="left">
<div class="list-toggler-container">
<div id="add_new_subscription">
{{#if can_create_streams}}
<a href="#channels/new">{{t 'Create a channel'}}</a>
<button class="create_stream_button two-pane-settings-plus-button tippy-zulip-delayed-tooltip" data-tooltip-template-id="create-new-stream-tooltip-template" data-tippy-placement="bottom">
<i class="create_button_plus_sign zulip-icon zulip-icon-square-plus" aria-hidden="true"></i>
</button>
{{/if}}
</span>
<div class="float-clear"></div>
</div>
</div>
</div>
<div class="streams-list two-pane-settings-left-simplebar-container" data-simplebar data-simplebar-tab-index="-1">
<div class="right">
<div class="display-type">
<div id="stream_settings_title" class="stream-info-title">{{t 'Channel settings' }}</div>
</div>
</div>
</div>
<div class="right">
<div class="display-type">
<div id="stream_settings_title" class="stream-info-title">{{t 'Channel settings' }}</div>
</div>
<div class="nothing-selected">
<div class="stream-info-banner"></div>
<div class="create-stream-button-container">
<button type="button" class="create_stream_button animated-purple-button" {{#unless can_create_streams}}disabled{{/unless}}>{{t 'Create channel' }}</button>
{{#unless can_create_streams}}
<span class="settings-empty-option-text">
{{t 'You do not have permission to create channels.' }}
</span>
{{/unless}}
<div class="two-pane-settings-body">
<div class="left">
<div class="input-append stream_name_search_section two-pane-settings-search" id="stream_filter">
<input type="text" name="stream_name" id="search_stream_name" class="filter_text_input" autocomplete="off"
placeholder="{{t 'Filter' }}" value=""/>
<button type="button" class="clear_search_button" id="clear_search_stream_name">
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
<div class="stream_settings_filter_container {{#unless realm_has_archived_channels}}hide_filter{{/unless}}">
{{> ../dropdown_widget widget_name="stream_settings_filter"}}
</div>
</div>
<div class="no-streams-to-show">
<div class="subscribed_streams_tab_empty_text">
<span class="settings-empty-option-text">
{{t 'You are not subscribed to any channels.'}}
{{#if can_view_all_streams}}
<a href="#channels/all">{{t 'View all channels'}}</a>
{{/if}}
</span>
</div>
<div class="not_subscribed_streams_tab_empty_text">
<span class="settings-empty-option-text">
{{t 'No channels to show.'}}
<a href="#channels/all">{{t 'View all channels'}}</a>
</span>
</div>
<div class="no_stream_match_filter_empty_text">
<span class="settings-empty-option-text">
{{t 'No channels match your filter.'}}
</span>
</div>
<div class="all_streams_tab_empty_text">
<span class="settings-empty-option-text">
{{t 'There are no channels you can view in this organization.'}}
{{#if can_create_streams}}
<a href="#channels/new">{{t 'Create a channel'}}</a>
{{/if}}
</span>
</div>
</div>
<div class="streams-list two-pane-settings-left-simplebar-container" data-simplebar data-simplebar-tab-index="-1">
</div>
</div>
<div id="stream_settings" class="two-pane-settings-right-simplebar-container settings" data-simplebar data-simplebar-tab-index="-1" data-simplebar-auto-hide="false">
{{!-- edit stream here --}}
<div class="right">
<div class="nothing-selected">
<div class="stream-info-banner"></div>
<div class="create-stream-button-container">
<button type="button" class="create_stream_button animated-purple-button" {{#unless can_create_streams}}disabled{{/unless}}>{{t 'Create channel' }}</button>
{{#unless can_create_streams}}
<span class="settings-empty-option-text">
{{t 'You do not have permission to create channels.' }}
</span>
{{/unless}}
</div>
</div>
<div id="stream_settings" class="two-pane-settings-right-simplebar-container settings" data-simplebar data-simplebar-tab-index="-1" data-simplebar-auto-hide="false">
{{!-- edit stream here --}}
</div>
{{> stream_creation_form . }}
</div>
{{> stream_creation_form . }}
</div>
</div>
</div>

View File

@@ -8,52 +8,60 @@
<span class="exit-sign">&times;</span>
</div>
</div>
<div class="left">
<div class="list-toggler-container">
<div id="add_new_user_group">
<button class="create_user_group_button two-pane-settings-plus-button">
<i class="create_button_plus_sign zulip-icon zulip-icon-user-group-plus" aria-hidden="true"></i>
</button>
<div class="float-clear"></div>
<div class="two-pane-settings-subheader">
<div class="left">
<div class="list-toggler-container">
<div id="add_new_user_group">
<button class="create_user_group_button two-pane-settings-plus-button">
<i class="create_button_plus_sign zulip-icon zulip-icon-user-group-plus" aria-hidden="true"></i>
</button>
<div class="float-clear"></div>
</div>
</div>
</div>
<div class="input-append group_name_search_section two-pane-settings-search" id="group_filter">
<input type="text" name="group_name" id="search_group_name" class="filter_text_input" autocomplete="off"
placeholder="{{t 'Filter' }}" value=""/>
<button type="button" class="clear_search_button" id="clear_search_group_name">
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
<span>
<label class="checkbox" id="user-group-edit-filter-options">
{{> ../dropdown_widget widget_name="user_group_visibility_settings"}}
</label>
</span>
</div>
<div class="no-groups-to-show">
</div>
<div class="user-groups-list-wrapper two-pane-settings-left-simplebar-container" data-simplebar data-simplebar-tab-index="-1">
<div class="user-groups-list"></div>
<div class="right">
<div class="display-type">
<div id="user_group_settings_title" class="user-group-info-title">{{t 'User group settings' }}</div>
<i class="fa fa-ban deactivated-user-icon deactivated-user-group-icon-right"></i>
</div>
</div>
</div>
<div class="right">
<div class="display-type">
<div id="user_group_settings_title" class="user-group-info-title">{{t 'User group settings' }}</div>
<i class="fa fa-ban deactivated-user-icon deactivated-user-group-icon-right"></i>
</div>
<div class="nothing-selected">
<div class="group-info-banner"></div>
<div class="create-group-button-container">
{{> ../settings/upgrade_tip_widget . }}
<button type="button" class="create_user_group_button animated-purple-button">{{t 'Create user group' }}</button>
<span class="settings-empty-option-text creation-permission-text">
{{t 'You do not have permission to create user groups.' }}
<div class="two-pane-settings-body">
<div class="left">
<div class="input-append group_name_search_section two-pane-settings-search" id="group_filter">
<input type="text" name="group_name" id="search_group_name" class="filter_text_input" autocomplete="off"
placeholder="{{t 'Filter' }}" value=""/>
<button type="button" class="clear_search_button" id="clear_search_group_name">
<i class="zulip-icon zulip-icon-close" aria-hidden="true"></i>
</button>
<span>
<label class="checkbox" id="user-group-edit-filter-options">
{{> ../dropdown_widget widget_name="user_group_visibility_settings"}}
</label>
</span>
</div>
<div class="no-groups-to-show">
</div>
<div class="user-groups-list-wrapper two-pane-settings-left-simplebar-container" data-simplebar data-simplebar-tab-index="-1">
<div class="user-groups-list"></div>
</div>
</div>
<div id="user_group_settings" class="two-pane-settings-right-simplebar-container settings" data-simplebar data-simplebar-tab-index="-1" data-simplebar-auto-hide="false">
{{!-- edit user group here --}}
<div class="right">
<div class="nothing-selected">
<div class="group-info-banner"></div>
<div class="create-group-button-container">
{{> ../settings/upgrade_tip_widget . }}
<button type="button" class="create_user_group_button animated-purple-button">{{t 'Create user group' }}</button>
<span class="settings-empty-option-text creation-permission-text">
{{t 'You do not have permission to create user groups.' }}
</span>
</div>
</div>
<div id="user_group_settings" class="two-pane-settings-right-simplebar-container settings" data-simplebar data-simplebar-tab-index="-1" data-simplebar-auto-hide="false">
{{!-- edit user group here --}}
</div>
{{> user_group_creation_form . }}
</div>
{{> user_group_creation_form . }}
</div>
</div>
</div>

View File

@@ -32,6 +32,10 @@ mock_esm("../src/group_permission_settings", {
},
});
mock_esm("../src/resize", {
resize_settings_overlay() {},
});
set_global("page_params", {});
const {set_current_user, set_realm} = zrequire("state_data");