Studio: restyle export source selector (#6562)
This commit is contained in:
parent
f10e47fc51
commit
6001000a79
2 changed files with 81 additions and 51 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue