unsloth/studio/frontend/src/lib/utils.ts
Michael Han 140b3fbe05
Studio: register text-ui tokens with tailwind-merge so cn() keeps them (#7396)
* Studio: register text-ui tokens with tailwind-merge so cn keeps them

Stock tailwind-merge classifies text-ui-* as a text color, so cn() dropped
the size class whenever a color utility followed it in the same call. The
element then fell back to the unscaled 16px root font, which made hub tabs
and capability pills look oversized at small UI font sizes. Extend the
merge config so text-ui-* and leading-ui-* resolve as font-size and
line-height groups, and cover the failure in the contract and Playwright
regression tests.

* Studio: rename the Models page to Model hub

Page heading, sidebar navigation label in all locales, and the chat
download toasts that point at the tab.
2026-07-24 00:48:54 -07:00

36 lines
1.1 KiB
TypeScript

// SPDX-License-Identifier: AGPL-3.0-only
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
import { type ClassValue, clsx } from "clsx";
import { extendTailwindMerge } from "tailwind-merge";
// text-ui-* / leading-ui-* are the scaled typography tokens from index.css.
// Register them as font-size / line-height so twMerge does not treat
// text-ui-* as a text color and drop it when a color class follows.
const isUiToken = (value: string) => /^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));
}
export function formatCompact(n: number): string {
if (n >= 1_000_000_000) {
return `${(n / 1_000_000_000).toFixed(1)}B`;
}
if (n >= 1_000_000) {
return `${(n / 1_000_000).toFixed(1)}M`;
}
if (n >= 1_000) {
return `${(n / 1_000).toFixed(1)}K`;
}
return String(n);
}