feat: replace Loader2 with Spinner component for consistent loading indicators

This commit is contained in:
Anish Sarkar 2026-01-25 15:23:45 +05:30
parent 9215118bab
commit 2d17d1a1b6
34 changed files with 113 additions and 105 deletions

View file

@ -1,10 +1,11 @@
"use client";
import { makeAssistantToolUI } from "@assistant-ui/react";
import { AlertCircleIcon, Loader2Icon, MicIcon } from "lucide-react";
import { AlertCircleIcon, MicIcon } from "lucide-react";
import { useCallback, useEffect, useRef, useState } from "react";
import { z } from "zod";
import { Audio } from "@/components/tool-ui/audio";
import { Spinner } from "@/components/ui/spinner";
import { baseApiService } from "@/lib/apis/base-api.service";
import { authenticatedFetch } from "@/lib/auth-utils";
import { clearActivePodcastTaskId, setActivePodcastTaskId } from "@/lib/chat/podcast-state";
@ -97,8 +98,8 @@ function PodcastGeneratingState({ title }: { title: string }) {
<div className="flex-1">
<h3 className="font-semibold text-foreground text-lg">{title}</h3>
<div className="mt-2 flex items-center gap-2 text-muted-foreground">
<Loader2Icon className="size-4 animate-spin" />
<span className="text-sm">Generating podcast. This may take a few minutes</span>
<Spinner size="sm" />
<span className="text-sm">Generating podcast. This may take a few minutes.</span>
</div>
<div className="mt-3">
<div className="h-1.5 w-full overflow-hidden rounded-full bg-primary/10">
@ -144,7 +145,7 @@ function AudioLoadingState({ title }: { title: string }) {
<div className="flex-1">
<h3 className="font-semibold text-foreground">{title}</h3>
<div className="mt-2 flex items-center gap-2 text-muted-foreground">
<Loader2Icon className="size-4 animate-spin" />
<Spinner size="sm" />
<span className="text-sm">Loading audio...</span>
</div>
</div>

View file

@ -1,11 +1,12 @@
"use client";
import { ExternalLinkIcon, ImageIcon, Loader2 } from "lucide-react";
import { ExternalLinkIcon, ImageIcon } from "lucide-react";
import NextImage from "next/image";
import { Component, type ReactNode, useState } from "react";
import { z } from "zod";
import { Badge } from "@/components/ui/badge";
import { Card } from "@/components/ui/card";
import { Spinner } from "@/components/ui/spinner";
import { cn } from "@/lib/utils";
/**
@ -184,7 +185,7 @@ export function ImageLoading({ title = "Loading image..." }: { title?: string })
<Card className="w-full max-w-md overflow-hidden">
<div className="aspect-[4/3] bg-muted flex items-center justify-center">
<div className="flex flex-col items-center gap-3">
<Loader2 className="size-8 text-muted-foreground animate-spin" />
<Spinner size="lg" className="text-muted-foreground" />
<p className="text-muted-foreground text-sm">{title}</p>
</div>
</div>

View file

@ -1,12 +1,13 @@
"use client";
import { ExternalLinkIcon, Globe, ImageIcon, LinkIcon, Loader2 } from "lucide-react";
import { ExternalLinkIcon, Globe, ImageIcon, LinkIcon } from "lucide-react";
import Image from "next/image";
import { Component, type ReactNode } from "react";
import { z } from "zod";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Spinner } from "@/components/ui/spinner";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
@ -299,18 +300,17 @@ export function MediaCard({
{/* Response Actions */}
{responseActions && responseActions.length > 0 && (
<div
className="mt-4 flex items-center justify-end gap-2 border-t pt-3"
onClick={(e) => e.stopPropagation()}
onKeyDown={(e) => e.stopPropagation()}
>
<div className="mt-4 flex items-center justify-end gap-2 border-t pt-3">
{responseActions.map((action) => (
<Tooltip key={action.id}>
<TooltipTrigger asChild>
<Button
variant={action.variant || "secondary"}
size="sm"
onClick={() => onResponseAction?.(action.id)}
onClick={(e) => {
e.stopPropagation();
onResponseAction?.(action.id);
}}
>
{action.label}
</Button>
@ -337,7 +337,7 @@ export function MediaCardLoading({ title = "Loading preview..." }: { title?: str
return (
<Card className="w-full max-w-md overflow-hidden">
<div className="aspect-[2/1] bg-muted animate-pulse flex items-center justify-center">
<Loader2 className="size-8 text-muted-foreground animate-spin" />
<Spinner size="lg" className="text-muted-foreground" />
</div>
<CardContent className="p-4">
<div className="flex items-center gap-3">

View file

@ -2,7 +2,6 @@
import { makeAssistantToolUI, useAssistantState } from "@assistant-ui/react";
import { useAtomValue, useSetAtom } from "jotai";
import { Loader2 } from "lucide-react";
import { useEffect, useMemo } from "react";
import { z } from "zod";
import {
@ -11,6 +10,7 @@ import {
registerPlanOwner,
updatePlanStateAtom,
} from "@/atoms/chat/plan-state.atom";
import { Spinner } from "@/components/ui/spinner";
import { Plan, PlanErrorBoundary, parseSerializablePlan, TodoStatusSchema } from "./plan";
// ============================================================================
@ -46,7 +46,7 @@ function WriteTodosLoading() {
return (
<div className="my-4 w-full max-w-xl rounded-2xl border bg-card/60 px-5 py-4 shadow-sm">
<div className="flex items-center gap-3">
<Loader2 className="size-5 animate-spin text-primary" />
<Spinner size="md" className="text-primary" />
<span className="text-sm text-muted-foreground">Creating plan...</span>
</div>
</div>