mirror of
https://github.com/zulip/zulip.git
synced 2025-10-22 20:42:14 +00:00
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:
@@ -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
|
||||
|
8
web/shared/icons/line-height-big.svg
Normal file
8
web/shared/icons/line-height-big.svg
Normal 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 |
3
web/shared/icons/minus.svg
Normal file
3
web/shared/icons/minus.svg
Normal 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 |
5
web/shared/icons/plus.svg
Normal file
5
web/shared/icons/plus.svg
Normal 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 |
3
web/shared/icons/type-big.svg
Normal file
3
web/shared/icons/type-big.svg
Normal 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 |
@@ -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,
|
||||
};
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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%);
|
||||
|
||||
|
@@ -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,
|
||||
|
11
web/templates/information_density_update_button_tooltip.hbs
Normal file
11
web/templates/information_density_update_button_tooltip.hbs
Normal 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>
|
@@ -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">
|
||||
|
30
web/templates/settings/info_density_control_button_group.hbs
Normal file
30
web/templates/settings/info_density_control_button_group.hbs
Normal 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>
|
@@ -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();
|
||||
|
Reference in New Issue
Block a user