personal_menu: Support changing information density settings.

This commit adds UI in personal popover menu for user to change
font-size and line-height.

Fixes part of #33186.
This commit is contained in:
Sahil Batra
2025-02-18 09:21:24 +05:30
committed by Tim Abbott
parent d8bc2f350e
commit 6f6059da73
18 changed files with 563 additions and 23 deletions

View File

@@ -268,6 +268,11 @@ Source: https://lucide.dev/icons/clock-10
Copyright: 2013-2022 Cole Bemis
License: ISC License
Files: web/shared/icons/plus.svg
Source: https://lucide.dev/icons/plus
Copyright: 2013-2022 Cole Bemis
License: ISC License
Files: web/third/bootstrap/css/bootstrap.app.css
Copyright: 2012 Twitter, Inc.
License: Apache-2.0

View File

@@ -0,0 +1,8 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.7">
<path d="M3.80319 1.52973L5.80319 3.52973C6.06289 3.78943 6.06289 4.21049 5.80319 4.47019C5.5435 4.72989 5.12244 4.72989 4.86274 4.47019L3.99797 3.60541V12.3945L4.86274 11.5298C5.12244 11.2701 5.5435 11.2701 5.80319 11.5298C6.06289 11.7895 6.06289 12.2105 5.80319 12.4702L3.80319 14.4702C3.5435 14.7299 3.12244 14.7299 2.86274 14.4702L0.862743 12.4702C0.603044 12.2105 0.603044 11.7895 0.862743 11.5298C1.12244 11.2701 1.5435 11.2701 1.80319 11.5298L2.66797 12.3945V3.60541L1.80319 4.47019C1.5435 4.72989 1.12244 4.72989 0.862743 4.47019C0.603044 4.21049 0.603044 3.78943 0.862743 3.52973L2.86274 1.52973C3.12244 1.27004 3.5435 1.27004 3.80319 1.52973Z" fill="#535663"/>
<path d="M8.0013 2.66659C8.0013 2.29932 8.29903 2.00159 8.6663 2.00159H14.9996C15.3669 2.00159 15.6646 2.29932 15.6646 2.66659C15.6646 3.03386 15.3669 3.33159 14.9996 3.33159H8.6663C8.29903 3.33159 8.0013 3.03386 8.0013 2.66659Z" fill="#535663"/>
<path d="M8.6663 7.33496H14.9996C15.3669 7.33496 15.6646 7.63269 15.6646 7.99996C15.6646 8.36723 15.3669 8.66496 14.9996 8.66496H8.6663C8.29903 8.66496 8.0013 8.36723 8.0013 7.99996C8.0013 7.63269 8.29903 7.33496 8.6663 7.33496Z" fill="#535663"/>
<path d="M8.6663 12.6683H14.9996C15.3669 12.6683 15.6646 12.966 15.6646 13.3333C15.6646 13.7005 15.3669 13.9983 14.9996 13.9983H8.6663C8.29903 13.9983 8.0013 13.7005 8.0013 13.3333C8.0013 12.966 8.29903 12.6683 8.6663 12.6683Z" fill="#535663"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,3 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.00098 7.99996C3.00098 7.63269 3.29871 7.33496 3.66598 7.33496H12.9993C13.3666 7.33496 13.6643 7.63269 13.6643 7.99996C13.6643 8.36723 13.3666 8.66496 12.9993 8.66496H3.66598C3.29871 8.66496 3.00098 8.36723 3.00098 7.99996Z" fill="#535663"/>
</svg>

After

Width:  |  Height:  |  Size: 356 B

View File

@@ -0,0 +1,5 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.7">
<path d="M9.33244 3.33346V7.33508H13.3343C13.7015 7.33508 13.9993 7.63281 13.9993 8.00008C13.9993 8.36735 13.7015 8.66508 13.3343 8.66508H9.33244V12.6668C9.33244 13.0341 9.03471 13.3318 8.66744 13.3318C8.30017 13.3318 8.00244 13.0341 8.00244 12.6668V8.66508H4.00094C3.63367 8.66508 3.33594 8.36735 3.33594 8.00008C3.33594 7.63281 3.63367 7.33508 4.00094 7.33508H8.00244V3.33346C8.00244 2.96619 8.30017 2.66846 8.66744 2.66846C9.03471 2.66846 9.33244 2.96619 9.33244 3.33346Z" fill="#535663"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 619 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16">
<path fill="#000" d="m8.67 1.665 3.994 7.986a.79.79 0 0 1 .01.021l.004.007 1.993 3.986a.75.75 0 1 1-1.342.67l-1.793-3.585H4.465L2.67 14.335a.75.75 0 1 1-1.342-.67l1.993-3.986a.74.74 0 0 1 .014-.028l3.993-7.986a.75.75 0 0 1 1.342 0Zm2.117 7.585L8 3.677 5.214 9.25h5.572Z"/>
</svg>

