* 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.
36 lines
1.1 KiB
TypeScript
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);
|
|
}
|