Files
buzz/desktop/src/shared/lib/fontSizePreference.test.mjs
klopez4212 7e2651791d Add font size and conversation density preferences (#5644)
## Summary

- Add separate **Font size** and **Conversation density** controls in
Appearance.
- Use a 13 / 14 / 15px conversation text ramp for Smaller / Default /
Larger while scaling interface typography through a shared virtual-rem
system.
- Keep layout geometry fixed while typography changes, and compose Cmd
+/- text zoom on top of the selected preference.
- Let Compact, Comfy, and Spacious control conversation row spacing plus
paragraph and list rhythm in Markdown content across Buzz.
- Preview font size and density together with click-and-drag comparison;
interrupted scrubbing restores the saved preference.
- Synchronize preferences across open Buzz windows, including full
local-storage clears during sign-out or dev reset.
- Promote the segmented control to shared UI and make Settings rows
adapt to their card width.

## Validation

- `just ci`
- 4,965+ desktop unit tests across the final merged branch
- 1,465 mobile tests through the full repository gate
- Focused Playwright coverage for font-size/density independence, drag
preview cancellation, Inbox geometry, thread rendering, keyboard zoom,
and cross-surface typography
- Fresh E2E build against the final merged branch

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
Signed-off-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
Co-authored-by: Princess Donut <b238ea756dee4d98afa5883fc7f1de61eeabe65bf700e3a5a5a80db5e42e2c2b@buzz.block.builderlab.xyz>
Co-authored-by: morgmart <98432065+morgmart@users.noreply.github.com>
2026-08-18 15:24:09 -07:00

98 lines
3.6 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import config from "../../../tailwind.config.js";
const values = new Map();
const attributes = new Map();
const styleValues = new Map();
const windowListeners = new Map();
const style = {
setProperty: (name, value) => styleValues.set(name, value),
};
globalThis.window = {
addEventListener: (type, listener) => windowListeners.set(type, listener),
};
globalThis.localStorage = {
getItem: (key) => values.get(key) ?? null,
setItem: (key, value) => values.set(key, String(value)),
};
globalThis.document = {
documentElement: {
setAttribute: (name, value) => attributes.set(name, value),
style,
},
};
const preference = await import("./fontSizePreference.ts");
test("scales fixed line-height utilities with the typography rem", () => {
assert.deepEqual(config.theme.extend.lineHeight, {
3: "calc(var(--buzz-type-rem) * 0.75)",
4: "var(--buzz-type-rem)",
5: "calc(var(--buzz-type-rem) * 1.25)",
6: "calc(var(--buzz-type-rem) * 1.5)",
7: "calc(var(--buzz-type-rem) * 1.75)",
8: "calc(var(--buzz-type-rem) * 2)",
"message-author": "var(--conversation-author-line-height)",
});
});
test("defaults invalid and missing font sizes to default", () => {
assert.equal(preference.parseFontSize(null), "default");
assert.equal(preference.parseFontSize("medium"), "default");
assert.equal(preference.parseFontSize("smaller"), "smaller");
assert.equal(preference.parseFontSize("default"), "default");
assert.equal(preference.parseFontSize("larger"), "larger");
});
test("persists and applies the selected font size across the app", () => {
preference.applyTextZoomFactor(1);
preference.setFontSize("smaller");
assert.equal(preference.getFontSize(), "smaller");
assert.equal(values.get(preference.FONT_SIZE_STORAGE_KEY), "smaller");
assert.equal(attributes.get("data-font-size"), "smaller");
assert.equal(styleValues.get("--buzz-type-rem"), "14.857143px");
});
test("previews a font size without changing the saved preference", () => {
preference.applyTextZoomFactor(1.1);
preference.setFontSize("smaller");
preference.previewFontSize("larger");
assert.equal(preference.getFontSize(), "smaller");
assert.equal(values.get(preference.FONT_SIZE_STORAGE_KEY), "smaller");
assert.equal(attributes.get("data-font-size"), "larger");
assert.equal(styleValues.get("--buzz-type-rem"), "18.857143px");
preference.previewFontSize(null);
assert.equal(attributes.get("data-font-size"), "smaller");
assert.equal(styleValues.get("--buzz-type-rem"), "16.342857px");
});
test("initializes from the stored font size", () => {
preference.applyTextZoomFactor(1);
values.set(preference.FONT_SIZE_STORAGE_KEY, "larger");
preference.initializeFontSizePreference();
assert.equal(preference.getFontSize(), "larger");
assert.equal(attributes.get("data-font-size"), "larger");
assert.equal(styleValues.get("--buzz-type-rem"), "17.142857px");
});
test("applies font size changes from another window", () => {
values.set(preference.FONT_SIZE_STORAGE_KEY, "smaller");
windowListeners.get("storage")({ key: preference.FONT_SIZE_STORAGE_KEY });
assert.equal(preference.getFontSize(), "smaller");
assert.equal(attributes.get("data-font-size"), "smaller");
assert.equal(styleValues.get("--buzz-type-rem"), "14.857143px");
});
test("returns to the default when another window clears storage", () => {
preference.setFontSize("larger");
values.clear();
windowListeners.get("storage")({ key: null });
assert.equal(preference.getFontSize(), "default");
assert.equal(attributes.get("data-font-size"), "default");
assert.equal(styleValues.get("--buzz-type-rem"), "16px");
});