Studio: drive UI font size through a typography scale instead of the root font size (#7359)
* Studio: drive UI font size through a typography scale, not the root font size Follow up to #7355. The preference now writes --ui-font-scale (selected / 16) and a data-ui-font-size attribute on the root instead of mutating the root font size, and the applier clears any stale inline root font-size left by older builds. Because the rem base never moves, every layout-only rem-to-px conversion from #7355 is reverted to its original form: the spacing, radius and container tokens, sidebar and thread widths, grid tracks, calc margins and hub.css dimensions match pre-#7355 main again, which also restores rem-based accessibility scaling for users with a larger browser default font size. Typography scales through tokens in index.css, all exact at 16px: - The named Tailwind sizes (--text-xs through --text-4xl) multiply their defaults by the scale, so standard utilities scale - One token per design px size (--text-ui-8 ... --text-ui-34) replaces every arbitrary text-[Npx] class; leading-ui-* mirrors the exact line heights and the numeric --leading-3..10 scale as well - CSS font-size and line-height declarations multiply by the scale - Chart labels scale through a .recharts-text rule; streamdown and react-flow px text is re-based via scaled overrides; KaTeX's 1px layout trick stays fixed by design - The logo lockups keep their half-rate behavior via the scale var - The explicit Code font size remains unmultiplied Keeps the #7355 behavior fixes: color chip min width, voice select min/max widths, and the select and dropdown menus scrolling an inner viewport so their corners stay rounded. The whitespace-password and IME rename guards that merged alongside are preserved. * Studio: contract and Playwright coverage for the UI font size scale test_ui_font_scale_contract.py pins the mechanism (scale var written, root font size never mutated, tokens scaled, code font size not multiplied, the Radix select viewport owning scroll state) and guards against new raw pixel typography, with a documented allowlist for the recharts fontSize props covered by the stylesheet override and the offscreen clipboard textarea. playwright_ui_font_scale.py drives the real appearance controls: root font size fixed at 12/16/20, text and line height scale by size/16, sidebar width invariant, explicit code font size stays fixed, an overflowing dictation select scrolls its Radix viewport by keyboard and wheel, and the default restores exactly. Wired into the UI smoke workflow against the second studio boot. The thinking-compact and descender contracts move back to the rem and token forms now that layout values no longer need px pinning.
This commit is contained in:
parent
5c3f56f1ef
commit
8aaf2f78eb
155 changed files with 1222 additions and 833 deletions
10
.github/workflows/studio-ui-smoke.yml
vendored
10
.github/workflows/studio-ui-smoke.yml
vendored
|
|
@ -231,6 +231,15 @@ jobs:
|
|||
mkdir -p logs/playwright_extra
|
||||
python tests/studio/playwright_extra_ui.py
|
||||
|
||||
- name: UI font size scaling regression (Playwright)
|
||||
env:
|
||||
BASE_URL: http://127.0.0.1:18894
|
||||
STUDIO_PW: ${{ env.STUDIO_EXTRA_NEW_PW }}
|
||||
PW_ART_DIR: logs/playwright_fontscale
|
||||
run: |
|
||||
mkdir -p logs/playwright_fontscale
|
||||
python tests/studio/playwright_ui_font_scale.py
|
||||
|
||||
- name: Stop second Unsloth
|
||||
if: always()
|
||||
run: |
|
||||
|
|
@ -352,6 +361,7 @@ jobs:
|
|||
logs/playwright
|
||||
logs/playwright-permissions-*
|
||||
logs/playwright_extra
|
||||
logs/playwright_fontscale
|
||||
logs/playwright_modelcfg
|
||||
logs/playwright_ime
|
||||
logs/studio-permissions-*.log
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ function TauriUpdateLayer({
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="pointer-events-none fixed bottom-4 right-4 z-[9998] flex w-[calc(100vw-32px)] max-w-[400px] flex-col items-stretch gap-2">
|
||||
<div className="pointer-events-none fixed bottom-4 right-4 z-[9998] flex w-[calc(100vw-2rem)] max-w-[400px] flex-col items-stretch gap-2">
|
||||
<UpdateBanner
|
||||
status={update.status}
|
||||
info={update.info}
|
||||
|
|
@ -263,8 +263,8 @@ const MAC_NATIVE_CHROME_STYLE = {
|
|||
const CUSTOM_CHROME_STYLE = {
|
||||
"--studio-titlebar-height": "0px",
|
||||
"--studio-custom-titlebar-height": "34px",
|
||||
"--studio-sidebar-expanded-width": "280px",
|
||||
"--studio-sidebar-collapsed-width": "48px",
|
||||
"--studio-sidebar-expanded-width": "17.5rem",
|
||||
"--studio-sidebar-collapsed-width": "3rem",
|
||||
"--studio-startup-top-inset": "42px",
|
||||
"--studio-content-top-inset": "34px",
|
||||
"--studio-hidden-route-top-inset": "34px",
|
||||
|
|
@ -380,7 +380,7 @@ function TauriWrapper({ children }: { children: ReactNode }) {
|
|||
{children}
|
||||
{/* One bottom-right stack so overlays never overlap; they stack with a
|
||||
gap, download panel anchored at the corner with banners above. */}
|
||||
<div className="pointer-events-none fixed bottom-4 right-4 z-[9998] flex w-[calc(100vw-32px)] max-w-[400px] flex-col items-stretch gap-2">
|
||||
<div className="pointer-events-none fixed bottom-4 right-4 z-[9998] flex w-[calc(100vw-2rem)] max-w-[400px] flex-col items-stretch gap-2">
|
||||
<WebUpdateBanner
|
||||
positioned={false}
|
||||
enabled={!WEB_UPDATE_HIDDEN_ROUTES.has(pathname)}
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ function NavItem({
|
|||
className="sidebar-nav-btn h-[33px] rounded-full gap-[8.5px] pl-3 pr-2.5 font-medium group-data-[collapsible=icon]:px-2.5 group-data-[collapsible=icon]:!w-[32px] group-data-[collapsible=icon]:mx-auto"
|
||||
>
|
||||
<HugeiconsIcon icon={icon} strokeWidth={1.75} className="size-icon! shrink-0 group-hover/menu-button:animate-icon-pop" />
|
||||
<span className="text-[0.90625rem] leading-[1.1875rem] tracking-nav">{label}</span>
|
||||
<span className="text-ui-14p5 leading-ui-19 tracking-nav">{label}</span>
|
||||
{spinner && (
|
||||
<Spinner className="ml-auto size-3.5 shrink-0 text-muted-foreground group-data-[collapsible=icon]:hidden" />
|
||||
)}
|
||||
|
|
@ -904,7 +904,7 @@ export function AppSidebar() {
|
|||
? "sidebar-row-action group-hover/project-chat-item:opacity-100 group-hover/project-chat-item:pointer-events-auto focus-visible:opacity-100 focus-visible:pointer-events-auto"
|
||||
: "sidebar-row-action group-hover/recent-item:opacity-100 group-hover/recent-item:pointer-events-auto focus-visible:opacity-100 focus-visible:pointer-events-auto";
|
||||
const buttonClass = cn(
|
||||
"sidebar-nav-btn h-[33px] cursor-pointer rounded-full pr-4 text-[0.90625rem] leading-[1.1875rem] tracking-nav font-medium",
|
||||
"sidebar-nav-btn h-[33px] cursor-pointer rounded-full pr-4 text-ui-14p5 leading-ui-19 tracking-nav font-medium",
|
||||
// pl-3 (12px) over the content's pl-1.5 (6px) = 18px, aligning the
|
||||
// title with the nav items above.
|
||||
variant === "project" ? "pl-[39px]" : "pl-3",
|
||||
|
|
@ -939,7 +939,7 @@ export function AppSidebar() {
|
|||
aria-label={translate("shell.dialog.renameChat.placeholder")}
|
||||
className={cn(
|
||||
// No pill or box; edit in place as plain highlighted text.
|
||||
"text-foreground h-[33px] w-full border-0 bg-transparent pr-4 text-[0.90625rem] leading-[1.1875rem] font-medium tracking-nav outline-none",
|
||||
"text-foreground h-[33px] w-full border-0 bg-transparent pr-4 text-ui-14p5 leading-ui-19 font-medium tracking-nav outline-none",
|
||||
variant === "project" ? "pl-[39px]" : "pl-3",
|
||||
)}
|
||||
/>
|
||||
|
|
@ -1185,16 +1185,16 @@ export function AppSidebar() {
|
|||
tabIndex={chatDisabled ? -1 : undefined}
|
||||
>
|
||||
{/* Logo lockup follows the UI font size at half rate:
|
||||
base + (root - 16px) / 2, written as (base - 8)px + 0.5rem. */}
|
||||
base + (root scale - 1) * 8px. Exact base sizes at 16px. */}
|
||||
<img
|
||||
src="/circle-logo-small.png"
|
||||
alt="Unsloth"
|
||||
className="h-[calc(26px+0.5rem)] w-[calc(26px+0.5rem)] rounded-full object-cover"
|
||||
className="h-[calc(26px+0.5rem*var(--ui-font-scale,1))] w-[calc(26px+0.5rem*var(--ui-font-scale,1))] rounded-full object-cover"
|
||||
/>
|
||||
<span className="font-heading text-[calc(13px+0.5rem)] font-semibold tracking-[0em] leading-none text-black dark:text-white dark:tracking-[0.02em]">
|
||||
<span className="font-heading text-[calc(13px+0.5rem*var(--ui-font-scale,1))] font-semibold tracking-[0em] leading-none text-black dark:text-white dark:tracking-[0.02em]">
|
||||
unsloth
|
||||
</span>
|
||||
<span className="nav-badge ml-0.5 inline-flex items-center justify-center rounded-full border border-nav-beta-border px-[5px] pt-[3px] pb-[2px] text-[calc(0px+0.5rem)] font-medium leading-none tracking-[0.04em] text-nav-fg-muted antialiased subpixel-antialiased shadow-[0_1px_2px_rgba(0,0,0,0.06)] dark:shadow-[0_1px_2px_rgba(0,0,0,0.35)]">
|
||||
<span className="nav-badge ml-0.5 inline-flex items-center justify-center rounded-full border border-nav-beta-border px-[5px] pt-[3px] pb-[2px] text-[calc(0.5rem*var(--ui-font-scale,1))] font-medium leading-none tracking-[0.04em] text-nav-fg-muted antialiased subpixel-antialiased shadow-[0_1px_2px_rgba(0,0,0,0.06)] dark:shadow-[0_1px_2px_rgba(0,0,0,0.35)]">
|
||||
{t("shell.beta")}
|
||||
</span>
|
||||
</Link>
|
||||
|
|
@ -1221,7 +1221,7 @@ export function AppSidebar() {
|
|||
hidden={isMobile}
|
||||
>
|
||||
{t("shell.navigation.search")}
|
||||
<kbd className="rounded bg-black/10 px-1 py-px text-[0.625rem] font-medium leading-none dark:bg-white/15">
|
||||
<kbd className="rounded bg-black/10 px-1 py-px text-ui-10 font-medium leading-none dark:bg-white/15">
|
||||
{isMacPlatform ? "⌘K" : "Ctrl+K"}
|
||||
</kbd>
|
||||
</TooltipContent>
|
||||
|
|
@ -1538,7 +1538,7 @@ export function AppSidebar() {
|
|||
className="sidebar-nav-btn h-[33px] rounded-full gap-[8.5px] pl-3 pr-2.5 font-medium group-hover/recent-item:pr-16 group-has-[.sidebar-row-action[data-state=open]]/recent-item:pr-8"
|
||||
>
|
||||
<HugeiconsIcon icon={Folder01Icon} strokeWidth={1.75} className="size-icon! shrink-0" />
|
||||
<span className="truncate text-[0.90625rem] leading-[1.1875rem] tracking-nav">{project.name}</span>
|
||||
<span className="truncate text-ui-14p5 leading-ui-19 tracking-nav">{project.name}</span>
|
||||
</SidebarMenuButton>
|
||||
{/* New chat in this project */}
|
||||
<button
|
||||
|
|
@ -1632,7 +1632,7 @@ export function AppSidebar() {
|
|||
// Show more would otherwise match the chat rows.
|
||||
className="sidebar-nav-btn h-[30px] rounded-full pl-9 pr-4 font-medium text-nav-fg-muted!"
|
||||
>
|
||||
<span className="text-[0.8125rem] leading-[1.125rem] tracking-nav">
|
||||
<span className="text-ui-13 leading-ui-18 tracking-nav">
|
||||
{showAll ? "Show less" : "Show more"}
|
||||
</span>
|
||||
</SidebarMenuButton>
|
||||
|
|
@ -1711,7 +1711,7 @@ export function AppSidebar() {
|
|||
>
|
||||
<SidebarMenuButton
|
||||
isActive={isActiveRun}
|
||||
className="sidebar-nav-btn h-auto flex-col items-start gap-0.5 py-[5px] rounded-[14px] pl-3 pr-7 text-[0.90625rem] tracking-nav font-medium"
|
||||
className="sidebar-nav-btn h-auto flex-col items-start gap-0.5 py-[5px] rounded-[14px] pl-3 pr-7 text-ui-14p5 tracking-nav font-medium"
|
||||
onClick={() => {
|
||||
setSelectedHistoryRunId(run.id);
|
||||
// From Recipes/Export, jump to Train so the run's
|
||||
|
|
@ -1731,7 +1731,7 @@ export function AppSidebar() {
|
|||
<span className="truncate">
|
||||
{getTrainingRunDisplayTitle(run)}
|
||||
</span>
|
||||
<span className="ml-auto mr-0.5 shrink-0 text-[0.625rem] text-muted-foreground">
|
||||
<span className="ml-auto mr-0.5 shrink-0 text-ui-10 text-muted-foreground">
|
||||
{formatRelativeShort(run.started_at)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -1832,11 +1832,11 @@ export function AppSidebar() {
|
|||
/>
|
||||
</span>
|
||||
<div className="flex min-w-0 flex-col gap-px leading-tight group-data-[collapsible=icon]:hidden">
|
||||
<span className="truncate font-heading text-[0.84375rem] font-semibold text-nav-fg">
|
||||
<span className="truncate font-heading text-ui-13p5 font-semibold text-nav-fg">
|
||||
{t("shell.updateAvailable")}
|
||||
</span>
|
||||
{updateVersion && (
|
||||
<span className="truncate text-[0.71875rem] text-muted-foreground">
|
||||
<span className="truncate text-ui-11p5 text-muted-foreground">
|
||||
v{updateVersion}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -1873,8 +1873,8 @@ export function AppSidebar() {
|
|||
{/* min-w-0 so long names truncate instead of overflowing;
|
||||
pr on the button reserves room for the settings cog */}
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-px leading-tight group-data-[collapsible=icon]:hidden">
|
||||
<span className="truncate font-heading text-[0.84375rem] tracking-[0.025em] dark:tracking-[0.04em] font-semibold text-nav-fg">{displayTitle}</span>
|
||||
<span className="truncate text-[0.71875rem] tracking-nav text-muted-foreground">Unsloth</span>
|
||||
<span className="truncate font-heading text-ui-13p5 tracking-[0.025em] dark:tracking-[0.04em] font-semibold text-nav-fg">{displayTitle}</span>
|
||||
<span className="truncate text-ui-11p5 tracking-nav text-muted-foreground">Unsloth</span>
|
||||
</div>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
|
|
@ -1882,7 +1882,7 @@ export function AppSidebar() {
|
|||
side="top"
|
||||
align="center"
|
||||
sideOffset={8}
|
||||
className="app-user-menu menu-soft-surface-up ring-0 w-[256px] px-2.5 py-2.5 font-heading rounded-[20px] border-0"
|
||||
className="app-user-menu menu-soft-surface-up ring-0 w-[16rem] px-2.5 py-2.5 font-heading rounded-[20px] border-0"
|
||||
>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ export const AudioPlayer: FC<AudioPlayerProps> = ({ src }) => {
|
|||
onChange={handleSeek}
|
||||
className="h-1.5 w-full cursor-pointer accent-primary"
|
||||
/>
|
||||
<div className="flex justify-between text-[0.625rem] text-muted-foreground">
|
||||
<div className="flex justify-between text-ui-10 text-muted-foreground">
|
||||
<span>{formatTime(progress)}</span>
|
||||
<span>{formatTime(duration)}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ function DetailRow({
|
|||
}) {
|
||||
if (value == null || value === "") return null;
|
||||
return (
|
||||
<div className="grid grid-cols-[136px_minmax(0,1fr)] items-start gap-3 text-[0.8125rem]">
|
||||
<div className="grid grid-cols-[8.5rem_minmax(0,1fr)] items-start gap-3 text-ui-13">
|
||||
<span className="text-muted-foreground">{label}</span>
|
||||
<span
|
||||
className={cn(
|
||||
|
|
@ -336,7 +336,7 @@ export const MessageResponseDetailsSheet: FC<{
|
|||
<Sheet open={open} onOpenChange={onOpenChange}>
|
||||
<SheetContent
|
||||
side="right"
|
||||
className="w-[min(448px,100vw)] p-0 sm:max-w-[448px]"
|
||||
className="w-[min(28rem,100vw)] p-0 sm:max-w-[28rem]"
|
||||
>
|
||||
<SheetHeader className="border-b p-4">
|
||||
<SheetTitle className="flex items-center gap-2 pr-10 font-heading text-base">
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ export const MessageTiming: FC<{
|
|||
data-slot="message-timing-trigger"
|
||||
aria-label="Message timing"
|
||||
className={cn(
|
||||
"flex items-center rounded-[10px] p-1 font-mono text-chat-icon-fg text-[0.8125rem] tabular-nums transition-colors hover:bg-chat-icon-bg-hover hover:text-chat-icon-fg-hover",
|
||||
"flex items-center rounded-[10px] p-1 font-mono text-chat-icon-fg text-ui-13 tabular-nums transition-colors hover:bg-chat-icon-bg-hover hover:text-chat-icon-fg-hover",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ function ReasoningContent({
|
|||
<CollapsibleContent
|
||||
data-slot="reasoning-content"
|
||||
className={cn(
|
||||
"aui-reasoning-content relative overflow-hidden text-foreground/85 text-[0.84375rem] outline-none",
|
||||
"aui-reasoning-content relative overflow-hidden text-foreground/85 text-ui-13p5 outline-none",
|
||||
"group/collapsible-content ease-out",
|
||||
"data-[state=closed]:animate-collapsible-up",
|
||||
"data-[state=open]:animate-collapsible-down",
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ function SourceIcon({
|
|||
<span
|
||||
data-slot="source-icon-fallback"
|
||||
className={cn(
|
||||
`flex ${sizeClass} shrink-0 items-center justify-center rounded-sm bg-muted font-medium text-[0.625rem]`,
|
||||
`flex ${sizeClass} shrink-0 items-center justify-center rounded-sm bg-muted font-medium text-ui-10`,
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -961,9 +961,9 @@ export const Thread: FC<{
|
|||
<ThreadPrimitive.Root
|
||||
className="aui-root aui-thread-root @container relative flex min-h-0 min-w-0 flex-1 basis-0 flex-col overflow-hidden"
|
||||
style={{
|
||||
["--thread-max-width" as string]: "768px",
|
||||
["--thread-max-width" as string]: "48rem",
|
||||
["--thread-content-max-width" as string]:
|
||||
"calc(var(--thread-max-width) - 24px)",
|
||||
"calc(var(--thread-max-width) - 1.5rem)",
|
||||
}}
|
||||
onDragEnter={onDragEnter}
|
||||
onDragOver={onDragOver}
|
||||
|
|
@ -1142,14 +1142,14 @@ const GeneratedImageViewportOverlay: FC<{
|
|||
/>
|
||||
</div>
|
||||
<div
|
||||
className="w-full max-w-[min(100%,736px)] shrink-0 text-center"
|
||||
className="w-full max-w-[min(100%,46rem)] shrink-0 text-center"
|
||||
title={overlay.title}
|
||||
>
|
||||
<p className="truncate text-xs font-semibold text-foreground/80">
|
||||
Generated image
|
||||
</p>
|
||||
{overlay.metadata ? (
|
||||
<p className="truncate text-[0.6875rem] font-medium text-muted-foreground">
|
||||
<p className="truncate text-ui-11 font-medium text-muted-foreground">
|
||||
{overlay.metadata}
|
||||
</p>
|
||||
) : null}
|
||||
|
|
@ -1390,7 +1390,7 @@ const ComposerAnimated: FC<{
|
|||
disableQueue?: boolean;
|
||||
}> = ({ disabled, threadId, menuSide, disableQueue }) => {
|
||||
return (
|
||||
<div className="relative mx-auto min-w-0 w-full max-w-[736px]">
|
||||
<div className="relative mx-auto min-w-0 w-full max-w-[46rem]">
|
||||
<div className="relative z-10 w-full">
|
||||
<Composer
|
||||
disabled={disabled}
|
||||
|
|
@ -1570,18 +1570,6 @@ const Composer: FC<{
|
|||
const t = setTimeout(() => writeComposerDraft(draftKey, composerText), 300);
|
||||
return () => clearTimeout(t);
|
||||
}, [composerText, draftKey]);
|
||||
// Without this the restore effect above puts the sent text back when the
|
||||
// runtime rebinds on the first message.
|
||||
const draftKeyRef = useRef(draftKey);
|
||||
useEffect(() => {
|
||||
draftKeyRef.current = draftKey;
|
||||
}, [draftKey]);
|
||||
const clearStoredDraft = useCallback(() => {
|
||||
const key = draftKeyRef.current;
|
||||
if (key) {
|
||||
writeComposerDraft(key, "");
|
||||
}
|
||||
}, []);
|
||||
// react-textarea-autosize re-measures only on value change or window resize,
|
||||
// not on the width swap from expanding, so it keeps the taller height and
|
||||
// leaves a stray blank row. Nudge a resize whenever input width changes.
|
||||
|
|
@ -1732,10 +1720,9 @@ const Composer: FC<{
|
|||
setPendingSend(false);
|
||||
dismissWaitToast();
|
||||
if (text.trim().length > 0 || attachments.length > 0) {
|
||||
clearStoredDraft();
|
||||
aui.composer().send();
|
||||
}
|
||||
}, [pendingSend, indexingActive, aui, clearStoredDraft, dismissWaitToast]);
|
||||
}, [pendingSend, indexingActive, aui, dismissWaitToast]);
|
||||
|
||||
// Drop any queued send + toast on unmount (e.g. thread switch).
|
||||
useEffect(
|
||||
|
|
@ -1778,7 +1765,6 @@ const Composer: FC<{
|
|||
flushResourcesSync(() => {
|
||||
aui.composer().setText("");
|
||||
});
|
||||
clearStoredDraft();
|
||||
startPromptQueue(
|
||||
[queuedPrompt],
|
||||
createPromptQueueTarget(),
|
||||
|
|
@ -1812,7 +1798,6 @@ const Composer: FC<{
|
|||
closeOverlay();
|
||||
return;
|
||||
}
|
||||
clearStoredDraft();
|
||||
setImageToolsEnabled(true);
|
||||
setPendingImageEditReference({
|
||||
threadId: overlay.threadId ?? referenceThreadId,
|
||||
|
|
@ -1830,15 +1815,11 @@ const Composer: FC<{
|
|||
);
|
||||
});
|
||||
closeOverlay();
|
||||
return;
|
||||
}
|
||||
|
||||
clearStoredDraft();
|
||||
},
|
||||
[
|
||||
aui,
|
||||
canQueueCurrentPrompt,
|
||||
clearStoredDraft,
|
||||
closeOverlay,
|
||||
composerText,
|
||||
createPromptQueueTarget,
|
||||
|
|
@ -1940,7 +1921,6 @@ const Composer: FC<{
|
|||
flushResourcesSync(() => {
|
||||
aui.composer().setText("");
|
||||
});
|
||||
clearStoredDraft();
|
||||
startPromptQueue([queuedPrompt], createPromptQueueTarget(), true);
|
||||
}}
|
||||
onSendClick={interceptSend}
|
||||
|
|
@ -3317,7 +3297,7 @@ const PromptQueueStack: FC<{ queueThreadIds: string[] }> = ({
|
|||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid h-10 grid-cols-[minmax(0,1fr)_auto_32px] items-center gap-2.5">
|
||||
<div className="grid h-10 grid-cols-[minmax(0,1fr)_auto_2rem] items-center gap-2.5">
|
||||
<div className="flex min-w-0 items-center gap-2.5">
|
||||
<CornerDownRightIcon className="size-4 shrink-0 text-muted-foreground/50" />
|
||||
<div className="truncate text-sm text-muted-foreground">
|
||||
|
|
@ -3329,7 +3309,7 @@ const PromptQueueStack: FC<{ queueThreadIds: string[] }> = ({
|
|||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 w-[84px] justify-center gap-1 px-0 text-sm font-normal text-muted-foreground/80 hover:text-foreground"
|
||||
className="h-7 w-[5.25rem] justify-center gap-1 px-0 text-sm font-normal text-muted-foreground/80 hover:text-foreground"
|
||||
onClick={() => startEditing(item)}
|
||||
>
|
||||
<HugeiconsIcon icon={Edit03Icon} strokeWidth={2} />
|
||||
|
|
@ -3565,14 +3545,14 @@ const DiffusionCanvas: FC = () => {
|
|||
canvas.total > 0 ? `step ${canvas.step + 1}/${canvas.total}` : "denoising";
|
||||
return (
|
||||
<div className="aui-diffusion-canvas my-1.5 overflow-hidden rounded-lg border border-primary/20 bg-primary/[0.03]">
|
||||
<div className="flex items-center gap-2 border-b border-primary/10 px-3 py-1.5 text-[0.6875rem] font-medium text-primary/80">
|
||||
<div className="flex items-center gap-2 border-b border-primary/10 px-3 py-1.5 text-ui-11 font-medium text-primary/80">
|
||||
<span className="inline-block size-1.5 animate-pulse rounded-full bg-primary" />
|
||||
<span>Denoising</span>
|
||||
<span className="opacity-60">
|
||||
block {canvas.block + 1} - {stepLabel}
|
||||
</span>
|
||||
</div>
|
||||
<pre className="max-h-[60vh] overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-[0.78125rem] leading-relaxed text-foreground/90">
|
||||
<pre className="max-h-[60vh] overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-ui-12p5 leading-relaxed text-foreground/90">
|
||||
{canvas.text}
|
||||
</pre>
|
||||
</div>
|
||||
|
|
@ -3646,7 +3626,7 @@ const AssistantMessage: FC = () => {
|
|||
|
||||
return (
|
||||
<MessagePrimitive.Root
|
||||
className="group/assistant-message aui-assistant-message-root relative mx-auto min-w-0 w-full max-w-(--thread-content-max-width) pt-0.5 pb-4 text-[0.96875rem] [font-weight:410] tracking-[0.01em] dark:tracking-[0.02em]"
|
||||
className="group/assistant-message aui-assistant-message-root relative mx-auto min-w-0 w-full max-w-(--thread-content-max-width) pt-0.5 pb-4 text-ui-15p5 [font-weight:410] tracking-[0.01em] dark:tracking-[0.02em]"
|
||||
data-role="assistant"
|
||||
>
|
||||
<div className="aui-assistant-message-content wrap-break-word min-w-0 text-[#0d0d0d] dark:text-foreground leading-relaxed">
|
||||
|
|
@ -3676,7 +3656,7 @@ const AssistantMessage: FC = () => {
|
|||
) : (
|
||||
<>
|
||||
<div className="pointer-events-none relative h-0 min-w-0">
|
||||
<MessageResponseModelBadge className="absolute -top-6 left-0 max-w-[min(352px,100%)]" />
|
||||
<MessageResponseModelBadge className="absolute -top-6 left-0 max-w-[min(22rem,100%)]" />
|
||||
</div>
|
||||
<GeneratingIndicator />
|
||||
<CancelledIndicator />
|
||||
|
|
@ -3759,7 +3739,7 @@ const ForkCountBadge: FC = () => {
|
|||
if (count <= 0) return null;
|
||||
return (
|
||||
<span
|
||||
className="mx-1 inline-flex items-center gap-1 rounded-sm bg-primary/10 px-1.5 py-0.5 text-[0.625rem] font-medium text-primary"
|
||||
className="mx-1 inline-flex items-center gap-1 rounded-sm bg-primary/10 px-1.5 py-0.5 text-ui-10 font-medium text-primary"
|
||||
title={`${count} fork${count === 1 ? "" : "s"} from this message`}
|
||||
>
|
||||
<GitBranchIcon strokeWidth={1.75} className="size-3" />
|
||||
|
|
@ -4084,7 +4064,7 @@ const UserMessageAudio: FC = () => {
|
|||
const UserMessage: FC = () => {
|
||||
return (
|
||||
<MessagePrimitive.Root
|
||||
className="aui-user-message-root fade-in slide-in-from-bottom-1 mx-auto flex w-full max-w-(--thread-content-max-width) animate-in flex-col items-end gap-y-2 pt-6 pb-4 text-[0.96875rem] [font-weight:410] tracking-[0.01em] dark:tracking-[0.02em] duration-150"
|
||||
className="aui-user-message-root fade-in slide-in-from-bottom-1 mx-auto flex w-full max-w-(--thread-content-max-width) animate-in flex-col items-end gap-y-2 pt-6 pb-4 text-ui-15p5 [font-weight:410] tracking-[0.01em] dark:tracking-[0.02em] duration-150"
|
||||
data-role="user"
|
||||
>
|
||||
<UserMessageAttachments />
|
||||
|
|
@ -4195,7 +4175,7 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|||
<BranchPickerPrimitive.Root
|
||||
hideWhenSingleBranch={true}
|
||||
className={cn(
|
||||
"aui-branch-picker-root inline-flex items-center text-chat-icon-fg text-[0.8125rem]",
|
||||
"aui-branch-picker-root inline-flex items-center text-chat-icon-fg text-ui-13",
|
||||
className,
|
||||
)}
|
||||
{...rest}
|
||||
|
|
@ -4209,7 +4189,7 @@ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|||
<ChevronLeftIcon strokeWidth={1.25} className="size-[36px]" />
|
||||
</button>
|
||||
</BranchPickerPrimitive.Previous>
|
||||
<span className="aui-branch-picker-state font-mono text-[0.8125rem] tabular-nums">
|
||||
<span className="aui-branch-picker-state font-mono text-ui-13 tabular-nums">
|
||||
<BranchPickerPrimitive.Number />/<BranchPickerPrimitive.Count />
|
||||
</span>
|
||||
<BranchPickerPrimitive.Next asChild={true}>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export function CitationBadge({
|
|||
<Badge
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className={`rounded-full inline-flex items-center gap-1.5 max-w-[240px] ${
|
||||
className={`rounded-full inline-flex items-center gap-1.5 max-w-[15rem] ${
|
||||
clickable
|
||||
? "cursor-pointer hover:bg-accent hover:text-accent-foreground transition-colors"
|
||||
: "cursor-default"
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ const RenderHtmlToolUIImpl: ToolCallMessagePartComponent = ({
|
|||
? "Canvas interrupted"
|
||||
: "Canvas unavailable"}
|
||||
</span>
|
||||
<span className="truncate text-[0.6875rem] leading-none text-muted-foreground">
|
||||
<span className="truncate text-ui-11 leading-none text-muted-foreground">
|
||||
{errorText ??
|
||||
(isStaleGeneratingArtifact
|
||||
? "Refresh stopped this preview"
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ export function FloatingMonitor() {
|
|||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.9 }}
|
||||
className="settings-surface fixed bottom-4 right-4 w-64 max-w-[calc(100vw-32px)] resize overflow-hidden rounded-xl border border-border/70 p-3 shadow-border ring-0 backdrop-blur-sm pointer-events-auto cursor-default select-none"
|
||||
className="settings-surface fixed bottom-4 right-4 w-64 max-w-[calc(100vw-2rem)] resize overflow-hidden rounded-xl border border-border/70 p-3 shadow-border ring-0 backdrop-blur-sm pointer-events-auto cursor-default select-none"
|
||||
>
|
||||
<div className="mb-2 flex items-center justify-between gap-2 border-b border-border/60 pb-2">
|
||||
<div className="flex min-w-0 flex-1 items-center gap-1.5 truncate text-xs font-semibold text-foreground">
|
||||
|
|
@ -139,7 +139,7 @@ export function FloatingMonitor() {
|
|||
className="space-y-3 overflow-hidden"
|
||||
>
|
||||
<div className="space-y-1">
|
||||
<div className="flex justify-between text-[0.6875rem] font-medium font-mono">
|
||||
<div className="flex justify-between text-ui-11 font-medium font-mono">
|
||||
<span>{t("settings.resources.liveMonitor.ram")}</span>
|
||||
<span
|
||||
className={cn("tabular-nums", usageTextClass(ramPercent))}
|
||||
|
|
@ -159,7 +159,7 @@ export function FloatingMonitor() {
|
|||
|
||||
{hasGpu && (
|
||||
<div className="space-y-1">
|
||||
<div className="flex justify-between text-[0.6875rem] font-medium font-mono">
|
||||
<div className="flex justify-between text-ui-11 font-medium font-mono">
|
||||
<span className="truncate flex-1 pr-2">
|
||||
{t("settings.resources.liveMonitor.vram")}{" "}
|
||||
{devices.length > 1
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export function LlamaUpdateBanner({
|
|||
<div
|
||||
className={cn(
|
||||
positioned
|
||||
? "fixed bottom-4 right-4 z-[9998] w-[calc(100vw-32px)] max-w-[400px]"
|
||||
? "fixed bottom-4 right-4 z-[9998] w-[calc(100vw-2rem)] max-w-[400px]"
|
||||
: "pointer-events-auto w-full",
|
||||
)}
|
||||
data-testid="llama-update-banner"
|
||||
|
|
@ -178,7 +178,7 @@ export function LlamaUpdateBanner({
|
|||
{status?.latest_tag ?? ""}
|
||||
</span>
|
||||
</p>
|
||||
<p className="mt-1 text-[0.6875rem] text-muted-foreground/70">
|
||||
<p className="mt-1 text-ui-11 text-muted-foreground/70">
|
||||
{sizeLabel ? `${sizeLabel} download · ` : ""}No restart needed
|
||||
after update
|
||||
</p>
|
||||
|
|
@ -209,7 +209,7 @@ export function LlamaUpdateBanner({
|
|||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-auto rounded-full px-3 py-2 text-[0.8125rem] font-medium text-foreground"
|
||||
className="h-auto rounded-full px-3 py-2 text-ui-13 font-medium text-foreground"
|
||||
onClick={snooze}
|
||||
data-testid="llama-update-snooze-button"
|
||||
>
|
||||
|
|
@ -218,7 +218,7 @@ export function LlamaUpdateBanner({
|
|||
<Button
|
||||
size="sm"
|
||||
// Align pill edge with card padding.
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-[0.8125rem]"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-ui-13"
|
||||
onClick={handleUpdate}
|
||||
data-testid="llama-update-button"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export function SectionCard({
|
|||
<div className="flex items-center gap-2 pb-1">
|
||||
<h3 className="text-sm font-semibold">{title}</h3>
|
||||
{badge && (
|
||||
<span className="rounded-full bg-control-accent/15 px-2 py-0.5 text-[0.625rem] font-semibold text-control-accent">
|
||||
<span className="rounded-full bg-control-accent/15 px-2 py-0.5 text-ui-10 font-semibold text-control-accent">
|
||||
{badge}
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ export function ShutdownDialog({
|
|||
onAfterShutdown?.();
|
||||
document.body.innerHTML = `
|
||||
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;font-family:sans-serif;gap:12px">
|
||||
<p style="font-size:1.1rem;font-weight:600;margin:0">Unsloth Studio has stopped.</p>
|
||||
<p style="font-size:0.9rem;color:#888;margin:0">You can now close this tab.</p>
|
||||
<p style="font-size:calc(1.1rem * var(--ui-font-scale, 1));font-weight:600;margin:0">Unsloth Studio has stopped.</p>
|
||||
<p style="font-size:calc(0.9rem * var(--ui-font-scale, 1));color:#888;margin:0">You can now close this tab.</p>
|
||||
</div>`;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ function DiagnosticsCopyActions({
|
|||
readOnly
|
||||
value={manualReport}
|
||||
onFocus={(event) => event.currentTarget.select()}
|
||||
className="h-32 w-full max-w-md resize-none rounded-lg border border-border/50 bg-muted/30 p-2 font-mono text-[0.625rem] text-muted-foreground"
|
||||
className="h-32 w-full max-w-md resize-none rounded-lg border border-border/50 bg-muted/30 p-2 font-mono text-ui-10 text-muted-foreground"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export function UpdateBanner({
|
|||
transition={{ duration: 0.35, ease: EASE_OUT_QUART }}
|
||||
className={cn(
|
||||
positioned
|
||||
? "fixed bottom-4 right-4 z-[9999] w-[calc(100vw-32px)] max-w-[400px]"
|
||||
? "fixed bottom-4 right-4 z-[9999] w-[calc(100vw-2rem)] max-w-[400px]"
|
||||
: "pointer-events-auto w-full",
|
||||
)}
|
||||
data-testid="tauri-update-banner"
|
||||
|
|
@ -142,7 +142,7 @@ export function UpdateBanner({
|
|||
</span>
|
||||
</p>
|
||||
)}
|
||||
<p className="mt-1 text-[0.6875rem] text-muted-foreground/70">
|
||||
<p className="mt-1 text-ui-11 text-muted-foreground/70">
|
||||
{showFailure
|
||||
? "Backend recovered. Diagnostics are still available."
|
||||
: isManualLinuxPackage
|
||||
|
|
@ -166,7 +166,7 @@ export function UpdateBanner({
|
|||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-auto rounded-full px-3 py-2 text-[0.8125rem] font-medium text-foreground"
|
||||
className="h-auto rounded-full px-3 py-2 text-ui-13 font-medium text-foreground"
|
||||
onClick={() => {
|
||||
handleCopyDiagnostics().catch(console.error);
|
||||
}}
|
||||
|
|
@ -176,14 +176,14 @@ export function UpdateBanner({
|
|||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-auto rounded-full px-3 py-2 text-[0.8125rem] font-medium text-foreground"
|
||||
className="h-auto rounded-full px-3 py-2 text-ui-13 font-medium text-foreground"
|
||||
onClick={onDismiss}
|
||||
>
|
||||
Later
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-[0.8125rem]"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-ui-13"
|
||||
onClick={onInstall}
|
||||
disabled={installDisabled}
|
||||
>
|
||||
|
|
@ -195,14 +195,14 @@ export function UpdateBanner({
|
|||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-auto rounded-full px-3 py-2 text-[0.8125rem] font-medium text-foreground"
|
||||
className="h-auto rounded-full px-3 py-2 text-ui-13 font-medium text-foreground"
|
||||
onClick={onDismiss}
|
||||
>
|
||||
Remind me later
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-[0.8125rem]"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-ui-13"
|
||||
onClick={onInstall}
|
||||
disabled={installDisabled}
|
||||
>
|
||||
|
|
@ -219,7 +219,7 @@ export function UpdateBanner({
|
|||
readOnly={true}
|
||||
value={manualReport}
|
||||
onFocus={(event) => event.currentTarget.select()}
|
||||
className="mt-2 h-28 w-full resize-none rounded-lg border border-border/50 bg-muted/30 p-2 font-mono text-[0.625rem] text-muted-foreground"
|
||||
className="mt-2 h-28 w-full resize-none rounded-lg border border-border/50 bg-muted/30 p-2 font-mono text-ui-10 text-muted-foreground"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ function LogViewer({ logs }: { logs: string[] }) {
|
|||
return (
|
||||
<div
|
||||
ref={scrollRef}
|
||||
className="mt-4 h-[180px] w-full max-w-xl overflow-y-auto rounded-lg border border-border/40 bg-muted/30 p-3 font-mono text-[0.6875rem] leading-relaxed text-muted-foreground"
|
||||
className="mt-4 h-[180px] w-full max-w-xl overflow-y-auto rounded-lg border border-border/40 bg-muted/30 p-3 font-mono text-ui-11 leading-relaxed text-muted-foreground"
|
||||
>
|
||||
{logs.map((line, i) => (
|
||||
<div key={i} className="whitespace-pre-wrap break-all">
|
||||
|
|
@ -197,7 +197,7 @@ export function UpdateScreen({
|
|||
readOnly
|
||||
value={manualReport}
|
||||
onFocus={(event) => event.currentTarget.select()}
|
||||
className="mt-2 h-32 w-full max-w-xl resize-none rounded-lg border border-border/50 bg-muted/30 p-2 font-mono text-[0.625rem] text-muted-foreground"
|
||||
className="mt-2 h-32 w-full max-w-xl resize-none rounded-lg border border-border/50 bg-muted/30 p-2 font-mono text-ui-10 text-muted-foreground"
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,8 +112,8 @@ export function WindowTitlebar({
|
|||
const { pinned, togglePinned } = useSidebarPin();
|
||||
const sidebarWidth = showSidebarSurface
|
||||
? pinned
|
||||
? "var(--studio-sidebar-expanded-width,280px)"
|
||||
: "var(--studio-sidebar-collapsed-width,48px)"
|
||||
? "var(--studio-sidebar-expanded-width,17.5rem)"
|
||||
: "var(--studio-sidebar-collapsed-width,3rem)"
|
||||
: "0px";
|
||||
const contentBorderLeft = pinned ? `calc(${sidebarWidth} + 12px)` : "0px";
|
||||
|
||||
|
|
@ -273,7 +273,7 @@ export function WindowTitlebar({
|
|||
draggable={false}
|
||||
className="size-5 shrink-0 rounded-[6px] object-cover"
|
||||
/>
|
||||
<span className="min-w-0 truncate text-[0.8125rem] font-semibold leading-none tracking-[0.01em] text-nav-fg">
|
||||
<span className="min-w-0 truncate text-ui-13 font-semibold leading-none tracking-[0.01em] text-nav-fg">
|
||||
Unsloth Studio
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -325,7 +325,7 @@ export function WindowTitlebar({
|
|||
className="pointer-events-auto absolute top-0 h-full"
|
||||
style={{
|
||||
left: sidebarWidth,
|
||||
right: "calc(var(--studio-window-control-inset,112px) + 8px)",
|
||||
right: "calc(var(--studio-window-control-inset,112px) + 0.5rem)",
|
||||
}}
|
||||
onMouseDown={handleDragMouseDown}
|
||||
onDoubleClick={handleDragDoubleClick}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ function Calendar({
|
|||
table: "w-full border-collapse",
|
||||
weekdays: cn("flex", defaultClassNames.weekdays),
|
||||
weekday: cn(
|
||||
"text-muted-foreground rounded-(--cell-radius) flex-1 font-normal text-[0.8rem] select-none",
|
||||
"text-muted-foreground rounded-(--cell-radius) flex-1 font-normal text-[calc(0.8rem*var(--ui-font-scale,1))] select-none",
|
||||
defaultClassNames.weekday,
|
||||
),
|
||||
week: cn("flex w-full mt-2", defaultClassNames.week),
|
||||
|
|
@ -102,7 +102,7 @@ function Calendar({
|
|||
defaultClassNames.week_number_header,
|
||||
),
|
||||
week_number: cn(
|
||||
"text-[0.8rem] select-none text-muted-foreground",
|
||||
"text-[calc(0.8rem*var(--ui-font-scale,1))] select-none text-muted-foreground",
|
||||
defaultClassNames.week_number,
|
||||
),
|
||||
day: cn(
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ function ChartTooltipContent({
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"border-border/50 corner-squircle bg-background gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl grid min-w-[128px] items-start",
|
||||
"border-border/50 corner-squircle bg-background gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl grid min-w-[8rem] items-start",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export function CopyableErrorChip({
|
|||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex max-w-[448px] min-w-0 cursor-pointer items-center rounded-md text-left text-xs text-destructive transition-colors hover:bg-destructive/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
||||
"flex max-w-[28rem] min-w-0 cursor-pointer items-center rounded-md text-left text-xs text-destructive transition-colors hover:bg-destructive/10 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
@ -63,7 +63,7 @@ export function CopyableErrorChip({
|
|||
<PopoverContent
|
||||
align="start"
|
||||
side="bottom"
|
||||
className="w-[min(576px,calc(100vw-16px))] gap-2"
|
||||
className="w-[min(36rem,calc(100vw-1rem))] gap-2"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<span className="text-xs font-medium text-destructive">Error</span>
|
||||
|
|
@ -72,7 +72,7 @@ export function CopyableErrorChip({
|
|||
onClick={handleCopy}
|
||||
aria-label={copied ? "Copied" : "Copy error message"}
|
||||
className={cn(
|
||||
"inline-flex items-center gap-1 rounded-md border border-border/60 px-2 py-1 text-[0.6875rem] text-muted-foreground transition-colors hover:bg-muted/60 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
||||
"inline-flex items-center gap-1 rounded-md border border-border/60 px-2 py-1 text-ui-11 text-muted-foreground transition-colors hover:bg-muted/60 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
||||
copied && "border-emerald-500/40 text-emerald-600 dark:text-emerald-500",
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ export function DataTable<TData, TValue>({
|
|||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
className="border-r border-border/20 last:border-r-0 text-[0.8125rem] py-3 px-4 align-top whitespace-normal"
|
||||
className="border-r border-border/20 last:border-r-0 text-ui-13 py-3 px-4 align-top whitespace-normal"
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ function DialogContent({
|
|||
<DialogPrimitive.Content
|
||||
data-slot="dialog-content"
|
||||
className={cn(
|
||||
"bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/5 grid max-w-[calc(100%-32px)] gap-6 rounded-4xl px-7 pt-8 pb-7 text-sm ring-1 duration-100 sm:max-w-md top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2",
|
||||
"bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/5 grid max-w-[calc(100%-2rem)] gap-6 rounded-4xl px-7 pt-8 pb-7 text-sm ring-1 duration-100 sm:max-w-md top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2",
|
||||
position === "fixed" ? "fixed" : "absolute",
|
||||
className,
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ const inputGroupAddonVariants = cva(
|
|||
variants: {
|
||||
align: {
|
||||
"inline-start":
|
||||
"pl-3 has-[>button]:ml-[-4px] has-[>kbd]:ml-[-2.4px] order-first",
|
||||
"pl-3 has-[>button]:ml-[-0.25rem] has-[>kbd]:ml-[-0.15rem] order-first",
|
||||
"inline-end":
|
||||
"pr-3 has-[>button]:mr-[-4px] has-[>kbd]:mr-[-2.4px] order-last",
|
||||
"pr-3 has-[>button]:mr-[-0.25rem] has-[>kbd]:mr-[-0.15rem] order-last",
|
||||
"block-start":
|
||||
"px-3 pt-3 group-has-[>input]/input-group:pt-3 [.border-b]:pb-3 order-first w-full justify-start",
|
||||
"block-end":
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ import { LayoutAlignLeftIcon } from "@hugeicons/core-free-icons"
|
|||
|
||||
const noop = () => {}
|
||||
|
||||
const SIDEBAR_WIDTH = "280px"
|
||||
const SIDEBAR_WIDTH_ICON = "48px"
|
||||
const SIDEBAR_WIDTH = "17.5rem"
|
||||
const SIDEBAR_WIDTH_ICON = "3rem"
|
||||
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
|
||||
|
||||
type SidebarContextProps = {
|
||||
|
|
@ -228,7 +228,7 @@ function Sidebar({
|
|||
data-sidebar="sidebar"
|
||||
data-slot="sidebar"
|
||||
data-mobile="true"
|
||||
className="bg-sidebar text-sidebar-foreground w-2/3 max-w-[288px] p-0 [&>button]:hidden"
|
||||
className="bg-sidebar text-sidebar-foreground w-2/3 max-w-[18rem] p-0 [&>button]:hidden"
|
||||
side={side}
|
||||
>
|
||||
<SheetHeader className="sr-only">
|
||||
|
|
@ -471,7 +471,7 @@ function SidebarGroupLabel({
|
|||
data-slot="sidebar-group-label"
|
||||
data-sidebar="group-label"
|
||||
className={cn(
|
||||
"text-[#94a3b8] dark:text-[#666] ring-sidebar-ring h-auto pt-3 pb-2 px-4 rounded-md text-[0.625rem] font-semibold uppercase tracking-[0em] group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-1 [&>svg]:size-3 flex shrink-0 items-center outline-hidden [&>svg]:shrink-0",
|
||||
"text-[#94a3b8] dark:text-[#666] ring-sidebar-ring h-auto pt-3 pb-2 px-4 rounded-md text-ui-10 font-semibold uppercase tracking-[0em] group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-1 [&>svg]:size-3 flex shrink-0 items-center outline-hidden [&>svg]:shrink-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export function WebUpdateBanner({
|
|||
transition={{ duration: 0.35, ease: EASE_OUT_QUART }}
|
||||
className={cn(
|
||||
positioned
|
||||
? "fixed bottom-4 right-4 z-[9999] w-[calc(100vw-32px)] max-w-[400px]"
|
||||
? "fixed bottom-4 right-4 z-[9999] w-[calc(100vw-2rem)] max-w-[400px]"
|
||||
: "pointer-events-auto w-full",
|
||||
)}
|
||||
data-testid="web-update-banner"
|
||||
|
|
@ -132,7 +132,7 @@ export function WebUpdateBanner({
|
|||
href={RELEASE_NOTES_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="-ml-2 whitespace-nowrap rounded-full px-2.5 py-2 text-[0.8125rem] font-medium text-foreground transition-colors hover:bg-muted"
|
||||
className="-ml-2 whitespace-nowrap rounded-full px-2.5 py-2 text-ui-13 font-medium text-foreground transition-colors hover:bg-muted"
|
||||
data-testid="web-update-release-notes-link"
|
||||
>
|
||||
Release notes
|
||||
|
|
@ -142,7 +142,7 @@ export function WebUpdateBanner({
|
|||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-auto rounded-full px-3 py-2 text-[0.8125rem] font-medium text-foreground"
|
||||
className="h-auto rounded-full px-3 py-2 text-ui-13 font-medium text-foreground"
|
||||
onClick={snooze}
|
||||
data-testid="web-update-snooze-button"
|
||||
>
|
||||
|
|
@ -151,7 +151,7 @@ export function WebUpdateBanner({
|
|||
<Button
|
||||
size="sm"
|
||||
// -mr optically aligns the filled pill's edge with the card padding
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-[0.8125rem]"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-ui-13"
|
||||
onClick={handleCopyCommand}
|
||||
data-testid="web-update-copy-button"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export function LoginPage() {
|
|||
length="70vh"
|
||||
className="opacity-35 dark:opacity-15"
|
||||
/>
|
||||
<Card className="relative z-10 w-full max-w-sm rounded-[40px] px-7 py-8 shadow-border ring-0 sm:px-8 sm:py-10">
|
||||
<Card className="relative z-10 w-full max-w-sm rounded-[2.5rem] px-7 py-8 shadow-border ring-0 sm:px-8 sm:py-10">
|
||||
<AuthForm mode="login" />
|
||||
</Card>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -145,12 +145,12 @@ export function ArtifactCard({
|
|||
<span className="truncate text-sm font-medium leading-tight text-foreground">
|
||||
{isCode ? "HTML Code" : artifact.title}
|
||||
</span>
|
||||
<span className="truncate text-[0.6875rem] leading-none text-muted-foreground">
|
||||
<span className="truncate text-ui-11 leading-none text-muted-foreground">
|
||||
HTML canvas
|
||||
</span>
|
||||
</span>
|
||||
{isStreaming && !isCode ? (
|
||||
<span className="shimmer shrink-0 rounded-full bg-primary/10 px-2 py-0.5 text-[0.625rem] font-medium text-primary motion-reduce:animate-none">
|
||||
<span className="shimmer shrink-0 rounded-full bg-primary/10 px-2 py-0.5 text-ui-10 font-medium text-primary motion-reduce:animate-none">
|
||||
Generating
|
||||
</span>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -576,7 +576,7 @@ function CompareShell({
|
|||
{children}
|
||||
</div>
|
||||
<div className="shrink-0 bg-background pl-5 pr-5 md:pr-[30px] pb-2 pt-1">
|
||||
<div className="mx-auto w-full max-w-[768px]">{composer}</div>
|
||||
<div className="mx-auto w-full max-w-[48rem]">{composer}</div>
|
||||
{showModelDisclaimer && (
|
||||
<p className="composer-footer-note">
|
||||
LLMs can make mistakes. Double-check responses.
|
||||
|
|
@ -651,7 +651,7 @@ const LoraCompareContent = memo(function LoraCompareContent({
|
|||
handleName="base"
|
||||
header={
|
||||
<div className="shrink-0 px-3 py-1.5">
|
||||
<span className="text-[0.625rem] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<span className="text-ui-10 font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
Base Model
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -665,8 +665,8 @@ const LoraCompareContent = memo(function LoraCompareContent({
|
|||
handleName="lora"
|
||||
borderClassName="border-t border-border/60 md:border-t-0 md:border-l"
|
||||
header={
|
||||
<div className="shrink-0 px-3 py-1.5 text-start md:text-end md:pr-[calc(64px+var(--studio-chat-header-right-inset,var(--studio-window-control-inset,0px)))]">
|
||||
<span className="text-[0.625rem] font-semibold uppercase tracking-wider text-primary">
|
||||
<div className="shrink-0 px-3 py-1.5 text-start md:text-end md:pr-[calc(4rem+var(--studio-chat-header-right-inset,var(--studio-window-control-inset,0px)))]">
|
||||
<span className="text-ui-10 font-semibold uppercase tracking-wider text-primary">
|
||||
Fine-tuned
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -721,8 +721,8 @@ function GeneralCompareHeader({
|
|||
side === "left"
|
||||
? pinned
|
||||
? "pl-12 pr-3 md:pl-2"
|
||||
: "pl-12 pr-3 md:pl-[calc(8px+max(0px,var(--studio-mac-traffic-light-inset,0px)-var(--sidebar-width-icon,48px)))]"
|
||||
: "pl-3 pr-[calc(48px+var(--studio-chat-header-right-inset,var(--studio-window-control-inset,0px)))]",
|
||||
: "pl-12 pr-3 md:pl-[calc(0.5rem+max(0px,var(--studio-mac-traffic-light-inset,0px)-var(--sidebar-width-icon,3rem)))]"
|
||||
: "pl-3 pr-[calc(3rem+var(--studio-chat-header-right-inset,var(--studio-window-control-inset,0px)))]",
|
||||
)}
|
||||
>
|
||||
<ModelSelector
|
||||
|
|
@ -1265,12 +1265,12 @@ function ProjectLanding({
|
|||
className="flex min-h-0 min-w-0 flex-1 basis-0 overflow-y-auto px-5"
|
||||
style={
|
||||
{
|
||||
["--thread-max-width" as string]: "768px",
|
||||
["--thread-max-width" as string]: "48rem",
|
||||
} as CSSProperties
|
||||
}
|
||||
>
|
||||
{/* Slightly narrower than the composer max; every block shares this. */}
|
||||
<div className="mx-auto flex w-full max-w-[704px] flex-col pt-[120px] pb-14">
|
||||
<div className="mx-auto flex w-full max-w-[44rem] flex-col pt-[120px] pb-14">
|
||||
<div className="mb-12 flex items-center gap-4">
|
||||
<span className="flex size-13 shrink-0 items-center justify-center rounded-[18px] bg-muted text-foreground/80">
|
||||
<HugeiconsIcon
|
||||
|
|
@ -1279,7 +1279,7 @@ function ProjectLanding({
|
|||
className="size-6.5"
|
||||
/>
|
||||
</span>
|
||||
<h1 className="min-w-0 flex-1 truncate font-sans text-[1.875rem] font-medium leading-tight tracking-normal text-foreground">
|
||||
<h1 className="min-w-0 flex-1 truncate font-sans text-ui-30 font-medium leading-tight tracking-normal text-foreground">
|
||||
{projectName}
|
||||
</h1>
|
||||
<DropdownMenu>
|
||||
|
|
@ -1349,7 +1349,7 @@ function ProjectLanding({
|
|||
type="button"
|
||||
onClick={() => setProjectTab("chats")}
|
||||
data-active={projectTab === "chats"}
|
||||
className="h-10 rounded-full px-5 text-[0.875rem] font-semibold transition-colors data-[active=true]:bg-muted data-[active=true]:text-foreground data-[active=false]:text-muted-foreground data-[active=false]:hover:bg-nav-surface-hover"
|
||||
className="h-10 rounded-full px-5 text-ui-14 font-semibold transition-colors data-[active=true]:bg-muted data-[active=true]:text-foreground data-[active=false]:text-muted-foreground data-[active=false]:hover:bg-nav-surface-hover"
|
||||
>
|
||||
Chats
|
||||
</button>
|
||||
|
|
@ -1357,7 +1357,7 @@ function ProjectLanding({
|
|||
type="button"
|
||||
onClick={() => setProjectTab("sources")}
|
||||
data-active={projectTab === "sources"}
|
||||
className="h-10 rounded-full px-5 text-[0.875rem] font-semibold transition-colors data-[active=true]:bg-muted data-[active=true]:text-foreground data-[active=false]:text-muted-foreground data-[active=false]:hover:bg-nav-surface-hover"
|
||||
className="h-10 rounded-full px-5 text-ui-14 font-semibold transition-colors data-[active=true]:bg-muted data-[active=true]:text-foreground data-[active=false]:text-muted-foreground data-[active=false]:hover:bg-nav-surface-hover"
|
||||
>
|
||||
Sources
|
||||
</button>
|
||||
|
|
@ -1425,7 +1425,7 @@ function ProjectLanding({
|
|||
onFocus={(event) => event.currentTarget.select()}
|
||||
maxLength={120}
|
||||
aria-label="Rename chat"
|
||||
className="w-full border-0 bg-transparent text-[0.9375rem] font-semibold leading-5 text-foreground outline-none"
|
||||
className="w-full border-0 bg-transparent text-ui-15 font-semibold leading-5 text-foreground outline-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1450,11 +1450,11 @@ function ProjectLanding({
|
|||
className="flex min-h-[58px] min-w-0 flex-1 items-center gap-4 rounded-full px-4 py-2 text-left"
|
||||
>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="truncate text-[0.9375rem] font-semibold leading-5 text-foreground">
|
||||
<div className="truncate text-ui-15 font-semibold leading-5 text-foreground">
|
||||
{displayTitle}
|
||||
</div>
|
||||
</div>
|
||||
<span className="shrink-0 text-[0.875rem] text-muted-foreground transition-opacity max-md:opacity-0 pointer-coarse:opacity-0 group-hover:opacity-0 group-has-[[data-state=open]]:opacity-0">
|
||||
<span className="shrink-0 text-ui-14 text-muted-foreground transition-opacity max-md:opacity-0 pointer-coarse:opacity-0 group-hover:opacity-0 group-has-[[data-state=open]]:opacity-0">
|
||||
{preview?.date ??
|
||||
formatProjectChatDate(item.createdAt)}
|
||||
</span>
|
||||
|
|
@ -3113,14 +3113,14 @@ export function ChatPage({
|
|||
)}
|
||||
<div
|
||||
className={cn(
|
||||
"pointer-events-none absolute top-[var(--studio-content-top-inset,0px)] left-0 right-[10px] z-40 flex h-[var(--studio-chat-header-height,48px)] shrink-0 items-start bg-background pt-[var(--studio-chat-header-padding-top,11px)] pr-[calc(8px+var(--studio-chat-header-right-inset,var(--studio-window-control-inset,0px)))]",
|
||||
"pointer-events-none absolute top-[var(--studio-content-top-inset,0px)] left-0 right-[10px] z-40 flex h-[var(--studio-chat-header-height,48px)] shrink-0 items-start bg-background pt-[var(--studio-chat-header-padding-top,11px)] pr-[calc(0.5rem+var(--studio-chat-header-right-inset,var(--studio-window-control-inset,0px)))]",
|
||||
isMobile
|
||||
? "pl-12"
|
||||
: pinned
|
||||
? "pl-2"
|
||||
: "pl-[calc(8px+max(0px,var(--studio-mac-traffic-light-inset,0px)-var(--sidebar-width-icon,48px)))]",
|
||||
: "pl-[calc(0.5rem+max(0px,var(--studio-mac-traffic-light-inset,0px)-var(--sidebar-width-icon,3rem)))]",
|
||||
view.mode === "compare" &&
|
||||
"right-[10px] left-auto w-auto bg-transparent pl-0 pr-[calc(8px+var(--studio-chat-header-right-inset,var(--studio-window-control-inset,0px)))]",
|
||||
"right-[10px] left-auto w-auto bg-transparent pl-0 pr-[calc(0.5rem+var(--studio-chat-header-right-inset,var(--studio-window-control-inset,0px)))]",
|
||||
)}
|
||||
>
|
||||
<div className="pointer-events-auto flex items-center gap-1">
|
||||
|
|
@ -3149,7 +3149,7 @@ export function ChatPage({
|
|||
/>
|
||||
)}
|
||||
{incognito && view.mode === "single" && (
|
||||
<div className="flex h-[var(--studio-chat-control-height,34px)] shrink-0 items-center gap-1.5 self-center rounded-full bg-primary/10 px-2.5 font-medium text-[0.8125rem] text-primary">
|
||||
<div className="flex h-[var(--studio-chat-control-height,34px)] shrink-0 items-center gap-1.5 self-center rounded-full bg-primary/10 px-2.5 font-medium text-ui-13 text-primary">
|
||||
<HugeiconsIcon
|
||||
icon={BubbleChatTemporaryIcon}
|
||||
strokeWidth={2}
|
||||
|
|
@ -3161,7 +3161,7 @@ export function ChatPage({
|
|||
{view.mode !== "compare" && currentProjectId && (
|
||||
<nav
|
||||
aria-label="Project location"
|
||||
className="flex h-[var(--studio-chat-control-height,34px)] min-w-0 items-center gap-1.5 self-center text-[0.84375rem] tracking-nav text-muted-foreground"
|
||||
className="flex h-[var(--studio-chat-control-height,34px)] min-w-0 items-center gap-1.5 self-center text-ui-13p5 tracking-nav text-muted-foreground"
|
||||
>
|
||||
<ProjectSwitcher
|
||||
currentProject={currentProject}
|
||||
|
|
|
|||
|
|
@ -1556,7 +1556,7 @@ export function ChatProvidersSettings({
|
|||
</div>
|
||||
<p
|
||||
id="chat-connections-description"
|
||||
className="max-w-md text-[0.6875rem] leading-snug text-muted-foreground/65 sm:text-right"
|
||||
className="max-w-md text-ui-11 leading-snug text-muted-foreground/65 sm:text-right"
|
||||
>
|
||||
When off, all connections are disabled.
|
||||
</p>
|
||||
|
|
@ -1616,7 +1616,7 @@ export function ChatProvidersSettings({
|
|||
<span className="truncate text-sm font-medium text-foreground">
|
||||
{provider.name}
|
||||
</span>
|
||||
<span className="shrink-0 rounded-[6px] border border-control-accent/15 bg-control-accent/8 px-1.5 py-0.5 text-[0.625rem] leading-none text-control-accent">
|
||||
<span className="shrink-0 rounded-[6px] border border-control-accent/15 bg-control-accent/8 px-1.5 py-0.5 text-ui-10 leading-none text-control-accent">
|
||||
{provider.models.length}{" "}
|
||||
{provider.models.length === 1 ? "model" : "models"}
|
||||
</span>
|
||||
|
|
@ -1631,7 +1631,7 @@ export function ChatProvidersSettings({
|
|||
) : null}
|
||||
</div>
|
||||
<div
|
||||
className="mt-1 truncate text-[0.6875rem] leading-4 text-muted-foreground/80"
|
||||
className="mt-1 truncate text-ui-11 leading-4 text-muted-foreground/80"
|
||||
title={provider.models.join(", ")}
|
||||
>
|
||||
{modelSummary}
|
||||
|
|
@ -1702,7 +1702,7 @@ export function ChatProvidersDialog({
|
|||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent
|
||||
overlayClassName="bg-black/50 backdrop-blur-sm"
|
||||
className="flex max-h-[90dvh] w-[96vw] flex-col gap-0 overflow-y-auto p-8 sm:max-w-none md:max-w-[704px]"
|
||||
className="flex max-h-[90dvh] w-[96vw] flex-col gap-0 overflow-y-auto p-8 sm:max-w-none md:max-w-[44rem]"
|
||||
>
|
||||
<DialogHeader className="sr-only">
|
||||
<DialogTitle>Connections</DialogTitle>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ export function ParamSlider({
|
|||
<div className="space-y-3.5">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="min-w-0 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
{label}
|
||||
</span>
|
||||
{info && <InfoHint>{info}</InfoHint>}
|
||||
|
|
@ -249,7 +249,7 @@ function CollapsibleSection({
|
|||
};
|
||||
|
||||
const headerClasses = cn(
|
||||
"flex w-full items-center justify-between text-[0.75rem] font-medium normal-case tracking-[0.04em] text-nav-fg-muted transition-colors focus-visible:outline-none focus-visible:ring-0",
|
||||
"flex w-full items-center justify-between text-ui-12 font-medium normal-case tracking-[0.04em] text-nav-fg-muted transition-colors focus-visible:outline-none focus-visible:ring-0",
|
||||
first ? "pt-4 pb-5" : "py-5",
|
||||
);
|
||||
|
||||
|
|
@ -695,12 +695,12 @@ export function ChatSettingsPanel({
|
|||
{/* Header is outside the scroll area so the scrollbar never shifts the close button. */}
|
||||
<div className="flex h-[48px] shrink-0 items-start gap-2 bg-panel-surface pl-[18px] pr-[16px] pt-[11px]">
|
||||
{isMobile ? (
|
||||
<span className="flex h-[34px] flex-1 items-center text-[1rem] font-semibold tracking-[0em] dark:tracking-[0.015em] text-nav-fg">
|
||||
<span className="flex h-[34px] flex-1 items-center text-ui-16 font-semibold tracking-[0em] dark:tracking-[0.015em] text-nav-fg">
|
||||
Run settings
|
||||
</span>
|
||||
) : (
|
||||
<>
|
||||
<span className="flex h-[34px] flex-1 items-center text-[1rem] font-semibold tracking-[0em] dark:tracking-[0.015em] text-nav-fg">
|
||||
<span className="flex h-[34px] flex-1 items-center text-ui-16 font-semibold tracking-[0em] dark:tracking-[0.015em] text-nav-fg">
|
||||
Run settings
|
||||
</span>
|
||||
<Tooltip>
|
||||
|
|
@ -740,7 +740,7 @@ export function ChatSettingsPanel({
|
|||
<div className="flex flex-col gap-3 pt-1">
|
||||
{modelConfig}
|
||||
{showSpecFallback && (
|
||||
<div className="rounded-lg bg-amber-500/[0.08] px-3 py-2 text-[0.75rem] leading-[1.4] text-nav-fg/80">
|
||||
<div className="rounded-lg bg-amber-500/[0.08] px-3 py-2 text-ui-12 leading-[1.4] text-nav-fg/80">
|
||||
<p>
|
||||
{specFallbackReason === "mla_mtp_disabled"
|
||||
? "MTP is disabled by default for this model architecture because it currently runs slower than standard decoding. Choose MTP in the model picker to force it."
|
||||
|
|
@ -757,7 +757,7 @@ export function ChatSettingsPanel({
|
|||
{mtpUpdatable && llamaUpdateStatus?.update_available && (
|
||||
<Button
|
||||
size="sm"
|
||||
className="corner-squircle mt-2 h-7 text-[0.75rem]"
|
||||
className="corner-squircle mt-2 h-7 text-ui-12"
|
||||
onClick={handleMtpUpdate}
|
||||
disabled={llamaUpdating}
|
||||
data-test-id="mtp-update-button"
|
||||
|
|
@ -768,7 +768,7 @@ export function ChatSettingsPanel({
|
|||
</div>
|
||||
)}
|
||||
{showContextVramWarning && (
|
||||
<p className="text-[0.6875rem] text-amber-500">
|
||||
<p className="text-ui-11 text-amber-500">
|
||||
Context length exceeds the estimated VRAM capacity (
|
||||
{ggufMaxContextLength?.toLocaleString()} tokens). The
|
||||
model may use system RAM.
|
||||
|
|
@ -812,7 +812,7 @@ export function ChatSettingsPanel({
|
|||
maxLength={80}
|
||||
autoComplete="off"
|
||||
className={cn(
|
||||
"!h-9 min-h-0 min-w-0 self-stretch !pl-3.5 !pr-2 py-0 text-[0.8125rem] font-medium leading-9 text-nav-fg md:text-[0.8125rem]",
|
||||
"!h-9 min-h-0 min-w-0 self-stretch !pl-3.5 !pr-2 py-0 text-ui-13 font-medium leading-9 text-nav-fg md:text-ui-13",
|
||||
presetSaveState.isSaveReady &&
|
||||
"placeholder:text-primary/50",
|
||||
)}
|
||||
|
|
@ -852,7 +852,7 @@ export function ChatSettingsPanel({
|
|||
}
|
||||
applyPreset(p.name);
|
||||
}}
|
||||
className="flex min-h-9 items-center px-3 py-0 text-[0.8125rem] font-medium leading-[1.4] tracking-nav"
|
||||
className="flex min-h-9 items-center px-3 py-0 text-ui-13 font-medium leading-[1.4] tracking-nav"
|
||||
>
|
||||
{p.name}
|
||||
</DropdownMenuItem>
|
||||
|
|
@ -874,7 +874,7 @@ export function ChatSettingsPanel({
|
|||
}
|
||||
size="sm"
|
||||
className={cn(
|
||||
"h-9 w-full rounded-full text-[0.8125rem] font-medium tracking-nav",
|
||||
"h-9 w-full rounded-full text-ui-13 font-medium tracking-nav",
|
||||
presetSaveState.isSaveReady &&
|
||||
"bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
)}
|
||||
|
|
@ -889,7 +889,7 @@ export function ChatSettingsPanel({
|
|||
disabled={!(settingsHydrated && activeCustomPreset)}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-9 w-full rounded-full text-[0.8125rem] font-medium tracking-nav text-muted-foreground"
|
||||
className="h-9 w-full rounded-full text-ui-13 font-medium tracking-nav text-muted-foreground"
|
||||
title={
|
||||
activeCustomPreset
|
||||
? activeBuiltinPreset
|
||||
|
|
@ -908,7 +908,7 @@ export function ChatSettingsPanel({
|
|||
<CollapsibleSection label="Provider" defaultOpen={true}>
|
||||
<div className="flex items-center justify-between gap-3 pt-1">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="min-w-0 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Prompt caching
|
||||
</span>
|
||||
<InfoHint>
|
||||
|
|
@ -931,7 +931,7 @@ export function ChatSettingsPanel({
|
|||
{showPromptCacheTtlControl && promptCachingEnabled ? (
|
||||
<div className="flex items-center justify-between gap-3 pt-3">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="min-w-0 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Cache TTL
|
||||
</span>
|
||||
<InfoHint>
|
||||
|
|
@ -968,7 +968,7 @@ export function ChatSettingsPanel({
|
|||
{showFastModeControl ? (
|
||||
<div className="flex items-center justify-between gap-3 pt-3">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="min-w-0 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Fast mode
|
||||
</span>
|
||||
<InfoHint>
|
||||
|
|
@ -1056,7 +1056,7 @@ export function ChatSettingsPanel({
|
|||
placeholder="Example: You are a helpful assistant..."
|
||||
aria-label="System prompt"
|
||||
className={cn(
|
||||
"block size-full resize-none bg-transparent px-3.5 py-2.5 text-left text-[0.8125rem] font-medium leading-relaxed text-nav-fg outline-none placeholder:text-muted-foreground",
|
||||
"block size-full resize-none bg-transparent px-3.5 py-2.5 text-left text-ui-13 font-medium leading-relaxed text-nav-fg outline-none placeholder:text-muted-foreground",
|
||||
systemPromptOverflows && "cursor-pointer",
|
||||
)}
|
||||
/>
|
||||
|
|
@ -1202,13 +1202,13 @@ export function ChatSettingsPanel({
|
|||
<div className="space-y-3">
|
||||
<div className="space-y-0.5 px-0.5">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="text-[0.6875rem] font-medium">Prompt editor</div>
|
||||
<div className="text-ui-11 font-medium">Prompt editor</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setSystemVariablesOpen((open) => !open)}
|
||||
className="h-7 gap-1.5 rounded-full px-2.5 text-[0.6875rem] text-muted-foreground"
|
||||
className="h-7 gap-1.5 rounded-full px-2.5 text-ui-11 text-muted-foreground"
|
||||
aria-expanded={systemVariablesOpen}
|
||||
>
|
||||
<Braces className="size-3.5" />
|
||||
|
|
@ -1221,7 +1221,7 @@ export function ChatSettingsPanel({
|
|||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-[0.6875rem] text-muted-foreground">
|
||||
<p className="text-ui-11 text-muted-foreground">
|
||||
Use this for longer edits. Save writes back to the active
|
||||
configuration only. Insert variables with {"{{ env }}"}.
|
||||
</p>
|
||||
|
|
@ -1230,16 +1230,16 @@ export function ChatSettingsPanel({
|
|||
<div className="space-y-2 px-0.5">
|
||||
<div className="flex flex-wrap items-start justify-between gap-2">
|
||||
<div className="space-y-0.5">
|
||||
<div className="text-[0.6875rem] font-medium">
|
||||
<div className="text-ui-11 font-medium">
|
||||
Prompt variables
|
||||
</div>
|
||||
<p className="text-[0.6875rem] text-muted-foreground">
|
||||
<p className="text-ui-11 text-muted-foreground">
|
||||
Define values as JSON below, then use each key in your
|
||||
prompt, like {"{{ env }}"}.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col items-end gap-1">
|
||||
<span className="text-[0.625rem] text-muted-foreground">
|
||||
<span className="text-ui-10 text-muted-foreground">
|
||||
Built-in, fill in automatically
|
||||
</span>
|
||||
<div className="flex flex-wrap justify-end gap-1">
|
||||
|
|
@ -1247,7 +1247,7 @@ export function ChatSettingsPanel({
|
|||
<span
|
||||
key={token}
|
||||
title={`${token} is replaced automatically when you send`}
|
||||
className="rounded-full bg-muted px-2 py-0.5 font-mono text-[0.625rem] text-muted-foreground"
|
||||
className="rounded-full bg-muted px-2 py-0.5 font-mono text-ui-10 text-muted-foreground"
|
||||
>
|
||||
{token}
|
||||
</span>
|
||||
|
|
@ -1272,11 +1272,11 @@ export function ChatSettingsPanel({
|
|||
aria-invalid={Boolean(systemVariablesError)}
|
||||
/>
|
||||
{systemVariablesError ? (
|
||||
<p className="px-1 text-[0.6875rem] text-destructive">
|
||||
<p className="px-1 text-ui-11 text-destructive">
|
||||
{systemVariablesError}
|
||||
</p>
|
||||
) : (
|
||||
<p className="px-1 text-[0.6875rem] text-muted-foreground">
|
||||
<p className="px-1 text-ui-11 text-muted-foreground">
|
||||
Names you don't define are left unchanged, so a stray
|
||||
{" {{ typo }} "}stays visible in the prompt.
|
||||
</p>
|
||||
|
|
@ -1288,7 +1288,7 @@ export function ChatSettingsPanel({
|
|||
onChange={(event) => setSystemPromptDraft(event.target.value)}
|
||||
placeholder="You are a helpful assistant..."
|
||||
fieldSizing="fixed"
|
||||
className="min-h-[320px] max-h-[48vh] overflow-y-auto border-0 text-sm leading-6 corner-squircle focus-visible:ring-0"
|
||||
className="min-h-[20rem] max-h-[48vh] overflow-y-auto border-0 text-sm leading-6 corner-squircle focus-visible:ring-0"
|
||||
rows={14}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -1333,7 +1333,7 @@ export function ChatSettingsPanel({
|
|||
if (isMobile) {
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={onOpenChange}>
|
||||
<SheetContent side="right" className="w-[288px] p-0 font-heading">
|
||||
<SheetContent side="right" className="w-[18rem] p-0 font-heading">
|
||||
<SheetHeader className="sr-only">
|
||||
<SheetTitle>Run settings</SheetTitle>
|
||||
<SheetDescription>Chat inference settings</SheetDescription>
|
||||
|
|
@ -1351,7 +1351,7 @@ export function ChatSettingsPanel({
|
|||
data-tour="chat-settings"
|
||||
className={cn(
|
||||
"relative z-50 shrink-0 overflow-hidden bg-panel-surface text-panel-surface-fg font-heading",
|
||||
open ? "w-[272px] border-l border-sidebar-border" : "w-0",
|
||||
open ? "w-[17rem] border-l border-sidebar-border" : "w-0",
|
||||
)}
|
||||
style={{
|
||||
height: "calc(100% - var(--studio-custom-titlebar-height, 0px))",
|
||||
|
|
@ -1426,7 +1426,7 @@ function AutoHealToolCallsToggle() {
|
|||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="min-w-0 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Auto-Healing Tool Calls
|
||||
</span>
|
||||
<InfoHint>
|
||||
|
|
@ -1450,7 +1450,7 @@ function NudgeToolCallsToggle() {
|
|||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="min-w-0 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Nudge Tool Calls
|
||||
</span>
|
||||
<InfoHint>
|
||||
|
|
@ -1475,7 +1475,7 @@ function ConfirmToolCallsToggle() {
|
|||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex min-w-0 flex-col gap-0.5">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="min-w-0 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Confirm tool calls
|
||||
</span>
|
||||
<InfoHint>
|
||||
|
|
@ -1487,7 +1487,7 @@ function ConfirmToolCallsToggle() {
|
|||
</InfoHint>
|
||||
</div>
|
||||
{permissionMode === "full" ? (
|
||||
<span className="text-[0.6875rem] text-muted-foreground">
|
||||
<span className="text-ui-11 text-muted-foreground">
|
||||
Overridden by Full access
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -1508,7 +1508,7 @@ function BypassPermissionsToggle() {
|
|||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="whitespace-nowrap text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="whitespace-nowrap text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Tool permissions
|
||||
</span>
|
||||
<InfoHint>
|
||||
|
|
@ -1517,9 +1517,9 @@ function BypassPermissionsToggle() {
|
|||
</InfoHint>
|
||||
</div>
|
||||
{/* Full width, styled like the panel selects/preset input. */}
|
||||
<PermissionModeDropdown triggerClassName="h-9 w-full justify-between rounded-full border-0 bg-[var(--panel-input-surface)] px-3.5 text-[0.8125rem] font-medium text-nav-fg shadow-none hover:bg-[var(--panel-input-surface)]" />
|
||||
<PermissionModeDropdown triggerClassName="h-9 w-full justify-between rounded-full border-0 bg-[var(--panel-input-surface)] px-3.5 text-ui-13 font-medium text-nav-fg shadow-none hover:bg-[var(--panel-input-surface)]" />
|
||||
{permissionMode === "full" ? (
|
||||
<span className="text-[0.6875rem] text-bypass">
|
||||
<span className="text-ui-11 text-bypass">
|
||||
Tool calls run with no confirmation and no sandbox.
|
||||
</span>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ export function ChatSearchDialog() {
|
|||
<CommandDialog
|
||||
open={isOpen}
|
||||
onOpenChange={setOpen}
|
||||
className="chat-search-surface rounded-3xl! top-1/2 -translate-y-1/2 w-[635px] max-w-[calc(100%-32px)] gap-0 p-0 ring-0 sm:max-w-[635px]"
|
||||
className="chat-search-surface rounded-3xl! top-1/2 -translate-y-1/2 w-[635px] max-w-[calc(100%-2rem)] gap-0 p-0 ring-0 sm:max-w-[635px]"
|
||||
overlayClassName="bg-transparent supports-backdrop-filter:backdrop-blur-none"
|
||||
>
|
||||
<Command className="rounded-3xl p-0" shouldFilter={false}>
|
||||
|
|
@ -143,10 +143,10 @@ export function ChatSearchDialog() {
|
|||
strokeWidth={2}
|
||||
className="size-4 shrink-0 text-muted-foreground"
|
||||
/>
|
||||
<span className="min-w-0 flex-1 truncate text-[0.8125rem] font-medium">
|
||||
<span className="min-w-0 flex-1 truncate text-ui-13 font-medium">
|
||||
{item.title || "Untitled chat"}
|
||||
</span>
|
||||
<span className="shrink-0 text-[0.6875rem] text-muted-foreground">
|
||||
<span className="shrink-0 text-ui-11 text-muted-foreground">
|
||||
{formatRelative(item.createdAt)}
|
||||
</span>
|
||||
</CommandPrimitive.Item>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export const ContextUsageBar: FC<{
|
|||
: `Token usage: ${formatTokenCount(used)} tokens`
|
||||
}
|
||||
className={cn(
|
||||
"flex items-center gap-2 rounded-[10px] px-2.5 py-1 font-mono text-chat-icon-fg text-[0.8125rem] tabular-nums transition-colors hover:bg-chat-icon-bg-hover hover:text-chat-icon-fg-hover",
|
||||
"flex items-center gap-2 rounded-[10px] px-2.5 py-1 font-mono text-chat-icon-fg text-ui-13 tabular-nums transition-colors hover:bg-chat-icon-bg-hover hover:text-chat-icon-fg-hover",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
@ -149,7 +149,7 @@ export const ContextUsageBar: FC<{
|
|||
</span>
|
||||
</div>
|
||||
{hasKnownLimit && percent !== null && percent > 85 ? (
|
||||
<div className="mt-1 max-w-64 text-[0.6875rem] leading-snug text-muted-foreground/90">
|
||||
<div className="mt-1 max-w-64 text-ui-11 leading-snug text-muted-foreground/90">
|
||||
Close to the context limit. Generation will stop at 100%.
|
||||
Increase <span className="font-medium">Context Length</span> in
|
||||
the chat Settings panel to keep going.
|
||||
|
|
|
|||
|
|
@ -54,14 +54,14 @@ export function ModelLoadDescription({
|
|||
{title ? <p className="text-foreground leading-tight font-semibold">{title}</p> : null}
|
||||
{hasProgress ? (
|
||||
<div className="w-full pt-1">
|
||||
<div className="flex items-center justify-between gap-2 text-[0.625rem] font-medium tracking-[0.08em] text-muted-foreground/80">
|
||||
<div className="flex items-center justify-between gap-2 text-ui-10 font-medium tracking-[0.08em] text-muted-foreground/80">
|
||||
<span className="min-w-0 truncate">{labelPrimary}</span>
|
||||
<span className="shrink-0 tabular-nums">
|
||||
{Math.round(clampProgress(progressPercent))}%
|
||||
</span>
|
||||
</div>
|
||||
{labelSecondary ? (
|
||||
<div className="truncate pt-0.5 text-[0.625rem] font-medium tracking-[0.08em] text-muted-foreground/60">
|
||||
<div className="truncate pt-0.5 text-ui-10 font-medium tracking-[0.08em] text-muted-foreground/60">
|
||||
{labelSecondary}
|
||||
</div>
|
||||
) : null}
|
||||
|
|
@ -96,18 +96,18 @@ export function ModelLoadInlineStatus({
|
|||
const hasProgress = typeof progressPercent === "number";
|
||||
|
||||
return (
|
||||
<div className="flex min-w-[320px] items-center gap-2.5 text-muted-foreground" title={title}>
|
||||
<div className="flex min-w-[20rem] items-center gap-2.5 text-muted-foreground" title={title}>
|
||||
<div className="flex items-center gap-1.5 shrink-0">
|
||||
<Spinner className="size-3.5 shrink-0" />
|
||||
<span className="text-xs">{label}</span>
|
||||
</div>
|
||||
{hasProgress ? (
|
||||
<div className="flex min-w-0 flex-[1.35] items-center gap-2.5">
|
||||
<div className="min-w-[112px] flex-1">
|
||||
<div className="min-w-[7rem] flex-1">
|
||||
<Progress value={clampProgress(progressPercent)} className="h-1 bg-foreground/[0.08]" />
|
||||
</div>
|
||||
<div
|
||||
className="flex shrink-0 items-center gap-1 text-[0.625rem] font-medium tracking-[0.08em] text-muted-foreground/80"
|
||||
className="flex shrink-0 items-center gap-1 text-ui-10 font-medium tracking-[0.08em] text-muted-foreground/80"
|
||||
title={progressLabel ?? undefined}
|
||||
>
|
||||
{/* Tight inline layout: show only the primary (bytes) chunk;
|
||||
|
|
@ -124,7 +124,7 @@ export function ModelLoadInlineStatus({
|
|||
type="button"
|
||||
size="xs"
|
||||
variant="outline"
|
||||
className="shrink-0 text-[0.6875rem]"
|
||||
className="shrink-0 text-ui-11"
|
||||
onClick={onStop}
|
||||
>
|
||||
Stop
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ export function OpenAICodeExecSection({
|
|||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<label
|
||||
htmlFor="openai-container-ttl"
|
||||
className="min-w-0 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg"
|
||||
className="min-w-0 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg"
|
||||
>
|
||||
Idle timeout
|
||||
</label>
|
||||
|
|
@ -459,7 +459,7 @@ export function OpenAICodeExecSection({
|
|||
ACTIVE pill marks which one (no separate picker). */}
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-[0.6875rem] uppercase tracking-wider text-muted-foreground">
|
||||
<span className="text-ui-11 uppercase tracking-wider text-muted-foreground">
|
||||
Containers
|
||||
</span>
|
||||
<Button
|
||||
|
|
@ -531,15 +531,15 @@ export function OpenAICodeExecSection({
|
|||
{c.name ?? "(unnamed)"}
|
||||
</span>
|
||||
{isPending ? (
|
||||
<span className="shrink-0 rounded-sm bg-muted px-1 py-px text-[0.5625rem] font-medium uppercase tracking-wider text-muted-foreground">
|
||||
<span className="shrink-0 rounded-sm bg-muted px-1 py-px text-ui-9 font-medium uppercase tracking-wider text-muted-foreground">
|
||||
Creating
|
||||
</span>
|
||||
) : isActive ? (
|
||||
<span className="shrink-0 rounded-sm bg-primary/15 px-1 py-px text-[0.5625rem] font-medium uppercase tracking-wider text-primary">
|
||||
<span className="shrink-0 rounded-sm bg-primary/15 px-1 py-px text-ui-9 font-medium uppercase tracking-wider text-primary">
|
||||
Active
|
||||
</span>
|
||||
) : statusLabel ? (
|
||||
<span className="shrink-0 rounded-sm bg-muted px-1 py-px text-[0.5625rem] font-medium uppercase tracking-wider text-muted-foreground">
|
||||
<span className="shrink-0 rounded-sm bg-muted px-1 py-px text-ui-9 font-medium uppercase tracking-wider text-muted-foreground">
|
||||
{statusLabel}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -548,10 +548,10 @@ export function OpenAICodeExecSection({
|
|||
className="flex min-w-0 items-center gap-1.5 text-muted-foreground"
|
||||
title={c.id}
|
||||
>
|
||||
<span className="min-w-0 truncate font-mono text-[0.6875rem]">
|
||||
<span className="min-w-0 truncate font-mono text-ui-11">
|
||||
{shortContainerId(c.id)}
|
||||
</span>
|
||||
<span className="shrink-0 text-[0.625rem] uppercase tracking-wider">
|
||||
<span className="shrink-0 text-ui-10 uppercase tracking-wider">
|
||||
· {ttlMinutes}m
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export function ProjectSwitcher({
|
|||
className="size-icon shrink-0 text-foreground/70"
|
||||
/>
|
||||
<span className="flex min-w-0 flex-1 items-baseline">
|
||||
<span className="min-w-0 flex max-w-[150px] flex-1 items-baseline truncate font-heading text-[1rem] font-medium leading-tight text-black dark:text-white">
|
||||
<span className="min-w-0 flex max-w-[150px] flex-1 items-baseline truncate font-heading text-ui-16 font-medium leading-tight text-black dark:text-white">
|
||||
{label}
|
||||
</span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ const MODEL_LOAD_TOAST_CLASSNAMES = {
|
|||
title: "leading-5",
|
||||
description: "mt-0 w-full",
|
||||
cancelButton:
|
||||
"!h-auto !rounded-none !border-0 !bg-transparent !px-1 !text-[0.6875rem] !font-normal !text-muted-foreground hover:!bg-transparent hover:!text-destructive focus-visible:!text-destructive",
|
||||
"!h-auto !rounded-none !border-0 !bg-transparent !px-1 !text-ui-11 !font-normal !text-muted-foreground hover:!bg-transparent hover:!text-destructive focus-visible:!text-destructive",
|
||||
} as const;
|
||||
|
||||
const MODEL_LOADED_TOAST_CLASSNAMES = {
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ export function PermissionModeMenuItems({
|
|||
>
|
||||
<option.icon className="mt-0.5 size-4 shrink-0" strokeWidth={2} />
|
||||
<span className="flex min-w-0 flex-1 flex-col gap-0.5">
|
||||
<span className="text-[0.8125rem] leading-tight">{option.label}</span>
|
||||
<span className="text-ui-13 leading-tight">{option.label}</span>
|
||||
<span className="text-xs font-normal leading-snug text-muted-foreground">
|
||||
{option.description}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ export function ProjectsPage() {
|
|||
}}
|
||||
/>
|
||||
<div className="flex flex-wrap items-center justify-between gap-4">
|
||||
<h1 className="text-[1.875rem] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[2.125rem]">
|
||||
<h1 className="text-ui-30 font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-ui-34">
|
||||
Projects
|
||||
</h1>
|
||||
<div className="flex items-center gap-3">
|
||||
|
|
@ -419,7 +419,7 @@ export function ProjectsPage() {
|
|||
<DropdownMenuSubTrigger>Export All Projects</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent className="w-52">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-[0.6875rem] font-medium">
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-ui-11 font-medium">
|
||||
Combined
|
||||
</DropdownMenuLabel>
|
||||
{EXPORT_FORMATS_LIST.map(({ fmt, label }) => (
|
||||
|
|
@ -430,7 +430,7 @@ export function ProjectsPage() {
|
|||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-[0.6875rem] font-medium">
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-ui-11 font-medium">
|
||||
Per chat
|
||||
</DropdownMenuLabel>
|
||||
{EXPORT_FORMATS_LIST.map(({ fmt, label }) => (
|
||||
|
|
@ -445,7 +445,7 @@ export function ProjectsPage() {
|
|||
<DropdownMenuSubTrigger>Export Projects + Recents</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent className="w-52">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-[0.6875rem] font-medium">
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-ui-11 font-medium">
|
||||
Combined
|
||||
</DropdownMenuLabel>
|
||||
{EXPORT_FORMATS_LIST.map(({ fmt, label }) => (
|
||||
|
|
@ -456,7 +456,7 @@ export function ProjectsPage() {
|
|||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-[0.6875rem] font-medium">
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-ui-11 font-medium">
|
||||
Per chat
|
||||
</DropdownMenuLabel>
|
||||
{EXPORT_FORMATS_LIST.map(({ fmt, label }) => (
|
||||
|
|
@ -482,7 +482,7 @@ export function ProjectsPage() {
|
|||
|
||||
{!hasLoaded ? (
|
||||
<div className="mt-16">
|
||||
<div className="mb-1 flex items-center gap-3 px-5 pb-1 text-[0.8125rem] font-medium text-muted-foreground">
|
||||
<div className="mb-1 flex items-center gap-3 px-5 pb-1 text-ui-13 font-medium text-muted-foreground">
|
||||
<span className="flex-1">Name</span>
|
||||
<span className="w-40 shrink-0">Modified</span>
|
||||
<span className="w-8 shrink-0" />
|
||||
|
|
@ -526,7 +526,7 @@ export function ProjectsPage() {
|
|||
<div className="mt-16">
|
||||
{/* Column header. Name starts at the folder icon's left edge; the
|
||||
right-anchored columns keep Modified over its values. */}
|
||||
<div className="mb-1 flex items-center gap-3 px-5 pb-1 text-[0.8125rem] font-medium text-muted-foreground">
|
||||
<div className="mb-1 flex items-center gap-3 px-5 pb-1 text-ui-13 font-medium text-muted-foreground">
|
||||
<span className="flex-1">Name</span>
|
||||
<span className="w-40 shrink-0">Modified</span>
|
||||
<span className="w-8 shrink-0" />
|
||||
|
|
@ -571,7 +571,7 @@ export function ProjectsPage() {
|
|||
className="size-5"
|
||||
/>
|
||||
</span>
|
||||
<span className="min-w-0 flex-1 truncate text-[0.9375rem] font-semibold text-foreground">
|
||||
<span className="min-w-0 flex-1 truncate text-ui-15 font-semibold text-foreground">
|
||||
{project.name}
|
||||
</span>
|
||||
<span className="w-40 shrink-0 text-sm text-muted-foreground">
|
||||
|
|
|
|||
|
|
@ -1341,7 +1341,7 @@ function ExportModal({
|
|||
|
||||
{/* */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-[0.6875rem] font-semibold uppercase tracking-wider text-muted-foreground/60">
|
||||
<p className="text-ui-11 font-semibold uppercase tracking-wider text-muted-foreground/60">
|
||||
Export as
|
||||
</p>
|
||||
<div className="flex flex-col gap-2">
|
||||
|
|
@ -1390,7 +1390,7 @@ function ExportModal({
|
|||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
ShareGPT format for Unsloth fine-tuning
|
||||
</p>
|
||||
<code className="mt-2 block w-full truncate rounded-md bg-muted px-2 py-1 font-mono text-[0.625rem] text-muted-foreground/60">
|
||||
<code className="mt-2 block w-full truncate rounded-md bg-muted px-2 py-1 font-mono text-ui-10 text-muted-foreground/60">
|
||||
{`{"conversations":[{"from":"human","value":"..."},{"from":"gpt","value":""}]}`}
|
||||
</code>
|
||||
</div>
|
||||
|
|
@ -1400,7 +1400,7 @@ function ExportModal({
|
|||
|
||||
{/* */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-[0.6875rem] font-semibold uppercase tracking-wider text-muted-foreground/60">
|
||||
<p className="text-ui-11 font-semibold uppercase tracking-wider text-muted-foreground/60">
|
||||
Format
|
||||
</p>
|
||||
<div className="flex items-center gap-1 self-start rounded-lg bg-muted/60 p-1">
|
||||
|
|
@ -1730,7 +1730,7 @@ function PromptListCard({
|
|||
<div className="group rounded-xl border border-border/60 bg-card p-4 flex flex-col gap-2.5 hover:border-border hover:shadow-sm transition-all">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-semibold text-sm flex-1 truncate tracking-tight">{entry.name}</span>
|
||||
<span className="shrink-0 rounded-full bg-muted px-2 py-0.5 text-[0.6875rem] font-medium text-muted-foreground">
|
||||
<span className="shrink-0 rounded-full bg-muted px-2 py-0.5 text-ui-11 font-medium text-muted-foreground">
|
||||
{entry.items.length}
|
||||
</span>
|
||||
<div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
|
|
@ -1779,7 +1779,7 @@ function PromptListCard({
|
|||
</p>
|
||||
))}
|
||||
{entry.items.length > 3 && (
|
||||
<p className="text-[0.6875rem] text-muted-foreground/50 ml-5">
|
||||
<p className="text-ui-11 text-muted-foreground/50 ml-5">
|
||||
+{entry.items.length - 3} more
|
||||
</p>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ export function ThreadSidebar({
|
|||
>
|
||||
{item.isFork ? (
|
||||
<span
|
||||
className="mr-1 rounded-sm bg-primary/10 px-1.5 py-0.5 text-[0.625rem] font-semibold uppercase tracking-wide text-primary"
|
||||
className="mr-1 rounded-sm bg-primary/10 px-1.5 py-0.5 text-ui-10 font-semibold uppercase tracking-wide text-primary"
|
||||
title="Forked from another chat"
|
||||
>
|
||||
fork
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ function LearningRecipeCards({
|
|||
<Badge
|
||||
key={`${template.title}-${badge}`}
|
||||
variant="outline"
|
||||
className="h-5 shrink-0 px-1.5 text-[0.625rem] dark:text-zinc-300"
|
||||
className="h-5 shrink-0 px-1.5 text-ui-10 dark:text-zinc-300"
|
||||
>
|
||||
{badge}
|
||||
</Badge>
|
||||
|
|
@ -288,7 +288,7 @@ function LearningRecipeCards({
|
|||
{extraLearningBadgeCount > 0 ? (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="h-5 shrink-0 px-1.5 text-[0.625rem] dark:text-zinc-300"
|
||||
className="h-5 shrink-0 px-1.5 text-ui-10 dark:text-zinc-300"
|
||||
>
|
||||
+{extraLearningBadgeCount}
|
||||
</Badge>
|
||||
|
|
@ -296,7 +296,7 @@ function LearningRecipeCards({
|
|||
{isReady ? null : (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="h-5 shrink-0 px-1.5 text-[0.625rem] dark:text-zinc-300"
|
||||
className="h-5 shrink-0 px-1.5 text-ui-10 dark:text-zinc-300"
|
||||
>
|
||||
Soon
|
||||
</Badge>
|
||||
|
|
@ -403,7 +403,7 @@ export function DataRecipesPage(): ReactElement {
|
|||
<main className="mx-auto w-full max-w-7xl px-5 py-8 sm:px-9">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-[1.875rem] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[2.125rem]">
|
||||
<h1 className="text-ui-30 font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-ui-34">
|
||||
Data Recipes
|
||||
</h1>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) {
|
|||
</div>
|
||||
<div className="flex items-stretch gap-2">
|
||||
<Input
|
||||
className="min-w-0 flex-1 font-mono text-[0.75rem]"
|
||||
className="min-w-0 flex-1 font-mono text-ui-12"
|
||||
value={saveDirectory}
|
||||
onChange={(e) => onSaveDirectoryChange(e.target.value)}
|
||||
spellCheck={false}
|
||||
|
|
@ -303,7 +303,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) {
|
|||
<TooltipContent>Browse</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<p className="text-[0.6875rem] text-muted-foreground/70">
|
||||
<p className="text-ui-11 text-muted-foreground/70">
|
||||
{saveDirectory !== defaultSaveDirectory ? (
|
||||
<>Default: {defaultSaveDirectory}</>
|
||||
) : (
|
||||
|
|
@ -350,7 +350,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) {
|
|||
href="https://huggingface.co/settings/tokens"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-1 text-[0.6875rem] text-emerald-600 hover:text-emerald-700 transition-colors"
|
||||
className="flex items-center gap-1 text-ui-11 text-emerald-600 hover:text-emerald-700 transition-colors"
|
||||
>
|
||||
Get token
|
||||
<HugeiconsIcon icon={ArrowRight01Icon} className="size-3" />
|
||||
|
|
@ -369,7 +369,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) {
|
|||
onChange={(e) => onHfTokenChange(e.target.value)}
|
||||
/>
|
||||
</InputGroup>
|
||||
<p className="text-[0.6875rem] text-muted-foreground/70">
|
||||
<p className="text-ui-11 text-muted-foreground/70">
|
||||
Leave empty if already logged in via CLI.
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -427,7 +427,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) {
|
|||
</span>
|
||||
) : null}
|
||||
<code
|
||||
className="select-all break-all font-mono text-[0.75rem] text-foreground/90"
|
||||
className="select-all break-all font-mono text-ui-12 text-foreground/90"
|
||||
title={o.path}
|
||||
>
|
||||
{o.path}
|
||||
|
|
@ -503,11 +503,11 @@ export function ExportRunPanel(props: ExportRunPanelProps) {
|
|||
{showProgress && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="rounded-full bg-foreground/10 px-2.5 py-1 text-[0.625rem] font-semibold">
|
||||
<span className="rounded-full bg-foreground/10 px-2.5 py-1 text-ui-10 font-semibold">
|
||||
{PHASE_LABELS[run.phase] ?? run.phase}
|
||||
</span>
|
||||
{summaryMethod === "gguf" && run.quantTotal > 1 && (
|
||||
<span className="text-[0.625rem] tabular-nums text-muted-foreground">
|
||||
<span className="text-ui-10 tabular-nums text-muted-foreground">
|
||||
Quant{" "}
|
||||
{Math.min(
|
||||
run.quantIndex + (isExporting ? 1 : 0),
|
||||
|
|
@ -516,10 +516,10 @@ export function ExportRunPanel(props: ExportRunPanelProps) {
|
|||
of {run.quantTotal}
|
||||
</span>
|
||||
)}
|
||||
<span className="rounded-full border border-border/60 px-2.5 py-1 text-[0.625rem] font-medium tabular-nums text-muted-foreground">
|
||||
<span className="rounded-full border border-border/60 px-2.5 py-1 text-ui-10 font-medium tabular-nums text-muted-foreground">
|
||||
{progress}%
|
||||
</span>
|
||||
<span className="text-[0.625rem] tabular-nums text-muted-foreground/70">
|
||||
<span className="text-ui-10 tabular-nums text-muted-foreground/70">
|
||||
{formatElapsed(elapsedSeconds)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -536,7 +536,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) {
|
|||
/>
|
||||
{run.stage && (
|
||||
<p
|
||||
className="truncate text-[0.6875rem] text-muted-foreground/80"
|
||||
className="truncate text-ui-11 text-muted-foreground/80"
|
||||
title={run.stage}
|
||||
>
|
||||
{run.stage}
|
||||
|
|
@ -552,7 +552,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) {
|
|||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Export output
|
||||
</label>
|
||||
<div className="flex items-center gap-2 text-[0.6875rem] text-muted-foreground/80">
|
||||
<div className="flex items-center gap-2 text-ui-11 text-muted-foreground/80">
|
||||
<span
|
||||
className={
|
||||
run.reconnecting
|
||||
|
|
@ -576,7 +576,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) {
|
|||
<div
|
||||
ref={logScrollRef}
|
||||
onScroll={handleLogScroll}
|
||||
className="h-56 w-full overflow-auto rounded-lg border border-border/40 bg-black/85 p-3 font-mono text-[0.6875rem] leading-[1.45] text-emerald-200/90"
|
||||
className="h-56 w-full overflow-auto rounded-lg border border-border/40 bg-black/85 p-3 font-mono text-ui-11 leading-[1.45] text-emerald-200/90"
|
||||
>
|
||||
{run.logLines.length === 0 ? (
|
||||
<div className="flex h-full items-center justify-center text-muted-foreground/70">
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ export function MethodPicker({ value, onChange, disabledMethods = [], disabledRe
|
|||
{m.badge && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="text-[0.625rem] px-1.5 py-0"
|
||||
className="text-ui-10 px-1.5 py-0"
|
||||
>
|
||||
{m.badge}
|
||||
</Badge>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export function QuantPicker({ value, onChange, sizes }: QuantPickerProps) {
|
|||
</a>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<span className="text-[0.6875rem] text-muted-foreground/70">
|
||||
<span className="text-ui-11 text-muted-foreground/70">
|
||||
— select one or more
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -90,10 +90,10 @@ export function QuantPicker({ value, onChange, sizes }: QuantPickerProps) {
|
|||
)}
|
||||
{q.label}
|
||||
{sizeLabel && (
|
||||
<span className="text-[0.625rem] opacity-60">{sizeLabel}</span>
|
||||
<span className="text-ui-10 opacity-60">{sizeLabel}</span>
|
||||
)}
|
||||
{q.recommended && !active && (
|
||||
<span className="rounded-full bg-emerald-100 px-1.5 py-0 text-[0.5625rem] font-semibold text-emerald-700 dark:bg-emerald-900 dark:text-emerald-300">
|
||||
<span className="rounded-full bg-emerald-100 px-1.5 py-0 text-ui-9 font-semibold text-emerald-700 dark:bg-emerald-900 dark:text-emerald-300">
|
||||
rec
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -103,13 +103,13 @@ export function QuantPicker({ value, onChange, sizes }: QuantPickerProps) {
|
|||
</div>
|
||||
{value.length > 0 && (
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-[0.6875rem] text-muted-foreground">
|
||||
<span className="text-ui-11 text-muted-foreground">
|
||||
{value.length} selected
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onChange([])}
|
||||
className="text-[0.6875rem] text-muted-foreground/70 hover:text-foreground transition-colors"
|
||||
className="text-ui-11 text-muted-foreground/70 hover:text-foreground transition-colors"
|
||||
>
|
||||
Clear all
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -895,7 +895,7 @@ export function ExportPage() {
|
|||
<GuidedTour {...tour.tourProps} />
|
||||
|
||||
<div className="mb-8 flex flex-col gap-0.5">
|
||||
<h1 className="text-[1.875rem] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[2.125rem]">
|
||||
<h1 className="text-ui-30 font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-ui-34">
|
||||
Export Model
|
||||
</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
|
|
@ -964,21 +964,21 @@ export function ExportPage() {
|
|||
<TabsTrigger
|
||||
value="local"
|
||||
indicatorClassName="hub-tab-toggle-pill rounded-full"
|
||||
className="h-9 rounded-full border-0 px-3 text-[0.78125rem] text-muted-foreground hover:text-foreground data-active:text-foreground data-[state=active]:text-foreground"
|
||||
className="h-9 rounded-full border-0 px-3 text-ui-12p5 text-muted-foreground hover:text-foreground data-active:text-foreground data-[state=active]:text-foreground"
|
||||
>
|
||||
Local Model
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="checkpoint"
|
||||
indicatorClassName="hub-tab-toggle-pill rounded-full"
|
||||
className="h-9 rounded-full border-0 px-3 text-[0.78125rem] text-muted-foreground hover:text-foreground data-active:text-foreground data-[state=active]:text-foreground"
|
||||
className="h-9 rounded-full border-0 px-3 text-ui-12p5 text-muted-foreground hover:text-foreground data-active:text-foreground data-[state=active]:text-foreground"
|
||||
>
|
||||
Fine-tuned
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="hf"
|
||||
indicatorClassName="hub-tab-toggle-pill rounded-full"
|
||||
className="h-9 rounded-full border-0 px-3 text-[0.78125rem] text-muted-foreground hover:text-foreground data-active:text-foreground data-[state=active]:text-foreground"
|
||||
className="h-9 rounded-full border-0 px-3 text-ui-12p5 text-muted-foreground hover:text-foreground data-active:text-foreground data-[state=active]:text-foreground"
|
||||
>
|
||||
Hugging Face
|
||||
</TabsTrigger>
|
||||
|
|
@ -1289,7 +1289,7 @@ export function ExportPage() {
|
|||
<span className="block min-w-0 flex-1 truncate">
|
||||
{model?.display_name ?? id}
|
||||
</span>
|
||||
<span className="ml-auto shrink-0 text-[0.625rem] text-muted-foreground">
|
||||
<span className="ml-auto shrink-0 text-ui-10 text-muted-foreground">
|
||||
{source}
|
||||
</span>
|
||||
</ComboboxItem>
|
||||
|
|
@ -1300,15 +1300,15 @@ export function ExportPage() {
|
|||
</Combobox>
|
||||
</div>
|
||||
{isLoadingLocalModels ? (
|
||||
<p className="text-[0.625rem] text-muted-foreground">
|
||||
<p className="text-ui-10 text-muted-foreground">
|
||||
Scanning local models...
|
||||
</p>
|
||||
) : localModelsError ? (
|
||||
<p className="text-[0.625rem] text-red-500">
|
||||
<p className="text-ui-10 text-red-500">
|
||||
{localModelsError}
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-[0.625rem] text-muted-foreground">
|
||||
<p className="text-ui-10 text-muted-foreground">
|
||||
{exportableLocalModels.length > 0
|
||||
? `${exportableLocalModels.length} local/cached models found`
|
||||
: "No local models found. Enter path manually."}
|
||||
|
|
@ -1318,7 +1318,7 @@ export function ExportPage() {
|
|||
)}
|
||||
|
||||
<div className="rounded-xl bg-foreground/[0.04] p-3">
|
||||
<p className="text-[0.6875rem] text-muted-foreground">
|
||||
<p className="text-ui-11 text-muted-foreground">
|
||||
Direct model exports currently support GGUF only.
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -1327,7 +1327,7 @@ export function ExportPage() {
|
|||
|
||||
{sourceMode === "checkpoint" && (
|
||||
<div className="rounded-xl bg-foreground/[0.04] p-3 flex flex-col gap-2">
|
||||
<span className="text-[0.6875rem] font-medium text-muted-foreground uppercase tracking-wider">
|
||||
<span className="text-ui-11 font-medium text-muted-foreground uppercase tracking-wider">
|
||||
Training Info
|
||||
</span>
|
||||
<div className="grid grid-cols-1 gap-x-6 gap-y-1.5 text-xs sm:grid-cols-2">
|
||||
|
|
@ -1374,7 +1374,7 @@ export function ExportPage() {
|
|||
key={step}
|
||||
className="flex items-start gap-2 text-xs text-muted-foreground"
|
||||
>
|
||||
<span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-foreground/10 text-[0.625rem] font-semibold">
|
||||
<span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-foreground/10 text-ui-10 font-semibold">
|
||||
{i + 1}
|
||||
</span>
|
||||
{step}
|
||||
|
|
@ -1422,7 +1422,7 @@ export function ExportPage() {
|
|||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-sm font-medium">Precision</div>
|
||||
<span className="text-[0.6875rem] text-muted-foreground/70">
|
||||
<span className="text-ui-11 text-muted-foreground/70">
|
||||
— select one or more
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -1479,7 +1479,7 @@ export function ExportPage() {
|
|||
{f.label}
|
||||
{f.needsCalibration ? " *" : ""}
|
||||
</span>
|
||||
<span className="text-[0.625rem] text-muted-foreground">
|
||||
<span className="text-ui-10 text-muted-foreground">
|
||||
{f.hint}
|
||||
</span>
|
||||
</span>
|
||||
|
|
@ -1492,7 +1492,7 @@ export function ExportPage() {
|
|||
|
||||
{selectedFormats.length > 0 && (
|
||||
<div className="flex flex-wrap items-center gap-x-3 gap-y-1">
|
||||
<span className="text-[0.6875rem] text-muted-foreground">
|
||||
<span className="text-ui-11 text-muted-foreground">
|
||||
{selectedFormats.length} selected:{" "}
|
||||
{selectedFormats
|
||||
.map(
|
||||
|
|
@ -1506,7 +1506,7 @@ export function ExportPage() {
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => setSelectedFormats(["16-bit"])}
|
||||
className="text-[0.6875rem] text-muted-foreground/70 hover:text-foreground transition-colors"
|
||||
className="text-ui-11 text-muted-foreground/70 hover:text-foreground transition-colors"
|
||||
>
|
||||
Reset to 16-bit
|
||||
</button>
|
||||
|
|
@ -1515,7 +1515,7 @@ export function ExportPage() {
|
|||
)}
|
||||
|
||||
{hubMultiFormat && (
|
||||
<div className="text-[0.6875rem] text-amber-600 dark:text-amber-500">
|
||||
<div className="text-ui-11 text-amber-600 dark:text-amber-500">
|
||||
Hub export supports one format at a time (each writes to
|
||||
the repository root). Select a single format, or export
|
||||
locally to produce several at once.
|
||||
|
|
@ -1527,13 +1527,13 @@ export function ExportPage() {
|
|||
MERGED_FORMATS.find((f) => f.value === v)
|
||||
?.needsCalibration,
|
||||
) && (
|
||||
<div className="text-[0.6875rem] text-muted-foreground">
|
||||
<div className="text-ui-11 text-muted-foreground">
|
||||
* calibrates on data (uses a small calibration set).
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!hasNvidia && (
|
||||
<div className="text-[0.6875rem] text-muted-foreground">
|
||||
<div className="text-ui-11 text-muted-foreground">
|
||||
No NVIDIA GPU detected: compressed-tensors formats are
|
||||
hidden. 16-bit and portable FP8/INT8 (torchao) still
|
||||
work here and load in vLLM.
|
||||
|
|
|
|||
|
|
@ -38,20 +38,20 @@ export function NetworkErrorState({
|
|||
<HugeiconsIcon icon={icon} strokeWidth={1.6} className="size-5" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[0.875rem] font-semibold tracking-tight text-foreground">
|
||||
<p className="text-ui-14 font-semibold tracking-tight text-foreground">
|
||||
{title}
|
||||
</p>
|
||||
<p className="max-w-md text-[0.78125rem] leading-5 text-muted-foreground">
|
||||
<p className="max-w-md text-ui-12p5 leading-5 text-muted-foreground">
|
||||
{body}
|
||||
</p>
|
||||
<p className="text-[0.6875rem] text-muted-foreground/70">{message}</p>
|
||||
<p className="text-ui-11 text-muted-foreground/70">{message}</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center justify-center gap-2">
|
||||
{onSwitchDevice ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onSwitchDevice}
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-foreground/[0.06] px-3 text-[0.75rem] font-medium text-foreground transition-colors hover:bg-foreground/[0.1] dark:bg-white/[0.06] dark:hover:bg-white/[0.1]"
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-foreground/[0.06] px-3 text-ui-12 font-medium text-foreground transition-colors hover:bg-foreground/[0.1] dark:bg-white/[0.06] dark:hover:bg-white/[0.1]"
|
||||
>
|
||||
On Device
|
||||
</button>
|
||||
|
|
@ -59,7 +59,7 @@ export function NetworkErrorState({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onRetry}
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-transparent px-3 text-[0.75rem] font-medium text-foreground transition-colors hover:bg-foreground/[0.04] dark:hover:bg-white/[0.05]"
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-transparent px-3 text-ui-12 font-medium text-foreground transition-colors hover:bg-foreground/[0.04] dark:hover:bg-white/[0.05]"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={Refresh01Icon}
|
||||
|
|
@ -92,10 +92,10 @@ export function DiscoverFetchMoreState({
|
|||
<HugeiconsIcon icon={FilterIcon} strokeWidth={1.5} className="size-5" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[0.875rem] font-semibold tracking-tight text-foreground">
|
||||
<p className="text-ui-14 font-semibold tracking-tight text-foreground">
|
||||
No matches yet
|
||||
</p>
|
||||
<p className="max-w-md text-[0.78125rem] leading-5 text-muted-foreground">
|
||||
<p className="max-w-md text-ui-12p5 leading-5 text-muted-foreground">
|
||||
Scanned {scannedCount.toLocaleString()} results. Load another page to
|
||||
keep searching Hugging Face.
|
||||
</p>
|
||||
|
|
@ -105,7 +105,7 @@ export function DiscoverFetchMoreState({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onClearFilters}
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-foreground/[0.06] px-3 text-[0.75rem] font-medium text-foreground transition-colors hover:bg-foreground/[0.1] dark:bg-white/[0.06] dark:hover:bg-white/[0.1]"
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-foreground/[0.06] px-3 text-ui-12 font-medium text-foreground transition-colors hover:bg-foreground/[0.1] dark:bg-white/[0.06] dark:hover:bg-white/[0.1]"
|
||||
>
|
||||
Clear filters
|
||||
</button>
|
||||
|
|
@ -114,7 +114,7 @@ export function DiscoverFetchMoreState({
|
|||
type="button"
|
||||
onClick={onFetchMore}
|
||||
disabled={isLoadingMore}
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-transparent px-3 text-[0.75rem] font-medium text-foreground transition-colors hover:bg-foreground/[0.04] disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-white/[0.05]"
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-transparent px-3 text-ui-12 font-medium text-foreground transition-colors hover:bg-foreground/[0.04] disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-white/[0.05]"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={Refresh01Icon}
|
||||
|
|
@ -141,7 +141,7 @@ export function DiscoverFetchMoreFooter({
|
|||
<div className="relative z-10 flex flex-col items-center gap-2 rounded-[16px] bg-card px-4 py-4 text-center">
|
||||
{/* Only warn about hidden results when a filter is actually narrowing them. */}
|
||||
{hasActiveFilters && (
|
||||
<p className="text-[0.71875rem] leading-4 text-muted-foreground">
|
||||
<p className="text-ui-11p5 leading-4 text-muted-foreground">
|
||||
Some results may be hidden by your filters.
|
||||
</p>
|
||||
)}
|
||||
|
|
@ -149,7 +149,7 @@ export function DiscoverFetchMoreFooter({
|
|||
type="button"
|
||||
onClick={onFetchMore}
|
||||
disabled={isLoadingMore}
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-foreground/[0.06] px-3 text-[0.75rem] font-medium text-foreground transition-colors hover:bg-foreground/[0.1] disabled:cursor-not-allowed disabled:opacity-50 dark:bg-white/[0.06] dark:hover:bg-white/[0.1]"
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-foreground/[0.06] px-3 text-ui-12 font-medium text-foreground transition-colors hover:bg-foreground/[0.1] disabled:cursor-not-allowed disabled:opacity-50 dark:bg-white/[0.06] dark:hover:bg-white/[0.1]"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={Refresh01Icon}
|
||||
|
|
@ -175,10 +175,10 @@ export function InventoryErrorState({
|
|||
<HugeiconsIcon icon={CloudOffIcon} strokeWidth={1.6} className="size-5" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[0.875rem] font-semibold tracking-tight text-foreground">
|
||||
<p className="text-ui-14 font-semibold tracking-tight text-foreground">
|
||||
Couldn't load your library
|
||||
</p>
|
||||
<p className="max-w-md text-[0.78125rem] leading-5 text-muted-foreground">
|
||||
<p className="max-w-md text-ui-12p5 leading-5 text-muted-foreground">
|
||||
Something went wrong reading your downloaded{" "}
|
||||
{isDataset ? "datasets" : "models"}. Check that the backend is running
|
||||
and try again.
|
||||
|
|
@ -187,7 +187,7 @@ export function InventoryErrorState({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onRetry}
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-transparent px-3 text-[0.75rem] font-medium text-foreground transition-colors hover:bg-foreground/[0.04] dark:hover:bg-white/[0.05]"
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-transparent px-3 text-ui-12 font-medium text-foreground transition-colors hover:bg-foreground/[0.04] dark:hover:bg-white/[0.05]"
|
||||
>
|
||||
<HugeiconsIcon icon={Refresh01Icon} strokeWidth={1.75} className="size-3.5" />
|
||||
Try again
|
||||
|
|
@ -213,10 +213,10 @@ export function EmptyState({
|
|||
<HugeiconsIcon icon={icon} strokeWidth={1.5} className="size-5" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[0.875rem] font-semibold tracking-tight text-foreground">
|
||||
<p className="text-ui-14 font-semibold tracking-tight text-foreground">
|
||||
{title}
|
||||
</p>
|
||||
<p className="max-w-md text-[0.78125rem] leading-5 text-muted-foreground">
|
||||
<p className="max-w-md text-ui-12p5 leading-5 text-muted-foreground">
|
||||
{body}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ export function DatasetDownloadSection({
|
|||
}
|
||||
>
|
||||
<div className="relative flex h-9 min-w-0 flex-1 items-center pl-3 pr-2">
|
||||
<span className="flex items-center gap-1.5 text-[0.75rem] text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5 text-ui-12 text-muted-foreground">
|
||||
{isDownloaded && <DotTag tone="success" label="On device" />}
|
||||
{!isDownloaded && isPartial && !downloading && (
|
||||
<Tooltip>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export function DotTag({
|
|||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex h-5 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full border border-border/60 bg-transparent px-2 text-[0.6875rem] font-medium leading-none text-muted-foreground",
|
||||
"inline-flex h-5 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full border border-border/60 bg-transparent px-2 text-ui-11 font-medium leading-none text-muted-foreground",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ export function CardUpdateButton({
|
|||
e.stopPropagation();
|
||||
onClick();
|
||||
}}
|
||||
className="inline-flex h-7 shrink-0 cursor-pointer items-center gap-1.5 rounded-full bg-amber-500/[0.07] pl-2 pr-2.5 text-[0.75rem] font-medium text-amber-800/90 transition-colors duration-150 hover:bg-amber-500/[0.12] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-amber-500/25 dark:bg-amber-400/[0.08] dark:text-amber-200/85 dark:hover:bg-amber-400/[0.16]"
|
||||
className="inline-flex h-7 shrink-0 cursor-pointer items-center gap-1.5 rounded-full bg-amber-500/[0.07] pl-2 pr-2.5 text-ui-12 font-medium text-amber-800/90 transition-colors duration-150 hover:bg-amber-500/[0.12] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-amber-500/25 dark:bg-amber-400/[0.08] dark:text-amber-200/85 dark:hover:bg-amber-400/[0.16]"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={ArrowReloadHorizontalIcon}
|
||||
|
|
|
|||
|
|
@ -54,10 +54,10 @@ export function ExternalLinkConfirmDialog() {
|
|||
</AlertDialogHeader>
|
||||
{pendingUrl && (
|
||||
<div className="min-w-0 rounded-[12px] bg-muted/50 px-3 py-2.5 text-left">
|
||||
<p className="truncate text-[0.8125rem] font-medium text-foreground">
|
||||
<p className="truncate text-ui-13 font-medium text-foreground">
|
||||
{hostOf(pendingUrl)}
|
||||
</p>
|
||||
<p className="mt-0.5 break-all text-[0.71875rem] leading-[1rem] text-muted-foreground">
|
||||
<p className="mt-0.5 break-all text-ui-11p5 leading-ui-16 text-muted-foreground">
|
||||
{pendingUrl}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ const FIT_BADGE: Record<GgufFitClass, FitBadgeMeta> = {
|
|||
|
||||
/** Chip styling matching the on-device list's StatChip, no icon. */
|
||||
const CHIP_BASE =
|
||||
"inline-flex h-5 shrink-0 items-center justify-center whitespace-nowrap rounded-full border px-2 text-[0.71875rem] font-medium tabular-nums leading-3 shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]";
|
||||
"inline-flex h-5 shrink-0 items-center justify-center whitespace-nowrap rounded-full border px-2 text-ui-11p5 font-medium tabular-nums leading-3 shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]";
|
||||
const CHIP_DEFAULT =
|
||||
"border-foreground/15 bg-muted text-foreground/85 dark:border-border/60 dark:bg-white/[0.04] dark:text-foreground/85";
|
||||
const CHIP_ACTIVE =
|
||||
|
|
@ -184,7 +184,7 @@ function QuantBadge({
|
|||
// group's `overflow-hidden` sacrifices the trailing status tags instead.
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex shrink-0 cursor-help items-center gap-1.5 whitespace-nowrap text-[0.78125rem] font-medium tracking-tight tabular-nums",
|
||||
"inline-flex shrink-0 cursor-help items-center gap-1.5 whitespace-nowrap text-ui-12p5 font-medium tracking-tight tabular-nums",
|
||||
active ? "text-control-accent" : "text-foreground",
|
||||
)}
|
||||
>
|
||||
|
|
@ -914,7 +914,7 @@ export function GgufDownloadCard({
|
|||
{/* Quant label + status tags travel together as one left-aligned
|
||||
group so the fit-info icon never floats orphaned from its tags;
|
||||
only the chevron pins right, the standard select affordance. */}
|
||||
<span className="flex min-w-0 flex-1 items-center gap-2 overflow-hidden text-[0.75rem] text-muted-foreground">
|
||||
<span className="flex min-w-0 flex-1 items-center gap-2 overflow-hidden text-ui-12 text-muted-foreground">
|
||||
{selected ? (
|
||||
<QuantBadge
|
||||
quant={selectedLabel ?? selected.quant}
|
||||
|
|
@ -923,7 +923,7 @@ export function GgufDownloadCard({
|
|||
active={Boolean(selectedIsActive)}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-[0.78125rem] text-muted-foreground">
|
||||
<span className="text-ui-12p5 text-muted-foreground">
|
||||
Select quantization
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -1126,7 +1126,7 @@ export function GgufDownloadCard({
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => void refresh()}
|
||||
className="self-start px-1 text-[0.6875rem] text-status-warning underline-offset-2 transition-colors hover:underline"
|
||||
className="self-start px-1 text-ui-11 text-status-warning underline-offset-2 transition-colors hover:underline"
|
||||
>
|
||||
Couldn't refresh quantizations. Retry
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export function GgufDownloadStatusCard({
|
|||
<div className="relative flex h-9 min-w-0 flex-1 items-center pl-3 pr-2">
|
||||
<span
|
||||
className={cn(
|
||||
"flex min-w-0 items-center gap-2 text-[0.78125rem]",
|
||||
"flex min-w-0 items-center gap-2 text-ui-12p5",
|
||||
tone === "danger" ? "text-destructive" : "text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
|
|
@ -91,7 +91,7 @@ export function GgufDownloadingFallbackCard({
|
|||
<div className="flex w-full flex-col gap-2">
|
||||
<DownloadCard job={job} progress={progress}>
|
||||
<div className="relative flex h-9 min-w-0 flex-1 items-center pl-3 pr-2">
|
||||
<span className="flex min-w-0 items-center gap-2 text-[0.78125rem] text-muted-foreground">
|
||||
<span className="flex min-w-0 items-center gap-2 text-ui-12p5 text-muted-foreground">
|
||||
{progress.variant && <DotTag tone="gguf" label={progress.variant} />}
|
||||
<span className="truncate">Downloading…</span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export function HubDetailView({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onBack}
|
||||
className="-ml-1.5 inline-flex h-8 cursor-pointer select-none items-center gap-1.5 rounded-full pl-1.5 pr-2.5 text-[0.78125rem] font-medium text-muted-foreground transition-colors hover:bg-foreground/[0.05] hover:text-foreground dark:hover:bg-white/[0.06]"
|
||||
className="-ml-1.5 inline-flex h-8 cursor-pointer select-none items-center gap-1.5 rounded-full pl-1.5 pr-2.5 text-ui-12p5 font-medium text-muted-foreground transition-colors hover:bg-foreground/[0.05] hover:text-foreground dark:hover:bg-white/[0.06]"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={ArrowLeft01Icon}
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ export function HubOptionMenu<T extends string>({
|
|||
aria-label={ariaLabel}
|
||||
title={title}
|
||||
className={cn(
|
||||
"field-trigger hub-menu-trigger field-soft field-filter inline-flex h-9 shrink-0 cursor-pointer items-center justify-between gap-2.5 rounded-full pl-3 pr-2.5 text-[0.78125rem] transition-colors",
|
||||
"field-trigger hub-menu-trigger field-soft field-filter inline-flex h-9 shrink-0 cursor-pointer items-center justify-between gap-2.5 rounded-full pl-3 pr-2.5 text-ui-12p5 transition-colors",
|
||||
"focus-visible:border-border focus-visible:ring-0 focus-visible:ring-offset-0",
|
||||
className,
|
||||
)}
|
||||
|
|
@ -205,7 +205,7 @@ export function HubOptionMenu<T extends string>({
|
|||
collisionPadding={12}
|
||||
onCloseAutoFocus={(event) => event.preventDefault()}
|
||||
className={cn(
|
||||
"hub-menu-instant menu-soft-surface w-max min-w-[var(--radix-popover-trigger-width)] max-w-[min(var(--radix-popover-content-available-width),calc(100vw-16px))] rounded-[14px] p-1 ring-0",
|
||||
"hub-menu-instant menu-soft-surface w-max min-w-[var(--radix-popover-trigger-width)] max-w-[min(var(--radix-popover-content-available-width),calc(100vw-1rem))] rounded-[14px] p-1 ring-0",
|
||||
contentClassName,
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export const HubSectionRow = memo(function HubSectionRow({
|
|||
type="button"
|
||||
onClick={onOpenList}
|
||||
aria-label={`See all ${title}`}
|
||||
className="hub-section-title group/section -mx-1 inline-flex cursor-pointer items-center gap-1.5 rounded-md px-1 text-[1.125rem] font-semibold tracking-[-0.02em] text-foreground outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
||||
className="hub-section-title group/section -mx-1 inline-flex cursor-pointer items-center gap-1.5 rounded-md px-1 text-ui-18 font-semibold tracking-[-0.02em] text-foreground outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
||||
>
|
||||
{title}
|
||||
<HugeiconsIcon
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export function LocalDatasetCard({
|
|||
<div className="hub-download-card">
|
||||
<div className="group/dl flex items-center">
|
||||
<div className="relative flex h-9 min-w-0 flex-1 items-center pl-3 pr-2">
|
||||
<span className="flex min-w-0 items-center gap-1.5 text-[0.75rem] text-muted-foreground">
|
||||
<span className="flex min-w-0 items-center gap-1.5 text-ui-12 text-muted-foreground">
|
||||
<DotTag tone="success" label="On device" />
|
||||
{source !== "hf_cache" && (
|
||||
<span className="truncate text-muted-foreground/85">
|
||||
|
|
|
|||
|
|
@ -138,15 +138,15 @@ function BaseModelReference({
|
|||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="shrink-0 text-[0.6875rem] font-medium text-muted-foreground">
|
||||
<span className="shrink-0 text-ui-11 font-medium text-muted-foreground">
|
||||
{baseModelSourceLabel(baseModelSource)}
|
||||
</span>
|
||||
<span className="truncate text-[0.75rem] font-medium text-foreground">
|
||||
<span className="truncate text-ui-12 font-medium text-foreground">
|
||||
{baseModel}
|
||||
</span>
|
||||
</div>
|
||||
{baseModelSummary && (
|
||||
<p className="mt-0.5 truncate text-[0.6875rem] text-muted-foreground">
|
||||
<p className="mt-0.5 truncate text-ui-11 text-muted-foreground">
|
||||
{baseModelSummary}
|
||||
</p>
|
||||
)}
|
||||
|
|
@ -424,7 +424,7 @@ export function LocalOnDeviceCard({
|
|||
return (
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
{showOldCacheHint && (
|
||||
<div className="flex items-start gap-2 rounded-[12px] border border-amber-500/20 bg-amber-500/8 px-3 py-2 text-[0.75rem] leading-5 text-amber-700 dark:text-amber-300">
|
||||
<div className="flex items-start gap-2 rounded-[12px] border border-amber-500/20 bg-amber-500/8 px-3 py-2 text-ui-12 leading-5 text-amber-700 dark:text-amber-300">
|
||||
<HugeiconsIcon
|
||||
icon={Alert02Icon}
|
||||
strokeWidth={1.75}
|
||||
|
|
@ -440,7 +440,7 @@ export function LocalOnDeviceCard({
|
|||
<div className="hub-download-card">
|
||||
<div className="group/dl flex items-center">
|
||||
<div className="relative flex h-9 min-w-0 flex-1 items-center pl-3 pr-2">
|
||||
<span className="flex min-w-0 items-center gap-1.5 text-[0.75rem] text-muted-foreground">
|
||||
<span className="flex min-w-0 items-center gap-1.5 text-ui-12 text-muted-foreground">
|
||||
<DotTag
|
||||
tone="success"
|
||||
label={selectedVariantIsActive ? "Loaded" : "On device"}
|
||||
|
|
@ -452,7 +452,7 @@ export function LocalOnDeviceCard({
|
|||
<button
|
||||
type="button"
|
||||
disabled={currentVariantState.loading}
|
||||
className="inline-flex h-6 max-w-[170px] shrink-0 cursor-pointer items-center gap-1.5 rounded-[8px] border border-format-gguf/35 px-2 font-mono text-[0.65625rem] leading-none text-format-gguf transition-colors hover:bg-format-gguf/8 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
className="inline-flex h-6 max-w-[170px] shrink-0 cursor-pointer items-center gap-1.5 rounded-[8px] border border-format-gguf/35 px-2 font-mono text-ui-10p5 leading-none text-format-gguf transition-colors hover:bg-format-gguf/8 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
<span className="truncate">
|
||||
{currentVariantState.loading
|
||||
|
|
@ -464,7 +464,7 @@ export function LocalOnDeviceCard({
|
|||
: "Select"}
|
||||
</span>
|
||||
{selectedVariant && (
|
||||
<span className="shrink-0 font-sans text-[0.625rem] text-muted-foreground tabular-nums">
|
||||
<span className="shrink-0 font-sans text-ui-10 text-muted-foreground tabular-nums">
|
||||
{formatBytes(selectedVariant.size_bytes)}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -503,20 +503,20 @@ export function LocalOnDeviceCard({
|
|||
setVariantOpen(false);
|
||||
}}
|
||||
className={cn(
|
||||
"mx-2 flex w-[calc(100%-16px)] min-w-0 cursor-pointer items-center gap-2 rounded-[10px] px-2.5 py-2 text-left transition-colors",
|
||||
"mx-2 flex w-[calc(100%-1rem)] min-w-0 cursor-pointer items-center gap-2 rounded-[10px] px-2.5 py-2 text-left transition-colors",
|
||||
isSelected
|
||||
? "bg-foreground/[0.07] dark:bg-foreground/[0.12]"
|
||||
: "hover:bg-foreground/[0.05] dark:hover:bg-foreground/[0.06]",
|
||||
)}
|
||||
>
|
||||
<span className="min-w-0 flex-1 truncate font-mono text-[0.75rem] text-format-gguf">
|
||||
<span className="min-w-0 flex-1 truncate font-mono text-ui-12 text-format-gguf">
|
||||
{label}
|
||||
</span>
|
||||
<span className="flex shrink-0 items-center gap-1.5">
|
||||
{isLoaded && (
|
||||
<DotTag tone="success" label="Loaded" />
|
||||
)}
|
||||
<span className="text-[0.625rem] text-muted-foreground tabular-nums">
|
||||
<span className="text-ui-10 text-muted-foreground tabular-nums">
|
||||
{formatBytes(variant.size_bytes)}
|
||||
</span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -283,14 +283,14 @@ export const ModelCard = memo(function ModelCard({
|
|||
<OwnerAvatar
|
||||
owner={row.owner}
|
||||
repoName={row.repo}
|
||||
className="size-11 shrink-0 rounded-[14px] text-[1.0625rem] ring-1 ring-white/10"
|
||||
className="size-11 shrink-0 rounded-[14px] text-ui-17 ring-1 ring-white/10"
|
||||
remote={false}
|
||||
/>
|
||||
<div className="min-w-0 flex-1 space-y-0.5">
|
||||
<p className="hub-trending-title line-clamp-2 text-[0.84375rem] font-semibold leading-[1rem] text-foreground">
|
||||
<p className="hub-trending-title line-clamp-2 text-ui-13p5 font-semibold leading-ui-16 text-foreground">
|
||||
{row.repo}
|
||||
</p>
|
||||
<span className="hub-trending-owner flex min-w-0 items-center gap-1 text-[0.71875rem] leading-[0.9375rem] text-muted-foreground/80">
|
||||
<span className="hub-trending-owner flex min-w-0 items-center gap-1 text-ui-11p5 leading-ui-15 text-muted-foreground/80">
|
||||
<span className="truncate">{row.owner}</span>
|
||||
{row.owner.toLowerCase() === "unsloth" && (
|
||||
<span
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ function StatRow({
|
|||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild={true}>
|
||||
<span className="hub-tag-meta inline-flex cursor-default items-center gap-1.5 px-2.5 py-1 text-[0.71875rem] text-muted-foreground transition-colors hover:text-foreground/80">
|
||||
<span className="hub-tag-meta inline-flex cursor-default items-center gap-1.5 px-2.5 py-1 text-ui-11p5 text-muted-foreground transition-colors hover:text-foreground/80">
|
||||
<HugeiconsIcon
|
||||
icon={icon}
|
||||
strokeWidth={1.75}
|
||||
|
|
@ -208,7 +208,7 @@ function StatusChip({
|
|||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex h-5 shrink-0 items-center whitespace-nowrap rounded-full border bg-transparent px-2 text-[0.6875rem] font-medium leading-none",
|
||||
"inline-flex h-5 shrink-0 items-center whitespace-nowrap rounded-full border bg-transparent px-2 text-ui-11 font-medium leading-none",
|
||||
toneClass,
|
||||
className,
|
||||
)}
|
||||
|
|
@ -248,12 +248,12 @@ function BaseModelSearchChip({
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => onSearchHub(searchTerm)}
|
||||
className="inline-flex h-6 max-w-full cursor-pointer items-center gap-1.5 rounded-full bg-muted px-2.5 text-[0.71875rem] transition-colors hover:bg-muted/80 dark:bg-[rgba(255,255,255,0.04)]"
|
||||
className="inline-flex h-6 max-w-full cursor-pointer items-center gap-1.5 rounded-full bg-muted px-2.5 text-ui-11p5 transition-colors hover:bg-muted/80 dark:bg-[rgba(255,255,255,0.04)]"
|
||||
>
|
||||
{content}
|
||||
</button>
|
||||
) : (
|
||||
<span className="inline-flex h-6 max-w-full items-center gap-1.5 rounded-full bg-muted px-2.5 text-[0.71875rem] dark:bg-[rgba(255,255,255,0.04)]">
|
||||
<span className="inline-flex h-6 max-w-full items-center gap-1.5 rounded-full bg-muted px-2.5 text-ui-11p5 dark:bg-[rgba(255,255,255,0.04)]">
|
||||
{content}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -325,11 +325,11 @@ function ModelStatusChips({
|
|||
>
|
||||
This model may not be supported yet.
|
||||
{unslothSupport.reason && (
|
||||
<span className="mt-1 block text-[0.65625rem] font-normal text-white/75">
|
||||
<span className="mt-1 block text-ui-10p5 font-normal text-white/75">
|
||||
{unslothSupport.reason}
|
||||
</span>
|
||||
)}
|
||||
<span className="mt-1 block text-[0.65625rem] font-normal text-white/75">
|
||||
<span className="mt-1 block text-ui-10p5 font-normal text-white/75">
|
||||
Still downloadable to your Hugging Face cache.
|
||||
</span>
|
||||
</TooltipContent>
|
||||
|
|
@ -349,7 +349,7 @@ function ModelStatusChips({
|
|||
>
|
||||
This device has no supported GPU or usable MLX, so only GGUF models
|
||||
can run here.
|
||||
<span className="mt-1 block text-[0.65625rem] font-normal text-white/75">
|
||||
<span className="mt-1 block text-ui-10p5 font-normal text-white/75">
|
||||
Still downloadable to your Hugging Face cache.
|
||||
</span>
|
||||
</TooltipContent>
|
||||
|
|
@ -368,7 +368,7 @@ function ModelStatusChips({
|
|||
className="tooltip-compact max-w-xs"
|
||||
>
|
||||
Estimated 4-bit memory load is around {vramInfo.est} GB.
|
||||
<span className="mt-1 block text-[0.65625rem] font-normal text-white/75">
|
||||
<span className="mt-1 block text-ui-10p5 font-normal text-white/75">
|
||||
{vramDetail}
|
||||
</span>
|
||||
</TooltipContent>
|
||||
|
|
@ -502,10 +502,10 @@ export const ModelInspector = memo(function ModelInspector({
|
|||
<HugeiconsIcon icon={CubeIcon} strokeWidth={1.5} className="size-5" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[0.9375rem] font-semibold tracking-tight text-foreground">
|
||||
<p className="text-ui-15 font-semibold tracking-tight text-foreground">
|
||||
Select a {isDataset ? "dataset" : "model"}
|
||||
</p>
|
||||
<p className="max-w-sm text-[0.78125rem] leading-5 text-muted-foreground">
|
||||
<p className="max-w-sm text-ui-12p5 leading-5 text-muted-foreground">
|
||||
{isDataset
|
||||
? "Choose a dataset from the catalog to inspect its download state and details."
|
||||
: "Choose an item from the catalog to inspect its runtime fit, download state, and model card."}
|
||||
|
|
@ -528,7 +528,7 @@ export const ModelInspector = memo(function ModelInspector({
|
|||
model.downloadsAllTime != null ? (
|
||||
<>
|
||||
Downloads (30 days)
|
||||
<span className="mt-1 block text-[0.65625rem] font-normal text-white/75">
|
||||
<span className="mt-1 block text-ui-10p5 font-normal text-white/75">
|
||||
{formatCompact(model.downloadsAllTime)} all time
|
||||
</span>
|
||||
</>
|
||||
|
|
@ -582,11 +582,11 @@ export const ModelInspector = memo(function ModelInspector({
|
|||
<OwnerAvatar
|
||||
owner={model.owner}
|
||||
repoName={model.title}
|
||||
className="size-[60px] rounded-[18px] text-[1.1875rem]"
|
||||
className="size-[60px] rounded-[18px] text-ui-19"
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<h2 className="truncate text-[1.5625rem] font-semibold leading-[1.9375rem] tracking-normal text-foreground">
|
||||
<h2 className="truncate text-ui-25 font-semibold leading-ui-31 tracking-normal text-foreground">
|
||||
{model.title}
|
||||
</h2>
|
||||
{model.hubRepoId && (
|
||||
|
|
@ -599,7 +599,7 @@ export const ModelInspector = memo(function ModelInspector({
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-0.5 flex min-w-0 items-center gap-1 text-[0.9375rem] leading-[1.5rem] text-muted-foreground">
|
||||
<div className="mt-0.5 flex min-w-0 items-center gap-1 text-ui-15 leading-ui-24 text-muted-foreground">
|
||||
<span className="truncate">{model.owner}</span>
|
||||
{model.owner.toLowerCase() === "unsloth" && (
|
||||
<span
|
||||
|
|
@ -613,12 +613,12 @@ export const ModelInspector = memo(function ModelInspector({
|
|||
|
||||
<div className="mt-4 flex flex-wrap items-center gap-1.5">
|
||||
{isDataset && (
|
||||
<span className="inline-flex shrink-0 items-center rounded-full border border-violet-500/40 bg-transparent px-2 py-0.5 text-[0.71875rem] font-medium text-violet-600 dark:text-violet-400">
|
||||
<span className="inline-flex shrink-0 items-center rounded-full border border-violet-500/40 bg-transparent px-2 py-0.5 text-ui-11p5 font-medium text-violet-600 dark:text-violet-400">
|
||||
Dataset
|
||||
</span>
|
||||
)}
|
||||
{!isDataset && (
|
||||
<span className="inline-flex h-6 items-center gap-1.5 rounded-full bg-muted px-2.5 text-[0.71875rem] font-medium text-foreground dark:bg-[rgba(255,255,255,0.04)]">
|
||||
<span className="inline-flex h-6 items-center gap-1.5 rounded-full bg-muted px-2.5 text-ui-11p5 font-medium text-foreground dark:bg-[rgba(255,255,255,0.04)]">
|
||||
<HugeiconsIcon
|
||||
icon={CubeIcon}
|
||||
strokeWidth={1.75}
|
||||
|
|
@ -736,12 +736,12 @@ export const ModelInspector = memo(function ModelInspector({
|
|||
|
||||
<div className="pb-5 pt-5">
|
||||
{selectionHiddenByFilters && (
|
||||
<p className="mb-3 rounded-[8px] border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-[0.71875rem] leading-snug text-muted-foreground">
|
||||
<p className="mb-3 rounded-[8px] border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-ui-11p5 leading-snug text-muted-foreground">
|
||||
Current selection is hidden by the active filters or search.
|
||||
</p>
|
||||
)}
|
||||
{metadataUnavailable && (
|
||||
<p className="mb-3 text-[0.71875rem] leading-snug text-muted-foreground">
|
||||
<p className="mb-3 text-ui-11p5 leading-snug text-muted-foreground">
|
||||
Couldn't load full details from Hugging Face. Some fields may be
|
||||
incomplete.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -126,17 +126,17 @@ function prepareReadmeBody(markdown: string): string {
|
|||
}
|
||||
|
||||
const PROSE = cn(
|
||||
"max-w-none text-[0.84375rem] leading-[1.7] text-foreground/85",
|
||||
"[&_h1]:text-[1.125rem] [&_h1]:font-semibold [&_h1]:tracking-tight [&_h1]:mt-2 [&_h1]:mb-3",
|
||||
"[&_h2]:text-[0.96875rem] [&_h2]:font-semibold [&_h2]:tracking-tight [&_h2]:mt-5 [&_h2]:mb-2",
|
||||
"[&_h3]:text-[0.875rem] [&_h3]:font-semibold [&_h3]:mt-4 [&_h3]:mb-1.5",
|
||||
"max-w-none text-ui-13p5 leading-[1.7] text-foreground/85",
|
||||
"[&_h1]:text-ui-18 [&_h1]:font-semibold [&_h1]:tracking-tight [&_h1]:mt-2 [&_h1]:mb-3",
|
||||
"[&_h2]:text-ui-15p5 [&_h2]:font-semibold [&_h2]:tracking-tight [&_h2]:mt-5 [&_h2]:mb-2",
|
||||
"[&_h3]:text-ui-14 [&_h3]:font-semibold [&_h3]:mt-4 [&_h3]:mb-1.5",
|
||||
"[&_p]:my-2.5 [&_ul]:my-2 [&_ol]:my-2 [&_li]:my-0.5",
|
||||
"[&_a]:text-primary [&_a:hover]:underline",
|
||||
"[&_code]:rounded-md [&_code]:bg-muted/60 [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-[0.75rem] [&_code]:font-mono",
|
||||
"[&_pre]:rounded-[12px] [&_pre]:border [&_pre]:border-border/60 [&_pre]:bg-muted/40 [&_pre]:p-3 [&_pre]:text-[0.75rem] [&_pre]:overflow-x-auto",
|
||||
"[&_code]:rounded-md [&_code]:bg-muted/60 [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-ui-12 [&_code]:font-mono",
|
||||
"[&_pre]:rounded-[12px] [&_pre]:border [&_pre]:border-border/60 [&_pre]:bg-muted/40 [&_pre]:p-3 [&_pre]:text-ui-12 [&_pre]:overflow-x-auto",
|
||||
"[&_pre_code]:bg-transparent [&_pre_code]:p-0",
|
||||
"[&_blockquote]:border-l-2 [&_blockquote]:border-border/60 [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground",
|
||||
"[&_table]:my-3 [&_table]:text-[0.78125rem]",
|
||||
"[&_table]:my-3 [&_table]:text-ui-12p5",
|
||||
"[&_th]:px-2 [&_th]:py-1.5 [&_th]:text-left [&_th]:font-semibold [&_th]:border-b [&_th]:border-border/60",
|
||||
"[&_td]:px-2 [&_td]:py-1.5 [&_td]:border-b [&_td]:border-border/40",
|
||||
"[&_img]:rounded-[10px] [&_img]:my-2 [&_img]:max-w-full",
|
||||
|
|
@ -300,7 +300,7 @@ function ReadmePlaceholder({
|
|||
aria-busy="true"
|
||||
aria-live="polite"
|
||||
>
|
||||
<div className="flex items-center gap-2 text-[0.78125rem] text-muted-foreground">
|
||||
<div className="flex items-center gap-2 text-ui-12p5 text-muted-foreground">
|
||||
<Spinner className="size-3.5" />
|
||||
{message ?? `Loading ${kind === "dataset" ? "dataset" : "model"} card…`}
|
||||
</div>
|
||||
|
|
@ -540,7 +540,7 @@ export function ModelReadme({
|
|||
? current.error
|
||||
: readmeUnavailableMessage(subject);
|
||||
return (
|
||||
<p className="min-h-[44px] text-[0.78125rem] text-muted-foreground">
|
||||
<p className="min-h-[44px] text-ui-12p5 text-muted-foreground">
|
||||
{errorMessage}
|
||||
</p>
|
||||
);
|
||||
|
|
@ -548,7 +548,7 @@ export function ModelReadme({
|
|||
|
||||
if (!current.body) {
|
||||
return (
|
||||
<p className="min-h-[44px] text-[0.78125rem] text-muted-foreground">
|
||||
<p className="min-h-[44px] text-ui-12p5 text-muted-foreground">
|
||||
{readmeMissingMessage(subject)}
|
||||
</p>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export function InventoryWarningRow({
|
|||
onRetry: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="mx-5 mt-2 rounded-[8px] border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-[0.78125rem] text-muted-foreground">
|
||||
<div className="mx-5 mt-2 rounded-[8px] border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-ui-12p5 text-muted-foreground">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<span>
|
||||
Some on-device sources couldn't be scanned. Showing available{" "}
|
||||
|
|
@ -76,7 +76,7 @@ export function InventoryWarningRow({
|
|||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className="shrink-0 text-[0.75rem] font-medium text-foreground transition-colors hover:text-primary"
|
||||
className="shrink-0 text-ui-12 font-medium text-foreground transition-colors hover:text-primary"
|
||||
onClick={onRetry}
|
||||
>
|
||||
Retry
|
||||
|
|
@ -388,7 +388,7 @@ export function DownloadedList({
|
|||
|
||||
if (!downloadedReady && !hasInventoryRows) {
|
||||
return (
|
||||
<div className="flex min-h-[240px] items-center justify-center gap-3 text-[0.8125rem] text-muted-foreground">
|
||||
<div className="flex min-h-[240px] items-center justify-center gap-3 text-ui-13 text-muted-foreground">
|
||||
<Spinner className="size-4" />
|
||||
Loading local inventory...
|
||||
</div>
|
||||
|
|
@ -416,7 +416,7 @@ export function DownloadedList({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onClearFilters}
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-transparent px-3 text-[0.75rem] font-medium text-foreground transition-colors hover:bg-foreground/[0.04] dark:hover:bg-white/[0.05]"
|
||||
className="inline-flex h-8 items-center gap-1.5 rounded-full bg-transparent px-3 text-ui-12 font-medium text-foreground transition-colors hover:bg-foreground/[0.04] dark:hover:bg-white/[0.05]"
|
||||
>
|
||||
Show all types
|
||||
</button>
|
||||
|
|
@ -444,7 +444,7 @@ export function DownloadedList({
|
|||
<>
|
||||
{pinnedItems.length > 0 && (
|
||||
<>
|
||||
<div className="flex items-center gap-1.5 px-1 pb-2 pt-3 text-[0.6875rem] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="flex items-center gap-1.5 px-1 pb-2 pt-3 text-ui-11 font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<HugeiconsIcon
|
||||
icon={PinIcon}
|
||||
strokeWidth={1.75}
|
||||
|
|
@ -474,7 +474,7 @@ export function DownloadedList({
|
|||
))}
|
||||
</div>
|
||||
{unpinnedItems.length > 0 && (
|
||||
<div className="px-1 pb-2 pt-2 text-[0.6875rem] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="px-1 pb-2 pt-2 text-ui-11 font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
All {isDataset ? "datasets" : "models"}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -188,14 +188,14 @@ function CachedSizeChipLive({
|
|||
<StatChip
|
||||
icon={PackageIcon}
|
||||
value={formatBytes(row.size_bytes)}
|
||||
className="text-[0.6875rem] text-white/70"
|
||||
className="text-ui-11 text-white/70"
|
||||
/>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<span className="block max-w-52 text-[0.6875rem] leading-4 text-muted-foreground">
|
||||
<span className="block max-w-52 text-ui-11 leading-4 text-muted-foreground">
|
||||
{variantMessage}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -225,7 +225,7 @@ export function StatChip({
|
|||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex shrink-0 items-center gap-1 whitespace-nowrap text-[0.625rem] font-medium leading-none tabular-nums text-muted-foreground/75",
|
||||
"inline-flex shrink-0 items-center gap-1 whitespace-nowrap text-ui-10 font-medium leading-none tabular-nums text-muted-foreground/75",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
@ -482,7 +482,7 @@ export const DiscoverModelRow = memo(function DiscoverModelRow({
|
|||
<div className="flex min-w-0 flex-1 flex-col gap-[3px]">
|
||||
<div className="flex h-[18px] min-w-0 items-center justify-between gap-2">
|
||||
<div className="flex min-w-0 items-center gap-2 pr-2">
|
||||
<p className="truncate text-[0.75rem] font-medium leading-[1.125rem] tracking-[-0.005em] text-foreground">
|
||||
<p className="truncate text-ui-12 font-medium leading-ui-18 tracking-[-0.005em] text-foreground">
|
||||
{row.repo}
|
||||
</p>
|
||||
<AccessGlyphs
|
||||
|
|
@ -518,7 +518,7 @@ export const DiscoverModelRow = memo(function DiscoverModelRow({
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex h-[16px] min-w-0 items-center justify-between gap-2 text-[0.71875rem] leading-[1rem] text-muted-foreground/85">
|
||||
<div className="flex h-[16px] min-w-0 items-center justify-between gap-2 text-ui-11p5 leading-ui-16 text-muted-foreground/85">
|
||||
<span className="flex min-w-0 items-center gap-1">
|
||||
<span className="truncate">{row.owner}</span>
|
||||
{row.owner.toLowerCase() === "unsloth" && (
|
||||
|
|
@ -528,7 +528,7 @@ export const DiscoverModelRow = memo(function DiscoverModelRow({
|
|||
/>
|
||||
)}
|
||||
</span>
|
||||
<span className="shrink-0 text-[0.65625rem] tabular-nums">
|
||||
<span className="shrink-0 text-ui-10p5 tabular-nums">
|
||||
{formatRelativeShort(row.result.updatedAt)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -666,7 +666,7 @@ export const InventoryRow = memo(function InventoryRow({
|
|||
<span className="hub-chip tabular-nums">{paramLabel}</span>
|
||||
)}
|
||||
{quantLabel && (
|
||||
<span className="hub-chip font-mono text-[0.65625rem] uppercase">
|
||||
<span className="hub-chip font-mono text-ui-10p5 uppercase">
|
||||
{quantLabel}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -716,7 +716,7 @@ export const InventoryRow = memo(function InventoryRow({
|
|||
) : null;
|
||||
|
||||
const ownerLine = (
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1 text-[0.71875rem] leading-[0.9375rem] text-muted-foreground/80">
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1 text-ui-11p5 leading-ui-15 text-muted-foreground/80">
|
||||
<span className="truncate">{subLabel}</span>
|
||||
{subLabel.toLowerCase() === "unsloth" && (
|
||||
<span
|
||||
|
|
@ -817,17 +817,17 @@ export const InventoryRow = memo(function InventoryRow({
|
|||
<OwnerAvatar
|
||||
owner={row.owner}
|
||||
repoName={title}
|
||||
className="size-8 shrink-0 rounded-[9px] text-[0.75rem]"
|
||||
className="size-8 shrink-0 rounded-[9px] text-ui-12"
|
||||
remote={false}
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="truncate text-[0.78125rem] font-semibold leading-[1rem] text-foreground">
|
||||
<span className="truncate text-ui-12p5 font-semibold leading-ui-16 text-foreground">
|
||||
{title}
|
||||
</span>
|
||||
{compactMarkers}
|
||||
</div>
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1.5 text-[0.65625rem] leading-[0.875rem] text-muted-foreground/75">
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1.5 text-ui-10p5 leading-ui-14 text-muted-foreground/75">
|
||||
<span className="flex min-w-0 items-center gap-1">
|
||||
<span className="truncate">{subLabel}</span>
|
||||
{subLabel.toLowerCase() === "unsloth" && (
|
||||
|
|
@ -851,7 +851,7 @@ export const InventoryRow = memo(function InventoryRow({
|
|||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-2 text-[0.65625rem] tabular-nums text-muted-foreground/70">
|
||||
<div className="flex shrink-0 items-center gap-2 text-ui-10p5 tabular-nums text-muted-foreground/70">
|
||||
{row.kind === "cache" ? (
|
||||
<CachedSizeChip
|
||||
repoId={row.repoId}
|
||||
|
|
@ -894,7 +894,7 @@ export const InventoryRow = memo(function InventoryRow({
|
|||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="truncate text-[0.84375rem] font-semibold leading-[1.0625rem] text-foreground">
|
||||
<span className="truncate text-ui-13p5 font-semibold leading-ui-17 text-foreground">
|
||||
{title}
|
||||
</span>
|
||||
{statusMarkers}
|
||||
|
|
@ -915,11 +915,11 @@ export const InventoryRow = memo(function InventoryRow({
|
|||
cachePath={row.cachePath}
|
||||
/>
|
||||
) : trailing ? (
|
||||
<span className="truncate text-[0.71875rem] tabular-nums text-muted-foreground/70">
|
||||
<span className="truncate text-ui-11p5 tabular-nums text-muted-foreground/70">
|
||||
{trailing}
|
||||
</span>
|
||||
) : sourceLabel ? (
|
||||
<span className="truncate text-[0.71875rem] text-muted-foreground/55">
|
||||
<span className="truncate text-ui-11p5 text-muted-foreground/55">
|
||||
{sourceLabel}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ export function ModelsHeader({
|
|||
<StatPill icon={CpuIcon} label="CPU" value={coreLabel} />
|
||||
|
||||
{activeCheckpoint && (
|
||||
<div className="hub-tag-soft ml-1 inline-flex items-center gap-1.5 px-2 py-1 text-[0.71875rem]">
|
||||
<div className="hub-tag-soft ml-1 inline-flex items-center gap-1.5 px-2 py-1 text-ui-11p5">
|
||||
<span
|
||||
className="size-1.5 rounded-full bg-emerald-500"
|
||||
aria-hidden="true"
|
||||
|
|
@ -115,7 +115,7 @@ export function ModelsHeader({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onEject}
|
||||
className="-mr-0.5 ml-0.5 inline-flex cursor-pointer items-center gap-1 rounded-md px-1.5 text-[0.6875rem] text-muted-foreground transition-colors hover:text-foreground"
|
||||
className="-mr-0.5 ml-0.5 inline-flex cursor-pointer items-center gap-1 rounded-md px-1.5 text-ui-11 text-muted-foreground transition-colors hover:text-foreground"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={RemoveCircleIcon}
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ export function InventorySortControl({
|
|||
title={selected?.label}
|
||||
// Capped and shrinkable so a long label truncates instead of wrapping
|
||||
// the "On device" heading beside these pills in the narrow split pane.
|
||||
className="h-8 min-w-[72px] max-w-[124px] shrink text-[0.71875rem]"
|
||||
className="h-8 min-w-[72px] max-w-[124px] shrink text-ui-11p5"
|
||||
triggerContent={
|
||||
<span className="flex min-w-0 items-center gap-1">
|
||||
<HugeiconsIcon
|
||||
|
|
@ -176,7 +176,7 @@ export function InventoryTypeFilterControl({
|
|||
title={selected?.label}
|
||||
// Capped and shrinkable so a long label ("Speech to text") truncates
|
||||
// instead of wrapping the "On device" heading beside these pills.
|
||||
className="h-8 min-w-[72px] max-w-[124px] shrink text-[0.71875rem]"
|
||||
className="h-8 min-w-[72px] max-w-[124px] shrink text-ui-11p5"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -230,11 +230,11 @@ export function HubListHeader({
|
|||
<div className="min-w-0 space-y-0.5">
|
||||
{/* truncate keeps the heading on one line and clips a long search
|
||||
query with an ellipsis instead of overflowing the pills. */}
|
||||
<h2 className="truncate text-[1.125rem] font-semibold tracking-[-0.02em] text-foreground">
|
||||
<h2 className="truncate text-ui-18 font-semibold tracking-[-0.02em] text-foreground">
|
||||
{title}
|
||||
</h2>
|
||||
{subtitle && (
|
||||
<p className="text-[0.78125rem] leading-tight text-muted-foreground">
|
||||
<p className="text-ui-12p5 leading-tight text-muted-foreground">
|
||||
{subtitle}
|
||||
</p>
|
||||
)}
|
||||
|
|
@ -309,7 +309,7 @@ export function HubListHeader({
|
|||
|
||||
export function ResultListHeader({ isDataset }: { isDataset: boolean }) {
|
||||
return (
|
||||
<div className="flex w-full items-center gap-3 px-4 pb-2 text-[0.6875rem] font-medium text-muted-foreground/55">
|
||||
<div className="flex w-full items-center gap-3 px-4 pb-2 text-ui-11 font-medium text-muted-foreground/55">
|
||||
<span className={LIST_COLS.model}>{isDataset ? "Dataset" : "Model"}</span>
|
||||
<span className={isDataset ? LIST_COLS.caps : LIST_COLS.capsModel}>
|
||||
{isDataset ? "Details" : "Capabilities"}
|
||||
|
|
@ -445,7 +445,7 @@ function CapabilitiesCell({
|
|||
))}
|
||||
{extra > 0 && <span className="hub-chip shrink-0">+{extra}</span>}
|
||||
{shown.length === 0 && taskLabel && (
|
||||
<span className="truncate text-[0.75rem] text-muted-foreground/75">
|
||||
<span className="truncate text-ui-12 text-muted-foreground/75">
|
||||
{taskLabel}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -454,7 +454,7 @@ function CapabilitiesCell({
|
|||
<TooltipContent side="top" align="start" className="tooltip-compact">
|
||||
<div className="flex flex-col items-start gap-1">
|
||||
{taskLabel && (
|
||||
<span className="text-[0.6875rem] font-medium text-muted-foreground">
|
||||
<span className="text-ui-11 font-medium text-muted-foreground">
|
||||
{taskLabel}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -642,12 +642,12 @@ export const ResultCard = memo(function ResultCard({
|
|||
<OwnerAvatar
|
||||
owner={row.owner}
|
||||
repoName={row.repo}
|
||||
className="size-[52px] shrink-0 rounded-[16px] text-[1rem] ring-1 ring-black/5 dark:ring-white/10"
|
||||
className="size-[52px] shrink-0 rounded-[16px] text-ui-16 ring-1 ring-black/5 dark:ring-white/10"
|
||||
remote={false}
|
||||
/>
|
||||
<div className="flex min-w-0 flex-1 flex-col">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<span className="truncate text-[0.9375rem] font-semibold leading-[1.125rem] text-foreground">
|
||||
<span className="truncate text-ui-15 font-semibold leading-ui-18 text-foreground">
|
||||
{row.repo}
|
||||
</span>
|
||||
<TitleMarkers
|
||||
|
|
@ -659,10 +659,10 @@ export const ResultCard = memo(function ResultCard({
|
|||
onDevice={onDevice}
|
||||
/>
|
||||
</div>
|
||||
<span className="flex min-w-0 items-center gap-1 text-[0.78125rem] leading-[1rem] text-muted-foreground/80">
|
||||
<span className="flex min-w-0 items-center gap-1 text-ui-12p5 leading-ui-16 text-muted-foreground/80">
|
||||
<VerifiedOwner owner={row.owner} />
|
||||
</span>
|
||||
<div className="flex min-w-0 items-center gap-2 overflow-hidden text-[0.71875rem] leading-[1rem] tabular-nums text-muted-foreground/65">
|
||||
<div className="flex min-w-0 items-center gap-2 overflow-hidden text-ui-11p5 leading-ui-16 tabular-nums text-muted-foreground/65">
|
||||
{textParts.map((part, index) => (
|
||||
<Fragment key={part.key}>
|
||||
{index > 0 && (
|
||||
|
|
@ -761,12 +761,12 @@ export const ResultGridRow = memo(function ResultGridRow({
|
|||
<OwnerAvatar
|
||||
owner={row.owner}
|
||||
repoName={row.repo}
|
||||
className="size-9 shrink-0 rounded-[12px] text-[0.8125rem] ring-1 ring-black/5 dark:ring-white/10"
|
||||
className="size-9 shrink-0 rounded-[12px] text-ui-13 ring-1 ring-black/5 dark:ring-white/10"
|
||||
remote={false}
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="truncate text-[0.84375rem] font-semibold leading-[1.0625rem] text-foreground">
|
||||
<span className="truncate text-ui-13p5 font-semibold leading-ui-17 text-foreground">
|
||||
{row.repo}
|
||||
</span>
|
||||
<TitleMarkers
|
||||
|
|
@ -778,7 +778,7 @@ export const ResultGridRow = memo(function ResultGridRow({
|
|||
onDevice={onDevice}
|
||||
/>
|
||||
</div>
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1 text-[0.71875rem] leading-[0.9375rem] text-muted-foreground/80">
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1 text-ui-11p5 leading-ui-15 text-muted-foreground/80">
|
||||
<VerifiedOwner owner={row.owner} />
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -786,7 +786,7 @@ export const ResultGridRow = memo(function ResultGridRow({
|
|||
<div className={isDataset ? LIST_COLS.caps : LIST_COLS.capsModel}>
|
||||
{isDataset ? (
|
||||
row.summary ? (
|
||||
<span className="truncate text-[0.75rem] text-muted-foreground/75">
|
||||
<span className="truncate text-ui-12 text-muted-foreground/75">
|
||||
{row.summary}
|
||||
</span>
|
||||
) : null
|
||||
|
|
@ -801,7 +801,7 @@ export const ResultGridRow = memo(function ResultGridRow({
|
|||
<div
|
||||
className={cn(
|
||||
LIST_COLS.size,
|
||||
"truncate text-[0.75rem] tabular-nums text-muted-foreground",
|
||||
"truncate text-ui-12 tabular-nums text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{sizeDisplay ?? "—"}
|
||||
|
|
@ -809,7 +809,7 @@ export const ResultGridRow = memo(function ResultGridRow({
|
|||
<div
|
||||
className={cn(
|
||||
LIST_COLS.updated,
|
||||
"truncate text-[0.75rem] tabular-nums text-muted-foreground",
|
||||
"truncate text-ui-12 tabular-nums text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{formatRelativeShort(row.result.updatedAt)}
|
||||
|
|
@ -817,7 +817,7 @@ export const ResultGridRow = memo(function ResultGridRow({
|
|||
<div
|
||||
className={cn(
|
||||
LIST_COLS.downloads,
|
||||
"text-[0.75rem] tabular-nums text-muted-foreground",
|
||||
"text-ui-12 tabular-nums text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
<StatItem
|
||||
|
|
@ -828,7 +828,7 @@ export const ResultGridRow = memo(function ResultGridRow({
|
|||
<div
|
||||
className={cn(
|
||||
LIST_COLS.likes,
|
||||
"text-[0.75rem] tabular-nums text-muted-foreground",
|
||||
"text-ui-12 tabular-nums text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
<StatItem
|
||||
|
|
@ -883,12 +883,12 @@ export const ResultSplitRow = memo(function ResultSplitRow({
|
|||
<OwnerAvatar
|
||||
owner={row.owner}
|
||||
repoName={row.repo}
|
||||
className="size-8 shrink-0 rounded-[9px] text-[0.75rem]"
|
||||
className="size-8 shrink-0 rounded-[9px] text-ui-12"
|
||||
remote={false}
|
||||
/>
|
||||
<div className="flex min-w-0 flex-1 flex-col">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="truncate text-[0.78125rem] font-semibold leading-[1rem] text-foreground">
|
||||
<span className="truncate text-ui-12p5 font-semibold leading-ui-16 text-foreground">
|
||||
{row.repo}
|
||||
</span>
|
||||
<TitleMarkers
|
||||
|
|
@ -900,11 +900,11 @@ export const ResultSplitRow = memo(function ResultSplitRow({
|
|||
onDevice={onDevice}
|
||||
/>
|
||||
</div>
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1 text-[0.65625rem] leading-[0.875rem] text-muted-foreground/80">
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1 text-ui-10p5 leading-ui-14 text-muted-foreground/80">
|
||||
<VerifiedOwner owner={row.owner} />
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex shrink-0 flex-col items-end gap-0.5 text-[0.65625rem] tabular-nums text-muted-foreground/70">
|
||||
<div className="flex shrink-0 flex-col items-end gap-0.5 text-ui-10p5 tabular-nums text-muted-foreground/70">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="inline-flex items-center gap-1">
|
||||
<HugeiconsIcon
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ export const ModelsToolbar = memo(function ModelsToolbar({
|
|||
aria-checked={tab === "discover"}
|
||||
onClick={() => onTabChange("discover")}
|
||||
className={cn(
|
||||
"relative z-10 inline-flex h-9 flex-1 items-center justify-center rounded-full px-3 text-[0.78125rem] transition-colors",
|
||||
"relative z-10 inline-flex h-9 flex-1 items-center justify-center rounded-full px-3 text-ui-12p5 transition-colors",
|
||||
tab === "discover"
|
||||
? "text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground",
|
||||
|
|
@ -208,7 +208,7 @@ export const ModelsToolbar = memo(function ModelsToolbar({
|
|||
aria-checked={tab === "downloaded"}
|
||||
onClick={() => onTabChange("downloaded")}
|
||||
className={cn(
|
||||
"relative z-10 inline-flex h-9 flex-1 items-center justify-center rounded-full px-3 text-[0.78125rem] transition-colors",
|
||||
"relative z-10 inline-flex h-9 flex-1 items-center justify-center rounded-full px-3 text-ui-12p5 transition-colors",
|
||||
tab === "downloaded"
|
||||
? "text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground",
|
||||
|
|
@ -261,7 +261,7 @@ export const ModelsToolbar = memo(function ModelsToolbar({
|
|||
: "Search all models"
|
||||
}
|
||||
className={cn(
|
||||
"field-soft h-9 rounded-full !border-0 pl-10 text-[0.8125rem] placeholder:text-muted-foreground/80 focus-visible:!ring-0",
|
||||
"field-soft h-9 rounded-full !border-0 pl-10 text-ui-13 placeholder:text-muted-foreground/80 focus-visible:!ring-0",
|
||||
hasTrailing ? "pr-10" : "pr-4",
|
||||
)}
|
||||
/>
|
||||
|
|
@ -306,7 +306,7 @@ export const ModelsToolbar = memo(function ModelsToolbar({
|
|||
onClick={onManageLocalFolders}
|
||||
className={cn(
|
||||
triggerBase,
|
||||
"field-filter inline-flex h-9 shrink-0 items-center gap-1.5 rounded-full px-3 text-[0.78125rem]",
|
||||
"field-filter inline-flex h-9 shrink-0 items-center gap-1.5 rounded-full px-3 text-ui-12p5",
|
||||
)}
|
||||
>
|
||||
<HugeiconsIcon
|
||||
|
|
@ -365,7 +365,7 @@ export const ModelsToolbar = memo(function ModelsToolbar({
|
|||
role="checkbox"
|
||||
aria-checked={fitOnDeviceOnly}
|
||||
onClick={() => onFitOnDeviceOnlyChange(!fitOnDeviceOnly)}
|
||||
className="flex w-full cursor-pointer select-none items-center gap-2 rounded-[10px] px-3 py-2 text-left text-[0.78125rem] text-muted-foreground transition-colors hover:text-foreground"
|
||||
className="flex w-full cursor-pointer select-none items-center gap-2 rounded-[10px] px-3 py-2 text-left text-ui-12p5 text-muted-foreground transition-colors hover:text-foreground"
|
||||
>
|
||||
<Checkbox
|
||||
checked={fitOnDeviceOnly}
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ export function OnDeviceFoldersDialog({
|
|||
overlayClassName="bg-black/20 backdrop-blur-none"
|
||||
>
|
||||
<DialogHeader className="border-b border-border/60 px-5 py-4">
|
||||
<DialogTitle className="text-[0.9375rem]">
|
||||
<DialogTitle className="text-ui-15">
|
||||
On-device locations
|
||||
</DialogTitle>
|
||||
<DialogDescription className="sr-only">
|
||||
|
|
@ -197,7 +197,7 @@ export function OnDeviceFoldersDialog({
|
|||
|
||||
<div className="space-y-4 px-5 py-4">
|
||||
<div className="rounded-[14px] border border-border/70 bg-muted/20 p-3">
|
||||
<div className="mb-2 flex items-center gap-2 text-[0.75rem] font-medium text-foreground">
|
||||
<div className="mb-2 flex items-center gap-2 text-ui-12 font-medium text-foreground">
|
||||
<HugeiconsIcon
|
||||
icon={FolderAddIcon}
|
||||
strokeWidth={1.75}
|
||||
|
|
@ -222,7 +222,7 @@ export function OnDeviceFoldersDialog({
|
|||
void handleAdd(path);
|
||||
}}
|
||||
placeholder="Paste model folder or file path"
|
||||
className="field-soft h-9 rounded-full pl-9 pr-3 font-mono text-[0.75rem] placeholder:font-sans"
|
||||
className="field-soft h-9 rounded-full pl-9 pr-3 font-mono text-ui-12 placeholder:font-sans"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-2">
|
||||
|
|
@ -252,7 +252,7 @@ export function OnDeviceFoldersDialog({
|
|||
size="sm"
|
||||
onClick={() => void handleAdd(path)}
|
||||
disabled={!path.trim() || pending !== null}
|
||||
className="h-9 rounded-full px-3 text-[0.78125rem]"
|
||||
className="h-9 rounded-full px-3 text-ui-12p5"
|
||||
>
|
||||
{pending === "add" ? (
|
||||
<Spinner className="size-3.5" />
|
||||
|
|
@ -271,14 +271,14 @@ export function OnDeviceFoldersDialog({
|
|||
</div>
|
||||
|
||||
{error ? (
|
||||
<div className="rounded-[10px] border border-destructive/20 bg-destructive/5 px-3 py-2 text-[0.75rem] text-destructive">
|
||||
<div className="rounded-[10px] border border-destructive/20 bg-destructive/5 px-3 py-2 text-ui-12 text-destructive">
|
||||
{error}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="overflow-hidden rounded-[14px] border border-border/70">
|
||||
<div className="flex h-10 items-center justify-between border-b border-border/60 px-3">
|
||||
<span className="text-[0.75rem] font-medium text-foreground">
|
||||
<span className="text-ui-12 font-medium text-foreground">
|
||||
Indexed locations
|
||||
</span>
|
||||
<Tooltip>
|
||||
|
|
@ -305,12 +305,12 @@ export function OnDeviceFoldersDialog({
|
|||
|
||||
<div className="max-h-64 overflow-y-auto">
|
||||
{loading ? (
|
||||
<div className="flex h-24 items-center justify-center gap-2 text-[0.75rem] text-muted-foreground">
|
||||
<div className="flex h-24 items-center justify-center gap-2 text-ui-12 text-muted-foreground">
|
||||
<Spinner className="size-3.5" />
|
||||
Loading locations...
|
||||
</div>
|
||||
) : sortedFolders.length === 0 ? (
|
||||
<div className="flex h-28 flex-col items-center justify-center gap-2 px-4 text-center text-[0.75rem] text-muted-foreground">
|
||||
<div className="flex h-28 flex-col items-center justify-center gap-2 px-4 text-center text-ui-12 text-muted-foreground">
|
||||
<HugeiconsIcon
|
||||
icon={FolderOpenIcon}
|
||||
strokeWidth={1.75}
|
||||
|
|
@ -327,8 +327,8 @@ export function OnDeviceFoldersDialog({
|
|||
className={cn(
|
||||
"grid min-h-12 w-full items-center gap-3 border-b border-border/50 px-3 py-2 last:border-b-0",
|
||||
isTauri
|
||||
? "grid-cols-[32px_minmax(0,1fr)_32px_32px]"
|
||||
: "grid-cols-[32px_minmax(0,1fr)_32px]",
|
||||
? "grid-cols-[2rem_minmax(0,1fr)_2rem_2rem]"
|
||||
: "grid-cols-[2rem_minmax(0,1fr)_2rem]",
|
||||
)}
|
||||
>
|
||||
<div className="flex size-8 shrink-0 items-center justify-center rounded-[9px] bg-muted text-muted-foreground">
|
||||
|
|
@ -340,14 +340,14 @@ export function OnDeviceFoldersDialog({
|
|||
</div>
|
||||
<div className="min-w-0 overflow-hidden">
|
||||
<p
|
||||
className="block w-full truncate text-[0.78125rem] font-medium text-foreground"
|
||||
className="block w-full truncate text-ui-12p5 font-medium text-foreground"
|
||||
title={pathTail(folder.path)}
|
||||
>
|
||||
{pathTail(folder.path)}
|
||||
</p>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild={true}>
|
||||
<p className="block w-full truncate font-mono text-[0.65625rem] text-muted-foreground">
|
||||
<p className="block w-full truncate font-mono text-ui-10p5 text-muted-foreground">
|
||||
{folder.path}
|
||||
</p>
|
||||
</TooltipTrigger>
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ import {
|
|||
type AvatarSize = "xs" | "sm" | "md" | "lg";
|
||||
|
||||
const SIZES: Record<AvatarSize, string> = {
|
||||
xs: "size-5 rounded-[8px] text-[0.5625rem]",
|
||||
sm: "size-7 rounded-[10px] text-[0.6875rem]",
|
||||
md: "size-9 rounded-[12px] text-[0.8125rem]",
|
||||
lg: "size-12 rounded-[15px] text-[1rem]",
|
||||
xs: "size-5 rounded-[8px] text-ui-9",
|
||||
sm: "size-7 rounded-[10px] text-ui-11",
|
||||
md: "size-9 rounded-[12px] text-ui-13",
|
||||
lg: "size-12 rounded-[15px] text-ui-16",
|
||||
};
|
||||
|
||||
const AVATAR_IMAGE_RETRY_BASE_MS = 60_000;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export function OwnerScopeToggle({
|
|||
ariaLabel="Publisher scope"
|
||||
align="end"
|
||||
// Extra gap before the chevron; min-width keeps the pill readable.
|
||||
className="h-8 min-w-[96px] gap-1.5 text-[0.71875rem]"
|
||||
className="h-8 min-w-[96px] gap-1.5 text-ui-11p5"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,13 +30,13 @@ export function RecentSearches({
|
|||
onMouseDown={(event) => event.preventDefault()}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2 px-2.5 pb-1.5 pt-1">
|
||||
<span className="text-[0.6875rem] font-semibold uppercase tracking-[0.04em] text-muted-foreground/70">
|
||||
<span className="text-ui-11 font-semibold uppercase tracking-[0.04em] text-muted-foreground/70">
|
||||
Recent searches
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClear}
|
||||
className="hub-recent-clear rounded-full px-2 py-0.5 text-[0.71875rem] font-medium text-muted-foreground transition-colors hover:text-foreground"
|
||||
className="hub-recent-clear rounded-full px-2 py-0.5 text-ui-11p5 font-medium text-muted-foreground transition-colors hover:text-foreground"
|
||||
>
|
||||
Clear all
|
||||
</button>
|
||||
|
|
@ -55,7 +55,7 @@ export function RecentSearches({
|
|||
strokeWidth={1.75}
|
||||
className="size-4 shrink-0 text-muted-foreground/70"
|
||||
/>
|
||||
<span className="truncate text-[0.8125rem] text-foreground">
|
||||
<span className="truncate text-ui-13 text-foreground">
|
||||
{query}
|
||||
</span>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ export function SafetensorsDownloadCard({
|
|||
}
|
||||
>
|
||||
<div className="relative flex h-9 min-w-0 flex-1 items-center pl-3 pr-2">
|
||||
<span className="flex items-center gap-1.5 text-[0.75rem] text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5 text-ui-12 text-muted-foreground">
|
||||
{(isActive || isDownloaded) && (
|
||||
<DotTag
|
||||
tone="success"
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ function SettingsSection({
|
|||
<div className="border-t border-border/50 pb-5 pt-5 first:border-t-0 first:pt-0">
|
||||
<div
|
||||
className={cn(
|
||||
"pb-4 text-[0.6875rem] font-semibold uppercase tracking-wider text-muted-foreground",
|
||||
"pb-4 text-ui-11 font-semibold uppercase tracking-wider text-muted-foreground",
|
||||
labelClassName,
|
||||
)}
|
||||
>
|
||||
|
|
@ -80,7 +80,7 @@ function ToggleRow({
|
|||
return (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="text-[0.8125rem] font-medium text-nav-fg">{label}</span>
|
||||
<span className="text-ui-13 font-medium text-nav-fg">{label}</span>
|
||||
{info && <InfoHint>{info}</InfoHint>}
|
||||
</div>
|
||||
<Switch
|
||||
|
|
@ -251,7 +251,7 @@ export function SamplingSettingsButton({ className }: { className?: string }) {
|
|||
}
|
||||
placeholder="Instructions sent before every conversation."
|
||||
aria-label="System prompt"
|
||||
className="min-h-[84px] resize-y text-[0.8125rem]"
|
||||
className="min-h-[84px] resize-y text-ui-13"
|
||||
/>
|
||||
</SettingsSection>
|
||||
|
||||
|
|
@ -264,7 +264,7 @@ export function SamplingSettingsButton({ className }: { className?: string }) {
|
|||
/>
|
||||
{reasoningEffortLevels.length > 0 && (
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<span className="text-[0.8125rem] font-medium text-nav-fg">
|
||||
<span className="text-ui-13 font-medium text-nav-fg">
|
||||
Reasoning effort
|
||||
</span>
|
||||
<HubOptionMenu
|
||||
|
|
@ -276,7 +276,7 @@ export function SamplingSettingsButton({ className }: { className?: string }) {
|
|||
onValueChange={setReasoningEffort}
|
||||
ariaLabel="Reasoning effort"
|
||||
align="end"
|
||||
className="h-8 text-[0.71875rem]"
|
||||
className="h-8 text-ui-11p5"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ const CAPABILITY_TONE: Record<CapabilityKey, string> = {
|
|||
|
||||
export function AccessChip({ label }: { label: string }) {
|
||||
return (
|
||||
<span className="inline-flex h-6 shrink-0 items-center rounded-full border border-amber-500/30 bg-amber-500/8 px-2 text-[0.6875rem] font-medium leading-none text-amber-700 dark:text-amber-300">
|
||||
<span className="inline-flex h-6 shrink-0 items-center rounded-full border border-amber-500/30 bg-amber-500/8 px-2 text-ui-11 font-medium leading-none text-amber-700 dark:text-amber-300">
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
|
|
@ -144,7 +144,7 @@ export function CapabilityPill({
|
|||
<span
|
||||
aria-label={iconOnly ? capability.label : undefined}
|
||||
className={cn(
|
||||
"inline-flex h-6 shrink-0 items-center rounded-full text-[0.71875rem] font-medium",
|
||||
"inline-flex h-6 shrink-0 items-center rounded-full text-ui-11p5 font-medium",
|
||||
iconOnly ? "w-6 justify-center px-0" : "gap-1.5 px-2.5",
|
||||
CAPABILITY_TONE[capability.key],
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export function TransportConflictDialog({
|
|||
if (!o) onCancel();
|
||||
}}
|
||||
>
|
||||
<AlertDialogContent className="sm:!max-w-[352px]">
|
||||
<AlertDialogContent className="sm:!max-w-[22rem]">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Different transport mode</AlertDialogTitle>
|
||||
<AlertDialogDescription>{description}</AlertDialogDescription>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export function TransportToggle() {
|
|||
return (
|
||||
<fieldset
|
||||
aria-label="Download transport"
|
||||
className="hub-tag-soft m-0 inline-flex h-[26px] min-w-0 items-center gap-0.5 rounded-full border-0 p-0.5 text-[0.6875rem]"
|
||||
className="hub-tag-soft m-0 inline-flex h-[26px] min-w-0 items-center gap-0.5 rounded-full border-0 p-0.5 text-ui-11"
|
||||
>
|
||||
{OPTIONS.map((opt) => {
|
||||
const active = mode === opt.value;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export function HfTokenIndicator({ showLabel = false }: HfTokenIndicatorProps =
|
|||
onClick={() => openDialog("general")}
|
||||
aria-label={ariaLabel}
|
||||
className={cn(
|
||||
"hub-menu-trigger field-soft inline-flex h-9 w-full items-center justify-between gap-2 rounded-[12px] py-0 pl-1.5 pr-3 text-[0.78125rem] font-medium text-foreground transition-colors",
|
||||
"hub-menu-trigger field-soft inline-flex h-9 w-full items-center justify-between gap-2 rounded-[12px] py-0 pl-1.5 pr-3 text-ui-12p5 font-medium text-foreground transition-colors",
|
||||
"focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0",
|
||||
)}
|
||||
>
|
||||
|
|
@ -64,7 +64,7 @@ export function HfTokenIndicator({ showLabel = false }: HfTokenIndicatorProps =
|
|||
</span>
|
||||
<span
|
||||
className={cn(
|
||||
"shrink-0 text-[0.6875rem] font-normal tabular-nums",
|
||||
"shrink-0 text-ui-11 font-normal tabular-nums",
|
||||
hasToken ? "text-verified" : "text-muted-foreground/70",
|
||||
)}
|
||||
>
|
||||
|
|
@ -89,7 +89,7 @@ export function HfTokenIndicator({ showLabel = false }: HfTokenIndicatorProps =
|
|||
className={cn(
|
||||
// Solid circle reads optically larger than the flat HTTP/Xet box, so
|
||||
// keep it 22px to sit within the row rather than bulging above it.
|
||||
"inline-flex h-[22px] w-[22px] items-center justify-center rounded-full text-[0.71875rem] transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
||||
"inline-flex h-[22px] w-[22px] items-center justify-center rounded-full text-ui-11p5 transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
||||
hasToken
|
||||
? "hub-tag-soft text-muted-foreground hover:text-foreground/80"
|
||||
: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ type PageHeadingProps = {
|
|||
};
|
||||
|
||||
const TITLE_CLASS =
|
||||
"text-[1.875rem] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[2.125rem]";
|
||||
"text-ui-30 font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-ui-34";
|
||||
|
||||
export function PageHeading({
|
||||
title,
|
||||
|
|
@ -38,7 +38,7 @@ export function PageHeading({
|
|||
<h1 className={TITLE_CLASS}>{title}</h1>
|
||||
)}
|
||||
{subtitle ? (
|
||||
<p className="mt-2 text-[0.8125rem] leading-[1.1875rem] text-muted-foreground">
|
||||
<p className="mt-2 text-ui-13 leading-ui-19 text-muted-foreground">
|
||||
{subtitle}
|
||||
</p>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ function DownloadRow({ jobKey }: { jobKey: string }) {
|
|||
return (
|
||||
<li className="flex flex-col gap-1.5 py-2.5 pl-4 pr-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="min-w-0 flex-1 truncate text-[0.78125rem] font-medium text-foreground">
|
||||
<span className="min-w-0 flex-1 truncate text-ui-12p5 font-medium text-foreground">
|
||||
{job.repoId}
|
||||
<span className="text-muted-foreground">{variantSuffix(job)}</span>
|
||||
</span>
|
||||
|
|
@ -165,7 +165,7 @@ function DownloadRow({ jobKey }: { jobKey: string }) {
|
|||
/>
|
||||
) : null}
|
||||
{terminal || job.state === "cancelling" || job.error ? (
|
||||
<div className="px-0 text-[0.6875rem] text-muted-foreground tabular-nums">
|
||||
<div className="px-0 text-ui-11 text-muted-foreground tabular-nums">
|
||||
<StatusLine job={job} />
|
||||
</div>
|
||||
) : null}
|
||||
|
|
@ -229,9 +229,9 @@ export function DownloadManagerPanel({
|
|||
</TooltipContent>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<div className="hub-download-panel pointer-events-auto w-[min(400px,calc(100vw-32px))] overflow-hidden">
|
||||
<div className="hub-download-panel pointer-events-auto w-[min(400px,calc(100vw-2rem))] overflow-hidden">
|
||||
<div className="flex items-center gap-2 border-b border-foreground/[0.07] py-2 pl-4 pr-3">
|
||||
<span className="min-w-0 flex-1 truncate text-[0.78125rem] font-semibold text-foreground">
|
||||
<span className="min-w-0 flex-1 truncate text-ui-12p5 font-semibold text-foreground">
|
||||
{headerLabel}
|
||||
</span>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export function DownloadProgressBar({
|
|||
style={{ left: `${exactPercent}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-2 text-[0.65625rem] text-muted-foreground tabular-nums">
|
||||
<div className="flex items-center justify-between gap-2 text-ui-10p5 text-muted-foreground tabular-nums">
|
||||
<span>
|
||||
{formatBytes(progress.downloadedBytes)}
|
||||
{totalLabel && ` / ${totalLabel}`}
|
||||
|
|
|
|||
|
|
@ -1606,7 +1606,7 @@ export function ModelsPage() {
|
|||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="hidden min-h-0 flex-1 items-center justify-center px-6 text-center text-[0.8125rem] text-muted-foreground lg:flex">
|
||||
<div className="hidden min-h-0 flex-1 items-center justify-center px-6 text-center text-ui-13 text-muted-foreground lg:flex">
|
||||
Select a model to preview its details.
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@
|
|||
}
|
||||
|
||||
.hub-page .hub-focused-heading {
|
||||
font-size: 1.125rem;
|
||||
font-size: calc(1.125rem * var(--ui-font-scale, 1));
|
||||
font-weight: 600;
|
||||
letter-spacing: 0;
|
||||
color: var(--foreground);
|
||||
|
|
@ -798,8 +798,8 @@
|
|||
.hub-download-fab {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -832,16 +832,16 @@
|
|||
top: -3px;
|
||||
right: -3px;
|
||||
display: inline-flex;
|
||||
width: 18px;
|
||||
min-width: 18px;
|
||||
height: 18px;
|
||||
width: 1.125rem;
|
||||
min-width: 1.125rem;
|
||||
height: 1.125rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 9999px;
|
||||
padding-inline: 0;
|
||||
background-color: var(--status-success);
|
||||
color: var(--primary-foreground);
|
||||
font-size: 0.65625rem;
|
||||
font-size: calc(0.65625rem * var(--ui-font-scale, 1));
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
font-variant-numeric: tabular-nums;
|
||||
|
|
@ -1082,7 +1082,7 @@
|
|||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.hub-readme-prose :is(p, div):has(> a:nth-of-type(2) > img) > br {
|
||||
|
|
@ -1107,19 +1107,19 @@
|
|||
@apply so the cascade is explicit and predictable. */
|
||||
.hub-action-btn {
|
||||
display: inline-flex;
|
||||
height: 36px;
|
||||
height: 2.25rem;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
gap: 0.5rem;
|
||||
white-space: nowrap;
|
||||
border-radius: 9999px;
|
||||
background-color: transparent;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
font-size: 0.8125rem;
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
font-size: calc(0.8125rem * var(--ui-font-scale, 1));
|
||||
font-weight: 500;
|
||||
line-height: 1.125rem;
|
||||
line-height: calc(1.125rem * var(--ui-font-scale, 1));
|
||||
letter-spacing: -0.025em;
|
||||
color: var(--foreground);
|
||||
transition: color 150ms, background-color 150ms;
|
||||
|
|
@ -1141,8 +1141,8 @@
|
|||
embedded SVG — locks to 16px so swapping icons or replacing the
|
||||
spinner can't drift the layout. */
|
||||
.hub-action-btn svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
|
@ -1154,19 +1154,19 @@
|
|||
so the height aligns with adjacent ghost buttons. */
|
||||
.hub-run-action-btn {
|
||||
display: inline-flex;
|
||||
height: 36px;
|
||||
height: 2.25rem;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6.4px;
|
||||
gap: 0.4rem;
|
||||
white-space: nowrap;
|
||||
border-radius: 9999px;
|
||||
background-color: var(--status-success);
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
font-size: 0.8125rem;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
font-size: calc(0.8125rem * var(--ui-font-scale, 1));
|
||||
font-weight: 600;
|
||||
line-height: 1.125rem;
|
||||
line-height: calc(1.125rem * var(--ui-font-scale, 1));
|
||||
letter-spacing: -0.025em;
|
||||
color: var(--primary-foreground);
|
||||
transition: background-color 150ms, transform 150ms;
|
||||
|
|
@ -1189,8 +1189,8 @@
|
|||
}
|
||||
|
||||
.hub-run-action-btn svg {
|
||||
width: 14.4px;
|
||||
height: 14.4px;
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
|
@ -1200,8 +1200,8 @@
|
|||
.hub-cta-indicator {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -1232,11 +1232,11 @@
|
|||
`.group/dl` ancestor for the hover scope (the Hub download row). */
|
||||
.hub-row-action {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
right: 0.25rem;
|
||||
top: 50%;
|
||||
display: inline-flex;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
width: 1.75rem;
|
||||
height: 1.75rem;
|
||||
transform: translateY(-50%);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -1261,8 +1261,8 @@
|
|||
}
|
||||
|
||||
.hub-row-action svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1271,9 +1271,9 @@
|
|||
.hub-page .field-trigger.field-filter {
|
||||
color: var(--muted-foreground);
|
||||
font-weight: 400;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
line-height: 1.25rem;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
line-height: calc(1.25rem * var(--ui-font-scale, 1));
|
||||
}
|
||||
|
||||
.hub-page .field-trigger.field-filter:hover {
|
||||
|
|
@ -1284,13 +1284,13 @@
|
|||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
gap: 6.4px;
|
||||
height: 32px;
|
||||
padding-inline: 11.2px;
|
||||
gap: 0.4rem;
|
||||
height: 2rem;
|
||||
padding-inline: 0.7rem;
|
||||
border-radius: 9999px;
|
||||
border: 1px solid color-mix(in srgb, var(--foreground) 8%, transparent);
|
||||
background-color: color-mix(in srgb, var(--foreground) 2.5%, transparent);
|
||||
font-size: 0.75rem;
|
||||
font-size: calc(0.75rem * var(--ui-font-scale, 1));
|
||||
line-height: 1;
|
||||
color: var(--muted-foreground);
|
||||
white-space: nowrap;
|
||||
|
|
@ -1478,7 +1478,7 @@
|
|||
|
||||
@layer utilities {
|
||||
.hub-chip {
|
||||
@apply inline-flex items-center gap-1 rounded-full px-2 py-[3px] text-[0.6875rem] font-medium leading-none;
|
||||
@apply inline-flex items-center gap-1 rounded-full px-2 py-[3px] text-ui-11 font-medium leading-none;
|
||||
background-color: color-mix(in srgb, var(--foreground) 5%, transparent);
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
|
@ -1488,7 +1488,7 @@
|
|||
}
|
||||
|
||||
.hub-meta-tag {
|
||||
@apply inline-flex h-[18px] shrink-0 items-center gap-1 rounded-full px-2 text-[0.6875rem] font-medium leading-none;
|
||||
@apply inline-flex h-[18px] shrink-0 items-center gap-1 rounded-full px-2 text-ui-11 font-medium leading-none;
|
||||
background-color: color-mix(in srgb, var(--foreground) 5%, transparent);
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,13 +126,13 @@ export function ChatTemplateEditorDialog({
|
|||
setError(null);
|
||||
}}
|
||||
readOnly={readOnly}
|
||||
className="min-h-[320px] max-h-[50vh] overflow-y-auto border-0 font-mono text-xs leading-5 corner-squircle focus-visible:ring-0"
|
||||
className="min-h-[20rem] max-h-[50vh] overflow-y-auto border-0 font-mono text-xs leading-5 corner-squircle focus-visible:ring-0"
|
||||
rows={14}
|
||||
spellCheck={false}
|
||||
placeholder={defaultLoading ? "Loading model default..." : ""}
|
||||
/>
|
||||
{readOnly ? null : (
|
||||
<div className="flex items-center justify-between gap-3 px-0.5 text-[0.6875rem]">
|
||||
<div className="flex items-center justify-between gap-3 px-0.5 text-ui-11">
|
||||
<span
|
||||
className={overLimit ? "text-amber-500" : "text-muted-foreground"}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -54,13 +54,13 @@ import { NumericValueInput } from "./numeric-value-input";
|
|||
|
||||
const ROW_CLASS = "flex min-h-8 items-center justify-between gap-3";
|
||||
const LABEL_CLASS =
|
||||
"min-w-0 truncate text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg";
|
||||
"min-w-0 truncate text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg";
|
||||
const LABEL_CLASS_WRAP =
|
||||
"min-w-0 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg";
|
||||
"min-w-0 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg";
|
||||
const CONTROL_SURFACE =
|
||||
"rounded-full border-transparent bg-black/[0.04] dark:bg-white/[0.05] hover:bg-black/[0.06] dark:hover:bg-white/[0.1]";
|
||||
const SELECT_TRIGGER_CLASS = `grid h-8 min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1 ${CONTROL_SURFACE} pl-3 pr-2 py-0 text-[0.8125rem]! font-medium text-nav-fg focus-visible:ring-0 focus-visible:border-transparent [&_[data-slot=select-value]]:min-w-0 [&_[data-slot=select-value]]:truncate [&>svg]:shrink-0`;
|
||||
const NUMBER_INPUT_CLASS = `h-8 w-[92px] ${CONTROL_SURFACE} pl-3 pr-2 py-0 text-right text-[0.8125rem] font-medium text-nav-fg outline-none focus-visible:ring-0`;
|
||||
const SELECT_TRIGGER_CLASS = `grid h-8 min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-1 ${CONTROL_SURFACE} pl-3 pr-2 py-0 text-ui-13! font-medium text-nav-fg focus-visible:ring-0 focus-visible:border-transparent [&_[data-slot=select-value]]:min-w-0 [&_[data-slot=select-value]]:truncate [&>svg]:shrink-0`;
|
||||
const NUMBER_INPUT_CLASS = `h-8 w-[92px] ${CONTROL_SURFACE} pl-3 pr-2 py-0 text-right text-ui-13 font-medium text-nav-fg outline-none focus-visible:ring-0`;
|
||||
|
||||
const KV_CACHE_DTYPE_DEFAULT = "f16";
|
||||
const SPECULATIVE_TYPE_LABELS: Record<(typeof SPECULATIVE_TYPES)[number], string> =
|
||||
|
|
@ -107,7 +107,7 @@ function ChatTemplateSetting({
|
|||
</div>
|
||||
<div className="flex shrink-0 items-center gap-2">
|
||||
{readOnly ? null : (
|
||||
<span className="text-[0.75rem] text-muted-foreground">
|
||||
<span className="text-ui-12 text-muted-foreground">
|
||||
{config.chatTemplateOverride ? "Custom" : "Default"}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -115,7 +115,7 @@ function ChatTemplateSetting({
|
|||
type="button"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className={`h-8 px-3 text-[0.8125rem] ${CONTROL_SURFACE}`}
|
||||
className={`h-8 px-3 text-ui-13 ${CONTROL_SURFACE}`}
|
||||
onClick={onEditTemplate}
|
||||
>
|
||||
{readOnly ? "View" : "Edit"}
|
||||
|
|
@ -370,7 +370,7 @@ function GpuMemorySettings({
|
|||
key={d.index}
|
||||
className="flex items-center justify-between gap-3"
|
||||
>
|
||||
<span className="min-w-0 truncate text-[0.75rem] text-nav-fg/80">
|
||||
<span className="min-w-0 truncate text-ui-12 text-nav-fg/80">
|
||||
GPU {d.index}: {d.name}
|
||||
{d.memoryTotalGb
|
||||
? ` · ${Math.round(d.memoryTotalGb)} GB`
|
||||
|
|
@ -812,10 +812,10 @@ export function ModelConfigPage({
|
|||
</button>
|
||||
)}
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-[0.625rem] font-semibold uppercase leading-none tracking-wider text-muted-foreground">
|
||||
<div className="text-ui-10 font-semibold uppercase leading-none tracking-wider text-muted-foreground">
|
||||
Run settings
|
||||
</div>
|
||||
<div className="mt-1.5 truncate text-[0.875rem] font-semibold leading-tight text-nav-fg">
|
||||
<div className="mt-1.5 truncate text-ui-14 font-semibold leading-tight text-nav-fg">
|
||||
{target.displayName}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -868,7 +868,7 @@ export function ModelConfigPage({
|
|||
{isActiveModel &&
|
||||
loadedMaxContextLength != null &&
|
||||
contextValue > loadedMaxContextLength && (
|
||||
<p className="text-[0.6875rem] text-amber-500">
|
||||
<p className="text-ui-11 text-amber-500">
|
||||
Exceeds estimated VRAM capacity (
|
||||
{loadedMaxContextLength.toLocaleString()} tokens). The model
|
||||
may use system RAM.
|
||||
|
|
@ -890,7 +890,7 @@ export function ModelConfigPage({
|
|||
|
||||
<div className={ROW_CLASS}>
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="min-w-0 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-muted-foreground">
|
||||
<span className="min-w-0 text-ui-13 font-medium leading-[1.25] tracking-nav text-muted-foreground">
|
||||
Advanced settings
|
||||
</span>
|
||||
<InfoHint>
|
||||
|
|
@ -943,7 +943,7 @@ export function ModelConfigPage({
|
|||
/>
|
||||
<label
|
||||
htmlFor={rememberId}
|
||||
className="cursor-pointer select-none truncate text-[0.8125rem] text-nav-fg"
|
||||
className="cursor-pointer select-none truncate text-ui-13 text-nav-fg"
|
||||
>
|
||||
Remember for this model
|
||||
</label>
|
||||
|
|
|
|||
|
|
@ -232,13 +232,13 @@ function ModelSelectorTrigger({
|
|||
</span>
|
||||
) : null}
|
||||
<span className="flex min-w-0 flex-1 items-baseline">
|
||||
<span className="min-w-0 flex flex-1 items-baseline truncate font-heading text-[1rem] font-medium leading-tight text-black dark:text-white">
|
||||
<span className="min-w-0 flex flex-1 items-baseline truncate font-heading text-ui-16 font-medium leading-tight text-black dark:text-white">
|
||||
{currentModel?.name ?? "Select model"}
|
||||
{showCloudIndicator ? (
|
||||
<HugeiconsIcon
|
||||
icon={CloudIcon}
|
||||
strokeWidth={1.75}
|
||||
className="relative top-[2.5px] ml-1.5 mr-[5.76px] size-3.5 shrink-0 text-muted-foreground"
|
||||
className="relative top-[0.15625rem] ml-1.5 mr-[0.36rem] size-3.5 shrink-0 text-muted-foreground"
|
||||
/>
|
||||
) : null}
|
||||
</span>
|
||||
|
|
@ -505,16 +505,16 @@ function ModelSelectorContent({
|
|||
data-tour={dataTour}
|
||||
onKeyDown={handlePickerEntryKeyDown}
|
||||
className={cn(
|
||||
"unsloth-model-selector-menu menu-soft-surface ring-0 max-w-[calc(100vw-16px)] min-w-0 gap-0",
|
||||
"unsloth-model-selector-menu menu-soft-surface ring-0 max-w-[calc(100vw-1rem)] min-w-0 gap-0",
|
||||
visibleConfigTarget
|
||||
? "w-[min(468px,calc(100vw-16px))] px-4 pt-4 pb-4"
|
||||
? "w-[min(468px,calc(100vw-1rem))] px-4 pt-4 pb-4"
|
||||
: cn(
|
||||
"pt-4 pb-0 pl-4",
|
||||
// Sized so the left-packed row keeps uniform gaps and the last
|
||||
// dropdown's right gap matches the pill's left gap (pl-4 vs pr-4).
|
||||
hasExternal
|
||||
? "w-[min(614px,calc(100vw-16px))] pr-4"
|
||||
: "w-[min(506px,calc(100vw-16px))] pr-2",
|
||||
? "w-[min(614px,calc(100vw-1rem))] pr-4"
|
||||
: "w-[min(506px,calc(100vw-1rem))] pr-2",
|
||||
),
|
||||
className,
|
||||
)}
|
||||
|
|
@ -881,7 +881,7 @@ function ExternalModelPicker({
|
|||
) : (
|
||||
grouped.map((group) => (
|
||||
<div key={group.providerId}>
|
||||
<div className="flex items-center gap-2 px-2.5 py-1.5 text-[0.625rem] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="flex items-center gap-2 px-2.5 py-1.5 text-ui-10 font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<ExternalProviderLogo
|
||||
providerType={group.models[0]?.providerType}
|
||||
className="size-3.5"
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ export function FolderBrowser({
|
|||
</DialogHeader>
|
||||
|
||||
{/* Breadcrumb */}
|
||||
<div className="flex flex-wrap items-center gap-0.5 border-t border-border/50 px-6 py-2 font-mono text-[0.6875rem] text-muted-foreground">
|
||||
<div className="flex flex-wrap items-center gap-0.5 border-t border-border/50 px-6 py-2 font-mono text-ui-11 text-muted-foreground">
|
||||
{crumbs.length === 0 ? (
|
||||
<span className="text-muted-foreground/60">(loading…)</span>
|
||||
) : (
|
||||
|
|
@ -185,7 +185,7 @@ export function FolderBrowser({
|
|||
type="button"
|
||||
onClick={() => navigate(s, showHidden)}
|
||||
disabled={loading}
|
||||
className="rounded-full border border-border/50 px-2 py-0.5 font-mono text-[0.625rem] text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-40"
|
||||
className="rounded-full border border-border/50 px-2 py-0.5 font-mono text-ui-10 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-40"
|
||||
title={s}
|
||||
>
|
||||
{s.length > 36 ? `…${s.slice(-33)}` : s}
|
||||
|
|
@ -237,14 +237,14 @@ export function FolderBrowser({
|
|||
)}
|
||||
{data.model_files_here !== undefined &&
|
||||
data.model_files_here > 0 && (
|
||||
<div className="border-t border-border/30 px-6 py-1.5 text-[0.625rem] text-foreground/70">
|
||||
<div className="border-t border-border/30 px-6 py-1.5 text-ui-10 text-foreground/70">
|
||||
{data.model_files_here} model file
|
||||
{data.model_files_here === 1 ? "" : "s"} in this folder.
|
||||
Click "Use this folder" to scan it.
|
||||
</div>
|
||||
)}
|
||||
{data.truncated === true && (
|
||||
<div className="border-t border-border/30 px-6 py-1.5 text-[0.625rem] text-muted-foreground/70">
|
||||
<div className="border-t border-border/30 px-6 py-1.5 text-ui-10 text-muted-foreground/70">
|
||||
Showing first {data.entries.length} entries. Narrow the path
|
||||
to see more.
|
||||
</div>
|
||||
|
|
@ -273,7 +273,7 @@ export function FolderBrowser({
|
|||
/>
|
||||
<span className="truncate font-mono">{e.name}</span>
|
||||
{e.has_models && (
|
||||
<span className="ml-auto shrink-0 rounded-full border border-border/50 px-1.5 py-0 text-[0.5625rem] uppercase tracking-wider text-muted-foreground">
|
||||
<span className="ml-auto shrink-0 rounded-full border border-border/50 px-1.5 py-0 text-ui-9 uppercase tracking-wider text-muted-foreground">
|
||||
models
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ function ListLabel({
|
|||
divider ? "mt-3 border-t border-border/50 pt-3" : "pt-3",
|
||||
)}
|
||||
>
|
||||
<span className="flex items-center gap-1.5 text-[0.625rem] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5 text-ui-10 font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
{icon}
|
||||
{children}
|
||||
</span>
|
||||
|
|
@ -526,7 +526,7 @@ function ModelRow({
|
|||
>
|
||||
<span className="flex min-w-0 flex-1 items-baseline">
|
||||
{owner && !hideOwner ? (
|
||||
<span className="inline-flex min-w-0 max-w-[45%] shrink items-baseline text-[0.8125rem] text-muted-foreground/90">
|
||||
<span className="inline-flex min-w-0 max-w-[45%] shrink items-baseline text-ui-13 text-muted-foreground/90">
|
||||
<span className="truncate">{owner}</span>
|
||||
<span className="shrink-0 text-muted-foreground/45">/</span>
|
||||
</span>
|
||||
|
|
@ -576,25 +576,25 @@ function ModelRow({
|
|||
</span>
|
||||
)}
|
||||
{vramStatus === "exceeds" && (
|
||||
<span className="text-[0.5625rem] font-medium !text-red-700 !bg-red-50 dark:!text-red-300 dark:!bg-red-500/15 px-1.5 py-0.5 rounded">
|
||||
<span className="text-ui-9 font-medium !text-red-700 !bg-red-50 dark:!text-red-300 dark:!bg-red-500/15 px-1.5 py-0.5 rounded">
|
||||
OOM
|
||||
</span>
|
||||
)}
|
||||
{vramStatus === "tight" && (
|
||||
<span className="text-[0.5625rem] font-medium !text-amber-400">TIGHT</span>
|
||||
<span className="text-ui-9 font-medium !text-amber-400">TIGHT</span>
|
||||
)}
|
||||
{paramLabel ? (
|
||||
<span className="rounded-md border border-border/60 px-1.5 py-px text-[0.625rem] font-medium text-muted-foreground tabular-nums">
|
||||
<span className="rounded-md border border-border/60 px-1.5 py-px text-ui-10 font-medium text-muted-foreground tabular-nums">
|
||||
{paramLabel}
|
||||
</span>
|
||||
) : null}
|
||||
{parsed.texts.map((text) => (
|
||||
<span key={text} className="text-[0.625rem] text-muted-foreground">
|
||||
<span key={text} className="text-ui-10 text-muted-foreground">
|
||||
{text}
|
||||
</span>
|
||||
))}
|
||||
{parsed.size !== undefined ? (
|
||||
<span className="text-[0.625rem] text-muted-foreground tabular-nums">
|
||||
<span className="text-ui-10 text-muted-foreground tabular-nums">
|
||||
{parsed.size}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -614,7 +614,7 @@ function ModelRow({
|
|||
// Optional Hugging Face address line for online/Hub rows, rendered under
|
||||
// whichever tooltip shows so the repo id / URL is always visible on hover.
|
||||
const hubUrlLine = hubUrl ? (
|
||||
<span className="block mt-1 text-[0.625rem] text-muted-foreground break-all">
|
||||
<span className="block mt-1 text-ui-10 text-muted-foreground break-all">
|
||||
{hubUrl}
|
||||
</span>
|
||||
) : null;
|
||||
|
|
@ -622,7 +622,7 @@ function ModelRow({
|
|||
const tooltipBody = vramTooltipText ? (
|
||||
<>
|
||||
{label}
|
||||
<span className="block text-[0.625rem] mt-1">{vramTooltipText}</span>
|
||||
<span className="block text-ui-10 mt-1">{vramTooltipText}</span>
|
||||
{hubUrlLine}
|
||||
</>
|
||||
) : tooltipText ? (
|
||||
|
|
@ -976,11 +976,11 @@ function GgufVariantExpander({
|
|||
redundant; its Vision badge is relayed to the name instead. */}
|
||||
{!onDevice && (
|
||||
<div className="px-2 py-1 flex items-center gap-1.5">
|
||||
<span className="text-[0.625rem] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<span className="text-ui-10 font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
Quantizations
|
||||
</span>
|
||||
{hasVision && (
|
||||
<span className="flex items-center gap-0.5 text-[0.5625rem] font-medium text-indigo-700 dark:text-indigo-300">
|
||||
<span className="flex items-center gap-0.5 text-ui-9 font-medium text-indigo-700 dark:text-indigo-300">
|
||||
<HugeiconsIcon
|
||||
icon={ViewIcon}
|
||||
className="size-3"
|
||||
|
|
@ -1018,33 +1018,33 @@ function GgufVariantExpander({
|
|||
</span>
|
||||
{v.downloaded ? (
|
||||
<>
|
||||
<span className="ml-1.5 text-[0.5625rem] font-sans font-medium text-green-600/90 dark:text-green-400/80">
|
||||
<span className="ml-1.5 text-ui-9 font-sans font-medium text-green-600/90 dark:text-green-400/80">
|
||||
downloaded
|
||||
</span>
|
||||
{v.update_available ? (
|
||||
<span className="ml-1.5 text-[0.5625rem] font-sans font-medium text-amber-700 dark:text-amber-300">
|
||||
<span className="ml-1.5 text-ui-9 font-sans font-medium text-amber-700 dark:text-amber-300">
|
||||
update available
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
) : v.quant === effectiveRecommended ? (
|
||||
<span className="ml-1.5 text-[0.5625rem] font-sans font-medium text-primary/70">
|
||||
<span className="ml-1.5 text-ui-9 font-sans font-medium text-primary/70">
|
||||
recommended
|
||||
</span>
|
||||
) : null}
|
||||
</span>
|
||||
<span className="flex items-center gap-1.5 shrink-0">
|
||||
{oom && (
|
||||
<span className="text-[0.5625rem] font-medium !text-red-700 !bg-red-50 dark:!text-red-300 dark:!bg-red-500/15 px-1.5 py-0.5 rounded">
|
||||
<span className="text-ui-9 font-medium !text-red-700 !bg-red-50 dark:!text-red-300 dark:!bg-red-500/15 px-1.5 py-0.5 rounded">
|
||||
OOM
|
||||
</span>
|
||||
)}
|
||||
{tight && (
|
||||
<span className="text-[0.5625rem] font-medium !text-amber-400">
|
||||
<span className="text-ui-9 font-medium !text-amber-400">
|
||||
TIGHT
|
||||
</span>
|
||||
)}
|
||||
<span className="text-[0.625rem] text-muted-foreground">
|
||||
<span className="text-ui-10 text-muted-foreground">
|
||||
{formatBytes(v.size_bytes)}
|
||||
</span>
|
||||
</span>
|
||||
|
|
@ -1316,7 +1316,7 @@ function localPathTooltip(name: string, path: string): ReactNode {
|
|||
return (
|
||||
<>
|
||||
<span className="block break-words">{name}</span>
|
||||
<span className="block mt-1 text-[0.625rem] text-muted-foreground break-all">
|
||||
<span className="block mt-1 text-ui-10 text-muted-foreground break-all">
|
||||
{path}
|
||||
</span>
|
||||
</>
|
||||
|
|
@ -2786,14 +2786,14 @@ export function HubModelPicker({
|
|||
>
|
||||
<span className="flex min-w-0 items-baseline">
|
||||
{owner ? (
|
||||
<span className="inline-flex min-w-0 max-w-[45%] shrink items-baseline text-[0.8125rem] text-muted-foreground/90">
|
||||
<span className="inline-flex min-w-0 max-w-[45%] shrink items-baseline text-ui-13 text-muted-foreground/90">
|
||||
<span className="truncate">{owner}</span>
|
||||
<span className="shrink-0 text-muted-foreground/45">/</span>
|
||||
</span>
|
||||
) : null}
|
||||
<span className="min-w-0 truncate">{name}</span>
|
||||
</span>
|
||||
<span className="shrink-0 rounded-md bg-black/[0.06] px-1.5 py-px font-mono text-[0.625rem] text-muted-foreground dark:bg-white/[0.1]">
|
||||
<span className="shrink-0 rounded-md bg-black/[0.06] px-1.5 py-px font-mono text-ui-10 text-muted-foreground dark:bg-white/[0.1]">
|
||||
{entry.quant}
|
||||
</span>
|
||||
{isLoaded && (
|
||||
|
|
@ -3107,7 +3107,7 @@ export function HubModelPicker({
|
|||
) : (
|
||||
connectedGroups.map((group) => (
|
||||
<div key={group.providerId}>
|
||||
<div className="flex items-center gap-2 px-2.5 py-1.5 text-[0.625rem] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="flex items-center gap-2 px-2.5 py-1.5 text-ui-10 font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<ApiProviderLogo
|
||||
providerType={group.providerType}
|
||||
className="size-3.5"
|
||||
|
|
@ -3312,7 +3312,7 @@ export function HubModelPicker({
|
|||
ref={fineTunedSectionRef}
|
||||
className="mt-3 flex items-center gap-1 border-t border-border/50 px-2.5 pb-1 pt-3"
|
||||
>
|
||||
<span className="flex items-center gap-1.5 text-[0.625rem] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5 text-ui-10 font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<HugeiconsIcon icon={TrainIcon} className="size-3.5" />
|
||||
Fine-tuned
|
||||
</span>
|
||||
|
|
@ -3365,7 +3365,7 @@ export function HubModelPicker({
|
|||
type="button"
|
||||
onClick={() => setShowFolderBrowser(true)}
|
||||
title="Browse folders on the server"
|
||||
className="flex items-center gap-1.5 text-[0.625rem] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground"
|
||||
className="flex items-center gap-1.5 text-ui-10 font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground"
|
||||
>
|
||||
<HugeiconsIcon
|
||||
icon={Folder02Icon}
|
||||
|
|
@ -3446,7 +3446,7 @@ export function HubModelPicker({
|
|||
className="size-3 shrink-0 text-muted-foreground/40"
|
||||
/>
|
||||
<span
|
||||
className="min-w-0 flex-1 truncate font-mono text-[0.625rem] text-muted-foreground/70"
|
||||
className="min-w-0 flex-1 truncate font-mono text-ui-10 text-muted-foreground/70"
|
||||
title={f.path}
|
||||
>
|
||||
{f.path}
|
||||
|
|
@ -3484,9 +3484,9 @@ export function HubModelPicker({
|
|||
onClick={() => void handleAddFolder(p)}
|
||||
disabled={folderLoading}
|
||||
title={`Add ${p}`}
|
||||
className="rounded-full border border-dashed border-border/50 px-2 py-0.5 font-mono text-[0.625rem] text-muted-foreground/70 transition-colors hover:border-foreground/30 hover:bg-accent hover:text-foreground disabled:opacity-40"
|
||||
className="rounded-full border border-dashed border-border/50 px-2 py-0.5 font-mono text-ui-10 text-muted-foreground/70 transition-colors hover:border-foreground/30 hover:bg-accent hover:text-foreground disabled:opacity-40"
|
||||
>
|
||||
<span className="text-[0.6875rem] font-semibold">
|
||||
<span className="text-ui-11 font-semibold">
|
||||
+
|
||||
</span>{" "}
|
||||
{p.length > 30 ? `...${p.slice(-27)}` : p}
|
||||
|
|
@ -3524,7 +3524,7 @@ export function HubModelPicker({
|
|||
}
|
||||
}}
|
||||
placeholder="/path/to/models"
|
||||
className="h-6 min-w-0 flex-1 rounded border border-border/50 bg-transparent px-1.5 font-mono text-[0.625rem] text-foreground outline-none placeholder:text-muted-foreground/40 focus:border-foreground/20"
|
||||
className="h-6 min-w-0 flex-1 rounded border border-border/50 bg-transparent px-1.5 font-mono text-ui-10 text-foreground outline-none placeholder:text-muted-foreground/40 focus:border-foreground/20"
|
||||
disabled={folderLoading}
|
||||
autoFocus={true}
|
||||
/>
|
||||
|
|
@ -3547,13 +3547,13 @@ export function HubModelPicker({
|
|||
void handleAddFolder();
|
||||
}}
|
||||
disabled={folderLoading || !folderInput.trim()}
|
||||
className="h-6 shrink-0 rounded border border-border/50 px-1.5 text-[0.625rem] text-muted-foreground transition-colors hover:bg-accent disabled:opacity-40"
|
||||
className="h-6 shrink-0 rounded border border-border/50 px-1.5 text-ui-10 text-muted-foreground transition-colors hover:bg-accent disabled:opacity-40"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
{folderError && (
|
||||
<p className="px-0.5 pt-0.5 text-[0.625rem] text-destructive">
|
||||
<p className="px-0.5 pt-0.5 text-ui-10 text-destructive">
|
||||
{folderError}
|
||||
</p>
|
||||
)}
|
||||
|
|
@ -4257,7 +4257,7 @@ export function HubModelPicker({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onEject}
|
||||
className="pointer-events-auto inline-flex items-center justify-center gap-2 rounded-md bg-popover px-3 py-2 text-[0.8125rem] font-medium text-destructive shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] transition-colors hover:bg-[color-mix(in_srgb,var(--destructive)_12%,var(--popover))] dark:bg-[color-mix(in_srgb,var(--foreground)_10%,var(--sidebar))] dark:shadow-none dark:hover:bg-[color-mix(in_srgb,var(--destructive)_22%,var(--sidebar))]"
|
||||
className="pointer-events-auto inline-flex items-center justify-center gap-2 rounded-md bg-popover px-3 py-2 text-ui-13 font-medium text-destructive shadow-[0_2px_8px_-2px_rgba(0,0,0,0.16)] transition-colors hover:bg-[color-mix(in_srgb,var(--destructive)_12%,var(--popover))] dark:bg-[color-mix(in_srgb,var(--foreground)_10%,var(--sidebar))] dark:shadow-none dark:hover:bg-[color-mix(in_srgb,var(--destructive)_22%,var(--sidebar))]"
|
||||
title="Eject model"
|
||||
>
|
||||
<HugeiconsIcon icon={RemoveCircleIcon} className="size-3.5" />
|
||||
|
|
@ -4382,7 +4382,7 @@ function FineTunedRows({
|
|||
tooltipText={
|
||||
<>
|
||||
<span className="block break-words">{adapter.name}</span>
|
||||
<span className="block mt-1 text-[0.625rem] text-muted-foreground break-all">
|
||||
<span className="block mt-1 text-ui-10 text-muted-foreground break-all">
|
||||
{adapter.id}
|
||||
</span>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ export function PillTabs({
|
|||
className={cn(
|
||||
"relative z-10 inline-flex items-center justify-center gap-1.5 rounded-full transition-colors",
|
||||
fit ? "shrink-0" : "min-w-0 flex-1",
|
||||
compact ? "h-7 px-2.5 text-[0.6875rem]" : "h-9 px-3 text-[0.78125rem]",
|
||||
compact ? "h-7 px-2.5 text-ui-11" : "h-9 px-3 text-ui-12p5",
|
||||
value === tab.value
|
||||
? "text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground",
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export function NativeModelChip({
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex min-w-0 max-w-[544px] items-center gap-2 rounded-lg border border-border/70 bg-muted/70 px-2.5 py-1.5 text-xs">
|
||||
<div className="flex min-w-0 max-w-[34rem] items-center gap-2 rounded-lg border border-border/70 bg-muted/70 px-2.5 py-1.5 text-xs">
|
||||
<span className="shrink-0 font-medium text-muted-foreground">Local GGUF</span>
|
||||
<span className="min-w-0 flex-1 truncate" title={label}>{label}</span>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export function NativeModelDropOverlay({ state }: { state: NativeModelDropState
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"pointer-events-none absolute left-1/2 top-4 z-50 w-[clamp(256px,28vw,352px)] max-w-[calc(100vw-16px)] -translate-x-1/2 transition-all duration-200 ease-out",
|
||||
"pointer-events-none absolute left-1/2 top-4 z-50 w-[clamp(16rem,28vw,22rem)] max-w-[calc(100vw-1rem)] -translate-x-1/2 transition-all duration-200 ease-out",
|
||||
isIdle ? "-translate-y-1 opacity-0" : "translate-y-0 opacity-100",
|
||||
)}
|
||||
role="status"
|
||||
|
|
@ -60,7 +60,7 @@ export function NativeModelDropOverlay({ state }: { state: NativeModelDropState
|
|||
<div className="truncate text-xs font-medium text-foreground">
|
||||
{title}
|
||||
</div>
|
||||
<div className="mt-0.5 truncate text-[0.6875rem] leading-4 text-muted-foreground">
|
||||
<div className="mt-0.5 truncate text-ui-11 leading-4 text-muted-foreground">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -286,12 +286,12 @@ export function ModelSelectionStep() {
|
|||
</Tooltip>
|
||||
<span className="flex items-center gap-1.5 shrink-0">
|
||||
{fitStatus === "exceeds" && (
|
||||
<span className="text-[0.5625rem] font-medium !text-red-700 !bg-red-50 dark:!text-red-400 dark:!bg-red-950 px-1.5 py-0.5 rounded">
|
||||
<span className="text-ui-9 font-medium !text-red-700 !bg-red-50 dark:!text-red-400 dark:!bg-red-950 px-1.5 py-0.5 rounded">
|
||||
OOM
|
||||
</span>
|
||||
)}
|
||||
{fitStatus === "tight" && (
|
||||
<span className="text-[0.5625rem] font-medium !text-amber-400">
|
||||
<span className="text-ui-9 font-medium !text-amber-400">
|
||||
TIGHT
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ export function ModelTypeStep(): ReactElement {
|
|||
{isDisabled && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="absolute top-2 right-2 text-[0.625rem]"
|
||||
className="absolute top-2 right-2 text-ui-10"
|
||||
>
|
||||
Coming Soon
|
||||
</Badge>
|
||||
|
|
|
|||
|
|
@ -18,15 +18,15 @@ export function WizardSidebar({ returnTo }: { returnTo: string }) {
|
|||
<aside className="w-full shrink-0 bg-muted/70 p-4 md:w-64 md:p-6">
|
||||
<div className="flex items-center gap-3 py-1 md:py-2">
|
||||
{/* Logo lockup follows the UI font size at half rate:
|
||||
base + (root - 16px) / 2, written as (base - 8)px + 0.5rem. */}
|
||||
base + (root scale - 1) * 8px. Exact base sizes at 16px. */}
|
||||
<img
|
||||
src={`${import.meta.env.BASE_URL}sticker.png`}
|
||||
alt="Unsloth"
|
||||
className="size-[calc(40px+0.5rem)]"
|
||||
className="size-[calc(40px+0.5rem*var(--ui-font-scale,1))]"
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-semibold text-[calc(10px+0.5rem)] leading-tight">Unsloth</span>
|
||||
<span className="text-[calc(4px+0.5rem)] text-muted-foreground">Studio</span>
|
||||
<span className="font-semibold text-[calc(10px+0.5rem*var(--ui-font-scale,1))] leading-tight">Unsloth</span>
|
||||
<span className="text-[calc(4px+0.5rem*var(--ui-font-scale,1))] text-muted-foreground">Studio</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 md:mt-0">
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ export function ProfilePersonalizationPanel() {
|
|||
name={previewName}
|
||||
imageUrl={shownAvatar}
|
||||
size="lg"
|
||||
className="size-[124px] text-[3.15rem]"
|
||||
className="size-[124px] text-[calc(3.15rem*var(--ui-font-scale,1))]"
|
||||
/>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
|
|
@ -288,7 +288,7 @@ export function ProfilePersonalizationPanel() {
|
|||
onClick={() => setAvatarShape(shape)}
|
||||
aria-pressed={avatarShape === shape}
|
||||
className={cn(
|
||||
"inline-flex h-8 items-center rounded-full px-4 text-[0.8125rem] font-medium transition-colors",
|
||||
"inline-flex h-8 items-center rounded-full px-4 text-ui-13 font-medium transition-colors",
|
||||
avatarShape === shape
|
||||
? "hub-tab-toggle-pill text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground",
|
||||
|
|
@ -366,7 +366,7 @@ export function ProfilePersonalizationPanel() {
|
|||
shownAvatar === null && "ring-ring-strong hover:ring-ring-strong",
|
||||
)}
|
||||
>
|
||||
<span className="text-[0.6875rem] font-medium">
|
||||
<span className="text-ui-11 font-medium">
|
||||
{t("settings.profile.noneLabel")}
|
||||
</span>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ const SIZE: Record<"sm" | "md" | "lg", string> = {
|
|||
sm: "size-9 text-xs",
|
||||
md: "size-11 text-sm",
|
||||
/** ~10% larger than `size-24` / `text-2xl` for the edit-profile dialog. */
|
||||
lg: "size-[106px] text-[1.65rem]",
|
||||
lg: "size-[106px] text-[calc(1.65rem*var(--ui-font-scale,1))]",
|
||||
};
|
||||
|
||||
// Percentage radius keeps the rounded-rectangle proportional across sizes.
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ function PdfPreview({
|
|||
);
|
||||
}
|
||||
|
||||
// Resizable preview width (px). Default matches the prior fixed 704px; drag the
|
||||
// Resizable preview width (px). Default matches the prior fixed 44rem; drag the
|
||||
// left edge to widen. Persisted so it survives reopen.
|
||||
const PREVIEW_WIDTH_KEY = "unsloth-rag-preview-width";
|
||||
const MIN_PREVIEW_WIDTH = 384;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export function DocumentStatusChip({
|
|||
size="sm"
|
||||
title={error ?? filename}
|
||||
className={cn(
|
||||
"rounded-full inline-flex items-center gap-1.5 max-w-[256px]",
|
||||
"rounded-full inline-flex items-center gap-1.5 max-w-[16rem]",
|
||||
status === "failed" && "border-destructive/40 text-destructive",
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export function ProjectSourcesPanel({ projectId }: { projectId: string }) {
|
|||
/>
|
||||
</span>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[0.9375rem] font-semibold text-foreground">
|
||||
<p className="text-ui-15 font-semibold text-foreground">
|
||||
Give this project context
|
||||
</p>
|
||||
<p className="max-w-sm text-sm text-muted-foreground">
|
||||
|
|
@ -94,7 +94,7 @@ export function ProjectSourcesPanel({ projectId }: { projectId: string }) {
|
|||
>
|
||||
Add sources
|
||||
</Button>
|
||||
<p className="text-[0.6875rem] text-muted-foreground">Or drop files here</p>
|
||||
<p className="text-ui-11 text-muted-foreground">Or drop files here</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col gap-4 rounded-[26px] bg-muted/30 px-6 py-5">
|
||||
|
|
|
|||
|
|
@ -75,10 +75,10 @@ function SliderRow({
|
|||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
{label}
|
||||
</span>
|
||||
<span className="text-[0.8125rem] tabular-nums text-muted-foreground">
|
||||
<span className="text-ui-13 tabular-nums text-muted-foreground">
|
||||
{format(value)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -120,7 +120,7 @@ export function RetrievalSettingsSection() {
|
|||
return (
|
||||
<div className="flex flex-col gap-5 pt-1">
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Search mode
|
||||
</span>
|
||||
<Select
|
||||
|
|
@ -143,10 +143,10 @@ export function RetrievalSettingsSection() {
|
|||
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Passages (top K)
|
||||
</span>
|
||||
<span className="text-[0.8125rem] tabular-nums text-muted-foreground">
|
||||
<span className="text-ui-13 tabular-nums text-muted-foreground">
|
||||
{ragTopK}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -163,7 +163,7 @@ export function RetrievalSettingsSection() {
|
|||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex flex-col">
|
||||
<span className="flex items-center gap-1.5 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="flex items-center gap-1.5 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Auto-retrieve documents
|
||||
<InfoHint>
|
||||
Auto turns retrieval on for smaller models (9B and below), which
|
||||
|
|
@ -171,7 +171,7 @@ export function RetrievalSettingsSection() {
|
|||
larger ones. On and Off force it either way.
|
||||
</InfoHint>
|
||||
</span>
|
||||
<span className="text-[0.75rem] leading-[1.3] text-muted-foreground">
|
||||
<span className="text-ui-12 leading-[1.3] text-muted-foreground">
|
||||
Search attached documents before answering.
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -212,7 +212,7 @@ export function RetrievalSettingsSection() {
|
|||
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex flex-col">
|
||||
<span className="flex items-center gap-1.5 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="flex items-center gap-1.5 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
OCR scanned pages
|
||||
<InfoHint>
|
||||
Read text off scanned or image-only PDF pages with the loaded
|
||||
|
|
@ -221,7 +221,7 @@ export function RetrievalSettingsSection() {
|
|||
unaffected.
|
||||
</InfoHint>
|
||||
</span>
|
||||
<span className="text-[0.75rem] leading-[1.3] text-muted-foreground">
|
||||
<span className="text-ui-12 leading-[1.3] text-muted-foreground">
|
||||
Transcribe image-only PDF pages when attaching.
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -235,7 +235,7 @@ export function RetrievalSettingsSection() {
|
|||
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex flex-col">
|
||||
<span className="flex items-center gap-1.5 text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="flex items-center gap-1.5 text-ui-13 font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Describe figures & charts
|
||||
<InfoHint>
|
||||
Caption PDF figures, charts, tables and diagrams at upload with the
|
||||
|
|
@ -243,7 +243,7 @@ export function RetrievalSettingsSection() {
|
|||
vision model; adds vision calls for detected figures.
|
||||
</InfoHint>
|
||||
</span>
|
||||
<span className="text-[0.75rem] leading-[1.3] text-muted-foreground">
|
||||
<span className="text-ui-12 leading-[1.3] text-muted-foreground">
|
||||
Read charts and diagrams when attaching.
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -205,12 +205,12 @@ function BlockSheetButton({
|
|||
{title}
|
||||
</p>
|
||||
{badge ? (
|
||||
<Badge variant="outline" className="rounded-full text-[0.625rem]">
|
||||
<Badge variant="outline" className="rounded-full text-ui-10">
|
||||
{badge}
|
||||
</Badge>
|
||||
) : null}
|
||||
</div>
|
||||
<p className="break-words text-[0.6875rem] text-muted-foreground">
|
||||
<p className="break-words text-ui-11 text-muted-foreground">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue