Align font sizes with production baseline

Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
kenny lopez
2026-08-12 13:06:42 +01:00
parent 1f92c81c10
commit c81bdce7a4
5 changed files with 136 additions and 120 deletions
@@ -32,7 +32,7 @@ test("persists and applies the selected font size across the app", () => {
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(style.fontSize, "15px");
assert.equal(style.fontSize, "16px");
});
test("previews a font size without changing the saved preference", () => {
@@ -42,11 +42,11 @@ test("previews a font size without changing the saved preference", () => {
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(style.fontSize, "18.7px");
assert.equal(style.fontSize, "20.114286px");
preference.previewFontSize(null);
assert.equal(attributes.get("data-font-size"), "smaller");
assert.equal(style.fontSize, "16.5px");
assert.equal(style.fontSize, "17.6px");
});
test("initializes from the stored font size", () => {
@@ -55,5 +55,5 @@ test("initializes from the stored font size", () => {
preference.initializeFontSizePreference();
assert.equal(preference.getFontSize(), "larger");
assert.equal(attributes.get("data-font-size"), "larger");
assert.equal(style.fontSize, "17px");
assert.equal(style.fontSize, "18.285714px");
});
+10 -4
View File
@@ -6,10 +6,14 @@ export type FontSize = "smaller" | "default" | "larger";
export const FONT_SIZE_STORAGE_KEY = "buzz.appearance.fontSize";
export const DEFAULT_FONT_SIZE: FontSize = "default";
/**
* Root sizes that map Tailwind's production `text-sm` size (0.875rem) to the
* three app-wide 14px, 15px, and 16px steps.
*/
const BASE_FONT_SIZE_PX: Record<FontSize, number> = {
smaller: 15,
default: 16,
larger: 17,
smaller: 14 / 0.875,
default: 15 / 0.875,
larger: 16 / 0.875,
};
const listeners = new Set<() => void>();
@@ -33,7 +37,9 @@ function readStoredFontSize(): FontSize {
}
function rootFontSizePx(size: FontSize): number {
return Math.round(BASE_FONT_SIZE_PX[size] * textZoomFactor * 1_000) / 1_000;
return (
Math.round(BASE_FONT_SIZE_PX[size] * textZoomFactor * 1_000_000) / 1_000_000
);
}
function applyFontSize(size: FontSize): void {
+3 -3
View File
@@ -7,14 +7,14 @@
* Inbox, and the composer. The app-wide Font size preference and Cmd +/-
* scale these rem values; Conversation density overrides only spacing.
*/
--conversation-message-font-size: 0.9375rem;
--conversation-message-font-size: 0.875rem;
--conversation-message-line-height: 1.25rem;
--conversation-author-line-height: 1.0625rem;
--conversation-author-line-height: 1rem;
--conversation-body-gap: 0.125rem;
--conversation-row-padding-block: 0.375rem;
--conversation-paragraph-gap: 0.5rem;
--conversation-list-item-gap: 0.375rem;
--conversation-timestamp-font-size: 0.6875rem;
--conversation-timestamp-font-size: 0.75rem;
--conversation-timestamp-line-height: 1rem;
--background: 220 23.08% 94.9%;
--foreground: 234 16.02% 35.49%;
@@ -731,13 +731,13 @@ test("app font size and conversation density apply independently", async ({
);
await expect(fontSizeDescription).toHaveText("Adjust text throughout Buzz.");
await expect.poll(readScale).toEqual({
authorLineHeight: 1.0625,
authorLineHeight: 1,
bodyGap: 0.125,
fontSize: 0.9375,
fontSize: 0.875,
lineHeight: 1.25,
paragraphGap: 0.5,
rowPadding: 0.375,
timestampFontSize: 0.6875,
timestampFontSize: 0.75,
timestampLineHeight: 1,
});
await expect
@@ -754,7 +754,7 @@ test("app font size and conversation density apply independently", async ({
.evaluate((element) => element.getBoundingClientRect().width),
]),
)
.toEqual([288, 288, 240]);
.toEqual([308.5625, 308.5625, 257.140625]);
await expect
.poll(() =>
previewMessage.evaluate((element) => {
@@ -762,15 +762,19 @@ test("app font size and conversation density apply independently", async ({
return [style.fontSize, style.lineHeight];
}),
)
.toEqual(["15px", "20px"]);
.toEqual(["15px", "21.4286px"]);
await expect.poll(readSettingsScale).toEqual({
fontSize: "14px",
lineHeight: "20px",
minHeight: "64px",
paddingBlock: "12px",
fontSize: "15px",
lineHeight: "21.4286px",
minHeight: "68.5714px",
paddingBlock: "12.8571px",
});
await expect.poll(readPreviewTimestampScale).toEqual(["11px", "16px"]);
await expect.poll(readSettingsChromeScale).toEqual(["24px", "14px", "18px"]);
await expect
.poll(readPreviewTimestampScale)
.toEqual(["12.8571px", "17.1429px"]);
await expect
.poll(readSettingsChromeScale)
.toEqual(["25.7143px", "15px", "19.2857px"]);
await expect(densityIndicator).toHaveCSS("transition-duration", "0.2s");
await expect(densityIndicator).toHaveCSS("transition-property", /transform/);
await expect(fontSizeIndicator).toHaveCSS("transition-duration", "0.2s");
@@ -811,29 +815,29 @@ test("app font size and conversation density apply independently", async ({
previewSurfaceBox.x +
previewSurfaceBox.width -
(previewChipBox.x + previewChipBox.width);
expect(previewChipRightInset).toBeGreaterThanOrEqual(12);
expect(previewChipRightInset).toBeLessThanOrEqual(13);
expect(previewChipRightInset).toBeGreaterThanOrEqual(13);
expect(previewChipRightInset).toBeLessThanOrEqual(15);
const previewChipTopInset = previewChipBox.y - previewSurfaceBox.y;
expect(previewChipTopInset).toBeGreaterThanOrEqual(12);
expect(previewChipTopInset).toBeLessThanOrEqual(13);
await expect(previewContent).toHaveCSS("padding-top", "16px");
await expect(previewContent).toHaveCSS("padding-right", "16px");
await expect(previewContent).toHaveCSS("padding-bottom", "16px");
await expect(previewContent).toHaveCSS("padding-left", "16px");
expect(previewChipTopInset).toBeGreaterThanOrEqual(13);
expect(previewChipTopInset).toBeLessThanOrEqual(15);
await expect(previewContent).toHaveCSS("padding-top", "17.1429px");
await expect(previewContent).toHaveCSS("padding-right", "17.1429px");
await expect(previewContent).toHaveCSS("padding-bottom", "17.1429px");
await expect(previewContent).toHaveCSS("padding-left", "17.1429px");
expect(firstPreviewMessageBox.x - previewSurfaceBox.x).toBeGreaterThanOrEqual(
16,
17,
);
expect(firstPreviewMessageBox.x - previewSurfaceBox.x).toBeLessThanOrEqual(
18,
19,
);
expect(firstPreviewMessageBox.y - previewSurfaceBox.y).toBeGreaterThanOrEqual(
16,
17,
);
expect(firstPreviewMessageBox.y - previewSurfaceBox.y).toBeLessThanOrEqual(
18,
19,
);
await expect(previewChip).toHaveCSS("padding-top", "4px");
await expect(previewChip).toHaveCSS("padding-bottom", "4px");
await expect(previewChip).toHaveCSS("padding-top", "4.28571px");
await expect(previewChip).toHaveCSS("padding-bottom", "4.28571px");
await densityIndicator.evaluate((element) => {
element.addEventListener(
@@ -857,23 +861,27 @@ test("app font size and conversation density apply independently", async ({
)
.toBe("compact");
await expect.poll(readScale).toEqual({
authorLineHeight: 1.0625,
authorLineHeight: 1,
bodyGap: 0,
fontSize: 0.9375,
fontSize: 0.875,
lineHeight: 1.25,
paragraphGap: 0.375,
rowPadding: 0.25,
timestampFontSize: 0.6875,
timestampFontSize: 0.75,
timestampLineHeight: 1,
});
await expect.poll(readSettingsScale).toEqual({
fontSize: "14px",
lineHeight: "20px",
minHeight: "64px",
paddingBlock: "12px",
fontSize: "15px",
lineHeight: "21.4286px",
minHeight: "68.5714px",
paddingBlock: "12.8571px",
});
await expect.poll(readPreviewTimestampScale).toEqual(["11px", "16px"]);
await expect.poll(readSettingsChromeScale).toEqual(["24px", "14px", "18px"]);
await expect
.poll(readPreviewTimestampScale)
.toEqual(["12.8571px", "17.1429px"]);
await expect
.poll(readSettingsChromeScale)
.toEqual(["25.7143px", "15px", "19.2857px"]);
await larger.click();
await expect(root).toHaveAttribute("data-conversation-density", "compact");
@@ -888,13 +896,13 @@ test("app font size and conversation density apply independently", async ({
)
.toBe("larger");
await expect.poll(readScale).toEqual({
authorLineHeight: 1.0625,
authorLineHeight: 1,
bodyGap: 0,
fontSize: 0.9375,
fontSize: 0.875,
lineHeight: 1.25,
paragraphGap: 0.375,
rowPadding: 0.25,
timestampFontSize: 0.6875,
timestampFontSize: 0.75,
timestampLineHeight: 1,
});
await expect
@@ -904,17 +912,19 @@ test("app font size and conversation density apply independently", async ({
return [style.fontSize, style.lineHeight];
}),
)
.toEqual(["15.9375px", "21.25px"]);
.toEqual(["16px", "22.8571px"]);
await expect.poll(readSettingsScale).toEqual({
fontSize: "14.875px",
lineHeight: "21.25px",
minHeight: "68px",
paddingBlock: "12.75px",
fontSize: "16px",
lineHeight: "22.8571px",
minHeight: "73.1429px",
paddingBlock: "13.7143px",
});
await expect.poll(readPreviewTimestampScale).toEqual(["11.6875px", "17px"]);
await expect
.poll(readPreviewTimestampScale)
.toEqual(["13.7143px", "18.2857px"]);
await expect
.poll(readSettingsChromeScale)
.toEqual(["25.5px", "14.875px", "19.125px"]);
.toEqual(["27.4286px", "16px", "20.5714px"]);
await waitForAnimations(page);
await page.getByTestId("appearance-preferences-card").screenshot({
path: `${SHOTS}/15-conversation-compact-larger.png`,
@@ -925,38 +935,40 @@ test("app font size and conversation density apply independently", async ({
await expect(root).toHaveAttribute("data-font-size", "larger");
await expect(spacious).toHaveAttribute("aria-pressed", "true");
await expect.poll(readScale).toEqual({
authorLineHeight: 1.0625,
authorLineHeight: 1,
bodyGap: 0.25,
fontSize: 0.9375,
fontSize: 0.875,
lineHeight: 1.25,
paragraphGap: 0.625,
rowPadding: 0.5,
timestampFontSize: 0.6875,
timestampFontSize: 0.75,
timestampLineHeight: 1,
});
await expect.poll(readSettingsScale).toEqual({
fontSize: "14.875px",
lineHeight: "21.25px",
minHeight: "68px",
paddingBlock: "12.75px",
fontSize: "16px",
lineHeight: "22.8571px",
minHeight: "73.1429px",
paddingBlock: "13.7143px",
});
await expect.poll(readPreviewTimestampScale).toEqual(["11.6875px", "17px"]);
await expect
.poll(readPreviewTimestampScale)
.toEqual(["13.7143px", "18.2857px"]);
await expect
.poll(readSettingsChromeScale)
.toEqual(["25.5px", "14.875px", "19.125px"]);
.toEqual(["27.4286px", "16px", "20.5714px"]);
await smaller.click();
await expect(root).toHaveAttribute("data-conversation-density", "spacious");
await expect(root).toHaveAttribute("data-font-size", "smaller");
await expect(smaller).toHaveAttribute("aria-pressed", "true");
await expect.poll(readScale).toEqual({
authorLineHeight: 1.0625,
authorLineHeight: 1,
bodyGap: 0.25,
fontSize: 0.9375,
fontSize: 0.875,
lineHeight: 1.25,
paragraphGap: 0.625,
rowPadding: 0.5,
timestampFontSize: 0.6875,
timestampFontSize: 0.75,
timestampLineHeight: 1,
});
await expect
@@ -966,17 +978,15 @@ test("app font size and conversation density apply independently", async ({
return [style.fontSize, style.lineHeight];
}),
)
.toEqual(["14.0625px", "18.75px"]);
.toEqual(["14px", "20px"]);
await expect.poll(readSettingsScale).toEqual({
fontSize: "13.125px",
lineHeight: "18.75px",
minHeight: "60px",
paddingBlock: "11.25px",
fontSize: "14px",
lineHeight: "20px",
minHeight: "64px",
paddingBlock: "12px",
});
await expect.poll(readPreviewTimestampScale).toEqual(["10.3125px", "15px"]);
await expect
.poll(readSettingsChromeScale)
.toEqual(["22.5px", "13.125px", "16.875px"]);
await expect.poll(readPreviewTimestampScale).toEqual(["12px", "16px"]);
await expect.poll(readSettingsChromeScale).toEqual(["24px", "14px", "18px"]);
await waitForAnimations(page);
await page.getByTestId("appearance-preferences-card").screenshot({
path: `${SHOTS}/16-conversation-spacious-smaller.png`,
@@ -1019,20 +1029,20 @@ test("app font size and conversation density apply independently", async ({
)
.toBe("comfortable");
await expect.poll(readScale).toEqual({
authorLineHeight: 1.0625,
authorLineHeight: 1,
bodyGap: 0.25,
fontSize: 0.9375,
fontSize: 0.875,
lineHeight: 1.25,
paragraphGap: 0.625,
rowPadding: 0.5,
timestampFontSize: 0.6875,
timestampFontSize: 0.75,
timestampLineHeight: 1,
});
await expect.poll(readSettingsScale).toEqual({
fontSize: "14px",
lineHeight: "20px",
minHeight: "64px",
paddingBlock: "12px",
fontSize: "15px",
lineHeight: "21.4286px",
minHeight: "68.5714px",
paddingBlock: "12.8571px",
});
await page.mouse.up();
await expect(spacious).toHaveAttribute("aria-pressed", "true");
@@ -1084,10 +1094,10 @@ test("app font size and conversation density apply independently", async ({
return [style.fontSize, style.lineHeight];
}),
)
.toEqual(["15.9375px", "21.25px"]);
.toEqual(["16px", "22.8571px"]);
await expect
.poll(readSettingsChromeScale)
.toEqual(["25.5px", "14.875px", "19.125px"]);
.toEqual(["27.4286px", "16px", "20.5714px"]);
await page.mouse.up();
await expect(larger).toHaveAttribute("aria-pressed", "true");
await expect
@@ -343,7 +343,7 @@ test.describe("inbox refactor screenshots", () => {
await expect(firstUnreadRow).toBeVisible();
const listPreview = firstUnreadRow.locator(".inbox-preview-markdown");
await expect(listPreview).toHaveCSS("font-size", "15px");
await expect(listPreview).toHaveCSS("line-height", "20px");
await expect(listPreview).toHaveCSS("line-height", "21.4286px");
await firstUnreadRow.click();
const detail = page.getByTestId("home-inbox-detail");
@@ -413,12 +413,12 @@ test.describe("inbox refactor screenshots", () => {
}),
]);
await expect.poll(readConversationMetrics).toEqual([
{ fontSize: "15px", lineHeight: "20px" },
{ paddingBottom: "6px", paddingTop: "6px" },
{ fontSize: "15px", lineHeight: "17px" },
{ fontSize: "15px", lineHeight: "20px" },
{ fontSize: "11px", lineHeight: "16px" },
{ fontSize: "15px", lineHeight: "20px" },
{ fontSize: "15px", lineHeight: "21.4286px" },
{ paddingBottom: "6.42857px", paddingTop: "6.42857px" },
{ fontSize: "15px", lineHeight: "17.1429px" },
{ fontSize: "15px", lineHeight: "21.4286px" },
{ fontSize: "12.8571px", lineHeight: "17.1429px" },
{ fontSize: "15px", lineHeight: "21.4286px" },
]);
await waitForAnimations(page);
@@ -428,25 +428,25 @@ test.describe("inbox refactor screenshots", () => {
root.setAttribute("data-conversation-density", "compact");
});
await expect.poll(readConversationMetrics).toEqual([
{ fontSize: "15px", lineHeight: "20px" },
{ paddingBottom: "4px", paddingTop: "4px" },
{ fontSize: "15px", lineHeight: "17px" },
{ fontSize: "15px", lineHeight: "20px" },
{ fontSize: "11px", lineHeight: "16px" },
{ fontSize: "15px", lineHeight: "20px" },
{ fontSize: "15px", lineHeight: "21.4286px" },
{ paddingBottom: "4.28571px", paddingTop: "4.28571px" },
{ fontSize: "15px", lineHeight: "17.1429px" },
{ fontSize: "15px", lineHeight: "21.4286px" },
{ fontSize: "12.8571px", lineHeight: "17.1429px" },
{ fontSize: "15px", lineHeight: "21.4286px" },
]);
await page.locator("html").evaluate((root) => {
root.setAttribute("data-font-size", "smaller");
root.style.fontSize = "15px";
root.style.fontSize = "16px";
});
await expect.poll(readConversationMetrics).toEqual([
{ fontSize: "14.0625px", lineHeight: "18.75px" },
{ paddingBottom: "3.75px", paddingTop: "3.75px" },
{ fontSize: "14.0625px", lineHeight: "15.9375px" },
{ fontSize: "14.0625px", lineHeight: "18.75px" },
{ fontSize: "10.3125px", lineHeight: "15px" },
{ fontSize: "14.0625px", lineHeight: "18.75px" },
{ fontSize: "14px", lineHeight: "20px" },
{ paddingBottom: "4px", paddingTop: "4px" },
{ fontSize: "14px", lineHeight: "16px" },
{ fontSize: "14px", lineHeight: "20px" },
{ fontSize: "12px", lineHeight: "16px" },
{ fontSize: "14px", lineHeight: "20px" },
]);
await waitForAnimations(page);
await page.screenshot({ path: `${SHOTS}/05-thread-context-compact.png` });
@@ -454,15 +454,15 @@ test.describe("inbox refactor screenshots", () => {
await page.locator("html").evaluate((root) => {
root.setAttribute("data-conversation-density", "spacious");
root.setAttribute("data-font-size", "larger");
root.style.fontSize = "17px";
root.style.fontSize = "18.285714px";
});
await expect.poll(readConversationMetrics).toEqual([
{ fontSize: "15.9375px", lineHeight: "21.25px" },
{ paddingBottom: "8.5px", paddingTop: "8.5px" },
{ fontSize: "15.9375px", lineHeight: "18.0625px" },
{ fontSize: "15.9375px", lineHeight: "21.25px" },
{ fontSize: "11.6875px", lineHeight: "17px" },
{ fontSize: "15.9375px", lineHeight: "21.25px" },
{ fontSize: "16px", lineHeight: "22.8571px" },
{ paddingBottom: "9.14286px", paddingTop: "9.14286px" },
{ fontSize: "16px", lineHeight: "18.2857px" },
{ fontSize: "16px", lineHeight: "22.8571px" },
{ fontSize: "13.7143px", lineHeight: "18.2857px" },
{ fontSize: "16px", lineHeight: "22.8571px" },
]);
await waitForAnimations(page);
await page.screenshot({ path: `${SHOTS}/06-thread-context-spacious.png` });
@@ -470,7 +470,7 @@ test.describe("inbox refactor screenshots", () => {
await page.locator("html").evaluate((root) => {
root.setAttribute("data-conversation-density", "comfortable");
root.setAttribute("data-font-size", "default");
root.style.fontSize = "16px";
root.style.fontSize = "17.142857px";
});
await page.evaluate(() => {
@@ -496,13 +496,13 @@ test.describe("inbox refactor screenshots", () => {
...(await readConversationMetrics()),
])
.toEqual([
"17.6px",
{ fontSize: "16.5px", lineHeight: "22px" },
{ paddingBottom: "6.6px", paddingTop: "6.6px" },
{ fontSize: "16.5px", lineHeight: "18.7px" },
{ fontSize: "16.5px", lineHeight: "22px" },
{ fontSize: "12.1px", lineHeight: "17.6px" },
{ fontSize: "16.5px", lineHeight: "22px" },
"18.8571px",
{ fontSize: "16.5px", lineHeight: "23.5714px" },
{ paddingBottom: "7.07143px", paddingTop: "7.07143px" },
{ fontSize: "16.5px", lineHeight: "18.8571px" },
{ fontSize: "16.5px", lineHeight: "23.5714px" },
{ fontSize: "14.1429px", lineHeight: "18.8571px" },
{ fontSize: "16.5px", lineHeight: "23.5714px" },
]);
});
});