After

Width:  |  Height:  |  Size: 378 B

View File

@@ -1,5 +1,8 @@
import $ from "jquery";
import assert from "minimalistic-assert";
import {z} from "zod";
import {$t} from "./i18n.ts";
import * as resize from "./resize.ts";
import {stringify_time} from "./timerender.ts";
import {user_settings} from "./user_settings.ts";
@@ -49,6 +52,35 @@ export const LEGACY_LINE_HEIGHT_PERCENT = 122;
export const NON_COMPACT_MODE_FONT_SIZE_PX = 16;
export const NON_COMPACT_MODE_LINE_HEIGHT_PERCENT = 140;
export const INFO_DENSITY_VALUES_DICT = {
web_font_size_px: {
default: NON_COMPACT_MODE_FONT_SIZE_PX,
minimum: 12,
maximum: 20,
// by how much the value will be changed on clicking +/- buttons.
step_value: 1,
},
web_line_height_percent: {
default: NON_COMPACT_MODE_LINE_HEIGHT_PERCENT,
minimum: 122,
maximum: 158,
// by how much the value will be changed on clicking +/- buttons.
step_value: 9,
},
};
// TODO: Compute these from INFO_DENSITY_VALUES_DICT, rather than repeating it.
const line_height_supported_values = [122, 131, 140, 149, 158];
export const MIN_VALUES = {
web_font_size_px: 12,
web_line_height_percent: 122,
};
export const MAX_VALUES = {
web_font_size_px: 20,
web_line_height_percent: 158,
};
function set_vertical_alignment_values(line_height_unitless: number): void {
// We work in ems to keep this agnostic to the font size.
const line_height_in_ems = line_height_unitless;
@@ -173,3 +205,267 @@ export function initialize(): void {
calculate_timestamp_widths();
determine_container_query_support();
}
export const information_density_properties_schema = z.enum([
"web_font_size_px",
"web_line_height_percent",
]);
export function enable_or_disable_control_buttons($container: JQuery): void {
const info_density_properties = z
.array(information_density_properties_schema)
.parse(["web_font_size_px", "web_line_height_percent"]);
for (const property of info_density_properties) {
const $button_group = $container.find(`[data-property='${CSS.escape(property)}']`);
const $current_elem = $button_group.find<HTMLInputElement>(".current-value");
const current_value = Number.parseInt($current_elem.val()!, 10);
$button_group
.find(".default-button")
.prop("disabled", current_value === INFO_DENSITY_VALUES_DICT[property].default);
$button_group
.find(".increase-button")
.prop("disabled", current_value >= INFO_DENSITY_VALUES_DICT[property].maximum);
$button_group
.find(".decrease-button")
.prop("disabled", current_value <= INFO_DENSITY_VALUES_DICT[property].minimum);
}
}
export function find_new_supported_value_for_setting(
$elem: JQuery,
property: "web_font_size_px" | "web_line_height_percent",
current_value: number,
): number {
if (current_value > INFO_DENSITY_VALUES_DICT[property].maximum) {
return INFO_DENSITY_VALUES_DICT[property].maximum;
}
if (current_value < INFO_DENSITY_VALUES_DICT[property].minimum) {
return INFO_DENSITY_VALUES_DICT[property].minimum;
}
// We know the value is inside the range of valid values, but not
// a recommended value. This is only possible with line height,
// where we allow any integer in the database, but only offer
// certain steps in the UI.
assert(property === "web_line_height_percent");
if ($elem.hasClass("increase-button")) {
return line_height_supported_values.find((valid_value) => valid_value > current_value)!;
}
return line_height_supported_values.findLast((valid_value) => valid_value < current_value)!;
}
export function check_setting_has_recommended_value(
property: "web_font_size_px" | "web_line_height_percent",
current_value: number,
): boolean {
if (current_value > INFO_DENSITY_VALUES_DICT[property].maximum) {
return false;
}
if (current_value < INFO_DENSITY_VALUES_DICT[property].minimum) {
return false;
}
if (property === "web_font_size_px") {
return true;
}
return line_height_supported_values.includes(current_value);
}
export function get_new_value_for_information_density_settings(
$elem: JQuery,
changed_property: "web_font_size_px" | "web_line_height_percent",
): number {
const $current_elem = $elem.closest(".button-group").find<HTMLInputElement>(".current-value");
const current_value = Number.parseInt($current_elem.val()!, 10);
if ($elem.hasClass("default-button")) {
return INFO_DENSITY_VALUES_DICT[changed_property].default;
}
if (!check_setting_has_recommended_value(changed_property, current_value)) {
return find_new_supported_value_for_setting($elem, changed_property, current_value);
}
if ($elem.hasClass("increase-button")) {
return current_value + INFO_DENSITY_VALUES_DICT[changed_property].step_value;
}
return current_value - INFO_DENSITY_VALUES_DICT[changed_property].step_value;
}
export function update_information_density_settings(
$elem: JQuery,
changed_property: "web_font_size_px" | "web_line_height_percent",
): number {
const new_value = get_new_value_for_information_density_settings($elem, changed_property);
user_settings[changed_property] = new_value;
$elem.closest(".button-group").find(".current-value").val(new_value);
set_base_typography_css_variables();
calculate_timestamp_widths();
return new_value;
}
export function get_string_display_value_for_line_height(setting_value: number): string {
const step_count =
(setting_value - NON_COMPACT_MODE_LINE_HEIGHT_PERCENT) /
INFO_DENSITY_VALUES_DICT.web_line_height_percent.step_value;
let display_value;
if (step_count % 1 === 0) {
// If value is an integer, we just return here to avoid showing
// 1.0 for 1.
display_value = step_count.toString();
} else {
display_value = step_count.toFixed(1);
}
if (step_count > 0) {
// We want to show "1" as "+1".
return "+" + display_value;
}
return display_value;
}
export function get_tooltip_context_for_info_density_buttons(
$elem: JQuery,
): Record<string, string | boolean> {
const property = information_density_properties_schema.parse(
$elem.closest(".button-group").attr("data-property"),
);
const is_default_button = $elem.hasClass("default-button");
const new_value = get_new_value_for_information_density_settings($elem, property);
const default_value = INFO_DENSITY_VALUES_DICT[property].default;
const current_value = Number.parseInt(
$elem.closest(".button-group").find<HTMLInputElement>(".current-value").val()!,
10,
);
const is_current_value_default = current_value === default_value;
let tooltip_first_line = "";
let tooltip_second_line = "";
if (property === "web_font_size_px") {
if (is_default_button) {
if (is_current_value_default) {
tooltip_first_line = $t(
{defaultMessage: "Already at default font size ({default_value}pt)"},
{default_value},
);
} else {
tooltip_first_line = $t(
{defaultMessage: "Reset to default font size ({default_value}pt)"},
{default_value},
);
tooltip_second_line = $t(
{defaultMessage: "Current font size: {current_value}pt"},
{current_value},
);
}
} else if (!$elem.prop("disabled")) {
tooltip_first_line = $t(
{defaultMessage: "Change to {new_value}pt font size"},
{new_value},
);
} else {
if ($elem.hasClass("increase-button")) {
const maximum_value = INFO_DENSITY_VALUES_DICT[property].maximum;
if (current_value === maximum_value) {
tooltip_first_line = $t(
{defaultMessage: "Already at maximum font size ({maximum_value}pt)"},
{maximum_value},
);
} else {
tooltip_first_line = $t(
{
defaultMessage:
"Already above recommended maximum font size ({maximum_value}pt)",
},
{maximum_value},
);
}
} else {
const minimum_value = INFO_DENSITY_VALUES_DICT[property].minimum;
if (current_value === minimum_value) {
tooltip_first_line = $t(
{defaultMessage: "Already at minimum font size ({minimum_value}pt)"},
{minimum_value},
);
} else {
tooltip_first_line = $t(
{
defaultMessage:
"Already below recommended minimum font size ({minimum_value}pt)",
},
{minimum_value},
);
}
}
}
}
if (property === "web_line_height_percent") {
if (is_default_button) {
if (is_current_value_default) {
tooltip_first_line = $t({defaultMessage: "Already at default line spacing"});
} else {
const current_value_string =
get_string_display_value_for_line_height(current_value);
tooltip_first_line = $t({defaultMessage: "Reset to default line spacing"});
tooltip_second_line = $t(
{defaultMessage: "Current line spacing: {current_value_string}"},
{current_value_string},
);
}
} else {
if (!$elem.prop("disabled")) {
if (new_value === default_value) {
tooltip_first_line = $t({defaultMessage: "Change to default line spacing"});
} else {
const new_value_string = get_string_display_value_for_line_height(new_value);
tooltip_first_line = $t(
{defaultMessage: "Change to {new_value_string} line spacing"},
{new_value_string},
);
}
} else {
if ($elem.hasClass("increase-button")) {
const maximum_value = INFO_DENSITY_VALUES_DICT[property].maximum;
if (current_value === maximum_value) {
tooltip_first_line = $t({
defaultMessage: "Already at maximum line spacing",
});
} else {
tooltip_first_line = $t({
defaultMessage: "Already above recommended maximum line spacing",
});
}
} else {
const minimum_value = INFO_DENSITY_VALUES_DICT[property].minimum;
if (current_value === minimum_value) {
tooltip_first_line = $t({
defaultMessage: "Already at minimum line spacing",
});
} else {
tooltip_first_line = $t({
defaultMessage: "Already below recommended minimum line spacing",
});
}
}
}
}
}
return {
tooltip_first_line,
tooltip_second_line,
};
}

View File

@@ -3,6 +3,7 @@ import $ from "jquery";
import render_navbar_personal_menu_popover from "../templates/popovers/navbar/navbar_personal_menu_popover.hbs";
import * as channel from "./channel.ts";
import * as information_density from "./information_density.ts";
import * as message_view from "./message_view.ts";
import * as people from "./people.ts";
import * as popover_menus from "./popover_menus.ts";
@@ -105,6 +106,48 @@ export function initialize(): void {
popovers.hide_all();
e.preventDefault();
});
$popper.on("click", ".info-density-controls button", function (this: HTMLElement, e) {
const changed_property =
information_density.information_density_properties_schema.parse(
$(this).closest(".button-group").attr("data-property"),
);
const new_setting_value = information_density.update_information_density_settings(
$(this),
changed_property,
);
const data: Record<string, number> = {};
data[changed_property] = new_setting_value;
information_density.enable_or_disable_control_buttons($popper);
void channel.patch({
url: "/json/settings",
data,
// We don't declare success or error
// handlers. We've already locally echoed the
// change, and the thinking for this component is
// that right answer for error handling is to do
// nothing. For the offline case, just letting you
// adjust the font size locally is great, and it's
// not obvious what good error handling is here
// for the server being down other than "try again
// later", which might as well be your next
// session.
//
// This strategy also avoids unpleasant races
// involving the button being clicked several
// times in quick succession.
});
e.preventDefault();
});
const resizeObserver = new ResizeObserver(() => {
requestAnimationFrame(() => {
void instance.popperInstance?.update();
});
});
resizeObserver.observe(document.querySelector("#personal-menu-dropdown")!);
information_density.enable_or_disable_control_buttons($popper);
void instance.popperInstance?.update();
},
onShow(instance) {

View File

@@ -97,6 +97,8 @@ type PersonalMenuContext = {
status_emoji_info: UserStatusEmojiInfo | undefined;
user_color_scheme: number;
color_scheme_values: ColorSchemeValues;
web_font_size_px: number;
web_line_height_percent: number;
};
type GearMenuContext = {
@@ -337,6 +339,10 @@ export function get_personal_menu_content_context(): PersonalMenuContext {
// user color scheme
user_color_scheme: user_settings.color_scheme,
color_scheme_values: settings_config.color_scheme_values,
// info density values
web_font_size_px: user_settings.web_font_size_px,
web_line_height_percent: user_settings.web_line_height_percent,
};
}

View File

@@ -821,7 +821,6 @@ export function dispatch_normal_event(event) {
"color_scheme",
"default_language",
"demote_inactive_streams",
"dense_mode",
"display_emoji_reaction_users",
"emojiset",
"enter_sends",
@@ -837,9 +836,7 @@ export function dispatch_normal_event(event) {
"web_animate_image_previews",
"web_channel_default_view",
"web_escape_navigates_to_home_view",
"web_font_size_px",
"web_home_view",
"web_line_height_percent",
"web_mark_read_on_scroll_policy",
"web_navigate_to_sent_message",
"web_stream_unreads_count_display_policy",
@@ -904,19 +901,19 @@ export function dispatch_normal_event(event) {
);
activity_ui.build_user_sidebar();
}
if (event.property === "dense_mode") {
$("body").toggleClass("less-dense-mode");
$("body").toggleClass("more-dense-mode");
information_density.set_base_typography_css_variables();
information_density.calculate_timestamp_widths();
}
if (
event.property === "dense_mode" ||
event.property === "web_font_size_px" ||
event.property === "web_line_height_percent"
) {
information_density.set_base_typography_css_variables();
information_density.calculate_timestamp_widths();
// We just ignore events for "dense_mode", "web_font_size_px"
// and "web_line_height_percent" settings as we are fine
// with a window not being updated due to changes being done
// from another window and also helps in avoiding weird issues
// on clicking the "+"/"-" buttons multiple times quickly when
// updating these settings.
}
if (event.property === "web_mark_read_on_scroll_policy") {
unread_ui.update_unread_banner();
}

View File

@@ -4,10 +4,12 @@ import * as tippy from "tippy.js";
import render_buddy_list_title_tooltip from "../templates/buddy_list/title_tooltip.hbs";
import render_change_visibility_policy_button_tooltip from "../templates/change_visibility_policy_button_tooltip.hbs";
import render_information_density_update_button_tooltip from "../templates/information_density_update_button_tooltip.hbs";
import render_org_logo_tooltip from "../templates/org_logo_tooltip.hbs";
import render_tooltip_templates from "../templates/tooltip_templates.hbs";
import {$t} from "./i18n.ts";
import * as information_density from "./information_density.ts";
import * as people from "./people.ts";
import * as settings_config from "./settings_config.ts";
import * as stream_data from "./stream_data.ts";
@@ -702,4 +704,28 @@ export function initialize(): void {
instance.destroy();
},
});
tippy.delegate("body", {
target: "#personal-menu-dropdown .info-density-button-container",
delay: LONG_HOVER_DELAY,
appendTo: () => document.body,
placement: "bottom",
onShow(instance) {
const button_container = instance.reference;
assert(button_container instanceof HTMLElement);
const tooltip_context =
information_density.get_tooltip_context_for_info_density_buttons(
$(button_container).find(".info-density-button"),
);
instance.setContent(
ui_util.parse_html(
render_information_density_update_button_tooltip(tooltip_context),
),
);
},
onHidden(instance) {
instance.destroy();
},
});
}

