From 29131cc85ed89784d89d3bb3c5d5b1f14fbf6182 Mon Sep 17 00:00:00 2001 From: Unsloth Date: Wed, 29 Jul 2026 00:47:41 -0700 Subject: [PATCH] Studio: size Agents and System to their pane, restore palette focus - The GPU row's breakpoint could never fire. The settings pane is about 664px at any window size, and the name, three figures, meter and percentage need more than that, so the one-row layout was dead code. Each device is now two compact lines: name with the percentage, then the figures with a fixed-width meter. The name stays readable, the meter no longer runs the width of the pane, and there is no breakpoint that cannot be reached. - The agent, model and quantization grid switched on the viewport, so between 768px and 1024px it went to three columns inside a 440px pane and crushed every control. It now keys on the pane and stacks until the columns genuinely fit. - Dark mode dropped the palette card's resting border, but that border is the only focus indicator since the card removes its outline, and an unlayered rule beats Tailwind's layered focus-visible utility. Keyboard focus paints the ring colour again. --- .../src/features/settings/tabs/agents-tab.tsx | 445 +++++++++--------- .../features/settings/tabs/resources-tab.tsx | 66 ++- studio/frontend/src/index.css | 7 + 3 files changed, 265 insertions(+), 253 deletions(-) diff --git a/studio/frontend/src/features/settings/tabs/agents-tab.tsx b/studio/frontend/src/features/settings/tabs/agents-tab.tsx index d810048a86..c4c464d62a 100644 --- a/studio/frontend/src/features/settings/tabs/agents-tab.tsx +++ b/studio/frontend/src/features/settings/tabs/agents-tab.tsx @@ -1113,233 +1113,240 @@ export function AgentsTab() { aria-label={t("settings.agents.commandBuilder")} className="flex w-full flex-col gap-6" > -
-
-
+ {/* Keyed to this pane, not the viewport. The dialog leaves the tab + about 440px at a 768px window, where three columns crush the agent + and model controls; 34rem is the point all three stay usable. */} +
+
+
+
+ + {t("settings.agents.agent")} + + + {t("settings.agents.docs")} + + +
+ +
+ + - { + chosenVariant.current = { model: selectedModel, variant }; + setSelectedVariant(variant); + resetCopied(); + }} + disabled={variantsLoading || variants.length === 0} + > + + + {selectedVariant} + + + + {variants.map((variant) => { + // Size only: the recommended/downloaded tags wrapped every + // row onto two lines and made the list hard to scan. + const size = formatBytes( + variant.download_size_bytes ?? variant.size_bytes, + ); + return ( + + + {variant.quant} + + {size ? ( + + {size} ) : null} - - - ); - })} - - -
- -
- - {t("settings.agents.model")} - - { - setModelPickerOpen(open); - if (!open) { - setModelSearch(""); - } - }} - > - - - - - - - - {t("settings.agents.noModels")} - {visibleModels.map((model) => ( - { - modelSelectionChanged.current = true; - setSelectedModel(model); - setSelectedVariant(knownVariants[model] ?? null); - setVariants([]); - setVariantsFailed(false); - setVariantsLoading(isHuggingFaceRepo(model)); - setModelSearch(""); - setModelPickerOpen(false); - resetCopied(); - }} - className="cursor-pointer font-mono text-xs" - > - - {labelFor(model)} - - - ))} - - {matchingModels.length > visibleModels.length ? ( -

- {t("settings.agents.showingModels", { - shown: visibleModels.length, - total: matchingModels.length, - })} -

- ) : null} -
-
-
-
- -
- - {t("settings.agents.quantization")} - - + + ); + })} + + +
diff --git a/studio/frontend/src/features/settings/tabs/resources-tab.tsx b/studio/frontend/src/features/settings/tabs/resources-tab.tsx index 8ac51f3e38..7725aaa0ad 100644 --- a/studio/frontend/src/features/settings/tabs/resources-tab.tsx +++ b/studio/frontend/src/features/settings/tabs/resources-tab.tsx @@ -456,9 +456,7 @@ export function ResourcesTab() {
)} - {/* Sized against this pane, not the viewport: the Settings dialog caps - the tab at roughly 650px however wide the window is. */} -
+
{hasGpu ? ( metrics.devices.map((device, index) => { const ordinal = deviceOrdinal(device); @@ -490,29 +488,37 @@ export function ResourcesTab() { ? formatPercent(safePercent) : unknownLabel; return ( - // One row per device: a full-width bar under a single GPU read - // as a page-wide rule, so the bar is sized to the row instead. + // Two compact lines per device. The settings pane is about + // 664px at any window size, which cannot hold the name, three + // figures, meter and percentage on one row, so no breakpoint + // would ever fire. Splitting them keeps the name readable and + // the meter narrow instead of running the width of the pane.
-
-
- {device.name ?? t("settings.resources.gpu.unknownDevice")} +
+
+
+ {device.name ?? + t("settings.resources.gpu.unknownDevice")} +
+
+ {ordinal === undefined + ? backendLabel + : `${t("settings.resources.gpu.deviceWithIndex", { + index: ordinal, + })}, ${backendLabel}`} +
-
- {ordinal === undefined - ? backendLabel - : `${t("settings.resources.gpu.deviceWithIndex", { - index: ordinal, - })}, ${backendLabel}`} +
+ {percentText}{" "} + {t("settings.resources.gpu.vramUtilization")}
- {/* Stacked until the pane is genuinely wide enough: the - figures, meter and percentage need about 50rem before the - name has room left to read. */} -
-
+ {/* Wraps rather than overflows once the pane gets narrow. */} +
+
{t("settings.resources.gpu.used", { value: usedText })} @@ -525,20 +531,12 @@ export function ResourcesTab() { })}
-
- {/* Fills the space left by the percentage rather than - claiming the full row, which overflowed once stacked. */} - -
- {percentText}{" "} - {t("settings.resources.gpu.vramUtilization")} -
-
+
); diff --git a/studio/frontend/src/index.css b/studio/frontend/src/index.css index 34897c08bc..e298dbbe8c 100644 --- a/studio/frontend/src/index.css +++ b/studio/frontend/src/index.css @@ -671,6 +671,13 @@ html[data-chat-font] .aui-root { border-color: transparent; } +/* The card removes its outline, so the border is the only focus indicator. + This rule is unlayered like the one above, which would otherwise beat + Tailwind's layered focus-visible:border-ring and leave nothing visible. */ +.dark .palette-card:focus-visible { + border-color: var(--ring); +} + .palette-card:hover { border-color: var(--ring-soft); }