Studio: restyle export source selector (#6562)

This commit is contained in:
Wasim Yousef Said 2026-06-22 12:52:11 +02:00 committed by GitHub
commit 6001000a79
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 81 additions and 51 deletions

View file

@ -66,25 +66,38 @@ export const tabsListVariants = cva(
export function TabsList({
className,
variant = "default",
unstyled = false,
...props
}: React.ComponentProps<typeof TabsPrimitive.List> &
VariantProps<typeof tabsListVariants>): React.ReactElement {
VariantProps<typeof tabsListVariants> & {
unstyled?: boolean;
}): React.ReactElement {
return (
<TabsPrimitive.List
data-slot="tabs-list"
data-variant={variant}
className={cn(tabsListVariants({ variant }), className)}
className={cn(
unstyled
? "group/tabs-list text-muted-foreground inline-flex items-center justify-center group-data-[orientation=vertical]/tabs:flex-col"
: tabsListVariants({ variant }),
className,
)}
{...props}
/>
);
}
type TabsTriggerProps = React.ComponentProps<typeof TabsPrimitive.Trigger> & {
indicatorClassName?: string;
};
export function TabsTrigger({
className,
indicatorClassName,
value,
children,
...props
}: React.ComponentProps<typeof TabsPrimitive.Trigger>): React.ReactElement {
}: TabsTriggerProps): React.ReactElement {
const ctx = React.useContext(TabsContext);
const isActive = ctx.value === value;
@ -106,7 +119,11 @@ export function TabsTrigger({
{isActive && (
<motion.span
layoutId={`tab-bg-${ctx.id}`}
className="absolute inset-0 rounded-xl bg-background dark:bg-input/30 dark:border dark:border-input group-data-[variant=line]/tabs-list:bg-[#ececec] dark:group-data-[variant=line]/tabs-list:bg-[#2d2f33] dark:group-data-[variant=line]/tabs-list:border-0"
className={cn(
"absolute inset-0",
indicatorClassName ??
"rounded-xl bg-background dark:bg-input/30 dark:border dark:border-input group-data-[variant=line]/tabs-list:bg-[#ececec] dark:group-data-[variant=line]/tabs-list:bg-[#2d2f33] dark:group-data-[variant=line]/tabs-list:border-0",
)}
transition={{
type: "spring",
stiffness: 500,

View file

@ -26,6 +26,7 @@ import {
} from "@/components/ui/select";
import { Separator } from "@/components/ui/separator";
import { Spinner } from "@/components/ui/spinner";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
Tooltip,
TooltipContent,
@ -76,6 +77,8 @@ import { exportTourSteps } from "./tour";
const SEARCH_INPUT_REASONS = new Set(["input-change", "input-paste", "input-clear"]);
type SourceTab = "local" | "checkpoint" | "hf";
function buildRelativeSaveDirectory(
exportMethod: ExportMethod | null,
sourceBaseModelName: string,
@ -351,6 +354,8 @@ export function ExportPage() {
: GUIDE_STEPS,
[sourceMode],
);
const sourceTab: SourceTab =
sourceMode === "checkpoint" ? "checkpoint" : modelSource;
// Reset checkpoint when the selected model changes
useEffect(() => {
@ -368,18 +373,22 @@ export function ExportPage() {
}
}, [isAdapter, isQuantized, exportMethod]);
const handleSourceModeSwitch = useCallback(
(next: "checkpoint" | "model") => {
setSourceMode(next);
if (next === "model") {
setExportMethod("gguf");
}
setSelectedSourceModel(null);
setLocalModelInput("");
setModelInput("");
},
[],
);
const handleSourceTabChange = useCallback((next: string) => {
if (next === "checkpoint") {
setSourceMode("checkpoint");
} else if (next === "hf" || next === "local") {
setSourceMode("model");
setModelSource(next);
setExportMethod("gguf");
} else {
return;
}
setSelectedSourceModel(null);
setLocalModelInput("");
setModelInput("");
hfModelInputRef.current = "";
localModelInputRef.current = "";
}, []);
useEffect(() => {
setSelectedSourceModel(null);
@ -676,10 +685,10 @@ export function ExportPage() {
<>
{/* Top row: Dropdowns + metadata | Guide */}
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 md:gap-8">
<div className="flex flex-col gap-2">
<div className="flex items-end justify-between">
<div className="flex flex-col gap-3">
<div className="flex flex-col gap-2">
<label className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground">
{sourceMode === "checkpoint" ? "Training Run" : "Model Source"}
Source
<Tooltip>
<TooltipTrigger asChild={true}>
<button
@ -693,30 +702,51 @@ export function ExportPage() {
</button>
</TooltipTrigger>
<TooltipContent>
{sourceMode === "checkpoint"
? "Select the training run that produced the checkpoints you want to export."
: "Select a Hugging Face model or local model path to export directly to GGUF."}
Choose a local model, fine-tuned checkpoint, or
Hugging Face model to export.
</TooltipContent>
</Tooltip>
</label>
<button
type="button"
onClick={() =>
handleSourceModeSwitch(
sourceMode === "checkpoint" ? "model" : "checkpoint",
)
}
className="text-xs text-primary underline cursor-pointer leading-none"
<Tabs
value={sourceTab}
onValueChange={handleSourceTabChange}
className="w-full"
>
{sourceMode === "checkpoint"
? "Use Hugging Face / Local Model"
: "Use Training Checkpoints"}
</button>
<TabsList
unstyled={true}
className="hub-menu-trigger hub-tab-toggle relative inline-flex h-9 w-full items-center rounded-full"
>
<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"
>
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"
>
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"
>
Hugging Face
</TabsTrigger>
</TabsList>
</Tabs>
</div>
{sourceMode === "checkpoint" ? (
<div className="flex flex-col gap-2 overflow-visible">
<div data-tour="export-training-run" className="flex flex-col gap-2">
<label className="text-xs font-medium text-muted-foreground">
Training Run
</label>
<Select
value={selectedModelIdx ?? ""}
onValueChange={setSelectedModelIdx}
@ -830,23 +860,6 @@ export function ExportPage() {
</div>
) : (
<div className="flex flex-col gap-2 overflow-visible">
<div className="flex gap-2">
<Button
variant={modelSource === "hf" ? "dark" : "outline"}
className="flex-1"
onClick={() => setModelSource("hf")}
>
Hugging Face
</Button>
<Button
variant={modelSource === "local" ? "dark" : "outline"}
className="flex-1"
onClick={() => setModelSource("local")}
>
Local Model
</Button>
</div>
{modelSource === "hf" ? (
<>
<div className="flex flex-col gap-2">