From fa5498db0b6c089c1c9ddc8e82043d82be202bc6 Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:44:42 -0700 Subject: [PATCH] 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 --- studio/frontend/src/app/provider.tsx | 8 +- .../frontend/src/components/app-sidebar.tsx | 34 ++-- .../components/assistant-ui/audio-player.tsx | 2 +- .../message-response-details-sheet.tsx | 4 +- .../assistant-ui/message-timing.tsx | 2 +- .../src/components/assistant-ui/reasoning.tsx | 2 +- .../src/components/assistant-ui/sources.tsx | 2 +- .../src/components/assistant-ui/thread.tsx | 30 +-- .../assistant-ui/tool-ui-knowledge-base.tsx | 2 +- .../assistant-ui/tool-ui-render-html.tsx | 2 +- .../src/components/floating-monitor.tsx | 6 +- .../src/components/llama-update-banner.tsx | 8 +- .../frontend/src/components/section-card.tsx | 2 +- .../src/components/tauri/startup-screen.tsx | 2 +- .../src/components/tauri/update-banner.tsx | 16 +- .../src/components/tauri/update-screen.tsx | 4 +- .../src/components/tauri/window-titlebar.tsx | 8 +- studio/frontend/src/components/ui/chart.tsx | 2 +- .../src/components/ui/copyable-error-chip.tsx | 6 +- .../frontend/src/components/ui/data-table.tsx | 2 +- studio/frontend/src/components/ui/dialog.tsx | 2 +- .../src/components/ui/dropdown-menu.tsx | 17 +- .../src/components/ui/input-group.tsx | 4 +- studio/frontend/src/components/ui/select.tsx | 12 +- studio/frontend/src/components/ui/sidebar.tsx | 8 +- .../src/components/web/update-banner.tsx | 8 +- .../frontend/src/features/auth/login-page.tsx | 2 +- .../features/chat/artifacts/artifact-card.tsx | 4 +- .../frontend/src/features/chat/chat-page.tsx | 38 ++-- .../features/chat/chat-providers-dialog.tsx | 8 +- .../src/features/chat/chat-settings-sheet.tsx | 68 +++---- .../chat/components/chat-search-dialog.tsx | 6 +- .../chat/components/context-usage-bar.tsx | 4 +- .../chat/components/model-load-status.tsx | 12 +- .../components/openai-code-exec-section.tsx | 14 +- .../chat/components/project-switcher.tsx | 2 +- .../chat/hooks/use-chat-model-runtime.ts | 2 +- .../features/chat/permission-mode-select.tsx | 2 +- .../src/features/chat/projects-page.tsx | 16 +- .../prompt-storage/prompt-storage-dialog.tsx | 10 +- .../src/features/chat/thread-sidebar.tsx | 2 +- .../data-recipes/pages/data-recipes-page.tsx | 8 +- .../export/components/export-run-panel.tsx | 24 +-- .../export/components/method-picker.tsx | 2 +- .../export/components/quant-picker.tsx | 10 +- .../src/features/export/export-page.tsx | 36 ++-- .../features/hub/catalog/catalog-states.tsx | 32 ++-- .../hub/catalog/dataset-download-section.tsx | 2 +- .../src/features/hub/catalog/dot-tag.tsx | 2 +- .../features/hub/catalog/download-card.tsx | 2 +- .../catalog/external-link-confirm-dialog.tsx | 4 +- .../hub/catalog/gguf-download-card.tsx | 10 +- .../hub/catalog/gguf-status-cards.tsx | 4 +- .../features/hub/catalog/hub-detail-view.tsx | 2 +- .../features/hub/catalog/hub-option-menu.tsx | 4 +- .../features/hub/catalog/hub-section-row.tsx | 2 +- .../hub/catalog/local-dataset-card.tsx | 2 +- .../hub/catalog/local-on-device-card.tsx | 20 +- .../src/features/hub/catalog/model-card.tsx | 6 +- .../features/hub/catalog/model-inspector.tsx | 36 ++-- .../src/features/hub/catalog/model-readme.tsx | 20 +- .../hub/catalog/models-catalog-lists.tsx | 12 +- .../hub/catalog/models-catalog-rows.tsx | 30 +-- .../features/hub/catalog/models-header.tsx | 4 +- .../src/features/hub/catalog/models-table.tsx | 46 ++--- .../features/hub/catalog/models-toolbar.tsx | 10 +- .../hub/catalog/on-device-folders-dialog.tsx | 24 +-- .../src/features/hub/catalog/owner-avatar.tsx | 8 +- .../hub/catalog/owner-scope-toggle.tsx | 2 +- .../features/hub/catalog/recent-searches.tsx | 6 +- .../hub/catalog/safetensors-download-card.tsx | 2 +- .../hub/catalog/sampling-settings-dialog.tsx | 10 +- .../src/features/hub/catalog/shared.tsx | 4 +- .../hub/catalog/transport-conflict-dialog.tsx | 2 +- .../features/hub/catalog/transport-toggle.tsx | 2 +- .../hub/components/hf-token-indicator.tsx | 6 +- .../features/hub/components/page-heading.tsx | 4 +- .../download-manager-panel.tsx | 8 +- .../download-progress-bar.tsx | 2 +- studio/frontend/src/features/hub/hub-page.tsx | 2 +- studio/frontend/src/features/hub/hub.css | 78 ++++---- .../chat-template-editor-dialog.tsx | 4 +- .../components/model-config-page.tsx | 24 +-- .../components/model-selector.tsx | 14 +- .../model-selector/folder-browser.tsx | 10 +- .../components/model-selector/pickers.tsx | 62 +++---- .../components/model-selector/pill-tabs.tsx | 2 +- .../components/native-model-chip.tsx | 2 +- .../components/native-model-drop-overlay.tsx | 4 +- .../components/steps/model-selection-step.tsx | 4 +- .../components/steps/model-type-step.tsx | 2 +- .../onboarding/components/wizard-sidebar.tsx | 8 +- .../profile-personalization-panel.tsx | 4 +- .../rag/components/document-preview-sheet.tsx | 2 +- .../rag/components/document-status-chip.tsx | 2 +- .../rag/components/project-sources-panel.tsx | 4 +- .../components/retrieval-settings-section.tsx | 22 +-- .../recipe-studio/components/block-sheet.tsx | 4 +- .../executions/execution-sidebar.tsx | 2 +- .../components/executions/executions-view.tsx | 2 +- .../inline/inline-category-badges.tsx | 6 +- .../components/inline/inline-field.tsx | 2 +- .../components/inline/inline-llm.tsx | 2 +- .../components/inline/inline-seed.tsx | 6 +- .../components/recipe-graph-node.tsx | 4 +- .../components/recipe-studio-header.tsx | 10 +- .../runtime/execution-progress-island.tsx | 16 +- .../shared/available-references-inline.tsx | 14 +- .../models/local-recipe-model-selector.tsx | 20 +- .../recipe-studio/dialogs/preview-dialog.tsx | 2 +- .../dialogs/seed/seed-dialog.tsx | 2 +- .../tool-profile/tool-profile-dialog.tsx | 6 +- .../easy/github-crawler-easy-view.tsx | 2 +- .../recipe-studio/recipe-studio-page.tsx | 2 +- .../features/recipe-studio/utils/ui-tones.ts | 6 +- .../components/remote-code-consent-dialog.tsx | 8 +- .../settings/components/api-key-row.tsx | 4 +- .../components/api-monitor-console.tsx | 10 +- .../settings/components/color-picker.tsx | 2 +- .../settings/components/create-key-form.tsx | 2 +- .../components/embedding-model-combobox.tsx | 4 +- .../settings/components/key-reveal-card.tsx | 2 +- .../settings/components/language-select.tsx | 2 +- .../components/sidebar-menu-customizer.tsx | 4 +- .../components/update-studio-instructions.tsx | 4 +- .../components/uploaded-files-dialog.tsx | 6 +- .../settings/components/usage-examples.tsx | 34 ++-- .../src/features/settings/settings-dialog.tsx | 14 +- .../features/settings/tabs/resources-tab.tsx | 4 +- .../src/features/settings/tabs/voice-tab.tsx | 12 +- .../src/features/studio/history-card-grid.tsx | 12 +- .../studio/recent-trainings-section.tsx | 2 +- .../sections/charts/chart-settings-sheet.tsx | 2 +- .../sections/charts/eval-loss-chart-card.tsx | 8 +- .../sections/charts/grad-norm-chart-card.tsx | 4 +- .../charts/learning-rate-chart-card.tsx | 4 +- .../charts/training-loss-chart-card.tsx | 6 +- .../dataset-preview-dialog-mapping.tsx | 14 +- .../sections/dataset-preview-dialog.tsx | 20 +- .../studio/sections/dataset-section.tsx | 14 +- .../studio/sections/model-section.tsx | 16 +- .../studio/sections/params-section.tsx | 16 +- .../studio/sections/progress-section.tsx | 22 +-- .../studio/sections/s3-config-form.tsx | 2 +- .../studio/sections/training-section.tsx | 4 +- .../src/features/studio/studio-page.tsx | 2 +- .../studio/training-start-overlay.tsx | 8 +- .../features/tour/components/guided-tour.tsx | 8 +- studio/frontend/src/index.css | 171 ++++++++++++------ .../test_chat_thinking_compact_layout.py | 2 +- .../studio/test_compact_dropdown_submenus.py | 2 +- .../test_studio_text_descender_clipping.py | 2 +- .../test_voice_settings_select_width.py | 16 ++ 153 files changed, 860 insertions(+), 762 deletions(-) create mode 100644 tests/studio/test_voice_settings_select_width.py diff --git a/studio/frontend/src/app/provider.tsx b/studio/frontend/src/app/provider.tsx index e6c89b9cd7..275c3c6623 100644 --- a/studio/frontend/src/app/provider.tsx +++ b/studio/frontend/src/app/provider.tsx @@ -213,7 +213,7 @@ function TauriUpdateLayer({ } return ( -
+
+
- {label} + {label} {spinner && ( )} @@ -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. */} Unsloth - + unsloth - + {t("shell.beta")} @@ -1219,7 +1221,7 @@ export function AppSidebar() { hidden={isMobile} > {t("shell.navigation.search")} - + {isMacPlatform ? "⌘K" : "Ctrl+K"} @@ -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" > - {project.name} + {project.name} {/* New chat in this project */}
@@ -1830,11 +1832,11 @@ export function AppSidebar() { />
- + {t("shell.updateAvailable")} {updateVersion && ( - + v{updateVersion} )} @@ -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 */}
- {displayTitle} - Unsloth + {displayTitle} + Unsloth
@@ -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" > = ({ src }) => { onChange={handleSeek} className="h-1.5 w-full cursor-pointer accent-primary" /> -
+
{formatTime(progress)} {formatTime(duration)}
diff --git a/studio/frontend/src/components/assistant-ui/message-response-details-sheet.tsx b/studio/frontend/src/components/assistant-ui/message-response-details-sheet.tsx index cca61b766a..5dd4f1c91d 100644 --- a/studio/frontend/src/components/assistant-ui/message-response-details-sheet.tsx +++ b/studio/frontend/src/components/assistant-ui/message-response-details-sheet.tsx @@ -207,7 +207,7 @@ function DetailRow({ }) { if (value == null || value === "") return null; return ( -
+
{label} diff --git a/studio/frontend/src/components/assistant-ui/message-timing.tsx b/studio/frontend/src/components/assistant-ui/message-timing.tsx index 8d40f587ad..c602a776cf 100644 --- a/studio/frontend/src/components/assistant-ui/message-timing.tsx +++ b/studio/frontend/src/components/assistant-ui/message-timing.tsx @@ -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, )} > diff --git a/studio/frontend/src/components/assistant-ui/reasoning.tsx b/studio/frontend/src/components/assistant-ui/reasoning.tsx index 9788c73605..d869cc93ef 100644 --- a/studio/frontend/src/components/assistant-ui/reasoning.tsx +++ b/studio/frontend/src/components/assistant-ui/reasoning.tsx @@ -163,7 +163,7 @@ function ReasoningContent({

Generated image

{overlay.metadata ? ( -

+

{overlay.metadata}

) : null} @@ -1390,7 +1390,7 @@ const ComposerAnimated: FC<{ disableQueue?: boolean; }> = ({ disabled, threadId, menuSide, disableQueue }) => { return ( -
+
= ({
) : ( -
+
@@ -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)} > @@ -3565,14 +3565,14 @@ const DiffusionCanvas: FC = () => { canvas.total > 0 ? `step ${canvas.step + 1}/${canvas.total}` : "denoising"; return (
-
+
Denoising block {canvas.block + 1} - {stepLabel}
-
+      
         {canvas.text}
       
@@ -3646,7 +3646,7 @@ const AssistantMessage: FC = () => { return (
@@ -3676,7 +3676,7 @@ const AssistantMessage: FC = () => { ) : ( <>
- +
@@ -3759,7 +3759,7 @@ const ForkCountBadge: FC = () => { if (count <= 0) return null; return ( @@ -4084,7 +4084,7 @@ const UserMessageAudio: FC = () => { const UserMessage: FC = () => { return ( @@ -4195,7 +4195,7 @@ const BranchPicker: FC = ({ = ({ - + / diff --git a/studio/frontend/src/components/assistant-ui/tool-ui-knowledge-base.tsx b/studio/frontend/src/components/assistant-ui/tool-ui-knowledge-base.tsx index ec24060072..4fbaa227bd 100644 --- a/studio/frontend/src/components/assistant-ui/tool-ui-knowledge-base.tsx +++ b/studio/frontend/src/components/assistant-ui/tool-ui-knowledge-base.tsx @@ -48,7 +48,7 @@ export function CitationBadge({ - + {errorText ?? (isStaleGeneratingArtifact ? "Refresh stopped this preview" diff --git a/studio/frontend/src/components/floating-monitor.tsx b/studio/frontend/src/components/floating-monitor.tsx index e38e2e5882..fb1ead3e63 100644 --- a/studio/frontend/src/components/floating-monitor.tsx +++ b/studio/frontend/src/components/floating-monitor.tsx @@ -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" >
@@ -139,7 +139,7 @@ export function FloatingMonitor() { className="space-y-3 overflow-hidden" >
-
+
{t("settings.resources.liveMonitor.ram")} -
+
{t("settings.resources.liveMonitor.vram")}{" "} {devices.length > 1 diff --git a/studio/frontend/src/components/llama-update-banner.tsx b/studio/frontend/src/components/llama-update-banner.tsx index 3db15ffe30..25c413ad61 100644 --- a/studio/frontend/src/components/llama-update-banner.tsx +++ b/studio/frontend/src/components/llama-update-banner.tsx @@ -131,7 +131,7 @@ export function LlamaUpdateBanner({

-

+

{sizeLabel ? `${sizeLabel} download · ` : ""}No restart needed after update

@@ -209,7 +209,7 @@ export function LlamaUpdateBanner({
diff --git a/studio/frontend/src/components/tauri/update-screen.tsx b/studio/frontend/src/components/tauri/update-screen.tsx index 3199425f69..64f2e95a87 100644 --- a/studio/frontend/src/components/tauri/update-screen.tsx +++ b/studio/frontend/src/components/tauri/update-screen.tsx @@ -72,7 +72,7 @@ function LogViewer({ logs }: { logs: string[] }) { return (
{logs.map((line, i) => (
@@ -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" /> )} diff --git a/studio/frontend/src/components/tauri/window-titlebar.tsx b/studio/frontend/src/components/tauri/window-titlebar.tsx index d5c74df463..66cc2e1b41 100644 --- a/studio/frontend/src/components/tauri/window-titlebar.tsx +++ b/studio/frontend/src/components/tauri/window-titlebar.tsx @@ -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" /> - + Unsloth Studio
@@ -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} diff --git a/studio/frontend/src/components/ui/chart.tsx b/studio/frontend/src/components/ui/chart.tsx index 32da410bb5..25dc88d1cd 100644 --- a/studio/frontend/src/components/ui/chart.tsx +++ b/studio/frontend/src/components/ui/chart.tsx @@ -246,7 +246,7 @@ function ChartTooltipContent({ return (
diff --git a/studio/frontend/src/components/ui/copyable-error-chip.tsx b/studio/frontend/src/components/ui/copyable-error-chip.tsx index 595df5cf62..6f21b6d829 100644 --- a/studio/frontend/src/components/ui/copyable-error-chip.tsx +++ b/studio/frontend/src/components/ui/copyable-error-chip.tsx @@ -53,7 +53,7 @@ export function CopyableErrorChip({
diff --git a/studio/frontend/src/features/chat/artifacts/artifact-card.tsx b/studio/frontend/src/features/chat/artifacts/artifact-card.tsx index 0345dc6e2a..82a236a387 100644 --- a/studio/frontend/src/features/chat/artifacts/artifact-card.tsx +++ b/studio/frontend/src/features/chat/artifacts/artifact-card.tsx @@ -145,12 +145,12 @@ export function ArtifactCard({ {isCode ? "HTML Code" : artifact.title} - + HTML canvas {isStreaming && !isCode ? ( - + Generating ) : null} diff --git a/studio/frontend/src/features/chat/chat-page.tsx b/studio/frontend/src/features/chat/chat-page.tsx index e59ce3a805..3daae8c50d 100644 --- a/studio/frontend/src/features/chat/chat-page.tsx +++ b/studio/frontend/src/features/chat/chat-page.tsx @@ -576,7 +576,7 @@ function CompareShell({ {children}
-
{composer}
+
{composer}
{showModelDisclaimer && (

LLMs can make mistakes. Double-check responses. @@ -651,7 +651,7 @@ const LoraCompareContent = memo(function LoraCompareContent({ handleName="base" header={

- + Base Model
@@ -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={ -
- +
+ Fine-tuned
@@ -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)))]", )} > {/* Slightly narrower than the composer max; every block shares this. */} -
+
-

+

{projectName}

@@ -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 @@ -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 @@ -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" />
@@ -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" >
-
+
{displayTitle}
- + {preview?.date ?? formatProjectChatDate(item.createdAt)} @@ -3105,14 +3105,14 @@ export function ChatPage({ )}
@@ -3141,7 +3141,7 @@ export function ChatPage({ /> )} {incognito && view.mode === "single" && ( -
+

When off, all connections are disabled.

@@ -1616,7 +1616,7 @@ export function ChatProvidersSettings({ {provider.name} - + {provider.models.length}{" "} {provider.models.length === 1 ? "model" : "models"} @@ -1631,7 +1631,7 @@ export function ChatProvidersSettings({ ) : null}
{modelSummary} @@ -1702,7 +1702,7 @@ export function ChatProvidersDialog({ Connections diff --git a/studio/frontend/src/features/chat/chat-settings-sheet.tsx b/studio/frontend/src/features/chat/chat-settings-sheet.tsx index d4f154882c..99d697f619 100644 --- a/studio/frontend/src/features/chat/chat-settings-sheet.tsx +++ b/studio/frontend/src/features/chat/chat-settings-sheet.tsx @@ -141,7 +141,7 @@ export function ParamSlider({
- + {label} {info && {info}} @@ -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. */}
{isMobile ? ( - + Run settings ) : ( <> - + Run settings @@ -740,7 +740,7 @@ export function ChatSettingsPanel({
{modelConfig} {showSpecFallback && ( -
+

{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 && (

-

+

Use this for longer edits. Save writes back to the active configuration only. Insert variables with {"{{ env }}"}.

@@ -1230,16 +1230,16 @@ export function ChatSettingsPanel({
-
+
Prompt variables
-

+

Define values as JSON below, then use each key in your prompt, like {"{{ env }}"}.

- + Built-in, fill in automatically
@@ -1247,7 +1247,7 @@ export function ChatSettingsPanel({ {token} @@ -1272,11 +1272,11 @@ export function ChatSettingsPanel({ aria-invalid={Boolean(systemVariablesError)} /> {systemVariablesError ? ( -

+

{systemVariablesError}

) : ( -

+

Names you don't define are left unchanged, so a stray {" {{ typo }} "}stays visible in the prompt.

@@ -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} />
@@ -1333,7 +1333,7 @@ export function ChatSettingsPanel({ if (isMobile) { return ( - + Run settings Chat inference settings @@ -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 (
- + Auto-Healing Tool Calls @@ -1450,7 +1450,7 @@ function NudgeToolCallsToggle() { return (
- + Nudge Tool Calls @@ -1475,7 +1475,7 @@ function ConfirmToolCallsToggle() {
- + Confirm tool calls @@ -1487,7 +1487,7 @@ function ConfirmToolCallsToggle() {
{permissionMode === "full" ? ( - + Overridden by Full access ) : null} @@ -1508,7 +1508,7 @@ function BypassPermissionsToggle() { return (
- + Tool permissions @@ -1517,9 +1517,9 @@ function BypassPermissionsToggle() {
{/* Full width, styled like the panel selects/preset input. */} - + {permissionMode === "full" ? ( - + Tool calls run with no confirmation and no sandbox. ) : null} diff --git a/studio/frontend/src/features/chat/components/chat-search-dialog.tsx b/studio/frontend/src/features/chat/components/chat-search-dialog.tsx index dc3e1aac29..ea95040f44 100644 --- a/studio/frontend/src/features/chat/components/chat-search-dialog.tsx +++ b/studio/frontend/src/features/chat/components/chat-search-dialog.tsx @@ -83,7 +83,7 @@ export function ChatSearchDialog() { @@ -143,10 +143,10 @@ export function ChatSearchDialog() { strokeWidth={2} className="size-4 shrink-0 text-muted-foreground" /> - + {item.title || "Untitled chat"} - + {formatRelative(item.createdAt)} diff --git a/studio/frontend/src/features/chat/components/context-usage-bar.tsx b/studio/frontend/src/features/chat/components/context-usage-bar.tsx index 80f502e222..eeacef66df 100644 --- a/studio/frontend/src/features/chat/components/context-usage-bar.tsx +++ b/studio/frontend/src/features/chat/components/context-usage-bar.tsx @@ -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<{
{hasKnownLimit && percent !== null && percent > 85 ? ( -
+
Close to the context limit. Generation will stop at 100%. Increase Context Length in the chat Settings panel to keep going. diff --git a/studio/frontend/src/features/chat/components/model-load-status.tsx b/studio/frontend/src/features/chat/components/model-load-status.tsx index 292c7884fd..613b5c260b 100644 --- a/studio/frontend/src/features/chat/components/model-load-status.tsx +++ b/studio/frontend/src/features/chat/components/model-load-status.tsx @@ -54,14 +54,14 @@ export function ModelLoadDescription({ {title ?

{title}

: null} {hasProgress ? (
-
+
{labelPrimary} {Math.round(clampProgress(progressPercent))}%
{labelSecondary ? ( -
+
{labelSecondary}
) : null} @@ -96,18 +96,18 @@ export function ModelLoadInlineStatus({ const hasProgress = typeof progressPercent === "number"; return ( -
+
{label}
{hasProgress ? (
-
+
{/* 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 diff --git a/studio/frontend/src/features/chat/components/openai-code-exec-section.tsx b/studio/frontend/src/features/chat/components/openai-code-exec-section.tsx index cb0234579b..04c88e4eba 100644 --- a/studio/frontend/src/features/chat/components/openai-code-exec-section.tsx +++ b/studio/frontend/src/features/chat/components/openai-code-exec-section.tsx @@ -435,7 +435,7 @@ export function OpenAICodeExecSection({
@@ -459,7 +459,7 @@ export function OpenAICodeExecSection({ ACTIVE pill marks which one (no separate picker). */}
- + Containers
diff --git a/studio/frontend/src/features/chat/components/project-switcher.tsx b/studio/frontend/src/features/chat/components/project-switcher.tsx index 8f923a8c80..2a170e5a39 100644 --- a/studio/frontend/src/features/chat/components/project-switcher.tsx +++ b/studio/frontend/src/features/chat/components/project-switcher.tsx @@ -57,7 +57,7 @@ export function ProjectSwitcher({ className="size-icon shrink-0 text-foreground/70" /> - + {label} diff --git a/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts b/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts index b72a7a95c2..4b3f57b368 100644 --- a/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts +++ b/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts @@ -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 = { diff --git a/studio/frontend/src/features/chat/permission-mode-select.tsx b/studio/frontend/src/features/chat/permission-mode-select.tsx index e6c89cf54a..7e0ecb0c7e 100644 --- a/studio/frontend/src/features/chat/permission-mode-select.tsx +++ b/studio/frontend/src/features/chat/permission-mode-select.tsx @@ -120,7 +120,7 @@ export function PermissionModeMenuItems({ > - {option.label} + {option.label} {option.description} diff --git a/studio/frontend/src/features/chat/projects-page.tsx b/studio/frontend/src/features/chat/projects-page.tsx index c9960ffaca..494368faec 100644 --- a/studio/frontend/src/features/chat/projects-page.tsx +++ b/studio/frontend/src/features/chat/projects-page.tsx @@ -367,7 +367,7 @@ export function ProjectsPage() { }} />
-

+

Projects

@@ -419,7 +419,7 @@ export function ProjectsPage() { Export All Projects - + Combined {EXPORT_FORMATS_LIST.map(({ fmt, label }) => ( @@ -430,7 +430,7 @@ export function ProjectsPage() { - + Per chat {EXPORT_FORMATS_LIST.map(({ fmt, label }) => ( @@ -445,7 +445,7 @@ export function ProjectsPage() { Export Projects + Recents - + Combined {EXPORT_FORMATS_LIST.map(({ fmt, label }) => ( @@ -456,7 +456,7 @@ export function ProjectsPage() { - + Per chat {EXPORT_FORMATS_LIST.map(({ fmt, label }) => ( @@ -482,7 +482,7 @@ export function ProjectsPage() { {!hasLoaded ? (
-
+
Name Modified @@ -526,7 +526,7 @@ export function ProjectsPage() {
{/* Column header. Name starts at the folder icon's left edge; the right-anchored columns keep Modified over its values. */} -
+
Name Modified @@ -571,7 +571,7 @@ export function ProjectsPage() { className="size-5" /> - + {project.name} diff --git a/studio/frontend/src/features/chat/prompt-storage/prompt-storage-dialog.tsx b/studio/frontend/src/features/chat/prompt-storage/prompt-storage-dialog.tsx index 09c4944a14..4b815a7695 100644 --- a/studio/frontend/src/features/chat/prompt-storage/prompt-storage-dialog.tsx +++ b/studio/frontend/src/features/chat/prompt-storage/prompt-storage-dialog.tsx @@ -1341,7 +1341,7 @@ function ExportModal({ {/* */}
-

+

Export as

@@ -1390,7 +1390,7 @@ function ExportModal({

ShareGPT format for Unsloth fine-tuning

- + {`{"conversations":[{"from":"human","value":"..."},{"from":"gpt","value":""}]}`}
@@ -1400,7 +1400,7 @@ function ExportModal({ {/* */}
-

+

Format

@@ -1730,7 +1730,7 @@ function PromptListCard({
{entry.name} - + {entry.items.length}
@@ -1779,7 +1779,7 @@ function PromptListCard({

))} {entry.items.length > 3 && ( -

+

+{entry.items.length - 3} more

)} diff --git a/studio/frontend/src/features/chat/thread-sidebar.tsx b/studio/frontend/src/features/chat/thread-sidebar.tsx index f85c74eb86..4e2765bebd 100644 --- a/studio/frontend/src/features/chat/thread-sidebar.tsx +++ b/studio/frontend/src/features/chat/thread-sidebar.tsx @@ -266,7 +266,7 @@ export function ThreadSidebar({ > {item.isFork ? ( fork diff --git a/studio/frontend/src/features/data-recipes/pages/data-recipes-page.tsx b/studio/frontend/src/features/data-recipes/pages/data-recipes-page.tsx index 088d016894..27584a646f 100644 --- a/studio/frontend/src/features/data-recipes/pages/data-recipes-page.tsx +++ b/studio/frontend/src/features/data-recipes/pages/data-recipes-page.tsx @@ -280,7 +280,7 @@ function LearningRecipeCards({ {badge} @@ -288,7 +288,7 @@ function LearningRecipeCards({ {extraLearningBadgeCount > 0 ? ( +{extraLearningBadgeCount} @@ -296,7 +296,7 @@ function LearningRecipeCards({ {isReady ? null : ( Soon @@ -403,7 +403,7 @@ export function DataRecipesPage(): ReactElement {
-

+

Data Recipes

diff --git a/studio/frontend/src/features/export/components/export-run-panel.tsx b/studio/frontend/src/features/export/components/export-run-panel.tsx index 6c2794420b..86c82935d6 100644 --- a/studio/frontend/src/features/export/components/export-run-panel.tsx +++ b/studio/frontend/src/features/export/components/export-run-panel.tsx @@ -278,7 +278,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) {

onSaveDirectoryChange(e.target.value)} spellCheck={false} @@ -303,7 +303,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) { Browse
-

+

{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 @@ -369,7 +369,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) { onChange={(e) => onHfTokenChange(e.target.value)} /> -

+

Leave empty if already logged in via CLI.

@@ -427,7 +427,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) { ) : null} {o.path} @@ -503,11 +503,11 @@ export function ExportRunPanel(props: ExportRunPanelProps) { {showProgress && (
- + {PHASE_LABELS[run.phase] ?? run.phase} {summaryMethod === "gguf" && run.quantTotal > 1 && ( - + Quant{" "} {Math.min( run.quantIndex + (isExporting ? 1 : 0), @@ -516,10 +516,10 @@ export function ExportRunPanel(props: ExportRunPanelProps) { of {run.quantTotal} )} - + {progress}% - + {formatElapsed(elapsedSeconds)}
@@ -536,7 +536,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) { /> {run.stage && (

{run.stage} @@ -552,7 +552,7 @@ export function ExportRunPanel(props: ExportRunPanelProps) { -

+
{run.logLines.length === 0 ? (
diff --git a/studio/frontend/src/features/export/components/method-picker.tsx b/studio/frontend/src/features/export/components/method-picker.tsx index 420a7f6146..e240fd44ca 100644 --- a/studio/frontend/src/features/export/components/method-picker.tsx +++ b/studio/frontend/src/features/export/components/method-picker.tsx @@ -123,7 +123,7 @@ export function MethodPicker({ value, onChange, disabledMethods = [], disabledRe {m.badge && ( {m.badge} diff --git a/studio/frontend/src/features/export/components/quant-picker.tsx b/studio/frontend/src/features/export/components/quant-picker.tsx index 289f6498ce..688e5fb87f 100644 --- a/studio/frontend/src/features/export/components/quant-picker.tsx +++ b/studio/frontend/src/features/export/components/quant-picker.tsx @@ -61,7 +61,7 @@ export function QuantPicker({ value, onChange, sizes }: QuantPickerProps) { - + — select one or more
@@ -90,10 +90,10 @@ export function QuantPicker({ value, onChange, sizes }: QuantPickerProps) { )} {q.label} {sizeLabel && ( - {sizeLabel} + {sizeLabel} )} {q.recommended && !active && ( - + rec )} @@ -103,13 +103,13 @@ export function QuantPicker({ value, onChange, sizes }: QuantPickerProps) {
{value.length > 0 && (
- + {value.length} selected diff --git a/studio/frontend/src/features/export/export-page.tsx b/studio/frontend/src/features/export/export-page.tsx index 3a970713ac..80235846d1 100644 --- a/studio/frontend/src/features/export/export-page.tsx +++ b/studio/frontend/src/features/export/export-page.tsx @@ -895,7 +895,7 @@ export function ExportPage() {
-

+

Export Model

@@ -964,21 +964,21 @@ export function ExportPage() { Local Model Fine-tuned Hugging Face @@ -1289,7 +1289,7 @@ export function ExportPage() { {model?.display_name ?? id} - + {source} @@ -1300,15 +1300,15 @@ export function ExportPage() {

{isLoadingLocalModels ? ( -

+

Scanning local models...

) : localModelsError ? ( -

+

{localModelsError}

) : ( -

+

{exportableLocalModels.length > 0 ? `${exportableLocalModels.length} local/cached models found` : "No local models found. Enter path manually."} @@ -1318,7 +1318,7 @@ export function ExportPage() { )}

-

+

Direct model exports currently support GGUF only.

@@ -1327,7 +1327,7 @@ export function ExportPage() { {sourceMode === "checkpoint" && (
- + Training Info
@@ -1374,7 +1374,7 @@ export function ExportPage() { key={step} className="flex items-start gap-2 text-xs text-muted-foreground" > - + {i + 1} {step} @@ -1422,7 +1422,7 @@ export function ExportPage() {
Precision
- + — select one or more
@@ -1479,7 +1479,7 @@ export function ExportPage() { {f.label} {f.needsCalibration ? " *" : ""} - + {f.hint} @@ -1492,7 +1492,7 @@ export function ExportPage() { {selectedFormats.length > 0 && (
- + {selectedFormats.length} selected:{" "} {selectedFormats .map( @@ -1506,7 +1506,7 @@ export function ExportPage() { @@ -1515,7 +1515,7 @@ export function ExportPage() { )} {hubMultiFormat && ( -
+
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, ) && ( -
+
* calibrates on data (uses a small calibration set).
)} {!hasNvidia && ( -
+
No NVIDIA GPU detected: compressed-tensors formats are hidden. 16-bit and portable FP8/INT8 (torchao) still work here and load in vLLM. diff --git a/studio/frontend/src/features/hub/catalog/catalog-states.tsx b/studio/frontend/src/features/hub/catalog/catalog-states.tsx index a36c4bb2da..693b5b40c0 100644 --- a/studio/frontend/src/features/hub/catalog/catalog-states.tsx +++ b/studio/frontend/src/features/hub/catalog/catalog-states.tsx @@ -38,20 +38,20 @@ export function NetworkErrorState({
-

+

{title}

-

+

{body}

-

{message}

+

{message}

{onSwitchDevice ? ( @@ -59,7 +59,7 @@ export function NetworkErrorState({
-

+

No matches yet

-

+

Scanned {scannedCount.toLocaleString()} results. Load another page to keep searching Hugging Face.

@@ -105,7 +105,7 @@ export function DiscoverFetchMoreState({ @@ -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]" > {/* Only warn about hidden results when a filter is actually narrowing them. */} {hasActiveFilters && ( -

+

Some results may be hidden by your filters.

)} @@ -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]" >
-

+

Couldn't load your library

-

+

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({

-

+

{title}

-

+

{body}

diff --git a/studio/frontend/src/features/hub/catalog/dataset-download-section.tsx b/studio/frontend/src/features/hub/catalog/dataset-download-section.tsx index b821be4b0b..ade8d2de30 100644 --- a/studio/frontend/src/features/hub/catalog/dataset-download-section.tsx +++ b/studio/frontend/src/features/hub/catalog/dataset-download-section.tsx @@ -126,7 +126,7 @@ export function DatasetDownloadSection({ } >
- + {isDownloaded && } {!isDownloaded && isPartial && !downloading && ( diff --git a/studio/frontend/src/features/hub/catalog/dot-tag.tsx b/studio/frontend/src/features/hub/catalog/dot-tag.tsx index 9452a201d4..5ae1be53d0 100644 --- a/studio/frontend/src/features/hub/catalog/dot-tag.tsx +++ b/studio/frontend/src/features/hub/catalog/dot-tag.tsx @@ -36,7 +36,7 @@ export function DotTag({ return ( diff --git a/studio/frontend/src/features/hub/catalog/download-card.tsx b/studio/frontend/src/features/hub/catalog/download-card.tsx index 9b4bc5fd01..9bc64ced0e 100644 --- a/studio/frontend/src/features/hub/catalog/download-card.tsx +++ b/studio/frontend/src/features/hub/catalog/download-card.tsx @@ -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]" > {pendingUrl && (
-

+

{hostOf(pendingUrl)}

-

+

{pendingUrl}

diff --git a/studio/frontend/src/features/hub/catalog/gguf-download-card.tsx b/studio/frontend/src/features/hub/catalog/gguf-download-card.tsx index 0d6878b687..9345874a53 100644 --- a/studio/frontend/src/features/hub/catalog/gguf-download-card.tsx +++ b/studio/frontend/src/features/hub/catalog/gguf-download-card.tsx @@ -128,7 +128,7 @@ const FIT_BADGE: Record = { /** 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. @@ -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. */} - + {selected ? ( ) : ( - + Select quantization )} @@ -1126,7 +1126,7 @@ export function GgufDownloadCard({ diff --git a/studio/frontend/src/features/hub/catalog/gguf-status-cards.tsx b/studio/frontend/src/features/hub/catalog/gguf-status-cards.tsx index 6cc764b876..c7f402159b 100644 --- a/studio/frontend/src/features/hub/catalog/gguf-status-cards.tsx +++ b/studio/frontend/src/features/hub/catalog/gguf-status-cards.tsx @@ -34,7 +34,7 @@ export function GgufDownloadStatusCard({
@@ -91,7 +91,7 @@ export function GgufDownloadingFallbackCard({
- + {progress.variant && } Downloading… diff --git a/studio/frontend/src/features/hub/catalog/hub-detail-view.tsx b/studio/frontend/src/features/hub/catalog/hub-detail-view.tsx index d733049ec3..e7d176442a 100644 --- a/studio/frontend/src/features/hub/catalog/hub-detail-view.tsx +++ b/studio/frontend/src/features/hub/catalog/hub-detail-view.tsx @@ -69,7 +69,7 @@ export function HubDetailView({ ) : ( - + {content} )} @@ -325,11 +325,11 @@ function ModelStatusChips({ > This model may not be supported yet. {unslothSupport.reason && ( - + {unslothSupport.reason} )} - + Still downloadable to your Hugging Face cache. @@ -349,7 +349,7 @@ function ModelStatusChips({ > This device has no supported GPU or usable MLX, so only GGUF models can run here. - + Still downloadable to your Hugging Face cache. @@ -368,7 +368,7 @@ function ModelStatusChips({ className="tooltip-compact max-w-xs" > Estimated 4-bit memory load is around {vramInfo.est} GB. - + {vramDetail} @@ -502,10 +502,10 @@ export const ModelInspector = memo(function ModelInspector({
-

+

Select a {isDataset ? "dataset" : "model"}

-

+

{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) - + {formatCompact(model.downloadsAllTime)} all time @@ -582,11 +582,11 @@ export const ModelInspector = memo(function ModelInspector({

-

+

{model.title}

{model.hubRepoId && ( @@ -599,7 +599,7 @@ export const ModelInspector = memo(function ModelInspector({
)}
-
+
{model.owner} {model.owner.toLowerCase() === "unsloth" && ( {isDataset && ( - + Dataset )} {!isDataset && ( - + {selectionHiddenByFilters && ( -

+

Current selection is hidden by the active filters or search.

)} {metadataUnavailable && ( -

+

Couldn't load full details from Hugging Face. Some fields may be incomplete.

diff --git a/studio/frontend/src/features/hub/catalog/model-readme.tsx b/studio/frontend/src/features/hub/catalog/model-readme.tsx index 3d215473e2..42cc55372a 100644 --- a/studio/frontend/src/features/hub/catalog/model-readme.tsx +++ b/studio/frontend/src/features/hub/catalog/model-readme.tsx @@ -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" > -
+
{message ?? `Loading ${kind === "dataset" ? "dataset" : "model"} card…`}
@@ -540,7 +540,7 @@ export function ModelReadme({ ? current.error : readmeUnavailableMessage(subject); return ( -

+

{errorMessage}

); @@ -548,7 +548,7 @@ export function ModelReadme({ if (!current.body) { return ( -

+

{readmeMissingMessage(subject)}

); diff --git a/studio/frontend/src/features/hub/catalog/models-catalog-lists.tsx b/studio/frontend/src/features/hub/catalog/models-catalog-lists.tsx index 8cf5fc491e..926c002a65 100644 --- a/studio/frontend/src/features/hub/catalog/models-catalog-lists.tsx +++ b/studio/frontend/src/features/hub/catalog/models-catalog-lists.tsx @@ -68,7 +68,7 @@ export function InventoryWarningRow({ onRetry: () => void; }) { return ( -
+
Some on-device sources couldn't be scanned. Showing available{" "} @@ -76,7 +76,7 @@ export function InventoryWarningRow({ @@ -444,7 +444,7 @@ export function DownloadedList({ <> {pinnedItems.length > 0 && ( <> -
+
{unpinnedItems.length > 0 && ( -
+
All {isDataset ? "datasets" : "models"}
)} diff --git a/studio/frontend/src/features/hub/catalog/models-catalog-rows.tsx b/studio/frontend/src/features/hub/catalog/models-catalog-rows.tsx index 6d1dc20414..156bafba70 100644 --- a/studio/frontend/src/features/hub/catalog/models-catalog-rows.tsx +++ b/studio/frontend/src/features/hub/catalog/models-catalog-rows.tsx @@ -188,14 +188,14 @@ function CachedSizeChipLive({ ))} ) : ( - + {variantMessage} )} @@ -225,7 +225,7 @@ export function StatChip({ return ( @@ -482,7 +482,7 @@ export const DiscoverModelRow = memo(function DiscoverModelRow({
-

+

{row.repo}

-
+
{row.owner} {row.owner.toLowerCase() === "unsloth" && ( @@ -528,7 +528,7 @@ export const DiscoverModelRow = memo(function DiscoverModelRow({ /> )} - + {formatRelativeShort(row.result.updatedAt)}
@@ -666,7 +666,7 @@ export const InventoryRow = memo(function InventoryRow({ {paramLabel} )} {quantLabel && ( - + {quantLabel} )} @@ -716,7 +716,7 @@ export const InventoryRow = memo(function InventoryRow({ ) : null; const ownerLine = ( - + {subLabel} {subLabel.toLowerCase() === "unsloth" && (
- + {title} {compactMarkers}
- + {subLabel} {subLabel.toLowerCase() === "unsloth" && ( @@ -851,7 +851,7 @@ export const InventoryRow = memo(function InventoryRow({ )}
-
+
{row.kind === "cache" ? (
- + {title} {statusMarkers} @@ -915,11 +915,11 @@ export const InventoryRow = memo(function InventoryRow({ cachePath={row.cachePath} /> ) : trailing ? ( - + {trailing} ) : sourceLabel ? ( - + {sourceLabel} ) : null} diff --git a/studio/frontend/src/features/hub/catalog/models-header.tsx b/studio/frontend/src/features/hub/catalog/models-header.tsx index 9629fc0a10..1702ed6fca 100644 --- a/studio/frontend/src/features/hub/catalog/models-header.tsx +++ b/studio/frontend/src/features/hub/catalog/models-header.tsx @@ -91,7 +91,7 @@ export function ModelsHeader({ {activeCheckpoint && ( -
+