Compare commits
2 commits
main
...
studio-con
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc6991b635 |
||
|
|
7aa065b363 |
15 changed files with 35 additions and 74 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -474,10 +475,7 @@ 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"
|
||||
/>
|
||||
<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