diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 1af5f14c74..1aefd0c904 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -119,6 +119,7 @@ EXEMPT_FILES = make_set( "web/src/inbox_ui.js", "web/src/inbox_util.ts", "web/src/info_overlay.ts", + "web/src/information_density.ts", "web/src/integration_url_modal.ts", "web/src/invite.ts", "web/src/left_sidebar_navigation_area.ts", diff --git a/web/src/information_density.ts b/web/src/information_density.ts new file mode 100644 index 0000000000..19bd0d5bf0 --- /dev/null +++ b/web/src/information_density.ts @@ -0,0 +1,16 @@ +import $ from "jquery"; + +import {user_settings} from "./user_settings"; + +export function set_base_typography_css_variables(): void { + const font_size_px = user_settings.web_font_size_px; + const line_height_percent = user_settings.web_line_height_percent; + const line_height_unitless = line_height_percent / 100; + + $(":root").css("--base-line-height-unitless", line_height_unitless); + $(":root").css("--base-font-size-px", `${font_size_px}px`); +} + +export function initialize(): void { + set_base_typography_css_variables(); +} diff --git a/web/src/server_events_dispatch.js b/web/src/server_events_dispatch.js index 487501424e..f8aa948162 100644 --- a/web/src/server_events_dispatch.js +++ b/web/src/server_events_dispatch.js @@ -22,6 +22,7 @@ import * as emoji_picker from "./emoji_picker"; import * as gear_menu from "./gear_menu"; import * as giphy from "./giphy"; import * as hotspots from "./hotspots"; +import * as information_density from "./information_density"; import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area"; import * as linkifiers from "./linkifiers"; import * as message_edit from "./message_edit"; @@ -773,6 +774,12 @@ export function dispatch_normal_event(event) { $("body").toggleClass("less_dense_mode"); $("body").toggleClass("more_dense_mode"); } + if ( + event.property === "web_font_size_px" || + event.property === "web_line_height_percent" + ) { + information_density.set_base_typography_css_variables(); + } if (event.property === "web_mark_read_on_scroll_policy") { unread_ui.update_unread_banner(); } diff --git a/web/src/ui_init.js b/web/src/ui_init.js index 95ae363e58..cf71f905c3 100644 --- a/web/src/ui_init.js +++ b/web/src/ui_init.js @@ -49,6 +49,7 @@ import * as hotkey from "./hotkey"; import * as hotspots from "./hotspots"; import * as i18n from "./i18n"; import * as inbox_ui from "./inbox_ui"; +import * as information_density from "./information_density"; import * as invite from "./invite"; import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area"; import * as left_sidebar_navigation_area_popovers from "./left_sidebar_navigation_area_popovers"; @@ -652,8 +653,10 @@ export function initialize_everything(state_data) { sentry.initialize(); /* To store theme data for spectators, we need to initialize - user_settings before setting the theme. */ + user_settings before setting the theme. Because information + density is so fundamental, we initialize that first, however. */ initialize_user_settings(user_settings_params); + information_density.initialize(); if (page_params.is_spectator) { const ls = localstorage(); const preferred_theme = ls.get("spectator-theme-preference"); diff --git a/web/styles/app_variables.css b/web/styles/app_variables.css index 5a37420faa..91870f3bd1 100644 --- a/web/styles/app_variables.css +++ b/web/styles/app_variables.css @@ -61,6 +61,11 @@ /* Tippy popover related values */ --popover-menu-min-width: 230px; + /* Information density and typography values */ + /* The legacy values here are updated via JavaScript */ + --base-font-size-px: 14px; + --base-line-height-unitless: calc(20 / 14); + /* Message box elements and values. */ diff --git a/web/tests/dispatch.test.js b/web/tests/dispatch.test.js index 2febf4a42e..abec2f0b02 100644 --- a/web/tests/dispatch.test.js +++ b/web/tests/dispatch.test.js @@ -34,6 +34,7 @@ const dark_theme = mock_esm("../src/dark_theme"); const emoji_picker = mock_esm("../src/emoji_picker"); const gear_menu = mock_esm("../src/gear_menu"); const hotspots = mock_esm("../src/hotspots"); +const information_density = mock_esm("../src/information_density"); const linkifiers = mock_esm("../src/linkifiers"); const message_events = mock_esm("../src/message_events"); const message_lists = mock_esm("../src/message_lists"); @@ -932,6 +933,18 @@ run_test("user_settings", ({override}) => { assert_same(user_settings.dense_mode, true); assert_same(toggled, ["less_dense_mode", "more_dense_mode"]); + event = event_fixtures.user_settings__web_font_size_px; + user_settings.web_font_size_px = 14; + override(information_density, "set_base_typography_css_variables", noop); + dispatch(event); + assert_same(user_settings.web_font_size_px, 16); + + event = event_fixtures.user_settings__web_line_height_percent; + user_settings.web_font_size_px = 122; + override(information_density, "set_base_typography_css_variables", noop); + dispatch(event); + assert_same(user_settings.web_line_height_percent, 130); + override(realm_logo, "render", noop); { diff --git a/web/tests/lib/events.js b/web/tests/lib/events.js index 7c0554c047..0c89f3e27a 100644 --- a/web/tests/lib/events.js +++ b/web/tests/lib/events.js @@ -1034,6 +1034,13 @@ exports.fixtures = { value: true, }, + user_settings__web_font_size_px: { + type: "user_settings", + op: "update", + property: "web_font_size_px", + value: 16, + }, + user_settings__web_home_view_all_messages: { type: "user_settings", op: "update", @@ -1055,6 +1062,13 @@ exports.fixtures = { value: "recent_topics", }, + user_settings__web_line_height_percent: { + type: "user_settings", + op: "update", + property: "web_line_height_percent", + value: 130, + }, + user_settings__web_mark_read_on_scroll_policy: { type: "user_settings", op: "update",