fix: Improve spinner visibility on primary-colored backgrounds

Add variant prop to Spinner component to support different color contexts:
- 'primary' (default): Uses text-primary for standard backgrounds
- 'foreground': Uses text-primary-foreground for primary backgrounds
- 'muted': Uses text-muted-foreground for subtle contexts

Updated components where spinners were invisible against primary backgrounds:
- TaskProgressPanel: Active task indicators now visible
- Button: Auto-detects spinner variant based on button style
- Various dialogs and setup views using buttons with loaders

Fixes #670

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Shirone
2026-01-24 15:26:47 +01:00
parent d8fa5c4cd1
commit 066ffe5639
13 changed files with 55 additions and 30 deletions

View File

@@ -330,7 +330,7 @@ export function MergeWorktreeDialog({
>
{isLoading ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Merging...
</>
) : (

View File

@@ -210,7 +210,7 @@ export function PlanApprovalDialog({
className="bg-green-600 hover:bg-green-700 text-white"
>
{isLoading ? (
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
) : (
<Check className="w-4 h-4 mr-2" />
)}

View File

@@ -572,7 +572,7 @@ export function InterviewView() {
>
{isGenerating ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Creating...
</>
) : (

View File

@@ -448,7 +448,7 @@ export function LoginView() {
>
{isLoggingIn ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Authenticating...
</>
) : (

View File

@@ -60,7 +60,7 @@ export function CliInstallationCard({
>
{isInstalling ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Installing...
</>
) : (

View File

@@ -412,7 +412,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
>
{isInstalling ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Installing...
</>
) : (
@@ -574,7 +574,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
>
{isSavingApiKey ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Saving...
</>
) : (

View File

@@ -408,7 +408,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup
>
{isInstalling ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Installing...
</>
) : (
@@ -681,7 +681,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup
>
{isSavingApiKey ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Saving...
</>
) : (

View File

@@ -318,7 +318,7 @@ export function CursorSetupStep({ onNext, onBack, onSkip }: CursorSetupStepProps
>
{isLoggingIn ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Waiting for login...
</>
) : (

View File

@@ -316,7 +316,7 @@ export function OpencodeSetupStep({ onNext, onBack, onSkip }: OpencodeSetupStepP
>
{isLoggingIn ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Waiting for login...
</>
) : (

View File

@@ -329,7 +329,7 @@ function ClaudeContent() {
>
{isInstalling ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Installing...
</>
) : (
@@ -424,7 +424,11 @@ function ClaudeContent() {
disabled={isSavingApiKey || !apiKey.trim()}
className="flex-1 bg-brand-500 hover:bg-brand-600 text-white"
>
{isSavingApiKey ? <Spinner size="sm" /> : 'Save API Key'}
{isSavingApiKey ? (
<Spinner size="sm" variant="foreground" />
) : (
'Save API Key'
)}
</Button>
{hasApiKey && (
<Button
@@ -661,7 +665,7 @@ function CursorContent() {
>
{isLoggingIn ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Waiting for login...
</>
) : (
@@ -918,7 +922,7 @@ function CodexContent() {
>
{isLoggingIn ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Waiting for login...
</>
) : (
@@ -961,7 +965,7 @@ function CodexContent() {
disabled={isSaving || !apiKey.trim()}
className="w-full bg-brand-500 hover:bg-brand-600 text-white"
>
{isSaving ? <Spinner size="sm" /> : 'Save API Key'}
{isSaving ? <Spinner size="sm" variant="foreground" /> : 'Save API Key'}
</Button>
</AccordionContent>
</AccordionItem>
@@ -1194,7 +1198,7 @@ function OpencodeContent() {
>
{isLoggingIn ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Waiting for login...
</>
) : (
@@ -1466,7 +1470,7 @@ function GeminiContent() {
>
{isLoggingIn ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Waiting for login...
</>
) : (
@@ -1509,7 +1513,7 @@ function GeminiContent() {
disabled={isSaving || !apiKey.trim()}
className="w-full bg-brand-500 hover:bg-brand-600 text-white"
>
{isSaving ? <Spinner size="sm" /> : 'Save API Key'}
{isSaving ? <Spinner size="sm" variant="foreground" /> : 'Save API Key'}
</Button>
</AccordionContent>
</AccordionItem>
@@ -1745,7 +1749,7 @@ function CopilotContent() {
>
{isLoggingIn ? (
<>
<Spinner size="sm" className="mr-2" />
<Spinner size="sm" variant="foreground" className="mr-2" />
Waiting for login...
</>
) : (