View File

@@ -1434,3 +1434,65 @@ input.invalid-input {
text-overflow: ellipsis;
overflow: hidden;
}
.info-density-controls {
.button-group {
border-radius: 5px;
border: 1px solid var(--color-info-density-control-border);
width: 100%;
display: grid;
grid-auto-flow: column;
.info-density-button-container {
display: inline-flex;
flex-direction: column;
&:first-of-type {
.info-density-button {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
}
&:last-of-type {
.info-density-button {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
}
}
.info-density-button {
border: none;
background-color: var(--color-background-popover);
padding: 0.25em 0.4375em;
display: inline-flex;
align-items: center;
vertical-align: unset;
justify-content: center;
margin: 0;
&:hover:not(:disabled) {
background-color: var(
--color-info-density-button-hover-background
);
}
&:focus {
outline: none;
}
&:disabled {
cursor: default;
opacity: 0.4;
}
.zulip-icon {
display: flex;
align-items: center;
color: var(--color-info-denisty-button-icon);
opacity: 0.7;
}
}
}
}

View File

@@ -2523,6 +2523,20 @@
hsl(0deg 35% 92%),
hsl(0deg 52% 18%)
);
/* Info density update UI */
--color-info-density-control-border: light-dark(
hsl(0deg 0% 0% / 20%),
hsl(0deg 0% 90% / 20%)
);
--color-info-denisty-button-icon: light-dark(
hsl(229deg 9% 36%),
hsl(0deg 0% 100% / 80%)
);
--color-info-density-button-hover-background: light-dark(
hsl(229deg 9% 36% / 7%),
hsl(229deg 10% 50% / 30%)
);
}
%dark-theme {

View File

@@ -284,7 +284,7 @@
/* these are converting grey things to "new grey".
:disabled rules are exploded for CSS selector performance reasons. */
button:disabled:not(.action-button, .icon-button),
button:disabled:not(.action-button, .icon-button, .info-density-button),
option:disabled,
select:disabled,
textarea:disabled,
@@ -298,6 +298,11 @@
opacity: 0.5;
}
button.info-density-button:disabled {
color: inherit;
opacity: 0.4;
}
.rendered_markdown .message_inline_image {
background: hsl(0deg 0% 100% / 3%);

View File

@@ -1275,6 +1275,17 @@ ul.popover-group-menu-member-list {
position: relative;
top: -1px;
}
.info-density-controls {
display: flex;
padding: 0.125em 0.625em;
gap: 0.5em;
.zulip-icon {
width: 0.933em;
height: 0.933em;
}
}
}
#help-menu-dropdown,

