Studio: UI font size scales all text consistently without moving layout (#7355)
* Studio: make UI font size scale all text without moving layout The UI font size setting changes the root rem base, so only rem sized text reacted. Hundreds of px text classes, px font sizes in CSS, and chart labels stayed fixed, while rem based padding, widths and radii wrongly grew. Convert all text sizes to rem so every font follows the setting, and pin spacing, radius, container widths, sidebar and thread widths to px so layout no longer follows the rem base. Library styles (streamdown, react-flow) are re-based via overrides. All conversions are exact at the default 16px root, so the default rendering is unchanged. * Studio: keep logo at fixed size and fit tight controls at large UI fonts The logo lockups (sidebar wordmark with beta badge, onboarding wizard) are branding and now keep px sizes at any UI font size. Two controls clipped their text at the largest setting: the appearance color chips (fixed w-24) and the voice tab selects (fixed w-56). Both use min widths now, so they keep the default look at 16px and only grow when the text needs the room. * Studio: keep dropdown corners rounded when the menu scrolls A scrolling dropdown lost its rounded corners on the scrollbar side: WebKit paints the surface square when the rounded element itself hosts the scrollbar, which shows up in the desktop app whenever a menu overflows, for example at larger UI font sizes. Dropdown menu and select content now clip with overflow hidden and scroll an inner viewport instead. The surface padding insets the scrollbar clear of the curve, so corners stay rounded in every engine. Submenus are unaffected since sub content is portaled. * Studio: scale the logo lockups at half the UI font size rate Rather than pinning the logo, the sidebar lockup (sticker, wordmark, beta badge) and the onboarding lockup now follow the UI font size at half the rate of the change: size = base + (root - 16px) / 2, written as calc((base - 8)px + 0.5rem). A 4px font size change moves the logo by 2px, and the default 16px root renders the exact base sizes. * Studio: address review feedback on leading, grid tracks and select scrolling Numeric leading utilities (leading-3 through leading-10) derive from --spacing, so pinning spacing to px also froze their line-heights while the paired text sizes now scale. Define them as rem theme tokens so line-height follows the UI font size again; values are identical at the 16px default. Convert the grid tracks the rem-to-px codemod missed (rem followed by an underscore escaped the word boundary): the response details label column and the on-device folder rows. Make the Radix select viewport the bounded scroller instead of a wrapper div, so Radix's scroll handling and the browser scroll the same element. Restore the app's thin scrollbar with an inline style, which beats the scrollbar hiding stylesheet Radix injects at runtime. * Studio: cap voice select widths and update CI contracts
This commit is contained in:
parent
13c7db1965
commit
fa5498db0b
153 changed files with 860 additions and 762 deletions
|
|
@ -213,7 +213,7 @@ function TauriUpdateLayer({
|
|||
}
|
||||
|
||||
return (
|
||||
<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">
|
||||
<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">
|
||||
<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": "17.5rem",
|
||||
"--studio-sidebar-collapsed-width": "3rem",
|
||||
"--studio-sidebar-expanded-width": "280px",
|
||||
"--studio-sidebar-collapsed-width": "48px",
|
||||
"--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-2rem)] 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-32px)] 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-[14.5px] leading-[19px] tracking-nav">{label}</span>
|
||||
<span className="text-[0.90625rem] leading-[1.1875rem] 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-[14.5px] leading-[19px] tracking-nav font-medium",
|
||||
"sidebar-nav-btn h-[33px] cursor-pointer rounded-full pr-4 text-[0.90625rem] leading-[1.1875rem] 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-[14.5px] leading-[19px] font-medium tracking-nav outline-none",
|
||||
"text-foreground h-[33px] w-full border-0 bg-transparent pr-4 text-[0.90625rem] leading-[1.1875rem] font-medium tracking-nav outline-none",
|
||||
variant === "project" ? "pl-[39px]" : "pl-3",
|
||||
)}
|
||||
/>
|
||||
|
|
@ -1184,15 +1184,17 @@ export function AppSidebar() {
|
|||
aria-disabled={chatDisabled}
|
||||
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. */}
|
||||
<img
|
||||
src="/circle-logo-small.png"
|
||||
alt="Unsloth"
|
||||
className="h-[34px] w-[34px] rounded-full object-cover"
|
||||
className="h-[calc(26px+0.5rem)] w-[calc(26px+0.5rem)] rounded-full object-cover"
|
||||
/>
|
||||
<span className="font-heading text-[21px] font-semibold tracking-[0em] leading-none text-black dark:text-white dark:tracking-[0.02em]">
|
||||
<span className="font-heading text-[calc(13px+0.5rem)] 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-[8px] 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(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)]">
|
||||
{t("shell.beta")}
|
||||
</span>
|
||||
</Link>
|
||||
|
|
@ -1219,7 +1221,7 @@ export function AppSidebar() {
|
|||
hidden={isMobile}
|
||||
>
|
||||
{t("shell.navigation.search")}
|
||||
<kbd className="rounded bg-black/10 px-1 py-px text-[10px] font-medium leading-none dark:bg-white/15">
|
||||
<kbd className="rounded bg-black/10 px-1 py-px text-[0.625rem] font-medium leading-none dark:bg-white/15">
|
||||
{isMacPlatform ? "⌘K" : "Ctrl+K"}
|
||||
</kbd>
|
||||
</TooltipContent>
|
||||
|
|
@ -1536,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-[14.5px] leading-[19px] tracking-nav">{project.name}</span>
|
||||
<span className="truncate text-[0.90625rem] leading-[1.1875rem] tracking-nav">{project.name}</span>
|
||||
</SidebarMenuButton>
|
||||
{/* New chat in this project */}
|
||||
<button
|
||||
|
|
@ -1630,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-[13px] leading-[18px] tracking-nav">
|
||||
<span className="text-[0.8125rem] leading-[1.125rem] tracking-nav">
|
||||
{showAll ? "Show less" : "Show more"}
|
||||
</span>
|
||||
</SidebarMenuButton>
|
||||
|
|
@ -1709,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-[14.5px] 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-[0.90625rem] tracking-nav font-medium"
|
||||
onClick={() => {
|
||||
setSelectedHistoryRunId(run.id);
|
||||
// From Recipes/Export, jump to Train so the run's
|
||||
|
|
@ -1729,7 +1731,7 @@ export function AppSidebar() {
|
|||
<span className="truncate">
|
||||
{getTrainingRunDisplayTitle(run)}
|
||||
</span>
|
||||
<span className="ml-auto mr-0.5 shrink-0 text-[10px] text-muted-foreground">
|
||||
<span className="ml-auto mr-0.5 shrink-0 text-[0.625rem] text-muted-foreground">
|
||||
{formatRelativeShort(run.started_at)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -1830,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-[13.5px] font-semibold text-nav-fg">
|
||||
<span className="truncate font-heading text-[0.84375rem] font-semibold text-nav-fg">
|
||||
{t("shell.updateAvailable")}
|
||||
</span>
|
||||
{updateVersion && (
|
||||
<span className="truncate text-[11.5px] text-muted-foreground">
|
||||
<span className="truncate text-[0.71875rem] text-muted-foreground">
|
||||
v{updateVersion}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -1871,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-[13.5px] tracking-[0.025em] dark:tracking-[0.04em] font-semibold text-nav-fg">{displayTitle}</span>
|
||||
<span className="truncate text-[11.5px] tracking-nav text-muted-foreground">Unsloth</span>
|
||||
<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>
|
||||
</div>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
|
|
@ -1880,7 +1882,7 @@ export function AppSidebar() {
|
|||
side="top"
|
||||
align="center"
|
||||
sideOffset={8}
|
||||
className="app-user-menu menu-soft-surface-up ring-0 w-[16rem] px-2.5 py-2.5 font-heading rounded-[20px] border-0"
|
||||
className="app-user-menu menu-soft-surface-up ring-0 w-[256px] 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-[10px] text-muted-foreground">
|
||||
<div className="flex justify-between text-[0.625rem] 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-[8.5rem_minmax(0,1fr)] items-start gap-3 text-[13px]">
|
||||
<div className="grid grid-cols-[136px_minmax(0,1fr)] items-start gap-3 text-[0.8125rem]">
|
||||
<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(28rem,100vw)] p-0 sm:max-w-[28rem]"
|
||||
className="w-[min(448px,100vw)] p-0 sm:max-w-[448px]"
|
||||
>
|
||||
<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-[13px] 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-[0.8125rem] 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-[13.5px] outline-none",
|
||||
"aui-reasoning-content relative overflow-hidden text-foreground/85 text-[0.84375rem] 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-[10px]`,
|
||||
`flex ${sizeClass} shrink-0 items-center justify-center rounded-sm bg-muted font-medium text-[0.625rem]`,
|
||||
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]: "48rem",
|
||||
["--thread-max-width" as string]: "768px",
|
||||
["--thread-content-max-width" as string]:
|
||||
"calc(var(--thread-max-width) - 1.5rem)",
|
||||
"calc(var(--thread-max-width) - 24px)",
|
||||
}}
|
||||
onDragEnter={onDragEnter}
|
||||
onDragOver={onDragOver}
|
||||
|
|
@ -1142,14 +1142,14 @@ const GeneratedImageViewportOverlay: FC<{
|
|||
/>
|
||||
</div>
|
||||
<div
|
||||
className="w-full max-w-[min(100%,46rem)] shrink-0 text-center"
|
||||
className="w-full max-w-[min(100%,736px)] 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-[11px] font-medium text-muted-foreground">
|
||||
<p className="truncate text-[0.6875rem] 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-[46rem]">
|
||||
<div className="relative mx-auto min-w-0 w-full max-w-[736px]">
|
||||
<div className="relative z-10 w-full">
|
||||
<Composer
|
||||
disabled={disabled}
|
||||
|
|
@ -3317,7 +3317,7 @@ const PromptQueueStack: FC<{ queueThreadIds: string[] }> = ({
|
|||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid h-10 grid-cols-[minmax(0,1fr)_auto_2rem] items-center gap-2.5">
|
||||
<div className="grid h-10 grid-cols-[minmax(0,1fr)_auto_32px] 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 +3329,7 @@ const PromptQueueStack: FC<{ queueThreadIds: string[] }> = ({
|
|||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 w-[5.25rem] justify-center gap-1 px-0 text-sm font-normal text-muted-foreground/80 hover:text-foreground"
|
||||
className="h-7 w-[84px] 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 +3565,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-[11px] font-medium text-primary/80">
|
||||
<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">
|
||||
<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-[12.5px] leading-relaxed text-foreground/90">
|
||||
<pre className="max-h-[60vh] overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-[0.78125rem] leading-relaxed text-foreground/90">
|
||||
{canvas.text}
|
||||
</pre>
|
||||
</div>
|
||||
|
|
@ -3646,7 +3646,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-[15.5px] [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-[0.96875rem] [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 +3676,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(22rem,100%)]" />
|
||||
<MessageResponseModelBadge className="absolute -top-6 left-0 max-w-[min(352px,100%)]" />
|
||||
</div>
|
||||
<GeneratingIndicator />
|
||||
<CancelledIndicator />
|
||||
|
|
@ -3759,7 +3759,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-[10px] 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-[0.625rem] font-medium text-primary"
|
||||
title={`${count} fork${count === 1 ? "" : "s"} from this message`}
|
||||
>
|
||||
<GitBranchIcon strokeWidth={1.75} className="size-3" />
|
||||
|
|
@ -4084,7 +4084,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-[15.5px] [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-[0.96875rem] [font-weight:410] tracking-[0.01em] dark:tracking-[0.02em] duration-150"
|
||||
data-role="user"
|
||||
>
|
||||
<UserMessageAttachments />
|
||||
|
|
@ -4195,7 +4195,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-[13px]",
|
||||
"aui-branch-picker-root inline-flex items-center text-chat-icon-fg text-[0.8125rem]",
|
||||
className,
|
||||
)}
|
||||
{...rest}
|
||||
|
|
@ -4209,7 +4209,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-[13px] tabular-nums">
|
||||
<span className="aui-branch-picker-state font-mono text-[0.8125rem] 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-[15rem] ${
|
||||
className={`rounded-full inline-flex items-center gap-1.5 max-w-[240px] ${
|
||||
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-[11px] leading-none text-muted-foreground">
|
||||
<span className="truncate text-[0.6875rem] 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-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"
|
||||
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"
|
||||
>
|
||||
<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-[11px] font-medium font-mono">
|
||||
<div className="flex justify-between text-[0.6875rem] 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-[11px] font-medium font-mono">
|
||||
<div className="flex justify-between text-[0.6875rem] 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-2rem)] max-w-[400px]"
|
||||
? "fixed bottom-4 right-4 z-[9998] w-[calc(100vw-32px)] 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-[11px] text-muted-foreground/70">
|
||||
<p className="mt-1 text-[0.6875rem] 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-[13px] font-medium text-foreground"
|
||||
className="h-auto rounded-full px-3 py-2 text-[0.8125rem] 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-[13px]"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-[0.8125rem]"
|
||||
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-[10px] font-semibold text-control-accent">
|
||||
<span className="rounded-full bg-control-accent/15 px-2 py-0.5 text-[0.625rem] font-semibold text-control-accent">
|
||||
{badge}
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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-[10px] 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-[0.625rem] 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-2rem)] max-w-[400px]"
|
||||
? "fixed bottom-4 right-4 z-[9999] w-[calc(100vw-32px)] 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-[11px] text-muted-foreground/70">
|
||||
<p className="mt-1 text-[0.6875rem] 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-[13px] font-medium text-foreground"
|
||||
className="h-auto rounded-full px-3 py-2 text-[0.8125rem] 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-[13px] font-medium text-foreground"
|
||||
className="h-auto rounded-full px-3 py-2 text-[0.8125rem] font-medium text-foreground"
|
||||
onClick={onDismiss}
|
||||
>
|
||||
Later
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-[13px]"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-[0.8125rem]"
|
||||
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-[13px] font-medium text-foreground"
|
||||
className="h-auto rounded-full px-3 py-2 text-[0.8125rem] 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-[13px]"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-[0.8125rem]"
|
||||
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-[10px] 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-[0.625rem] 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-[11px] 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-[0.6875rem] 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-[10px] 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-[0.625rem] text-muted-foreground"
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,8 +112,8 @@ export function WindowTitlebar({
|
|||
const { pinned, togglePinned } = useSidebarPin();
|
||||
const sidebarWidth = showSidebarSurface
|
||||
? pinned
|
||||
? "var(--studio-sidebar-expanded-width,17.5rem)"
|
||||
: "var(--studio-sidebar-collapsed-width,3rem)"
|
||||
? "var(--studio-sidebar-expanded-width,280px)"
|
||||
: "var(--studio-sidebar-collapsed-width,48px)"
|
||||
: "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-[13px] font-semibold leading-none tracking-[0.01em] text-nav-fg">
|
||||
<span className="min-w-0 truncate text-[0.8125rem] 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) + 0.5rem)",
|
||||
right: "calc(var(--studio-window-control-inset,112px) + 8px)",
|
||||
}}
|
||||
onMouseDown={handleDragMouseDown}
|
||||
onDoubleClick={handleDragDoubleClick}
|
||||
|
|
|
|||
|
|
@ -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-[8rem] 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-[128px] items-start",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export function CopyableErrorChip({
|
|||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
"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",
|
||||
"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",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
@ -63,7 +63,7 @@ export function CopyableErrorChip({
|
|||
<PopoverContent
|
||||
align="start"
|
||||
side="bottom"
|
||||
className="w-[min(36rem,calc(100vw-1rem))] gap-2"
|
||||
className="w-[min(576px,calc(100vw-16px))] 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-[11px] 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-[0.6875rem] 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-[13px] py-3 px-4 align-top whitespace-normal"
|
||||
className="border-r border-border/20 last:border-r-0 text-[0.8125rem] 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%-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",
|
||||
"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",
|
||||
position === "fixed" ? "fixed" : "absolute",
|
||||
className,
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ function DropdownMenuContent({
|
|||
className,
|
||||
align = "start",
|
||||
sideOffset = 0,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
||||
return (
|
||||
|
|
@ -51,11 +52,21 @@ function DropdownMenuContent({
|
|||
// The 3px alignment nudge must be margin, not translate: a transform
|
||||
// here makes this scroll container the containing block for nested
|
||||
// position:fixed submenu wrappers, clipping every submenu.
|
||||
"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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 bg-popover text-popover-foreground min-w-48 rounded-lg p-1 duration-100 z-50 max-h-(--radix-dropdown-menu-content-available-height) w-[calc(var(--radix-dropdown-menu-trigger-width)_+_6px)] data-[align=start]:-ml-[3px] data-[align=end]:ml-[3px] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto data-[state=closed]:overflow-hidden",
|
||||
"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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 bg-popover text-popover-foreground min-w-48 rounded-lg p-1 duration-100 z-50 max-h-(--radix-dropdown-menu-content-available-height) w-[calc(var(--radix-dropdown-menu-trigger-width)_+_6px)] data-[align=start]:-ml-[3px] data-[align=end]:ml-[3px] origin-(--radix-dropdown-menu-content-transform-origin) flex flex-col overflow-hidden",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
>
|
||||
{/* Scroll an inner viewport, not the rounded surface: a scrollbar on
|
||||
the surface squares its corners in WebKit. The surface padding
|
||||
insets the scrollbar clear of the curve. */}
|
||||
<div
|
||||
data-slot="dropdown-menu-viewport"
|
||||
className="min-h-0 flex-1 overflow-x-hidden overflow-y-auto"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</DropdownMenuPrimitive.Content>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
);
|
||||
}
|
||||
|
|
@ -307,7 +318,7 @@ function DropdownMenuSubContent({
|
|||
isMobile && contentWidth === 0 ? "hidden" : style?.visibility,
|
||||
}}
|
||||
className={cn(
|
||||
"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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 bg-popover text-popover-foreground min-w-36 max-w-[calc(100vw-2rem)] rounded-lg p-1 duration-100 z-50 origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden",
|
||||
"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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 bg-popover text-popover-foreground min-w-36 max-w-[calc(100vw-32px)] rounded-lg p-1 duration-100 z-50 origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ const inputGroupAddonVariants = cva(
|
|||
variants: {
|
||||
align: {
|
||||
"inline-start":
|
||||
"pl-3 has-[>button]:ml-[-0.25rem] has-[>kbd]:ml-[-0.15rem] order-first",
|
||||
"pl-3 has-[>button]:ml-[-4px] has-[>kbd]:ml-[-2.4px] order-first",
|
||||
"inline-end":
|
||||
"pr-3 has-[>button]:mr-[-0.25rem] has-[>kbd]:mr-[-0.15rem] order-last",
|
||||
"pr-3 has-[>button]:mr-[-4px] has-[>kbd]:mr-[-2.4px] 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":
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ function SelectContent({
|
|||
data-slot="select-content"
|
||||
data-align-trigger={position === "item-aligned"}
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground font-heading 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 min-w-36 rounded-xl p-1 corner-squircle duration-100 relative z-50 max-h-(--radix-select-content-available-height) origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto ",
|
||||
"bg-popover text-popover-foreground font-heading 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 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 min-w-36 rounded-xl p-1 corner-squircle duration-100 relative z-50 max-h-(--radix-select-content-available-height) origin-(--radix-select-content-transform-origin) flex flex-col overflow-hidden",
|
||||
// No popper translate offset: the menu sits flush against the trigger.
|
||||
className,
|
||||
)}
|
||||
|
|
@ -135,10 +135,18 @@ function SelectContent({
|
|||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
{/* The Radix viewport is the scroller (not the rounded surface, whose
|
||||
scrollbar would square its corners in WebKit; not a wrapper, which
|
||||
would blind Radix's scroll handling). The surface padding insets
|
||||
the scrollbar clear of the curve. */}
|
||||
<SelectPrimitive.Viewport
|
||||
data-position={position}
|
||||
// Inline: Radix injects a scrollbar-width:none stylesheet rule that
|
||||
// Firefox lets win over author !important.
|
||||
style={{ scrollbarWidth: "thin" }}
|
||||
className={cn(
|
||||
"data-[position=popper]:h-[var(--radix-select-trigger-height)] data-[position=popper]:w-full data-[position=popper]:min-w-[var(--radix-select-trigger-width)]",
|
||||
"min-h-0 flex-1 overflow-x-hidden overflow-y-auto",
|
||||
"data-[position=popper]:w-full data-[position=popper]:min-w-[var(--radix-select-trigger-width)]",
|
||||
position === "popper" && "",
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ import { LayoutAlignLeftIcon } from "@hugeicons/core-free-icons"
|
|||
|
||||
const noop = () => {}
|
||||
|
||||
const SIDEBAR_WIDTH = "17.5rem"
|
||||
const SIDEBAR_WIDTH_ICON = "3rem"
|
||||
const SIDEBAR_WIDTH = "280px"
|
||||
const SIDEBAR_WIDTH_ICON = "48px"
|
||||
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-[18rem] p-0 [&>button]:hidden"
|
||||
className="bg-sidebar text-sidebar-foreground w-2/3 max-w-[288px] 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-[10px] 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-[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",
|
||||
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-2rem)] max-w-[400px]"
|
||||
? "fixed bottom-4 right-4 z-[9999] w-[calc(100vw-32px)] 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-[13px] font-medium text-foreground transition-colors hover:bg-muted"
|
||||
className="-ml-2 whitespace-nowrap rounded-full px-2.5 py-2 text-[0.8125rem] 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-[13px] font-medium text-foreground"
|
||||
className="h-auto rounded-full px-3 py-2 text-[0.8125rem] 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-[13px]"
|
||||
className="-mr-1 h-auto rounded-full px-3.5 py-2 text-[0.8125rem]"
|
||||
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-[2.5rem] 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-[40px] 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-[11px] leading-none text-muted-foreground">
|
||||
<span className="truncate text-[0.6875rem] 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-[10px] font-medium text-primary motion-reduce:animate-none">
|
||||
<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">
|
||||
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-[48rem]">{composer}</div>
|
||||
<div className="mx-auto w-full max-w-[768px]">{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-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<span className="text-[0.625rem] 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(4rem+var(--studio-chat-header-right-inset,var(--studio-window-control-inset,0px)))]">
|
||||
<span className="text-[10px] font-semibold uppercase tracking-wider text-primary">
|
||||
<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">
|
||||
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(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)))]",
|
||||
: "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)))]",
|
||||
)}
|
||||
>
|
||||
<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]: "48rem",
|
||||
["--thread-max-width" as string]: "768px",
|
||||
} as CSSProperties
|
||||
}
|
||||
>
|
||||
{/* Slightly narrower than the composer max; every block shares this. */}
|
||||
<div className="mx-auto flex w-full max-w-[44rem] flex-col pt-[120px] pb-14">
|
||||
<div className="mx-auto flex w-full max-w-[704px] 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-[30px] font-medium leading-tight tracking-normal text-foreground">
|
||||
<h1 className="min-w-0 flex-1 truncate font-sans text-[1.875rem] 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-[14px] 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-[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"
|
||||
>
|
||||
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-[14px] 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-[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"
|
||||
>
|
||||
Sources
|
||||
</button>
|
||||
|
|
@ -1417,7 +1417,7 @@ function ProjectLanding({
|
|||
onFocus={(event) => event.currentTarget.select()}
|
||||
maxLength={120}
|
||||
aria-label="Rename chat"
|
||||
className="w-full border-0 bg-transparent text-[15px] font-semibold leading-5 text-foreground outline-none"
|
||||
className="w-full border-0 bg-transparent text-[0.9375rem] font-semibold leading-5 text-foreground outline-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1442,11 +1442,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-[15px] font-semibold leading-5 text-foreground">
|
||||
<div className="truncate text-[0.9375rem] font-semibold leading-5 text-foreground">
|
||||
{displayTitle}
|
||||
</div>
|
||||
</div>
|
||||
<span className="shrink-0 text-[14px] 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-[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">
|
||||
{preview?.date ??
|
||||
formatProjectChatDate(item.createdAt)}
|
||||
</span>
|
||||
|
|
@ -3105,14 +3105,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(0.5rem+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(8px+var(--studio-chat-header-right-inset,var(--studio-window-control-inset,0px)))]",
|
||||
isMobile
|
||||
? "pl-12"
|
||||
: pinned
|
||||
? "pl-2"
|
||||
: "pl-[calc(0.5rem+max(0px,var(--studio-mac-traffic-light-inset,0px)-var(--sidebar-width-icon,3rem)))]",
|
||||
: "pl-[calc(8px+max(0px,var(--studio-mac-traffic-light-inset,0px)-var(--sidebar-width-icon,48px)))]",
|
||||
view.mode === "compare" &&
|
||||
"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)))]",
|
||||
"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)))]",
|
||||
)}
|
||||
>
|
||||
<div className="pointer-events-auto flex items-center gap-1">
|
||||
|
|
@ -3141,7 +3141,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-[13px] 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-[0.8125rem] text-primary">
|
||||
<HugeiconsIcon
|
||||
icon={BubbleChatTemporaryIcon}
|
||||
strokeWidth={2}
|
||||
|
|
@ -3153,7 +3153,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-[13.5px] 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-[0.84375rem] 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-[11px] leading-snug text-muted-foreground/65 sm:text-right"
|
||||
className="max-w-md text-[0.6875rem] 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-[10px] 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-[0.625rem] 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-[11px] leading-4 text-muted-foreground/80"
|
||||
className="mt-1 truncate text-[0.6875rem] 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-[44rem]"
|
||||
className="flex max-h-[90dvh] w-[96vw] flex-col gap-0 overflow-y-auto p-8 sm:max-w-none md:max-w-[704px]"
|
||||
>
|
||||
<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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-[0.8125rem] 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-[12px] 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-[0.75rem] 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-[16px] font-semibold tracking-[0em] dark:tracking-[0.015em] text-nav-fg">
|
||||
<span className="flex h-[34px] flex-1 items-center text-[1rem] font-semibold tracking-[0em] dark:tracking-[0.015em] text-nav-fg">
|
||||
Run settings
|
||||
</span>
|
||||
) : (
|
||||
<>
|
||||
<span className="flex h-[34px] flex-1 items-center text-[16px] font-semibold tracking-[0em] dark:tracking-[0.015em] text-nav-fg">
|
||||
<span className="flex h-[34px] flex-1 items-center text-[1rem] 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-[12px] leading-[1.4] text-nav-fg/80">
|
||||
<div className="rounded-lg bg-amber-500/[0.08] px-3 py-2 text-[0.75rem] 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-[12px]"
|
||||
className="corner-squircle mt-2 h-7 text-[0.75rem]"
|
||||
onClick={handleMtpUpdate}
|
||||
disabled={llamaUpdating}
|
||||
data-test-id="mtp-update-button"
|
||||
|
|
@ -768,7 +768,7 @@ export function ChatSettingsPanel({
|
|||
</div>
|
||||
)}
|
||||
{showContextVramWarning && (
|
||||
<p className="text-[11px] text-amber-500">
|
||||
<p className="text-[0.6875rem] 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-[13px] font-medium leading-9 text-nav-fg md:text-[13px]",
|
||||
"!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]",
|
||||
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-[13px] font-medium leading-[1.4] tracking-nav"
|
||||
className="flex min-h-9 items-center px-3 py-0 text-[0.8125rem] 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-[13px] font-medium tracking-nav",
|
||||
"h-9 w-full rounded-full text-[0.8125rem] 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-[13px] font-medium tracking-nav text-muted-foreground"
|
||||
className="h-9 w-full rounded-full text-[0.8125rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-[0.8125rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-[0.8125rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-[0.8125rem] 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-[13px] 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-[0.8125rem] 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-[11px] font-medium">Prompt editor</div>
|
||||
<div className="text-[0.6875rem] 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-[11px] text-muted-foreground"
|
||||
className="h-7 gap-1.5 rounded-full px-2.5 text-[0.6875rem] text-muted-foreground"
|
||||
aria-expanded={systemVariablesOpen}
|
||||
>
|
||||
<Braces className="size-3.5" />
|
||||
|
|
@ -1221,7 +1221,7 @@ export function ChatSettingsPanel({
|
|||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-[0.6875rem] 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-[11px] font-medium">
|
||||
<div className="text-[0.6875rem] font-medium">
|
||||
Prompt variables
|
||||
</div>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-[0.6875rem] 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-[10px] text-muted-foreground">
|
||||
<span className="text-[0.625rem] 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-[10px] text-muted-foreground"
|
||||
className="rounded-full bg-muted px-2 py-0.5 font-mono text-[0.625rem] text-muted-foreground"
|
||||
>
|
||||
{token}
|
||||
</span>
|
||||
|
|
@ -1272,11 +1272,11 @@ export function ChatSettingsPanel({
|
|||
aria-invalid={Boolean(systemVariablesError)}
|
||||
/>
|
||||
{systemVariablesError ? (
|
||||
<p className="px-1 text-[11px] text-destructive">
|
||||
<p className="px-1 text-[0.6875rem] text-destructive">
|
||||
{systemVariablesError}
|
||||
</p>
|
||||
) : (
|
||||
<p className="px-1 text-[11px] text-muted-foreground">
|
||||
<p className="px-1 text-[0.6875rem] 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-[20rem] max-h-[48vh] overflow-y-auto border-0 text-sm leading-6 corner-squircle focus-visible:ring-0"
|
||||
className="min-h-[320px] 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-[18rem] p-0 font-heading">
|
||||
<SheetContent side="right" className="w-[288px] 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-[17rem] border-l border-sidebar-border" : "w-0",
|
||||
open ? "w-[272px] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-[0.8125rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-[0.8125rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="min-w-0 text-[0.8125rem] 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-[11px] text-muted-foreground">
|
||||
<span className="text-[0.6875rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="whitespace-nowrap text-[0.8125rem] 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-[13px] 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-[0.8125rem] font-medium text-nav-fg shadow-none hover:bg-[var(--panel-input-surface)]" />
|
||||
{permissionMode === "full" ? (
|
||||
<span className="text-[11px] text-bypass">
|
||||
<span className="text-[0.6875rem] 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%-2rem)] 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%-32px)] 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-[13px] font-medium">
|
||||
<span className="min-w-0 flex-1 truncate text-[0.8125rem] font-medium">
|
||||
{item.title || "Untitled chat"}
|
||||
</span>
|
||||
<span className="shrink-0 text-[11px] text-muted-foreground">
|
||||
<span className="shrink-0 text-[0.6875rem] 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-[13px] 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-[0.8125rem] 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-[11px] leading-snug text-muted-foreground/90">
|
||||
<div className="mt-1 max-w-64 text-[0.6875rem] 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-[10px] font-medium tracking-[0.08em] text-muted-foreground/80">
|
||||
<div className="flex items-center justify-between gap-2 text-[0.625rem] 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-[10px] font-medium tracking-[0.08em] text-muted-foreground/60">
|
||||
<div className="truncate pt-0.5 text-[0.625rem] 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-[20rem] items-center gap-2.5 text-muted-foreground" title={title}>
|
||||
<div className="flex min-w-[320px] 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-[7rem] flex-1">
|
||||
<div className="min-w-[112px] flex-1">
|
||||
<Progress value={clampProgress(progressPercent)} className="h-1 bg-foreground/[0.08]" />
|
||||
</div>
|
||||
<div
|
||||
className="flex shrink-0 items-center gap-1 text-[10px] font-medium tracking-[0.08em] text-muted-foreground/80"
|
||||
className="flex shrink-0 items-center gap-1 text-[0.625rem] 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-[11px]"
|
||||
className="shrink-0 text-[0.6875rem]"
|
||||
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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg"
|
||||
className="min-w-0 text-[0.8125rem] 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-[11px] uppercase tracking-wider text-muted-foreground">
|
||||
<span className="text-[0.6875rem] 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-[9px] font-medium uppercase tracking-wider text-muted-foreground">
|
||||
<span className="shrink-0 rounded-sm bg-muted px-1 py-px text-[0.5625rem] 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-[9px] font-medium uppercase tracking-wider text-primary">
|
||||
<span className="shrink-0 rounded-sm bg-primary/15 px-1 py-px text-[0.5625rem] font-medium uppercase tracking-wider text-primary">
|
||||
Active
|
||||
</span>
|
||||
) : statusLabel ? (
|
||||
<span className="shrink-0 rounded-sm bg-muted px-1 py-px text-[9px] font-medium uppercase tracking-wider text-muted-foreground">
|
||||
<span className="shrink-0 rounded-sm bg-muted px-1 py-px text-[0.5625rem] 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-[11px]">
|
||||
<span className="min-w-0 truncate font-mono text-[0.6875rem]">
|
||||
{shortContainerId(c.id)}
|
||||
</span>
|
||||
<span className="shrink-0 text-[10px] uppercase tracking-wider">
|
||||
<span className="shrink-0 text-[0.625rem] 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-[16px] 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-[1rem] 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-[11px] !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-[0.6875rem] !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-[13px] leading-tight">{option.label}</span>
|
||||
<span className="text-[0.8125rem] 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-[30px] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[34px]">
|
||||
<h1 className="text-[1.875rem] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[2.125rem]">
|
||||
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-[11px] font-medium">
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-[0.6875rem] 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-[11px] font-medium">
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-[0.6875rem] 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-[11px] font-medium">
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-[0.6875rem] 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-[11px] font-medium">
|
||||
<DropdownMenuLabel className="pb-1 pt-2 text-[0.6875rem] 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-[13px] font-medium text-muted-foreground">
|
||||
<div className="mb-1 flex items-center gap-3 px-5 pb-1 text-[0.8125rem] 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-[13px] font-medium text-muted-foreground">
|
||||
<div className="mb-1 flex items-center gap-3 px-5 pb-1 text-[0.8125rem] 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-[15px] font-semibold text-foreground">
|
||||
<span className="min-w-0 flex-1 truncate text-[0.9375rem] 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-[11px] font-semibold uppercase tracking-wider text-muted-foreground/60">
|
||||
<p className="text-[0.6875rem] 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-[10px] text-muted-foreground/60">
|
||||
<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">
|
||||
{`{"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-[11px] font-semibold uppercase tracking-wider text-muted-foreground/60">
|
||||
<p className="text-[0.6875rem] 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-[11px] font-medium text-muted-foreground">
|
||||
<span className="shrink-0 rounded-full bg-muted px-2 py-0.5 text-[0.6875rem] 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-[11px] text-muted-foreground/50 ml-5">
|
||||
<p className="text-[0.6875rem] 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-[10px] font-semibold uppercase tracking-wide text-primary"
|
||||
className="mr-1 rounded-sm bg-primary/10 px-1.5 py-0.5 text-[0.625rem] 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-[10px] dark:text-zinc-300"
|
||||
className="h-5 shrink-0 px-1.5 text-[0.625rem] 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-[10px] dark:text-zinc-300"
|
||||
className="h-5 shrink-0 px-1.5 text-[0.625rem] 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-[10px] dark:text-zinc-300"
|
||||
className="h-5 shrink-0 px-1.5 text-[0.625rem] 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-[30px] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[34px]">
|
||||
<h1 className="text-[1.875rem] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[2.125rem]">
|
||||
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-[12px]"
|
||||
className="min-w-0 flex-1 font-mono text-[0.75rem]"
|
||||
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-[11px] text-muted-foreground/70">
|
||||
<p className="text-[0.6875rem] 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-[11px] text-emerald-600 hover:text-emerald-700 transition-colors"
|
||||
className="flex items-center gap-1 text-[0.6875rem] 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-[11px] text-muted-foreground/70">
|
||||
<p className="text-[0.6875rem] 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-[12px] text-foreground/90"
|
||||
className="select-all break-all font-mono text-[0.75rem] 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-[10px] font-semibold">
|
||||
<span className="rounded-full bg-foreground/10 px-2.5 py-1 text-[0.625rem] font-semibold">
|
||||
{PHASE_LABELS[run.phase] ?? run.phase}
|
||||
</span>
|
||||
{summaryMethod === "gguf" && run.quantTotal > 1 && (
|
||||
<span className="text-[10px] tabular-nums text-muted-foreground">
|
||||
<span className="text-[0.625rem] 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-[10px] font-medium tabular-nums text-muted-foreground">
|
||||
<span className="rounded-full border border-border/60 px-2.5 py-1 text-[0.625rem] font-medium tabular-nums text-muted-foreground">
|
||||
{progress}%
|
||||
</span>
|
||||
<span className="text-[10px] tabular-nums text-muted-foreground/70">
|
||||
<span className="text-[0.625rem] 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-[11px] text-muted-foreground/80"
|
||||
className="truncate text-[0.6875rem] 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-[11px] text-muted-foreground/80">
|
||||
<div className="flex items-center gap-2 text-[0.6875rem] 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-[11px] 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-[0.6875rem] 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-[10px] px-1.5 py-0"
|
||||
className="text-[0.625rem] 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-[11px] text-muted-foreground/70">
|
||||
<span className="text-[0.6875rem] 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-[10px] opacity-60">{sizeLabel}</span>
|
||||
<span className="text-[0.625rem] opacity-60">{sizeLabel}</span>
|
||||
)}
|
||||
{q.recommended && !active && (
|
||||
<span className="rounded-full bg-emerald-100 px-1.5 py-0 text-[9px] 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-[0.5625rem] 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-[11px] text-muted-foreground">
|
||||
<span className="text-[0.6875rem] text-muted-foreground">
|
||||
{value.length} selected
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onChange([])}
|
||||
className="text-[11px] text-muted-foreground/70 hover:text-foreground transition-colors"
|
||||
className="text-[0.6875rem] 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-[30px] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[34px]">
|
||||
<h1 className="text-[1.875rem] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[2.125rem]">
|
||||
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-[12.5px] 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-[0.78125rem] 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-[12.5px] 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-[0.78125rem] 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-[12.5px] 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-[0.78125rem] 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-[10px] text-muted-foreground">
|
||||
<span className="ml-auto shrink-0 text-[0.625rem] text-muted-foreground">
|
||||
{source}
|
||||
</span>
|
||||
</ComboboxItem>
|
||||
|
|
@ -1300,15 +1300,15 @@ export function ExportPage() {
|
|||
</Combobox>
|
||||
</div>
|
||||
{isLoadingLocalModels ? (
|
||||
<p className="text-[10px] text-muted-foreground">
|
||||
<p className="text-[0.625rem] text-muted-foreground">
|
||||
Scanning local models...
|
||||
</p>
|
||||
) : localModelsError ? (
|
||||
<p className="text-[10px] text-red-500">
|
||||
<p className="text-[0.625rem] text-red-500">
|
||||
{localModelsError}
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-[10px] text-muted-foreground">
|
||||
<p className="text-[0.625rem] 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-[11px] text-muted-foreground">
|
||||
<p className="text-[0.6875rem] 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-[11px] font-medium text-muted-foreground uppercase tracking-wider">
|
||||
<span className="text-[0.6875rem] 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-[10px] font-semibold">
|
||||
<span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-foreground/10 text-[0.625rem] 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-[11px] text-muted-foreground/70">
|
||||
<span className="text-[0.6875rem] 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-[10px] text-muted-foreground">
|
||||
<span className="text-[0.625rem] 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-[11px] text-muted-foreground">
|
||||
<span className="text-[0.6875rem] text-muted-foreground">
|
||||
{selectedFormats.length} selected:{" "}
|
||||
{selectedFormats
|
||||
.map(
|
||||
|
|
@ -1506,7 +1506,7 @@ export function ExportPage() {
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => setSelectedFormats(["16-bit"])}
|
||||
className="text-[11px] text-muted-foreground/70 hover:text-foreground transition-colors"
|
||||
className="text-[0.6875rem] 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-[11px] text-amber-600 dark:text-amber-500">
|
||||
<div className="text-[0.6875rem] 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-[11px] text-muted-foreground">
|
||||
<div className="text-[0.6875rem] text-muted-foreground">
|
||||
* calibrates on data (uses a small calibration set).
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!hasNvidia && (
|
||||
<div className="text-[11px] text-muted-foreground">
|
||||
<div className="text-[0.6875rem] 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-[14px] font-semibold tracking-tight text-foreground">
|
||||
<p className="text-[0.875rem] font-semibold tracking-tight text-foreground">
|
||||
{title}
|
||||
</p>
|
||||
<p className="max-w-md text-[12.5px] leading-5 text-muted-foreground">
|
||||
<p className="max-w-md text-[0.78125rem] leading-5 text-muted-foreground">
|
||||
{body}
|
||||
</p>
|
||||
<p className="text-[11px] text-muted-foreground/70">{message}</p>
|
||||
<p className="text-[0.6875rem] 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-[12px] 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-[0.75rem] 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-[12px] 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-[0.75rem] 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-[14px] font-semibold tracking-tight text-foreground">
|
||||
<p className="text-[0.875rem] font-semibold tracking-tight text-foreground">
|
||||
No matches yet
|
||||
</p>
|
||||
<p className="max-w-md text-[12.5px] leading-5 text-muted-foreground">
|
||||
<p className="max-w-md text-[0.78125rem] 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-[12px] 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-[0.75rem] 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-[12px] 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-[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]"
|
||||
>
|
||||
<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-[11.5px] leading-4 text-muted-foreground">
|
||||
<p className="text-[0.71875rem] 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-[12px] 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-[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]"
|
||||
>
|
||||
<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-[14px] font-semibold tracking-tight text-foreground">
|
||||
<p className="text-[0.875rem] font-semibold tracking-tight text-foreground">
|
||||
Couldn't load your library
|
||||
</p>
|
||||
<p className="max-w-md text-[12.5px] leading-5 text-muted-foreground">
|
||||
<p className="max-w-md text-[0.78125rem] 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-[12px] 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-[0.75rem] 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-[14px] font-semibold tracking-tight text-foreground">
|
||||
<p className="text-[0.875rem] font-semibold tracking-tight text-foreground">
|
||||
{title}
|
||||
</p>
|
||||
<p className="max-w-md text-[12.5px] leading-5 text-muted-foreground">
|
||||
<p className="max-w-md text-[0.78125rem] 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-[12px] text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5 text-[0.75rem] 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-[11px] 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-[0.6875rem] 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-[12px] 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-[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]"
|
||||
>
|
||||
<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-[13px] font-medium text-foreground">
|
||||
<p className="truncate text-[0.8125rem] font-medium text-foreground">
|
||||
{hostOf(pendingUrl)}
|
||||
</p>
|
||||
<p className="mt-0.5 break-all text-[11.5px] leading-[16px] text-muted-foreground">
|
||||
<p className="mt-0.5 break-all text-[0.71875rem] leading-[1rem] 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-[11.5px] 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-[0.71875rem] 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-[12.5px] font-medium tracking-tight tabular-nums",
|
||||
"inline-flex shrink-0 cursor-help items-center gap-1.5 whitespace-nowrap text-[0.78125rem] 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-[12px] text-muted-foreground">
|
||||
<span className="flex min-w-0 flex-1 items-center gap-2 overflow-hidden text-[0.75rem] text-muted-foreground">
|
||||
{selected ? (
|
||||
<QuantBadge
|
||||
quant={selectedLabel ?? selected.quant}
|
||||
|
|
@ -923,7 +923,7 @@ export function GgufDownloadCard({
|
|||
active={Boolean(selectedIsActive)}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-[12.5px] text-muted-foreground">
|
||||
<span className="text-[0.78125rem] 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-[11px] text-status-warning underline-offset-2 transition-colors hover:underline"
|
||||
className="self-start px-1 text-[0.6875rem] 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-[12.5px]",
|
||||
"flex min-w-0 items-center gap-2 text-[0.78125rem]",
|
||||
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-[12.5px] text-muted-foreground">
|
||||
<span className="flex min-w-0 items-center gap-2 text-[0.78125rem] 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-[12.5px] 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-[0.78125rem] 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-[12.5px] 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-[0.78125rem] 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-1rem))] 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-16px))] 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-[18px] 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-[1.125rem] 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-[12px] text-muted-foreground">
|
||||
<span className="flex min-w-0 items-center gap-1.5 text-[0.75rem] 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-[11px] font-medium text-muted-foreground">
|
||||
<span className="shrink-0 text-[0.6875rem] font-medium text-muted-foreground">
|
||||
{baseModelSourceLabel(baseModelSource)}
|
||||
</span>
|
||||
<span className="truncate text-[12px] font-medium text-foreground">
|
||||
<span className="truncate text-[0.75rem] font-medium text-foreground">
|
||||
{baseModel}
|
||||
</span>
|
||||
</div>
|
||||
{baseModelSummary && (
|
||||
<p className="mt-0.5 truncate text-[11px] text-muted-foreground">
|
||||
<p className="mt-0.5 truncate text-[0.6875rem] 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-[12px] 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-[0.75rem] 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-[12px] text-muted-foreground">
|
||||
<span className="flex min-w-0 items-center gap-1.5 text-[0.75rem] 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-[10.5px] 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-[0.65625rem] 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-[10px] text-muted-foreground tabular-nums">
|
||||
<span className="shrink-0 font-sans text-[0.625rem] 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%-1rem)] 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%-16px)] 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-[12px] text-format-gguf">
|
||||
<span className="min-w-0 flex-1 truncate font-mono text-[0.75rem] text-format-gguf">
|
||||
{label}
|
||||
</span>
|
||||
<span className="flex shrink-0 items-center gap-1.5">
|
||||
{isLoaded && (
|
||||
<DotTag tone="success" label="Loaded" />
|
||||
)}
|
||||
<span className="text-[10px] text-muted-foreground tabular-nums">
|
||||
<span className="text-[0.625rem] 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-[17px] ring-1 ring-white/10"
|
||||
className="size-11 shrink-0 rounded-[14px] text-[1.0625rem] 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-[13.5px] font-semibold leading-[16px] text-foreground">
|
||||
<p className="hub-trending-title line-clamp-2 text-[0.84375rem] font-semibold leading-[1rem] text-foreground">
|
||||
{row.repo}
|
||||
</p>
|
||||
<span className="hub-trending-owner flex min-w-0 items-center gap-1 text-[11.5px] leading-[15px] text-muted-foreground/80">
|
||||
<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="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-[11.5px] 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-[0.71875rem] 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-[11px] font-medium leading-none",
|
||||
"inline-flex h-5 shrink-0 items-center whitespace-nowrap rounded-full border bg-transparent px-2 text-[0.6875rem] 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-[11.5px] 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-[0.71875rem] 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-[11.5px] 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-[0.71875rem] 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-[10.5px] font-normal text-white/75">
|
||||
<span className="mt-1 block text-[0.65625rem] font-normal text-white/75">
|
||||
{unslothSupport.reason}
|
||||
</span>
|
||||
)}
|
||||
<span className="mt-1 block text-[10.5px] font-normal text-white/75">
|
||||
<span className="mt-1 block text-[0.65625rem] 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-[10.5px] font-normal text-white/75">
|
||||
<span className="mt-1 block text-[0.65625rem] 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-[10.5px] font-normal text-white/75">
|
||||
<span className="mt-1 block text-[0.65625rem] 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-[15px] font-semibold tracking-tight text-foreground">
|
||||
<p className="text-[0.9375rem] font-semibold tracking-tight text-foreground">
|
||||
Select a {isDataset ? "dataset" : "model"}
|
||||
</p>
|
||||
<p className="max-w-sm text-[12.5px] leading-5 text-muted-foreground">
|
||||
<p className="max-w-sm text-[0.78125rem] 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-[10.5px] font-normal text-white/75">
|
||||
<span className="mt-1 block text-[0.65625rem] 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-[19px]"
|
||||
className="size-[60px] rounded-[18px] text-[1.1875rem]"
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<h2 className="truncate text-[25px] font-semibold leading-[31px] tracking-normal text-foreground">
|
||||
<h2 className="truncate text-[1.5625rem] font-semibold leading-[1.9375rem] 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-[15px] leading-[24px] text-muted-foreground">
|
||||
<div className="mt-0.5 flex min-w-0 items-center gap-1 text-[0.9375rem] leading-[1.5rem] 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-[11.5px] 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-[0.71875rem] 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-[11.5px] 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-[0.71875rem] 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-[11.5px] 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-[0.71875rem] leading-snug text-muted-foreground">
|
||||
Current selection is hidden by the active filters or search.
|
||||
</p>
|
||||
)}
|
||||
{metadataUnavailable && (
|
||||
<p className="mb-3 text-[11.5px] leading-snug text-muted-foreground">
|
||||
<p className="mb-3 text-[0.71875rem] 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-[13.5px] leading-[1.7] text-foreground/85",
|
||||
"[&_h1]:text-[18px] [&_h1]:font-semibold [&_h1]:tracking-tight [&_h1]:mt-2 [&_h1]:mb-3",
|
||||
"[&_h2]:text-[15.5px] [&_h2]:font-semibold [&_h2]:tracking-tight [&_h2]:mt-5 [&_h2]:mb-2",
|
||||
"[&_h3]:text-[14px] [&_h3]:font-semibold [&_h3]:mt-4 [&_h3]:mb-1.5",
|
||||
"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",
|
||||
"[&_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-[12px] [&_code]:font-mono",
|
||||
"[&_pre]:rounded-[12px] [&_pre]:border [&_pre]:border-border/60 [&_pre]:bg-muted/40 [&_pre]:p-3 [&_pre]:text-[12px] [&_pre]:overflow-x-auto",
|
||||
"[&_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",
|
||||
"[&_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-[12.5px]",
|
||||
"[&_table]:my-3 [&_table]:text-[0.78125rem]",
|
||||
"[&_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-[12.5px] text-muted-foreground">
|
||||
<div className="flex items-center gap-2 text-[0.78125rem] 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-[12.5px] text-muted-foreground">
|
||||
<p className="min-h-[44px] text-[0.78125rem] text-muted-foreground">
|
||||
{errorMessage}
|
||||
</p>
|
||||
);
|
||||
|
|
@ -548,7 +548,7 @@ export function ModelReadme({
|
|||
|
||||
if (!current.body) {
|
||||
return (
|
||||
<p className="min-h-[44px] text-[12.5px] text-muted-foreground">
|
||||
<p className="min-h-[44px] text-[0.78125rem] 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-[12.5px] 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-[0.78125rem] 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-[12px] font-medium text-foreground transition-colors hover:text-primary"
|
||||
className="shrink-0 text-[0.75rem] 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-[13px] text-muted-foreground">
|
||||
<div className="flex min-h-[240px] items-center justify-center gap-3 text-[0.8125rem] 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-[12px] 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-[0.75rem] 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-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<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">
|
||||
<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-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="px-1 pb-2 pt-2 text-[0.6875rem] 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-[11px] text-white/70"
|
||||
className="text-[0.6875rem] text-white/70"
|
||||
/>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<span className="block max-w-52 text-[11px] leading-4 text-muted-foreground">
|
||||
<span className="block max-w-52 text-[0.6875rem] 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-[10px] font-medium leading-none tabular-nums text-muted-foreground/75",
|
||||
"inline-flex shrink-0 items-center gap-1 whitespace-nowrap text-[0.625rem] 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-[12px] font-medium leading-[18px] tracking-[-0.005em] text-foreground">
|
||||
<p className="truncate text-[0.75rem] font-medium leading-[1.125rem] 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-[11.5px] leading-[16px] text-muted-foreground/85">
|
||||
<div className="flex h-[16px] min-w-0 items-center justify-between gap-2 text-[0.71875rem] leading-[1rem] 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-[10.5px] tabular-nums">
|
||||
<span className="shrink-0 text-[0.65625rem] 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-[10.5px] uppercase">
|
||||
<span className="hub-chip font-mono text-[0.65625rem] 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-[11.5px] leading-[15px] text-muted-foreground/80">
|
||||
<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="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-[12px]"
|
||||
className="size-8 shrink-0 rounded-[9px] text-[0.75rem]"
|
||||
remote={false}
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="truncate text-[12.5px] font-semibold leading-[16px] text-foreground">
|
||||
<span className="truncate text-[0.78125rem] font-semibold leading-[1rem] text-foreground">
|
||||
{title}
|
||||
</span>
|
||||
{compactMarkers}
|
||||
</div>
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1.5 text-[10.5px] leading-[14px] text-muted-foreground/75">
|
||||
<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="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-[10.5px] tabular-nums text-muted-foreground/70">
|
||||
<div className="flex shrink-0 items-center gap-2 text-[0.65625rem] 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-[13.5px] font-semibold leading-[17px] text-foreground">
|
||||
<span className="truncate text-[0.84375rem] font-semibold leading-[1.0625rem] text-foreground">
|
||||
{title}
|
||||
</span>
|
||||
{statusMarkers}
|
||||
|
|
@ -915,11 +915,11 @@ export const InventoryRow = memo(function InventoryRow({
|
|||
cachePath={row.cachePath}
|
||||
/>
|
||||
) : trailing ? (
|
||||
<span className="truncate text-[11.5px] tabular-nums text-muted-foreground/70">
|
||||
<span className="truncate text-[0.71875rem] tabular-nums text-muted-foreground/70">
|
||||
{trailing}
|
||||
</span>
|
||||
) : sourceLabel ? (
|
||||
<span className="truncate text-[11.5px] text-muted-foreground/55">
|
||||
<span className="truncate text-[0.71875rem] 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-[11.5px]">
|
||||
<div className="hub-tag-soft ml-1 inline-flex items-center gap-1.5 px-2 py-1 text-[0.71875rem]">
|
||||
<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-[11px] 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-[0.6875rem] 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-[11.5px]"
|
||||
className="h-8 min-w-[72px] max-w-[124px] shrink text-[0.71875rem]"
|
||||
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-[11.5px]"
|
||||
className="h-8 min-w-[72px] max-w-[124px] shrink text-[0.71875rem]"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -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-[18px] font-semibold tracking-[-0.02em] text-foreground">
|
||||
<h2 className="truncate text-[1.125rem] font-semibold tracking-[-0.02em] text-foreground">
|
||||
{title}
|
||||
</h2>
|
||||
{subtitle && (
|
||||
<p className="text-[12.5px] leading-tight text-muted-foreground">
|
||||
<p className="text-[0.78125rem] 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-[11px] font-medium text-muted-foreground/55">
|
||||
<div className="flex w-full items-center gap-3 px-4 pb-2 text-[0.6875rem] 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-[12px] text-muted-foreground/75">
|
||||
<span className="truncate text-[0.75rem] 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-[11px] font-medium text-muted-foreground">
|
||||
<span className="text-[0.6875rem] 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-[16px] ring-1 ring-black/5 dark:ring-white/10"
|
||||
className="size-[52px] shrink-0 rounded-[16px] text-[1rem] 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-[15px] font-semibold leading-[18px] text-foreground">
|
||||
<span className="truncate text-[0.9375rem] font-semibold leading-[1.125rem] 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-[12.5px] leading-[16px] text-muted-foreground/80">
|
||||
<span className="flex min-w-0 items-center gap-1 text-[0.78125rem] leading-[1rem] text-muted-foreground/80">
|
||||
<VerifiedOwner owner={row.owner} />
|
||||
</span>
|
||||
<div className="flex min-w-0 items-center gap-2 overflow-hidden text-[11.5px] leading-[16px] tabular-nums text-muted-foreground/65">
|
||||
<div className="flex min-w-0 items-center gap-2 overflow-hidden text-[0.71875rem] leading-[1rem] 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-[13px] ring-1 ring-black/5 dark:ring-white/10"
|
||||
className="size-9 shrink-0 rounded-[12px] text-[0.8125rem] 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-[13.5px] font-semibold leading-[17px] text-foreground">
|
||||
<span className="truncate text-[0.84375rem] font-semibold leading-[1.0625rem] 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-[11.5px] leading-[15px] text-muted-foreground/80">
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1 text-[0.71875rem] leading-[0.9375rem] 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-[12px] text-muted-foreground/75">
|
||||
<span className="truncate text-[0.75rem] 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-[12px] tabular-nums text-muted-foreground",
|
||||
"truncate text-[0.75rem] tabular-nums text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{sizeDisplay ?? "—"}
|
||||
|
|
@ -809,7 +809,7 @@ export const ResultGridRow = memo(function ResultGridRow({
|
|||
<div
|
||||
className={cn(
|
||||
LIST_COLS.updated,
|
||||
"truncate text-[12px] tabular-nums text-muted-foreground",
|
||||
"truncate text-[0.75rem] 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-[12px] tabular-nums text-muted-foreground",
|
||||
"text-[0.75rem] tabular-nums text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
<StatItem
|
||||
|
|
@ -828,7 +828,7 @@ export const ResultGridRow = memo(function ResultGridRow({
|
|||
<div
|
||||
className={cn(
|
||||
LIST_COLS.likes,
|
||||
"text-[12px] tabular-nums text-muted-foreground",
|
||||
"text-[0.75rem] 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-[12px]"
|
||||
className="size-8 shrink-0 rounded-[9px] text-[0.75rem]"
|
||||
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-[12.5px] font-semibold leading-[16px] text-foreground">
|
||||
<span className="truncate text-[0.78125rem] font-semibold leading-[1rem] 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-[10.5px] leading-[14px] text-muted-foreground/80">
|
||||
<span className="mt-0.5 flex min-w-0 items-center gap-1 text-[0.65625rem] leading-[0.875rem] text-muted-foreground/80">
|
||||
<VerifiedOwner owner={row.owner} />
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex shrink-0 flex-col items-end gap-0.5 text-[10.5px] tabular-nums text-muted-foreground/70">
|
||||
<div className="flex shrink-0 flex-col items-end gap-0.5 text-[0.65625rem] 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-[12.5px] transition-colors",
|
||||
"relative z-10 inline-flex h-9 flex-1 items-center justify-center rounded-full px-3 text-[0.78125rem] 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-[12.5px] transition-colors",
|
||||
"relative z-10 inline-flex h-9 flex-1 items-center justify-center rounded-full px-3 text-[0.78125rem] 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-[13px] placeholder:text-muted-foreground/80 focus-visible:!ring-0",
|
||||
"field-soft h-9 rounded-full !border-0 pl-10 text-[0.8125rem] 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-[12.5px]",
|
||||
"field-filter inline-flex h-9 shrink-0 items-center gap-1.5 rounded-full px-3 text-[0.78125rem]",
|
||||
)}
|
||||
>
|
||||
<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-[12.5px] 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-[0.78125rem] 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-[15px]">
|
||||
<DialogTitle className="text-[0.9375rem]">
|
||||
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-[12px] font-medium text-foreground">
|
||||
<div className="mb-2 flex items-center gap-2 text-[0.75rem] 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-[12px] placeholder:font-sans"
|
||||
className="field-soft h-9 rounded-full pl-9 pr-3 font-mono text-[0.75rem] 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-[12.5px]"
|
||||
className="h-9 rounded-full px-3 text-[0.78125rem]"
|
||||
>
|
||||
{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-[12px] text-destructive">
|
||||
<div className="rounded-[10px] border border-destructive/20 bg-destructive/5 px-3 py-2 text-[0.75rem] 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-[12px] font-medium text-foreground">
|
||||
<span className="text-[0.75rem] 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-[12px] text-muted-foreground">
|
||||
<div className="flex h-24 items-center justify-center gap-2 text-[0.75rem] 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-[12px] text-muted-foreground">
|
||||
<div className="flex h-28 flex-col items-center justify-center gap-2 px-4 text-center text-[0.75rem] 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-[2rem_minmax(0,1fr)_2rem_2rem]"
|
||||
: "grid-cols-[2rem_minmax(0,1fr)_2rem]",
|
||||
? "grid-cols-[32px_minmax(0,1fr)_32px_32px]"
|
||||
: "grid-cols-[32px_minmax(0,1fr)_32px]",
|
||||
)}
|
||||
>
|
||||
<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-[12.5px] font-medium text-foreground"
|
||||
className="block w-full truncate text-[0.78125rem] 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-[10.5px] text-muted-foreground">
|
||||
<p className="block w-full truncate font-mono text-[0.65625rem] 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-[9px]",
|
||||
sm: "size-7 rounded-[10px] text-[11px]",
|
||||
md: "size-9 rounded-[12px] text-[13px]",
|
||||
lg: "size-12 rounded-[15px] text-[16px]",
|
||||
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]",
|
||||
};
|
||||
|
||||
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-[11.5px]"
|
||||
className="h-8 min-w-[96px] gap-1.5 text-[0.71875rem]"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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-[11px] font-semibold uppercase tracking-[0.04em] text-muted-foreground/70">
|
||||
<span className="text-[0.6875rem] 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-[11.5px] font-medium text-muted-foreground transition-colors hover:text-foreground"
|
||||
className="hub-recent-clear rounded-full px-2 py-0.5 text-[0.71875rem] 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-[13px] text-foreground">
|
||||
<span className="truncate text-[0.8125rem] 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-[12px] text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5 text-[0.75rem] 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-[11px] font-semibold uppercase tracking-wider text-muted-foreground",
|
||||
"pb-4 text-[0.6875rem] 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-[13px] font-medium text-nav-fg">{label}</span>
|
||||
<span className="text-[0.8125rem] 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-[13px]"
|
||||
className="min-h-[84px] resize-y text-[0.8125rem]"
|
||||
/>
|
||||
</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-[13px] font-medium text-nav-fg">
|
||||
<span className="text-[0.8125rem] 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-[11.5px]"
|
||||
className="h-8 text-[0.71875rem]"
|
||||
/>
|
||||
</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-[11px] 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-[0.6875rem] 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-[11.5px] font-medium",
|
||||
"inline-flex h-6 shrink-0 items-center rounded-full text-[0.71875rem] 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-[22rem]">
|
||||
<AlertDialogContent className="sm:!max-w-[352px]">
|
||||
<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-[11px]"
|
||||
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]"
|
||||
>
|
||||
{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-[12.5px] 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-[0.78125rem] 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-[11px] font-normal tabular-nums",
|
||||
"shrink-0 text-[0.6875rem] 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-[11.5px] 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-[0.71875rem] 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-[30px] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[34px]";
|
||||
"text-[1.875rem] font-semibold leading-[1.04] tracking-[-0.028em] text-foreground sm:text-[2.125rem]";
|
||||
|
||||
export function PageHeading({
|
||||
title,
|
||||
|
|
@ -38,7 +38,7 @@ export function PageHeading({
|
|||
<h1 className={TITLE_CLASS}>{title}</h1>
|
||||
)}
|
||||
{subtitle ? (
|
||||
<p className="mt-2 text-[13px] leading-[19px] text-muted-foreground">
|
||||
<p className="mt-2 text-[0.8125rem] leading-[1.1875rem] 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-[12.5px] font-medium text-foreground">
|
||||
<span className="min-w-0 flex-1 truncate text-[0.78125rem] 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-[11px] text-muted-foreground tabular-nums">
|
||||
<div className="px-0 text-[0.6875rem] 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-2rem))] overflow-hidden">
|
||||
<div className="hub-download-panel pointer-events-auto w-[min(400px,calc(100vw-32px))] 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-[12.5px] font-semibold text-foreground">
|
||||
<span className="min-w-0 flex-1 truncate text-[0.78125rem] 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-[10.5px] text-muted-foreground tabular-nums">
|
||||
<div className="flex items-center justify-between gap-2 text-[0.65625rem] 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-[13px] text-muted-foreground lg:flex">
|
||||
<div className="hidden min-h-0 flex-1 items-center justify-center px-6 text-center text-[0.8125rem] text-muted-foreground lg:flex">
|
||||
Select a model to preview its details.
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@
|
|||
}
|
||||
|
||||
.hub-page .hub-focused-heading {
|
||||
font-size: 18px;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0;
|
||||
color: var(--foreground);
|
||||
|
|
@ -798,8 +798,8 @@
|
|||
.hub-download-fab {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -832,16 +832,16 @@
|
|||
top: -3px;
|
||||
right: -3px;
|
||||
display: inline-flex;
|
||||
width: 1.125rem;
|
||||
min-width: 1.125rem;
|
||||
height: 1.125rem;
|
||||
width: 18px;
|
||||
min-width: 18px;
|
||||
height: 18px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 9999px;
|
||||
padding-inline: 0;
|
||||
background-color: var(--status-success);
|
||||
color: var(--primary-foreground);
|
||||
font-size: 10.5px;
|
||||
font-size: 0.65625rem;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
font-variant-numeric: tabular-nums;
|
||||
|
|
@ -1082,7 +1082,7 @@
|
|||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.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: 2.25rem;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
gap: 8px;
|
||||
white-space: nowrap;
|
||||
border-radius: 9999px;
|
||||
background-color: transparent;
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
font-size: 13px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
line-height: 18px;
|
||||
line-height: 1.125rem;
|
||||
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: 1rem;
|
||||
height: 1rem;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
|
@ -1154,19 +1154,19 @@
|
|||
so the height aligns with adjacent ghost buttons. */
|
||||
.hub-run-action-btn {
|
||||
display: inline-flex;
|
||||
height: 2.25rem;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
gap: 6.4px;
|
||||
white-space: nowrap;
|
||||
border-radius: 9999px;
|
||||
background-color: var(--status-success);
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
font-size: 13px;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
line-height: 18px;
|
||||
line-height: 1.125rem;
|
||||
letter-spacing: -0.025em;
|
||||
color: var(--primary-foreground);
|
||||
transition: background-color 150ms, transform 150ms;
|
||||
|
|
@ -1189,8 +1189,8 @@
|
|||
}
|
||||
|
||||
.hub-run-action-btn svg {
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
width: 14.4px;
|
||||
height: 14.4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
|
@ -1200,8 +1200,8 @@
|
|||
.hub-cta-indicator {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
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: 0.25rem;
|
||||
right: 4px;
|
||||
top: 50%;
|
||||
display: inline-flex;
|
||||
width: 1.75rem;
|
||||
height: 1.75rem;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
transform: translateY(-50%);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -1261,8 +1261,8 @@
|
|||
}
|
||||
|
||||
.hub-row-action svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1271,8 +1271,8 @@
|
|||
.hub-page .field-trigger.field-filter {
|
||||
color: var(--muted-foreground);
|
||||
font-weight: 400;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
|
|
@ -1284,13 +1284,13 @@
|
|||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
height: 2rem;
|
||||
padding-inline: 0.7rem;
|
||||
gap: 6.4px;
|
||||
height: 32px;
|
||||
padding-inline: 11.2px;
|
||||
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: 12px;
|
||||
font-size: 0.75rem;
|
||||
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-[11px] font-medium leading-none;
|
||||
@apply inline-flex items-center gap-1 rounded-full px-2 py-[3px] text-[0.6875rem] 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-[11px] font-medium leading-none;
|
||||
@apply inline-flex h-[18px] shrink-0 items-center gap-1 rounded-full px-2 text-[0.6875rem] 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-[20rem] max-h-[50vh] overflow-y-auto border-0 font-mono text-xs leading-5 corner-squircle focus-visible:ring-0"
|
||||
className="min-h-[320px] 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-[11px]">
|
||||
<div className="flex items-center justify-between gap-3 px-0.5 text-[0.6875rem]">
|
||||
<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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg";
|
||||
"min-w-0 truncate text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg";
|
||||
const LABEL_CLASS_WRAP =
|
||||
"min-w-0 text-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg";
|
||||
"min-w-0 text-[0.8125rem] 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-[13px]! 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-[13px] 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-[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 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-[12px] text-muted-foreground">
|
||||
<span className="text-[0.75rem] 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-[13px] ${CONTROL_SURFACE}`}
|
||||
className={`h-8 px-3 text-[0.8125rem] ${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-[12px] text-nav-fg/80">
|
||||
<span className="min-w-0 truncate text-[0.75rem] 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-[10px] font-semibold uppercase leading-none tracking-wider text-muted-foreground">
|
||||
<div className="text-[0.625rem] font-semibold uppercase leading-none tracking-wider text-muted-foreground">
|
||||
Run settings
|
||||
</div>
|
||||
<div className="mt-1.5 truncate text-[14px] font-semibold leading-tight text-nav-fg">
|
||||
<div className="mt-1.5 truncate text-[0.875rem] 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-[11px] text-amber-500">
|
||||
<p className="text-[0.6875rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-muted-foreground">
|
||||
<span className="min-w-0 text-[0.8125rem] 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-[13px] text-nav-fg"
|
||||
className="cursor-pointer select-none truncate text-[0.8125rem] 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-[16px] font-medium leading-tight text-black dark:text-white">
|
||||
<span className="min-w-0 flex flex-1 items-baseline truncate font-heading text-[1rem] font-medium leading-tight text-black dark:text-white">
|
||||
{currentModel?.name ?? "Select model"}
|
||||
{showCloudIndicator ? (
|
||||
<HugeiconsIcon
|
||||
icon={CloudIcon}
|
||||
strokeWidth={1.75}
|
||||
className="relative top-[0.15625rem] ml-1.5 mr-[0.36rem] size-3.5 shrink-0 text-muted-foreground"
|
||||
className="relative top-[2.5px] ml-1.5 mr-[5.76px] 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-1rem)] min-w-0 gap-0",
|
||||
"unsloth-model-selector-menu menu-soft-surface ring-0 max-w-[calc(100vw-16px)] min-w-0 gap-0",
|
||||
visibleConfigTarget
|
||||
? "w-[min(468px,calc(100vw-1rem))] px-4 pt-4 pb-4"
|
||||
? "w-[min(468px,calc(100vw-16px))] 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-1rem))] pr-4"
|
||||
: "w-[min(506px,calc(100vw-1rem))] pr-2",
|
||||
? "w-[min(614px,calc(100vw-16px))] pr-4"
|
||||
: "w-[min(506px,calc(100vw-16px))] 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-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="flex items-center gap-2 px-2.5 py-1.5 text-[0.625rem] 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-[11px] 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-[0.6875rem] 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-[10px] 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-[0.625rem] 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-[10px] text-foreground/70">
|
||||
<div className="border-t border-border/30 px-6 py-1.5 text-[0.625rem] 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-[10px] text-muted-foreground/70">
|
||||
<div className="border-t border-border/30 px-6 py-1.5 text-[0.625rem] 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-[9px] uppercase tracking-wider text-muted-foreground">
|
||||
<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">
|
||||
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-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5 text-[0.625rem] 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-[13px] text-muted-foreground/90">
|
||||
<span className="inline-flex min-w-0 max-w-[45%] shrink items-baseline text-[0.8125rem] 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-[9px] 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-[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">
|
||||
OOM
|
||||
</span>
|
||||
)}
|
||||
{vramStatus === "tight" && (
|
||||
<span className="text-[9px] font-medium !text-amber-400">TIGHT</span>
|
||||
<span className="text-[0.5625rem] font-medium !text-amber-400">TIGHT</span>
|
||||
)}
|
||||
{paramLabel ? (
|
||||
<span className="rounded-md border border-border/60 px-1.5 py-px text-[10px] font-medium text-muted-foreground tabular-nums">
|
||||
<span className="rounded-md border border-border/60 px-1.5 py-px text-[0.625rem] font-medium text-muted-foreground tabular-nums">
|
||||
{paramLabel}
|
||||
</span>
|
||||
) : null}
|
||||
{parsed.texts.map((text) => (
|
||||
<span key={text} className="text-[10px] text-muted-foreground">
|
||||
<span key={text} className="text-[0.625rem] text-muted-foreground">
|
||||
{text}
|
||||
</span>
|
||||
))}
|
||||
{parsed.size !== undefined ? (
|
||||
<span className="text-[10px] text-muted-foreground tabular-nums">
|
||||
<span className="text-[0.625rem] 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-[10px] text-muted-foreground break-all">
|
||||
<span className="block mt-1 text-[0.625rem] text-muted-foreground break-all">
|
||||
{hubUrl}
|
||||
</span>
|
||||
) : null;
|
||||
|
|
@ -622,7 +622,7 @@ function ModelRow({
|
|||
const tooltipBody = vramTooltipText ? (
|
||||
<>
|
||||
{label}
|
||||
<span className="block text-[10px] mt-1">{vramTooltipText}</span>
|
||||
<span className="block text-[0.625rem] 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-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<span className="text-[0.625rem] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
Quantizations
|
||||
</span>
|
||||
{hasVision && (
|
||||
<span className="flex items-center gap-0.5 text-[9px] font-medium text-indigo-700 dark:text-indigo-300">
|
||||
<span className="flex items-center gap-0.5 text-[0.5625rem] 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-[9px] font-sans font-medium text-green-600/90 dark:text-green-400/80">
|
||||
<span className="ml-1.5 text-[0.5625rem] font-sans font-medium text-green-600/90 dark:text-green-400/80">
|
||||
downloaded
|
||||
</span>
|
||||
{v.update_available ? (
|
||||
<span className="ml-1.5 text-[9px] font-sans font-medium text-amber-700 dark:text-amber-300">
|
||||
<span className="ml-1.5 text-[0.5625rem] font-sans font-medium text-amber-700 dark:text-amber-300">
|
||||
update available
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
) : v.quant === effectiveRecommended ? (
|
||||
<span className="ml-1.5 text-[9px] font-sans font-medium text-primary/70">
|
||||
<span className="ml-1.5 text-[0.5625rem] 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-[9px] 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-[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">
|
||||
OOM
|
||||
</span>
|
||||
)}
|
||||
{tight && (
|
||||
<span className="text-[9px] font-medium !text-amber-400">
|
||||
<span className="text-[0.5625rem] font-medium !text-amber-400">
|
||||
TIGHT
|
||||
</span>
|
||||
)}
|
||||
<span className="text-[10px] text-muted-foreground">
|
||||
<span className="text-[0.625rem] 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-[10px] text-muted-foreground break-all">
|
||||
<span className="block mt-1 text-[0.625rem] 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-[13px] text-muted-foreground/90">
|
||||
<span className="inline-flex min-w-0 max-w-[45%] shrink items-baseline text-[0.8125rem] 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-[10px] 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-[0.625rem] 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-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<div className="flex items-center gap-2 px-2.5 py-1.5 text-[0.625rem] 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-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<span className="flex items-center gap-1.5 text-[0.625rem] 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-[10px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground"
|
||||
className="flex items-center gap-1.5 text-[0.625rem] 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-[10px] text-muted-foreground/70"
|
||||
className="min-w-0 flex-1 truncate font-mono text-[0.625rem] 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-[10px] 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-[0.625rem] text-muted-foreground/70 transition-colors hover:border-foreground/30 hover:bg-accent hover:text-foreground disabled:opacity-40"
|
||||
>
|
||||
<span className="text-[11px] font-semibold">
|
||||
<span className="text-[0.6875rem] 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-[10px] 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-[0.625rem] 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-[10px] 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-[0.625rem] text-muted-foreground transition-colors hover:bg-accent disabled:opacity-40"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
{folderError && (
|
||||
<p className="px-0.5 pt-0.5 text-[10px] text-destructive">
|
||||
<p className="px-0.5 pt-0.5 text-[0.625rem] 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-[13px] 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-[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))]"
|
||||
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-[10px] text-muted-foreground break-all">
|
||||
<span className="block mt-1 text-[0.625rem] 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-[11px]" : "h-9 px-3 text-[12.5px]",
|
||||
compact ? "h-7 px-2.5 text-[0.6875rem]" : "h-9 px-3 text-[0.78125rem]",
|
||||
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-[34rem] 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-[544px] 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(16rem,28vw,22rem)] max-w-[calc(100vw-1rem)] -translate-x-1/2 transition-all duration-200 ease-out",
|
||||
"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",
|
||||
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-[11px] leading-4 text-muted-foreground">
|
||||
<div className="mt-0.5 truncate text-[0.6875rem] 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-[9px] 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-[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">
|
||||
OOM
|
||||
</span>
|
||||
)}
|
||||
{fitStatus === "tight" && (
|
||||
<span className="text-[9px] font-medium !text-amber-400">
|
||||
<span className="text-[0.5625rem] 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-[10px]"
|
||||
className="absolute top-2 right-2 text-[0.625rem]"
|
||||
>
|
||||
Coming Soon
|
||||
</Badge>
|
||||
|
|
|
|||
|
|
@ -17,14 +17,16 @@ export function WizardSidebar({ returnTo }: { returnTo: string }) {
|
|||
return (
|
||||
<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. */}
|
||||
<img
|
||||
src={`${import.meta.env.BASE_URL}sticker.png`}
|
||||
alt="Unsloth"
|
||||
className="size-12"
|
||||
className="size-[calc(40px+0.5rem)]"
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-semibold text-lg leading-tight">Unsloth</span>
|
||||
<span className="text-xs text-muted-foreground">Studio</span>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 md:mt-0">
|
||||
|
|
|
|||
|
|
@ -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-[13px] font-medium transition-colors",
|
||||
"inline-flex h-8 items-center rounded-full px-4 text-[0.8125rem] 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-[11px] font-medium">
|
||||
<span className="text-[0.6875rem] font-medium">
|
||||
{t("settings.profile.noneLabel")}
|
||||
</span>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ function PdfPreview({
|
|||
);
|
||||
}
|
||||
|
||||
// Resizable preview width (px). Default matches the prior fixed 44rem; drag the
|
||||
// Resizable preview width (px). Default matches the prior fixed 704px; 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-[16rem]",
|
||||
"rounded-full inline-flex items-center gap-1.5 max-w-[256px]",
|
||||
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-[15px] font-semibold text-foreground">
|
||||
<p className="text-[0.9375rem] 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-[11px] text-muted-foreground">Or drop files here</p>
|
||||
<p className="text-[0.6875rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
{label}
|
||||
</span>
|
||||
<span className="text-[13px] tabular-nums text-muted-foreground">
|
||||
<span className="text-[0.8125rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="text-[0.8125rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="text-[0.8125rem] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
Passages (top K)
|
||||
</span>
|
||||
<span className="text-[13px] tabular-nums text-muted-foreground">
|
||||
<span className="text-[0.8125rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="flex items-center gap-1.5 text-[0.8125rem] 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-[12px] leading-[1.3] text-muted-foreground">
|
||||
<span className="text-[0.75rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="flex items-center gap-1.5 text-[0.8125rem] 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-[12px] leading-[1.3] text-muted-foreground">
|
||||
<span className="text-[0.75rem] 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-[13px] font-medium leading-[1.25] tracking-nav text-nav-fg">
|
||||
<span className="flex items-center gap-1.5 text-[0.8125rem] 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-[12px] leading-[1.3] text-muted-foreground">
|
||||
<span className="text-[0.75rem] 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-[10px]">
|
||||
<Badge variant="outline" className="rounded-full text-[0.625rem]">
|
||||
{badge}
|
||||
</Badge>
|
||||
) : null}
|
||||
</div>
|
||||
<p className="break-words text-[11px] text-muted-foreground">
|
||||
<p className="break-words text-[0.6875rem] text-muted-foreground">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export function ExecutionSidebar({
|
|||
</p>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={cn("capitalize text-[11px]", statusTone(execution.status))}
|
||||
className={cn("capitalize text-[0.6875rem]", statusTone(execution.status))}
|
||||
>
|
||||
{formatStatus(execution.status)}
|
||||
</Badge>
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ export function ExecutionsView({
|
|||
const value = formatCellValue(rawValue);
|
||||
const isWide = wideColumns.has(name);
|
||||
return (
|
||||
<div className={cn(isWide ? "min-w-[48rem]" : "min-w-[12rem]")}>
|
||||
<div className={cn(isWide ? "min-w-[768px]" : "min-w-[192px]")}>
|
||||
<p className="whitespace-pre-wrap break-all">{value}</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