diff --git a/studio/frontend/src/features/chat/chat-page.tsx b/studio/frontend/src/features/chat/chat-page.tsx index c241607e28..7452cf3447 100644 --- a/studio/frontend/src/features/chat/chat-page.tsx +++ b/studio/frontend/src/features/chat/chat-page.tsx @@ -2289,7 +2289,7 @@ export function ChatPage({ } else if (outcome === "conflict") { toast.info("Resume this download from Models", { description: - "An earlier partial download used a different transport. Open the Models tab to resume or restart it.", + "An earlier partial download used a different transport. Open the Model hub tab to resume or restart it.", }); } else if (outcome === "busy") { toast.info("Download already in progress", { @@ -2410,7 +2410,7 @@ export function ChatPage({ // surface's onComplete auto-loads, mirroring the "started" branch. toast.info("Resume this download from Models", { description: - "An earlier partial download used a different transport. Open the Models tab to resume or restart it.", + "An earlier partial download used a different transport. Open the Model hub tab to resume or restart it.", }); return; } diff --git a/studio/frontend/src/features/hub/catalog/models-header.tsx b/studio/frontend/src/features/hub/catalog/models-header.tsx index f0e0950871..f844336d4a 100644 --- a/studio/frontend/src/features/hub/catalog/models-header.tsx +++ b/studio/frontend/src/features/hub/catalog/models-header.tsx @@ -64,7 +64,7 @@ export function ModelsHeader({ return (
/^ui-\d+(p5)?$/.test(value); + +const twMerge = extendTailwindMerge({ + extend: { + classGroups: { + "font-size": [{ text: [isUiToken] }], + leading: [{ leading: [isUiToken] }], + }, + }, +}); export function cn(...inputs: ClassValue[]): string { return twMerge(clsx(inputs)); diff --git a/tests/studio/playwright_ui_font_scale.py b/tests/studio/playwright_ui_font_scale.py index 89c7894929..0f14c42422 100644 --- a/tests/studio/playwright_ui_font_scale.py +++ b/tests/studio/playwright_ui_font_scale.py @@ -193,6 +193,25 @@ def main(): page.set_viewport_size({"width": 1440, "height": 900}) page.wait_for_timeout(400) + step("cn keeps text-ui-* next to color classes (hub tabs)") + page.keyboard.press("Escape") + page.wait_for_timeout(400) + page.goto(f"{BASE}/hub", wait_until = "domcontentloaded") + page.wait_for_timeout(2000) + open_appearance(page) + set_input(page, "UI font size", 12) + page.keyboard.press("Escape") + page.wait_for_timeout(400) + tab = page.get_by_role("radio").filter(has_text = "Discover").first + tab.wait_for(state = "visible", timeout = 15000) + tab_font = tab.evaluate("el => parseFloat(getComputedStyle(el).fontSize)") + # text-ui-12p5 at scale 0.75; 16px means twMerge dropped the token. + if not near(tab_font, 12.5 * 12 / 16): + fail(f"hub tab font did not scale (twMerge drop?): {tab_font}") + page.goto(BASE, wait_until = "domcontentloaded") + page.wait_for_timeout(1500) + open_appearance(page) + step("default restores exactly") page.get_by_role("dialog").get_by_role("button").filter(has_text = "Appearance").first.click() page.wait_for_timeout(500) diff --git a/tests/studio/test_ui_font_scale_contract.py b/tests/studio/test_ui_font_scale_contract.py index 393c60dd6b..1153eea643 100644 --- a/tests/studio/test_ui_font_scale_contract.py +++ b/tests/studio/test_ui_font_scale_contract.py @@ -17,6 +17,7 @@ SRC = REPO / "studio/frontend/src" INDEX_CSS = (SRC / "index.css").read_text(encoding = "utf-8") STORE = (SRC / "features/settings/stores/appearance-custom-store.ts").read_text(encoding = "utf-8") SELECT = (SRC / "components/ui/select.tsx").read_text(encoding = "utf-8") +UTILS = (SRC / "lib/utils.ts").read_text(encoding = "utf-8") # Raw numeric fontSize props are only allowed where a scaled stylesheet rule # (.recharts-text) overrides the presentation attribute at render time. @@ -87,6 +88,16 @@ def test_radix_select_viewport_owns_the_scroll_state(): assert "overflow-y-auto" not in content_cls.group(1) +def test_cn_knows_the_ui_typography_tokens(): + """Stock tailwind-merge classifies text-ui-* as a text color and deletes + it whenever a real color class follows in the same cn() call, so the + element falls back to the unscaled inherited font size.""" + assert "extendTailwindMerge" in UTILS + assert '"font-size": [{ text: [isUiToken] }]' in UTILS + assert "leading: [{ leading: [isUiToken] }]" in UTILS + assert "/^ui-\\d+(p5)?$/.test(value)" in UTILS + + def test_no_raw_pixel_text_utilities(): offenders = [] for path in _frontend_sources():