= {};
+ 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) {
diff --git a/web/src/popover_menus_data.ts b/web/src/popover_menus_data.ts
index b1d5a923b4..9507745a6a 100644
--- a/web/src/popover_menus_data.ts
+++ b/web/src/popover_menus_data.ts
@@ -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,
};
}
diff --git a/web/src/server_events_dispatch.js b/web/src/server_events_dispatch.js
index e375e83094..c9ea3cc8ff 100644
--- a/web/src/server_events_dispatch.js
+++ b/web/src/server_events_dispatch.js
@@ -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();
}
diff --git a/web/src/tippyjs.ts b/web/src/tippyjs.ts
index de1423e2c6..c1e3ad5143 100644
--- a/web/src/tippyjs.ts
+++ b/web/src/tippyjs.ts
@@ -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();
+ },
+ });
}
diff --git a/web/styles/app_components.css b/web/styles/app_components.css
index 9f1d4b9731..c125683071 100644
--- a/web/styles/app_components.css
+++ b/web/styles/app_components.css
@@ -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;
+ }
+ }
+ }
+}
diff --git a/web/styles/app_variables.css b/web/styles/app_variables.css
index aa6df3c318..ae101548b6 100644
--- a/web/styles/app_variables.css
+++ b/web/styles/app_variables.css
@@ -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 {
diff --git a/web/styles/dark_theme.css b/web/styles/dark_theme.css
index 68995522fe..5b8ac197f5 100644
--- a/web/styles/dark_theme.css
+++ b/web/styles/dark_theme.css
@@ -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%);
diff --git a/web/styles/popovers.css b/web/styles/popovers.css
index 995bf7156b..cded53a735 100644
--- a/web/styles/popovers.css
+++ b/web/styles/popovers.css
@@ -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,
diff --git a/web/templates/information_density_update_button_tooltip.hbs b/web/templates/information_density_update_button_tooltip.hbs
new file mode 100644
index 0000000000..7d866c04a8
--- /dev/null
+++ b/web/templates/information_density_update_button_tooltip.hbs
@@ -0,0 +1,11 @@
+
diff --git a/web/templates/popovers/navbar/navbar_personal_menu_popover.hbs b/web/templates/popovers/navbar/navbar_personal_menu_popover.hbs
index eeedea9e34..0d94a8c264 100644
--- a/web/templates/popovers/navbar/navbar_personal_menu_popover.hbs
+++ b/web/templates/popovers/navbar/navbar_personal_menu_popover.hbs
@@ -115,6 +115,24 @@
+
{{!-- Group 4 --}}