Fix Train tab example cards and Create/Train tab layout
The example-dataset cards used a two-column grid in the ~340px config column, which wrapped titles one word per line and let the long license text overrun into the neighbouring card. Switch to one card per row with a horizontal layout: title with a compact truncated license badge (full text in the tooltip), a two-line clamped description, and the Import button on the right. The Create/Train switch had an icon inside the Train trigger that overhung the pill corner. Drop the icon, make both triggers a fixed equal width so the active pill sits flush in the top bar.
This commit is contained in:
parent
56b08cc15b
commit
7cd7c588f2
2 changed files with 61 additions and 41 deletions
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
||||
import {
|
||||
AiMagicIcon,
|
||||
ArrowLeftRightIcon,
|
||||
ArrowReloadHorizontalIcon,
|
||||
Delete02Icon,
|
||||
|
|
@ -465,34 +464,41 @@ function Field({
|
|||
function AdvancedSelect({
|
||||
label,
|
||||
hint,
|
||||
desc,
|
||||
value,
|
||||
onValueChange,
|
||||
options,
|
||||
}: {
|
||||
label: string;
|
||||
hint?: ReactNode;
|
||||
// A short always-visible description under the row (the hint tooltip carries the full
|
||||
// detail). Used for controls whose label alone does not convey what they do.
|
||||
desc?: string;
|
||||
value: string;
|
||||
onValueChange: (v: string) => void;
|
||||
options: Array<[string, string]>;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="flex items-center gap-1 text-xs font-medium text-muted-foreground">
|
||||
{label}
|
||||
{hint && <InfoHint>{hint}</InfoHint>}
|
||||
</span>
|
||||
<Select value={value} onValueChange={onValueChange}>
|
||||
<SelectTrigger className="h-8 w-[160px] text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{options.map(([v, l]) => (
|
||||
<SelectItem key={v} value={v} className="text-xs">
|
||||
{l}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="flex items-center gap-1 text-xs font-medium text-muted-foreground">
|
||||
{label}
|
||||
{hint && <InfoHint>{hint}</InfoHint>}
|
||||
</span>
|
||||
<Select value={value} onValueChange={onValueChange}>
|
||||
<SelectTrigger className="h-8 w-[160px] text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{options.map(([v, l]) => (
|
||||
<SelectItem key={v} value={v} className="text-xs">
|
||||
{l}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
{desc && <p className="text-[11px] leading-snug text-muted-foreground/70">{desc}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1865,7 +1871,8 @@ export function ImagesPage({ active = true }: { active?: boolean }) {
|
|||
to GGUF (or nothing loaded) and otherwise show why it is unavailable. */}
|
||||
{!status?.loaded || status.model_kind === "gguf" ? (
|
||||
<AdvancedSelect
|
||||
label="GGUF speed mode"
|
||||
label="GGUF compute"
|
||||
desc="Off runs the GGUF as-is. INT8/FP8/FP4 dequantise the transformer onto low-precision tensor cores for a faster step, at the cost of a larger download and more VRAM."
|
||||
hint="Optional speed-up for GGUF models. Off runs the GGUF as-is. FP8/INT8/FP4 instead load the FULL base model and quantise its transformer onto low-precision tensor cores: faster per step, but a larger download and more VRAM, and it falls back to the GGUF if it can't fit. Needs CUDA."
|
||||
value={transformerQuant}
|
||||
onValueChange={(v) => setTransformerQuant(v as typeof transformerQuant)}
|
||||
|
|
@ -1879,9 +1886,11 @@ export function ImagesPage({ active = true }: { active?: boolean }) {
|
|||
]}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex items-center justify-between gap-2 text-xs">
|
||||
<span className="text-muted-foreground">GGUF speed mode</span>
|
||||
<span className="text-muted-foreground/70">GGUF models only</span>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="flex items-center gap-1 text-xs font-medium text-muted-foreground">
|
||||
GGUF compute
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground/60">GGUF models only</span>
|
||||
</div>
|
||||
)}
|
||||
<AdvancedSelect
|
||||
|
|
@ -1964,9 +1973,10 @@ export function ImagesPage({ active = true }: { active?: boolean }) {
|
|||
generation workspace; Train is the full-page LoRA training workspace. */}
|
||||
<Tabs value={pageMode} onValueChange={(v) => setPageMode(v as "create" | "train")}>
|
||||
<TabsList className="h-[34px]">
|
||||
<TabsTrigger value="create">Create</TabsTrigger>
|
||||
<TabsTrigger value="train">
|
||||
<HugeiconsIcon icon={AiMagicIcon} className="mr-1 size-3.5" />
|
||||
<TabsTrigger value="create" className="w-[64px]">
|
||||
Create
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="train" className="w-[64px]">
|
||||
Train
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
|
|
|||
|
|
@ -14,9 +14,13 @@ import {
|
|||
listDiffusionDatasetExamples,
|
||||
} from "../api";
|
||||
|
||||
// One-click example-dataset importers. Each card shows the license verbatim so users see
|
||||
// the terms before importing. On success the parent refreshes its dataset list and selects
|
||||
// the imported folder (and can seed the trigger prompt from suggested_trigger).
|
||||
// One-click example-dataset importers. Each card shows the license so users see the terms
|
||||
// before importing. On success the parent refreshes its dataset list and selects the
|
||||
// imported folder (and can seed the trigger prompt from suggested_trigger).
|
||||
//
|
||||
// Layout: one card per row (the config column is only ~340px, so a two-column grid wrapped
|
||||
// titles one word per line and let the long license text overrun into the next card). The
|
||||
// license is a compact truncated badge with the full text in its title tooltip.
|
||||
export function ExampleDatasetCards({
|
||||
onImported,
|
||||
}: {
|
||||
|
|
@ -66,29 +70,35 @@ export function ExampleDatasetCards({
|
|||
|
||||
return (
|
||||
<div className="grid gap-2">
|
||||
<span className="text-[11px] text-muted-foreground">
|
||||
Or start from an example dataset:
|
||||
<span className="text-[11px] font-medium text-muted-foreground">
|
||||
Or start from an example dataset
|
||||
</span>
|
||||
<div className="grid gap-2 sm:grid-cols-2">
|
||||
<div className="grid gap-2">
|
||||
{examples.map((ex) => (
|
||||
<div
|
||||
key={ex.id}
|
||||
className="flex flex-col gap-1.5 rounded-lg border border-border p-2.5"
|
||||
className="flex items-center gap-3 rounded-lg border border-border p-2.5"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<span className="text-xs font-medium">{ex.label}</span>
|
||||
<Badge variant="secondary" className="shrink-0 text-[10px]">
|
||||
{ex.license}
|
||||
</Badge>
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<span className="truncate text-xs font-medium">{ex.label}</span>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="max-w-[120px] shrink-0 truncate text-[10px] font-normal"
|
||||
title={ex.license}
|
||||
>
|
||||
{ex.license}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="line-clamp-2 text-[11px] leading-snug text-muted-foreground">
|
||||
{ex.description}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-[11px] leading-snug text-muted-foreground">
|
||||
{ex.description}
|
||||
</p>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
className="h-7 w-fit text-xs"
|
||||
className="h-7 shrink-0 self-center px-3 text-xs"
|
||||
onClick={() => void doImport(ex)}
|
||||
disabled={busyId !== null}
|
||||
>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue