Studio: loading spinner consolidation and sidebar hover pill polish (#6334)
* Studio: use the shared spinner for loading toasts The loading toast used a different spinner from the model download toast, so 'Unloading model' and 'Downloading model' looked inconsistent. Switch the sonner loading icon to the app-wide Spinner so they match. * Studio: consolidate loading spinners onto the shared Spinner Replace the duplicate ToolCallSpinner and the remaining inline loading spinners (hugeicons Loading03, lucide Loader2/Loader/LoaderCircle, and the hand-rolled border rings) with the shared Spinner component, then delete tool-call-spinner.tsx. Refresh and regenerate action icons and the shimmer button are left alone since they are not loading spinners. * Studio: align and even out sidebar hover pills The Recents chat rows started further left than the nav items above them and the hover pill widths varied. Give every nav and chat group the same pl-1.5 pr-2 so the pills line up and share one width, and on hover the chat rows only reserve room for the kebab so the title keeps one more character. * Studio: address review feedback on spinner and sidebar polish - recipe-graph-node: restore rounded-full bg-background on the spinner wrapper so it keeps masking the grid lines behind the floating spinner (the original hand-rolled ring had this mask). - app-sidebar: revert the pinned-row open-state padding to pr-8 so the unpin button stays clear of the title when the kebab menu is open. - app-sidebar: correct the now-stale inset comment (pl-1.5 = 6px, 18px).
This commit is contained in:
parent
5b0986fe30
commit
4ed40cb074
17 changed files with 53 additions and 93 deletions
|
|
@ -668,15 +668,17 @@ export function AppSidebar() {
|
|||
: "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",
|
||||
// pl-3 (12px) plus the content's pl-1 (4px) lines the title up with the
|
||||
// Recents label text at 16px.
|
||||
// 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",
|
||||
variant === "project"
|
||||
? "group-hover/project-chat-item:pr-8 group-has-[.sidebar-row-action[data-state=open]]/project-chat-item:pr-8"
|
||||
? "group-hover/project-chat-item:pr-6 group-has-[.sidebar-row-action[data-state=open]]/project-chat-item:pr-6"
|
||||
: isPinned
|
||||
? // Pinned rows show an extra unpin button on hover, so reserve more room.
|
||||
? // Pinned rows show an extra unpin button on hover, so reserve more room
|
||||
// (pr-8 when the menu is open keeps the unpin button clear of the title).
|
||||
"group-hover/recent-item:pr-16 group-has-[.sidebar-row-action[data-state=open]]/recent-item:pr-8"
|
||||
: "group-hover/recent-item:pr-8 group-has-[.sidebar-row-action[data-state=open]]/recent-item:pr-8",
|
||||
: // Hover room for the kebab only; title keeps one more character.
|
||||
"group-hover/recent-item:pr-6 group-has-[.sidebar-row-action[data-state=open]]/recent-item:pr-6",
|
||||
);
|
||||
|
||||
const isRenamingThis =
|
||||
|
|
@ -962,7 +964,8 @@ export function AppSidebar() {
|
|||
)}
|
||||
</SidebarHeader>
|
||||
|
||||
<SidebarGroup className="group-data-[collapsible=icon]:px-0 px-1.5 pt-[9px] pb-px shrink-0">
|
||||
{/* Uniform pl-1.5 pr-2 keeps every hover pill the same width, inset from the edge. */}
|
||||
<SidebarGroup className="group-data-[collapsible=icon]:px-0 pl-1.5 pr-2 pt-[9px] pb-px shrink-0">
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
<NavItem
|
||||
|
|
@ -1002,7 +1005,7 @@ export function AppSidebar() {
|
|||
scrolled && "is-scrolled",
|
||||
)}
|
||||
>
|
||||
<SidebarGroup className="group-data-[collapsible=icon]:px-0 px-1.5 py-0 shrink-0">
|
||||
<SidebarGroup className="group-data-[collapsible=icon]:px-0 pl-1.5 pr-2 py-0 shrink-0">
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
<NavItem
|
||||
|
|
@ -1074,7 +1077,7 @@ export function AppSidebar() {
|
|||
</CollapsibleTrigger>
|
||||
</SidebarGroupLabel>
|
||||
<CollapsibleContent>
|
||||
<SidebarGroupContent className="px-1.5">
|
||||
<SidebarGroupContent className="pl-1.5 pr-2">
|
||||
<SidebarMenu>
|
||||
<NavItem
|
||||
icon={TestTubeOutlineIcon}
|
||||
|
|
@ -1124,7 +1127,7 @@ export function AppSidebar() {
|
|||
</CollapsibleTrigger>
|
||||
</SidebarGroupLabel>
|
||||
<CollapsibleContent>
|
||||
<SidebarGroupContent className="pl-1 pr-1.5">
|
||||
<SidebarGroupContent className="pl-1.5 pr-2">
|
||||
<SidebarMenu>
|
||||
{pinnedChatItems.map((item) =>
|
||||
renderChatSidebarItem(item, "recent"),
|
||||
|
|
@ -1146,7 +1149,7 @@ export function AppSidebar() {
|
|||
</CollapsibleTrigger>
|
||||
</SidebarGroupLabel>
|
||||
<CollapsibleContent>
|
||||
<SidebarGroupContent className="pl-1 pr-1.5">
|
||||
<SidebarGroupContent className="pl-1.5 pr-2">
|
||||
<SidebarMenu>
|
||||
{recentChatItems.map((item) =>
|
||||
renderChatSidebarItem(item, "recent"),
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ import {
|
|||
CopyIcon,
|
||||
ImageIcon,
|
||||
ImageOffIcon,
|
||||
Loader2Icon,
|
||||
RefreshCwIcon,
|
||||
ShieldAlertIcon,
|
||||
} from "lucide-react";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Download01Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import {
|
||||
|
|
@ -348,7 +348,7 @@ function ImageGenerating({ className }: { className?: string }) {
|
|||
className,
|
||||
)}
|
||||
>
|
||||
<Loader2Icon className="size-8 animate-spin text-muted-foreground" />
|
||||
<Spinner className="size-8 text-muted-foreground" />
|
||||
<span className="sr-only">Generating image…</span>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
"use client";
|
||||
|
||||
import { Loader2Icon } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/** Spinner shown while a tool call runs. Inherits text color to match its surroundings. */
|
||||
export function ToolCallSpinner({ className }: { className?: string }) {
|
||||
return (
|
||||
<Loader2Icon
|
||||
aria-label="Loading"
|
||||
className={cn("size-4 shrink-0 animate-spin", className)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ import {
|
|||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import { ToolCallSpinner } from "@/components/assistant-ui/tool-call-spinner";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { useCollapseScrollLock } from "@/hooks/use-collapse-scroll-lock";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
|
|
@ -142,7 +142,7 @@ function ToolFallbackTrigger({
|
|||
{...props}
|
||||
>
|
||||
{isRunning ? (
|
||||
<ToolCallSpinner className="aui-tool-fallback-trigger-icon" />
|
||||
<Spinner className="aui-tool-fallback-trigger-icon" />
|
||||
) : ToolIcon ? (
|
||||
<ToolIcon
|
||||
data-slot="tool-fallback-trigger-icon"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import {
|
|||
} from "@/components/ui/collapsible";
|
||||
import { useCollapseScrollLock } from "@/hooks/use-collapse-scroll-lock";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ToolCallSpinner } from "@/components/assistant-ui/tool-call-spinner";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
|
||||
const ANIMATION_DURATION = 200;
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ function ToolGroupTrigger({
|
|||
{...props}
|
||||
>
|
||||
{active ? (
|
||||
<ToolCallSpinner className="aui-tool-group-trigger-loader" />
|
||||
<Spinner className="aui-tool-group-trigger-loader" />
|
||||
) : (
|
||||
<HugeiconsIcon
|
||||
icon={Wrench01Icon}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import {
|
|||
FileTextIcon,
|
||||
TerminalIcon,
|
||||
} from "lucide-react";
|
||||
import { ToolCallSpinner } from "@/components/assistant-ui/tool-call-spinner";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
ToolFallbackContent,
|
||||
|
|
@ -181,7 +181,7 @@ const CodeExecutionToolUIImpl: ToolCallMessagePartComponent = ({
|
|||
<ToolFallbackContent>
|
||||
{isRunning ? (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<ToolCallSpinner className="size-3.5" />
|
||||
<Spinner className="size-3.5" />
|
||||
<span>{runningLabel}</span>
|
||||
</div>
|
||||
) : resultText ? (
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ import {
|
|||
type ToolCallMessagePartComponent,
|
||||
useAuiState,
|
||||
} from "@assistant-ui/react";
|
||||
import { FileTextIcon, LibraryBigIcon, LoaderIcon } from "lucide-react";
|
||||
import { FileTextIcon, LibraryBigIcon } from "lucide-react";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { memo, useEffect, useMemo, useState } from "react";
|
||||
import { Badge } from "./badge";
|
||||
import {
|
||||
|
|
@ -106,7 +107,7 @@ const KnowledgeBaseToolUIImpl: ToolCallMessagePartComponent = ({
|
|||
<ToolFallbackContent>
|
||||
{isRunning ? (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<LoaderIcon className="size-3.5 animate-spin" />
|
||||
<Spinner className="size-3.5" />
|
||||
<span>
|
||||
{query ? (
|
||||
<>Searching documents for “{query}”…</>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { getAuthToken } from "@/features/auth/session";
|
|||
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
||||
import { code as codePlugin } from "@streamdown/code";
|
||||
import { CheckIcon, CodeIcon, CopyIcon } from "lucide-react";
|
||||
import { ToolCallSpinner } from "@/components/assistant-ui/tool-call-spinner";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Streamdown } from "streamdown";
|
||||
import {
|
||||
|
|
@ -149,7 +149,7 @@ const PythonToolUIImpl: ToolCallMessagePartComponent = ({
|
|||
{/* Output */}
|
||||
{isRunning ? (
|
||||
<div className="mt-2 flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<ToolCallSpinner className="size-3.5" />
|
||||
<Spinner className="size-3.5" />
|
||||
<span>Running…</span>
|
||||
</div>
|
||||
) : output ? (
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import { copyToClipboard } from "@/lib/copy-to-clipboard";
|
||||
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
||||
import { CheckIcon, CopyIcon, TerminalIcon } from "lucide-react";
|
||||
import { ToolCallSpinner } from "@/components/assistant-ui/tool-call-spinner";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
ToolFallbackContent,
|
||||
|
|
@ -87,7 +87,7 @@ const TerminalToolUIImpl: ToolCallMessagePartComponent = ({
|
|||
<div className="border-l-2 border-muted-foreground/20 pl-2">
|
||||
{isRunning ? (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<ToolCallSpinner className="size-3.5" />
|
||||
<Spinner className="size-3.5" />
|
||||
<span>Running…</span>
|
||||
</div>
|
||||
) : output ? (
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
import { ShimmerButton } from "@/components/ui/shimmer-button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import type { BackendStatus } from "@/hooks/use-tauri-backend";
|
||||
import type { CopySupportDiagnosticsResult } from "@/lib/tauri-diagnostics";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
|
|
@ -98,15 +99,6 @@ const EASE_OUT_QUART: [number, number, number, number] = [0.165, 0.84, 0.44, 1];
|
|||
// Sub-components
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function TealSpinner({ size = 24 }: { size?: number }) {
|
||||
return (
|
||||
<span
|
||||
className="inline-block animate-spin rounded-full border-2 border-primary border-t-transparent"
|
||||
style={{ width: size, height: size, animationDuration: "0.8s" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Logo() {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
|
|
@ -148,7 +140,7 @@ function CheckingContent() {
|
|||
<Logo />
|
||||
</div>
|
||||
<div className="mb-10 flex flex-col items-center gap-2">
|
||||
<TealSpinner />
|
||||
<Spinner className="size-6 text-primary" />
|
||||
<p className="text-sm text-muted-foreground">Checking...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -194,7 +186,7 @@ function InstallingContent({
|
|||
<Logo />
|
||||
</div>
|
||||
<div className="mb-10 flex flex-col items-center gap-2">
|
||||
<TealSpinner />
|
||||
<Spinner className="size-6 text-primary" />
|
||||
<p className="text-sm font-bold text-foreground">Installing...</p>
|
||||
<p className="text-sm font-bold text-muted-foreground">
|
||||
Please wait a few mins, then you can start training.
|
||||
|
|
@ -227,7 +219,7 @@ function RepairingContent({
|
|||
<Logo />
|
||||
</div>
|
||||
<div className="mb-10 flex flex-col items-center gap-2">
|
||||
<TealSpinner />
|
||||
<Spinner className="size-6 text-primary" />
|
||||
<p className="text-sm font-bold text-foreground">Updating existing Unsloth install...</p>
|
||||
{latest && (
|
||||
<p className="max-w-xs text-center text-xs text-muted-foreground">{latest}</p>
|
||||
|
|
@ -325,7 +317,7 @@ function StartingContent() {
|
|||
<Logo />
|
||||
</div>
|
||||
<div className="mb-10 flex flex-col items-center gap-2">
|
||||
<TealSpinner />
|
||||
<Spinner className="size-6 text-primary" />
|
||||
<p className="text-sm text-muted-foreground">Starting server...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import type { UpdateStatus } from "@/hooks/use-tauri-update";
|
||||
import type { CopySupportDiagnosticsResult } from "@/lib/tauri-diagnostics";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
interface UpdateScreenProps {
|
||||
|
|
@ -18,15 +19,6 @@ interface UpdateScreenProps {
|
|||
|
||||
const EASE_OUT_QUART: [number, number, number, number] = [0.165, 0.84, 0.44, 1];
|
||||
|
||||
function Spinner({ size = 24 }: { size?: number }) {
|
||||
return (
|
||||
<span
|
||||
className="inline-block animate-spin rounded-full border-2 border-primary border-t-transparent"
|
||||
style={{ width: size, height: size, animationDuration: "0.8s" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Logo() {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
|
|
@ -135,7 +127,7 @@ export function UpdateScreen({
|
|||
<Logo />
|
||||
|
||||
<div className="mt-8 flex flex-col items-center gap-2">
|
||||
{!isError && <Spinner />}
|
||||
{!isError && <Spinner className="size-6 text-primary" />}
|
||||
<p className="text-sm font-semibold text-foreground">
|
||||
{statusLabel(status)}
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import {
|
|||
Alert02Icon,
|
||||
CheckmarkCircle02Icon,
|
||||
InformationCircleIcon,
|
||||
Loading03Icon,
|
||||
MultiplicationSignCircleIcon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { useTheme } from "next-themes";
|
||||
import { Toaster as Sonner, type ToasterProps } from "sonner";
|
||||
|
||||
|
|
@ -51,13 +51,8 @@ const Toaster = ({ ...props }: ToasterProps) => {
|
|||
className="size-4"
|
||||
/>
|
||||
),
|
||||
loading: (
|
||||
<HugeiconsIcon
|
||||
icon={Loading03Icon}
|
||||
strokeWidth={2}
|
||||
className="size-4 animate-spin"
|
||||
/>
|
||||
),
|
||||
// App-wide arc spinner so loading toasts match the "Downloading model" toast.
|
||||
loading: <Spinner className="size-4 text-muted-foreground" />,
|
||||
}}
|
||||
style={
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import {
|
|||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
FileTextIcon,
|
||||
LoaderIcon,
|
||||
ZoomInIcon,
|
||||
ZoomOutIcon,
|
||||
} from "lucide-react";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
|
||||
import {
|
||||
Sheet,
|
||||
|
|
@ -209,7 +209,7 @@ function PdfPreview({
|
|||
onLoadError={(e) => setError(e.message)}
|
||||
loading={
|
||||
<div className="flex items-center gap-2 p-6 text-sm text-muted-foreground">
|
||||
<LoaderIcon className="size-3.5 animate-spin" /> Loading PDF…
|
||||
<Spinner className="size-3.5" /> Loading PDF…
|
||||
</div>
|
||||
}
|
||||
>
|
||||
|
|
@ -444,7 +444,7 @@ export function DocumentPreviewSheet() {
|
|||
<div className="min-h-0 flex-1">
|
||||
{loading ? (
|
||||
<div className="flex items-center gap-2 p-6 text-sm text-muted-foreground">
|
||||
<LoaderIcon className="size-3.5 animate-spin" /> Resolving source…
|
||||
<Spinner className="size-3.5" /> Resolving source…
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="p-6 text-sm text-muted-foreground">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
import { LoaderCircleIcon, XIcon } from "lucide-react";
|
||||
import { XIcon } from "lucide-react";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { File02Icon } from "@hugeicons/core-free-icons";
|
||||
import { Badge } from "@/components/assistant-ui/badge";
|
||||
|
|
@ -40,11 +41,7 @@ export function DocumentStatusChip({
|
|||
<span className="truncate">{filename}</span>
|
||||
{/* spinner while indexing, else close button */}
|
||||
{processing ? (
|
||||
<LoaderCircleIcon
|
||||
className="shrink-0 animate-spin size-3.5 text-muted-foreground"
|
||||
role="status"
|
||||
aria-label="Loading"
|
||||
/>
|
||||
<Spinner className="shrink-0 size-3.5 text-muted-foreground" />
|
||||
) : onRemove ? (
|
||||
<button
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import { MarkdownPreview } from "@/components/markdown/markdown-preview";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
BalanceScaleIcon,
|
||||
|
|
@ -473,11 +474,9 @@ function RecipeGraphNodeBase({
|
|||
)}
|
||||
>
|
||||
{runtimeState === "running" && config?.kind === "llm" && (
|
||||
<div className="pointer-events-none absolute -top-7 right-2 z-20">
|
||||
<span
|
||||
className="block size-6 animate-spin rounded-full border-[3px] border-primary/90 border-t-transparent bg-background"
|
||||
aria-label="Running"
|
||||
/>
|
||||
// rounded-full bg-background masks grid lines behind the floating spinner
|
||||
<div className="pointer-events-none absolute -top-7 right-2 z-20 rounded-full bg-background">
|
||||
<Spinner className="size-6 text-primary/90" />
|
||||
</div>
|
||||
)}
|
||||
<NodeResizer
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|||
import {
|
||||
CloudUploadIcon,
|
||||
Cancel01Icon,
|
||||
Loading03Icon,
|
||||
CheckmarkCircle02Icon,
|
||||
Alert02Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { uploadUnstructuredFile, removeUnstructuredFile } from "../../api";
|
||||
import {
|
||||
|
|
@ -226,10 +226,7 @@ export function UnstructuredDropZone({
|
|||
className="flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm"
|
||||
>
|
||||
{entry.status === "uploading" && (
|
||||
<HugeiconsIcon
|
||||
icon={Loading03Icon}
|
||||
className="text-muted-foreground size-4 animate-spin"
|
||||
/>
|
||||
<Spinner className="text-muted-foreground size-4" />
|
||||
)}
|
||||
{entry.status === "ok" && (
|
||||
<HugeiconsIcon
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ import type { CheckFormatResponse } from "@/features/training/types/datasets";
|
|||
import { cn } from "@/lib/utils";
|
||||
import { AlertCircleIcon, CheckmarkCircle02Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { Loader2, Sparkles } from "lucide-react";
|
||||
import { Sparkles } from "lucide-react";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
|
||||
const CHATML_ROLES = ["system", "user", "assistant"] as const;
|
||||
const ALPACA_ROLES = ["instruction", "input", "output"] as const;
|
||||
|
|
@ -203,7 +204,7 @@ export function DatasetMappingCard({
|
|||
>
|
||||
{isAiLoading ? (
|
||||
<>
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
|
||||
<Spinner className="mr-1.5 size-3.5" />
|
||||
Analyzing dataset...
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue