refactor: replace Loader2 with Spinner component across the application

This update standardizes the loading indicators by replacing all instances of Loader2 with the new Spinner component. The Spinner component provides a consistent look and feel for loading states throughout the UI, enhancing the user experience.

Changes include:
- Updated loading indicators in various components such as popovers, modals, and views.
- Ensured that the Spinner component is used with appropriate sizes for different contexts.

No functional changes were made; this is purely a visual and structural improvement.
This commit is contained in:
webdevcody
2026-01-17 17:58:16 -05:00
parent 044c3d50d1
commit 832d10e133
93 changed files with 351 additions and 333 deletions

View File

@@ -1,6 +1,7 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Download, Loader2, AlertCircle } from 'lucide-react';
import { Download, AlertCircle } from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { CopyableCommandField } from './copyable-command-field';
import { TerminalOutput } from './terminal-output';
@@ -59,7 +60,7 @@ export function CliInstallationCard({
>
{isInstalling ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Installing...
</>
) : (

View File

@@ -1,4 +1,5 @@
import { CheckCircle2, XCircle, Loader2, AlertCircle } from 'lucide-react';
import { CheckCircle2, XCircle, AlertCircle } from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
interface StatusBadgeProps {
status:
@@ -34,7 +35,7 @@ export function StatusBadge({ status, label }: StatusBadgeProps) {
};
case 'checking':
return {
icon: <Loader2 className="w-4 h-4 animate-spin" />,
icon: <Spinner size="sm" />,
className: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/20',
};
case 'unverified':

View File

@@ -14,7 +14,6 @@ import { useAppStore } from '@/store/app-store';
import { getElectronAPI } from '@/lib/electron';
import {
CheckCircle2,
Loader2,
Key,
ArrowRight,
ArrowLeft,
@@ -27,6 +26,7 @@ import {
XCircle,
Trash2,
} from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { toast } from 'sonner';
import { StatusBadge, TerminalOutput } from '../components';
import { useCliStatus, useCliInstallation, useTokenSave } from '../hooks';
@@ -330,7 +330,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
Authentication Methods
</CardTitle>
<Button variant="ghost" size="sm" onClick={checkStatus} disabled={isChecking}>
<RefreshCw className={`w-4 h-4 ${isChecking ? 'animate-spin' : ''}`} />
{isChecking ? <Spinner size="sm" /> : <RefreshCw className="w-4 h-4" />}
</Button>
</div>
<CardDescription>
@@ -412,7 +412,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
>
{isInstalling ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Installing...
</>
) : (
@@ -435,7 +435,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
{/* CLI Verification Status */}
{cliVerificationStatus === 'verifying' && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<div>
<p className="font-medium text-foreground">Verifying CLI authentication...</p>
<p className="text-sm text-muted-foreground">Running a test query</p>
@@ -494,7 +494,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
>
{cliVerificationStatus === 'verifying' ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Verifying...
</>
) : cliVerificationStatus === 'error' ? (
@@ -574,7 +574,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
>
{isSavingApiKey ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Saving...
</>
) : (
@@ -589,11 +589,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
className="border-red-500/50 text-red-500 hover:bg-red-500/10 hover:text-red-400"
data-testid="delete-anthropic-key-button"
>
{isDeletingApiKey ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
<Trash2 className="w-4 h-4" />
)}
{isDeletingApiKey ? <Spinner size="sm" /> : <Trash2 className="w-4 h-4" />}
</Button>
)}
</div>
@@ -602,7 +598,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
{/* API Key Verification Status */}
{apiKeyVerificationStatus === 'verifying' && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<div>
<p className="font-medium text-foreground">Verifying API key...</p>
<p className="text-sm text-muted-foreground">Running a test query</p>
@@ -642,7 +638,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
>
{apiKeyVerificationStatus === 'verifying' ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Verifying...
</>
) : apiKeyVerificationStatus === 'error' ? (

View File

@@ -14,7 +14,6 @@ import { useAppStore } from '@/store/app-store';
import { getElectronAPI } from '@/lib/electron';
import {
CheckCircle2,
Loader2,
Key,
ArrowRight,
ArrowLeft,
@@ -27,6 +26,7 @@ import {
XCircle,
Trash2,
} from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { toast } from 'sonner';
import { StatusBadge, TerminalOutput } from '../components';
import { useCliStatus, useCliInstallation, useTokenSave } from '../hooks';
@@ -332,7 +332,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup
Authentication Methods
</CardTitle>
<Button variant="ghost" size="sm" onClick={checkStatus} disabled={isChecking}>
<RefreshCw className={`w-4 h-4 ${isChecking ? 'animate-spin' : ''}`} />
{isChecking ? <Spinner size="sm" /> : <RefreshCw className="w-4 h-4" />}
</Button>
</div>
<CardDescription>Choose one of the following methods to authenticate:</CardDescription>
@@ -408,7 +408,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup
>
{isInstalling ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Installing...
</>
) : (
@@ -427,7 +427,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup
{cliVerificationStatus === 'verifying' && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<div>
<p className="font-medium text-foreground">Verifying CLI authentication...</p>
<p className="text-sm text-muted-foreground">Running a test query</p>
@@ -605,7 +605,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup
>
{cliVerificationStatus === 'verifying' ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Verifying...
</>
) : cliVerificationStatus === 'error' ? (
@@ -681,7 +681,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup
>
{isSavingApiKey ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Saving...
</>
) : (
@@ -696,11 +696,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup
className="border-red-500/50 text-red-500 hover:bg-red-500/10 hover:text-red-400"
data-testid={config.testIds.deleteApiKeyButton}
>
{isDeletingApiKey ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
<Trash2 className="w-4 h-4" />
)}
{isDeletingApiKey ? <Spinner size="sm" /> : <Trash2 className="w-4 h-4" />}
</Button>
)}
</div>
@@ -708,7 +704,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup
{apiKeyVerificationStatus === 'verifying' && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<div>
<p className="font-medium text-foreground">Verifying API key...</p>
<p className="text-sm text-muted-foreground">Running a test query</p>
@@ -767,7 +763,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup
>
{apiKeyVerificationStatus === 'verifying' ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Verifying...
</>
) : apiKeyVerificationStatus === 'error' ? (

View File

@@ -7,7 +7,6 @@ import { useSetupStore } from '@/store/setup-store';
import { getElectronAPI } from '@/lib/electron';
import {
CheckCircle2,
Loader2,
ArrowRight,
ArrowLeft,
ExternalLink,
@@ -16,6 +15,7 @@ import {
AlertTriangle,
XCircle,
} from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { toast } from 'sonner';
import { StatusBadge } from '../components';
import { CursorIcon } from '@/components/ui/provider-icon';
@@ -204,7 +204,7 @@ export function CursorSetupStep({ onNext, onBack, onSkip }: CursorSetupStepProps
<div className="flex items-center gap-2">
{getStatusBadge()}
<Button variant="ghost" size="sm" onClick={checkStatus} disabled={isChecking}>
<RefreshCw className={`w-4 h-4 ${isChecking ? 'animate-spin' : ''}`} />
{isChecking ? <Spinner size="sm" /> : <RefreshCw className="w-4 h-4" />}
</Button>
</div>
</div>
@@ -318,7 +318,7 @@ export function CursorSetupStep({ onNext, onBack, onSkip }: CursorSetupStepProps
>
{isLoggingIn ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Waiting for login...
</>
) : (
@@ -332,7 +332,7 @@ export function CursorSetupStep({ onNext, onBack, onSkip }: CursorSetupStepProps
{/* Loading State */}
{isChecking && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<div>
<p className="font-medium text-foreground">Checking Cursor CLI status...</p>
</div>

View File

@@ -6,7 +6,6 @@ import { useSetupStore } from '@/store/setup-store';
import { getElectronAPI } from '@/lib/electron';
import {
CheckCircle2,
Loader2,
ArrowRight,
ArrowLeft,
ExternalLink,
@@ -16,6 +15,7 @@ import {
Github,
XCircle,
} from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { toast } from 'sonner';
import { StatusBadge } from '../components';
@@ -116,7 +116,7 @@ export function GitHubSetupStep({ onNext, onBack, onSkip }: GitHubSetupStepProps
<div className="flex items-center gap-2">
{getStatusBadge()}
<Button variant="ghost" size="sm" onClick={checkStatus} disabled={isChecking}>
<RefreshCw className={`w-4 h-4 ${isChecking ? 'animate-spin' : ''}`} />
{isChecking ? <Spinner size="sm" /> : <RefreshCw className="w-4 h-4" />}
</Button>
</div>
</div>
@@ -252,7 +252,7 @@ export function GitHubSetupStep({ onNext, onBack, onSkip }: GitHubSetupStepProps
{/* Loading State */}
{isChecking && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<div>
<p className="font-medium text-foreground">Checking GitHub CLI status...</p>
</div>

View File

@@ -7,7 +7,6 @@ import { useSetupStore } from '@/store/setup-store';
import { getElectronAPI } from '@/lib/electron';
import {
CheckCircle2,
Loader2,
ArrowRight,
ArrowLeft,
ExternalLink,
@@ -17,6 +16,7 @@ import {
XCircle,
Terminal,
} from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { toast } from 'sonner';
import { StatusBadge } from '../components';
@@ -204,7 +204,7 @@ export function OpencodeSetupStep({ onNext, onBack, onSkip }: OpencodeSetupStepP
<div className="flex items-center gap-2">
{getStatusBadge()}
<Button variant="ghost" size="sm" onClick={checkStatus} disabled={isChecking}>
<RefreshCw className={`w-4 h-4 ${isChecking ? 'animate-spin' : ''}`} />
{isChecking ? <Spinner size="sm" /> : <RefreshCw className="w-4 h-4" />}
</Button>
</div>
</div>
@@ -316,7 +316,7 @@ export function OpencodeSetupStep({ onNext, onBack, onSkip }: OpencodeSetupStepP
>
{isLoggingIn ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Waiting for login...
</>
) : (
@@ -330,7 +330,7 @@ export function OpencodeSetupStep({ onNext, onBack, onSkip }: OpencodeSetupStepP
{/* Loading State */}
{isChecking && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<div>
<p className="font-medium text-foreground">Checking OpenCode CLI status...</p>
</div>

View File

@@ -17,7 +17,6 @@ import {
ArrowRight,
ArrowLeft,
CheckCircle2,
Loader2,
Key,
ExternalLink,
Copy,
@@ -29,6 +28,7 @@ import {
Terminal,
AlertCircle,
} from 'lucide-react';
import { Spinner } from '@/components/ui/spinner';
import { toast } from 'sonner';
import { cn } from '@/lib/utils';
import { AnthropicIcon, CursorIcon, OpenAIIcon, OpenCodeIcon } from '@/components/ui/provider-icon';
@@ -240,7 +240,7 @@ function ClaudeContent() {
onClick={checkStatus}
disabled={isChecking || isVerifying}
>
<RefreshCw className={`w-4 h-4 ${isChecking || isVerifying ? 'animate-spin' : ''}`} />
{isChecking || isVerifying ? <Spinner size="sm" /> : <RefreshCw className="w-4 h-4" />}
</Button>
</div>
<CardDescription>
@@ -278,7 +278,7 @@ function ClaudeContent() {
{/* Checking/Verifying State */}
{(isChecking || isVerifying) && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<p className="font-medium text-foreground">
{isChecking ? 'Checking Claude CLI status...' : 'Verifying authentication...'}
</p>
@@ -322,7 +322,7 @@ function ClaudeContent() {
>
{isInstalling ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Installing...
</>
) : (
@@ -417,11 +417,7 @@ function ClaudeContent() {
disabled={isSavingApiKey || !apiKey.trim()}
className="flex-1 bg-brand-500 hover:bg-brand-600 text-white"
>
{isSavingApiKey ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
'Save API Key'
)}
{isSavingApiKey ? <Spinner size="sm" /> : 'Save API Key'}
</Button>
{hasApiKey && (
<Button
@@ -431,7 +427,7 @@ function ClaudeContent() {
className="border-red-500/50 text-red-500 hover:bg-red-500/10"
>
{isDeletingApiKey ? (
<Loader2 className="w-4 h-4 animate-spin" />
<Spinner size="sm" />
) : (
<Trash2 className="w-4 h-4" />
)}
@@ -553,7 +549,7 @@ function CursorContent() {
Cursor CLI Status
</CardTitle>
<Button variant="ghost" size="sm" onClick={checkStatus} disabled={isChecking}>
<RefreshCw className={`w-4 h-4 ${isChecking ? 'animate-spin' : ''}`} />
{isChecking ? <Spinner size="sm" /> : <RefreshCw className="w-4 h-4" />}
</Button>
</div>
<CardDescription>
@@ -658,7 +654,7 @@ function CursorContent() {
>
{isLoggingIn ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Waiting for login...
</>
) : (
@@ -671,7 +667,7 @@ function CursorContent() {
{isChecking && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<p className="font-medium text-foreground">Checking Cursor CLI status...</p>
</div>
)}
@@ -807,7 +803,7 @@ function CodexContent() {
Codex CLI Status
</CardTitle>
<Button variant="ghost" size="sm" onClick={checkStatus} disabled={isChecking}>
<RefreshCw className={`w-4 h-4 ${isChecking ? 'animate-spin' : ''}`} />
{isChecking ? <Spinner size="sm" /> : <RefreshCw className="w-4 h-4" />}
</Button>
</div>
<CardDescription>
@@ -915,7 +911,7 @@ function CodexContent() {
>
{isLoggingIn ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Waiting for login...
</>
) : (
@@ -958,7 +954,7 @@ function CodexContent() {
disabled={isSaving || !apiKey.trim()}
className="w-full bg-brand-500 hover:bg-brand-600 text-white"
>
{isSaving ? <Loader2 className="w-4 h-4 animate-spin" /> : 'Save API Key'}
{isSaving ? <Spinner size="sm" /> : 'Save API Key'}
</Button>
</AccordionContent>
</AccordionItem>
@@ -968,7 +964,7 @@ function CodexContent() {
{isChecking && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<p className="font-medium text-foreground">Checking Codex CLI status...</p>
</div>
)}
@@ -1082,7 +1078,7 @@ function OpencodeContent() {
OpenCode CLI Status
</CardTitle>
<Button variant="ghost" size="sm" onClick={checkStatus} disabled={isChecking}>
<RefreshCw className={`w-4 h-4 ${isChecking ? 'animate-spin' : ''}`} />
{isChecking ? <Spinner size="sm" /> : <RefreshCw className="w-4 h-4" />}
</Button>
</div>
<CardDescription>
@@ -1191,7 +1187,7 @@ function OpencodeContent() {
>
{isLoggingIn ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
<Spinner size="sm" className="mr-2" />
Waiting for login...
</>
) : (
@@ -1204,7 +1200,7 @@ function OpencodeContent() {
{isChecking && (
<div className="flex items-center gap-3 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<p className="font-medium text-foreground">Checking OpenCode CLI status...</p>
</div>
)}
@@ -1416,7 +1412,7 @@ export function ProvidersSetupStep({ onNext, onBack }: ProvidersSetupStepProps)
);
case 'verifying':
return (
<Loader2 className="w-3 h-3 text-blue-500 absolute -top-1 -right-1.5 bg-background rounded-full animate-spin" />
<Spinner size="xs" className="absolute -top-1 -right-1.5 bg-background rounded-full" />
);
case 'installed_not_auth':
return (
@@ -1436,7 +1432,7 @@ export function ProvidersSetupStep({ onNext, onBack }: ProvidersSetupStepProps)
{isInitialChecking && (
<div className="flex items-center justify-center gap-2 p-4 rounded-lg bg-blue-500/10 border border-blue-500/20">
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
<Spinner size="md" />
<p className="font-medium text-foreground">Checking provider status...</p>
</div>
)}