mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-07-28 00:48:07 +00:00
* fix(frontend): address mobile workspace polish blockers * fix(frontend): prevent mobile landing overflow * fix(frontend): keep landing sections within mobile viewport Section titles used a fixed text-5xl with no word breaking, and the <section> flex items had default min-width:auto, so wider Linux font metrics in CI pushed content past the viewport (scrollWidth 345 > 320). Make titles/subtitles responsive with break-words, constrain section width with min-w-0, and add an overflow-x-clip guard on the page root. * fix(frontend): address review feedback on mobile landing PR - add hamburger Sheet nav below sm: so mobile users keep docs/blog access - switch useIsMobile to useSyncExternalStore to avoid hydration swap flash - memoize artifactContent so it isn't rebuilt on every streamed token - use slot-based key in HeroWordRotate; drop flex-wrap so SuperAgent never orphans at 320px - delete unused word-rotate.tsx dead code - move section gutter to <main> for a uniform mobile padding contract - harden e2e: per-viewport overflow tests, locale-stable artifact selector, focus-ring asserts light vs dark differ --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
79 lines
2.5 KiB
TypeScript
79 lines
2.5 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
import { MOCK_THREAD_ID, mockLangGraphAPI } from "./utils/mock-api";
|
|
|
|
test.describe("UI polish mobile regressions", () => {
|
|
test("workspace exposes mobile sidebar navigation from the chat header", async ({
|
|
page,
|
|
}) => {
|
|
await page.setViewportSize({ width: 375, height: 812 });
|
|
mockLangGraphAPI(page);
|
|
|
|
await page.goto("/workspace/chats/new");
|
|
|
|
await page.getByRole("button", { name: /toggle sidebar/i }).click();
|
|
|
|
await expect(page.getByRole("link", { name: /new chat/i })).toBeVisible();
|
|
await expect(page.getByRole("link", { name: /agents/i })).toBeVisible();
|
|
await expect
|
|
.poll(() => page.evaluate(() => document.documentElement.scrollWidth))
|
|
.toBeLessThanOrEqual(375);
|
|
});
|
|
|
|
test("mobile artifacts open in a drawer without horizontal overflow", async ({
|
|
page,
|
|
}) => {
|
|
await page.setViewportSize({ width: 375, height: 812 });
|
|
mockLangGraphAPI(page, {
|
|
threads: [
|
|
{
|
|
thread_id: MOCK_THREAD_ID,
|
|
title: "Thread with artifact",
|
|
artifacts: ["reports/mobile-summary.md"],
|
|
},
|
|
],
|
|
});
|
|
|
|
await page.goto(`/workspace/chats/${MOCK_THREAD_ID}`);
|
|
await page.getByTestId("artifact-trigger").click();
|
|
|
|
await expect(
|
|
page.getByRole("dialog", { name: /artifacts/i }),
|
|
).toBeVisible();
|
|
await expect(page.getByText("mobile-summary.md")).toBeVisible();
|
|
await expect
|
|
.poll(() => page.evaluate(() => document.documentElement.scrollWidth))
|
|
.toBeLessThanOrEqual(375);
|
|
});
|
|
|
|
test("global focus ring tokens are visible in light and dark themes", async ({
|
|
page,
|
|
}) => {
|
|
mockLangGraphAPI(page);
|
|
await page.goto("/workspace/chats/new");
|
|
|
|
const readRing = () =>
|
|
page.evaluate(() =>
|
|
getComputedStyle(document.documentElement)
|
|
.getPropertyValue("--ring")
|
|
.trim(),
|
|
);
|
|
|
|
await page.evaluate(() =>
|
|
document.documentElement.classList.remove("dark"),
|
|
);
|
|
const lightRing = await readRing();
|
|
expect(lightRing).not.toBe("transparent");
|
|
expect(lightRing).not.toBe("");
|
|
|
|
await page.evaluate(() => document.documentElement.classList.add("dark"));
|
|
const darkRing = await readRing();
|
|
expect(darkRing).not.toBe("transparent");
|
|
expect(darkRing).not.toBe("");
|
|
|
|
// The two themes must resolve to different ring tokens, otherwise the test
|
|
// would pass trivially if <html> were stuck in one mode.
|
|
expect(darkRing).not.toBe(lightRing);
|
|
});
|
|
});
|