mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-02 22:17:14 +00:00
fix(cliproxy): streamline sidebar routing control
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { ArrowRightLeft, ChevronDown, ChevronUp } from 'lucide-react';
|
import { ArrowRightLeft, ChevronDown, ChevronUp, RefreshCw } from 'lucide-react';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import type { CliproxyRoutingState, RoutingStrategy } from '@/lib/api-client';
|
import type { CliproxyRoutingState, RoutingStrategy } from '@/lib/api-client';
|
||||||
@@ -43,88 +43,48 @@ export function RoutingGuidanceCard({
|
|||||||
const detailToggleLabel = detailsOpen ? 'Hide details' : 'Show details';
|
const detailToggleLabel = detailsOpen ? 'Hide details' : 'Show details';
|
||||||
|
|
||||||
if (compact) {
|
if (compact) {
|
||||||
const statusLine = selected === 'fill-first' ? 'One account first' : 'Balanced usage';
|
const handleApply = (s: RoutingStrategy) => {
|
||||||
|
setSelected(s);
|
||||||
|
if (s !== currentStrategy) {
|
||||||
|
onApply(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={cn('border-t border-border/60 pt-3', className)}>
|
<div className={cn('flex items-center justify-between', className)}>
|
||||||
<div className="space-y-2.5 rounded-xl border border-border/70 bg-background/90 p-2.5">
|
<div className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground">
|
||||||
<div className="flex items-start justify-between gap-2">
|
<ArrowRightLeft className="h-3.5 w-3.5" />
|
||||||
<div className="flex min-w-0 items-start gap-2">
|
<span>Routing</span>
|
||||||
<div className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-muted/80 text-primary transition-transform duration-200 hover:scale-105">
|
{isSaving && <RefreshCw className="ml-0.5 h-3 w-3 shrink-0 animate-spin opacity-50" />}
|
||||||
<ArrowRightLeft className="h-3.5 w-3.5" />
|
|
||||||
</div>
|
|
||||||
<div className="min-w-0 flex-1">
|
|
||||||
<div className="flex flex-wrap items-center gap-1.5">
|
|
||||||
<span className="text-[11px] font-semibold uppercase tracking-[0.14em] text-muted-foreground">
|
|
||||||
Routing
|
|
||||||
</span>
|
|
||||||
<Badge variant="outline" className="h-5 px-1.5 text-[10px]">
|
|
||||||
{currentStrategy}
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
<p className="mt-1 text-[11px] leading-4 text-muted-foreground">{statusLine}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!state?.reachable ? (
|
|
||||||
<Badge variant="secondary" className="h-5 px-1.5 text-[10px]">
|
|
||||||
Saved default
|
|
||||||
</Badge>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="relative grid grid-cols-2 gap-1 rounded-xl border border-border/70 bg-muted/30 p-1">
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
'absolute inset-y-1 left-1 w-[calc(50%-0.375rem)] rounded-lg bg-background shadow-[0_1px_0_rgba(255,255,255,0.9)_inset,0_6px_16px_rgba(15,23,42,0.06)] transition-transform duration-300 ease-out',
|
|
||||||
selected === 'fill-first' ? 'translate-x-[calc(100%+0.25rem)]' : 'translate-x-0'
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{(
|
|
||||||
Object.entries(STRATEGY_COPY) as Array<
|
|
||||||
[RoutingStrategy, { title: string; description: string }]
|
|
||||||
>
|
|
||||||
).map(([strategy, copy]) => {
|
|
||||||
const active = selected === strategy;
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={strategy}
|
|
||||||
type="button"
|
|
||||||
className={cn(
|
|
||||||
'relative z-10 rounded-lg px-2 py-1.5 text-[11px] font-medium transition-colors duration-200 active:scale-[0.98]',
|
|
||||||
active ? 'text-foreground' : 'text-muted-foreground hover:text-foreground'
|
|
||||||
)}
|
|
||||||
onClick={() => setSelected(strategy)}
|
|
||||||
disabled={isLoading || isSaving || !!error}
|
|
||||||
title={copy.description}
|
|
||||||
>
|
|
||||||
{copy.title}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center justify-between gap-2">
|
|
||||||
<div className="flex flex-wrap items-center gap-1.5 text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
|
|
||||||
<span>Proxy-wide</span>
|
|
||||||
{state?.source === 'config' ? (
|
|
||||||
<>
|
|
||||||
<span className="text-border">•</span>
|
|
||||||
<span>Local</span>
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
className="h-7 px-2.5 text-[11px] transition-transform duration-200 hover:-translate-y-px active:translate-y-0"
|
|
||||||
onClick={() => onApply(selected)}
|
|
||||||
disabled={saveDisabled || !!error}
|
|
||||||
>
|
|
||||||
{isSaving ? 'Saving...' : 'Apply'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
|
||||||
|
<div className="flex items-center rounded-md border border-border/50 bg-muted/40 p-0.5">
|
||||||
|
{(
|
||||||
|
Object.entries(STRATEGY_COPY) as Array<
|
||||||
|
[RoutingStrategy, { title: string; description: string }]
|
||||||
|
>
|
||||||
|
).map(([strategy, copy]) => {
|
||||||
|
const active = selected === strategy;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={strategy}
|
||||||
|
type="button"
|
||||||
|
className={cn(
|
||||||
|
'relative z-10 rounded-[4px] px-2 py-0.5 text-[10px] font-medium transition-all duration-200',
|
||||||
|
active
|
||||||
|
? 'bg-background text-foreground shadow-[0_1px_2px_rgba(0,0,0,0.06)] ring-1 ring-black/5 dark:ring-white/10'
|
||||||
|
: 'text-muted-foreground hover:bg-black/5 hover:text-foreground dark:hover:bg-white/5'
|
||||||
|
)}
|
||||||
|
onClick={() => handleApply(strategy)}
|
||||||
|
disabled={isLoading || isSaving || !!error}
|
||||||
|
title={copy.description}
|
||||||
|
>
|
||||||
|
{copy.title}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user