View File

@@ -0,0 +1,11 @@
<div id="information_density_tooltip_template">
<div class="tooltip-inner-content">
<span>
{{tooltip_first_line}}
{{#if tooltip_second_line}}
<br />
<i>{{tooltip_second_line}}</i>
{{/if}}
</span>
</div>
</div>

View File

@@ -115,6 +115,24 @@
<span class="slider"></span>
</div>
</li>
<li role="none" class="popover-menu-list-item">
<div class="info-density-controls">
{{> ../../settings/info_density_control_button_group
property="web_font_size_px"
default_icon_class="zulip-icon-type-big"
property_value=web_font_size_px
for_settings_ui=false
prefix="personal_menu_"
}}
{{> ../../settings/info_density_control_button_group
property="web_line_height_percent"
default_icon_class="zulip-icon-line-height-big"
property_value=web_line_height_percent
for_settings_ui=false
prefix="personal_menu_"
}}
</div>
</li>
{{!-- Group 4 --}}
<li role="separator" class="popover-menu-separator"></li>
<li role="none" class="link-item popover-menu-list-item">

View File

@@ -0,0 +1,30 @@
<div class="button-group" data-property="{{property}}">
{{#if for_settings_ui}}
<div class="info-density-button-container">
<button class="info-density-button default-button" aria-label="{{#if (eq property "web_font_size_px")}}{{t 'Set font size to default'}}{{else}}{{t 'Set line spacing to default' }}{{/if}}">
<i class="zulip-icon {{default_icon_class}}" aria-hidden="true"></i>
</button>
</div>
{{/if}}
{{#if for_settings_ui}}
<span class="display-value">{{display_value}}</span>
{{/if}}
<input class="current-value prop-element" id="{{prefix}}{{property}}" data-setting-widget-type="info-density-setting" type="hidden" value="{{property_value}}" />
<div class="info-density-button-container">
<button class="info-density-button decrease-button" aria-label="{{#if (eq property "web_font_size_px")}}{{t 'Decrease font size'}}{{else}}{{t 'Decrease line spacing' }}{{/if}}">
<i class="zulip-icon zulip-icon-minus" aria-hidden="true"></i>
</button>
</div>
{{#unless for_settings_ui}}
<div class="info-density-button-container">
<button class="info-density-button default-button" aria-label="{{#if (eq property "web_font_size_px")}}{{t 'Set font size to default'}}{{else}}{{t 'Set line spacing to default' }}{{/if}}">
<i class="zulip-icon {{default_icon_class}}" aria-hidden="true"></i>
</button>
</div>
{{/unless}}
<div class="info-density-button-container">
<button class="info-density-button increase-button" aria-label="{{#if (eq property "web_font_size_px")}}{{t 'Increase font size'}}{{else}}{{t 'Increase line spacing' }}{{/if}}">
<i class="zulip-icon zulip-icon-plus" aria-hidden="true"></i>
</button>
</div>
</div>

View File

@@ -1042,26 +1042,23 @@ run_test("user_settings", ({override}) => {
event = event_fixtures.user_settings__dense_mode;
override(user_settings, "dense_mode", false);
settings_preferences.user_settings_panel = {
container: "#user-preferences",
};
override(information_density, "set_base_typography_css_variables", noop);
toggled = [];
assert_same(event.value, true);
dispatch(event);
assert_same(user_settings.dense_mode, true);
assert_same(toggled, ["less-dense-mode", "more-dense-mode"]);
assert_same(user_settings.dense_mode, false);
assert_same(toggled, []);
event = event_fixtures.user_settings__web_font_size_px;
override(user_settings, "web_font_size_px", 14);
override(information_density, "set_base_typography_css_variables", noop);
assert_same(event.value, 16);
dispatch(event);
assert_same(user_settings.web_font_size_px, 16);
assert_same(user_settings.web_font_size_px, 14);
event = event_fixtures.user_settings__web_line_height_percent;
override(user_settings, "web_font_size_px", 122);
override(information_density, "set_base_typography_css_variables", noop);
override(user_settings, "web_line_height_percent", 122);
assert_same(event.value, 130);
dispatch(event);
assert_same(user_settings.web_line_height_percent, 130);
assert_same(user_settings.web_line_height_percent, 122);
{
const stub = make_stub();