refactor(ui): normalize trade profile controls
This commit is contained in:
parent
1300de98a9
commit
cdc0e57ae9
@ -28,6 +28,7 @@ import { Button } from './ui/button';
|
||||
import { Card } from './ui/card';
|
||||
import { Input } from './ui/input';
|
||||
import { Select } from './ui/select';
|
||||
import { Textarea } from './ui/Primitives';
|
||||
import { cn } from '../lib/utils';
|
||||
// ChatControl is now rendered globally in App.tsx
|
||||
|
||||
@ -254,16 +255,19 @@ export const summarizePortfolioStats = (
|
||||
// --- UI COMPONENTS ---
|
||||
|
||||
const ToggleSwitch = ({ checked, onChange }: { checked: boolean, onChange: (v: boolean) => void }) => (
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
role="switch"
|
||||
aria-checked={checked}
|
||||
onClick={(e) => { e.stopPropagation(); onChange(!checked); }}
|
||||
className={cn(
|
||||
'relative inline-flex h-5 w-9 items-center rounded-full border transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]',
|
||||
'relative inline-flex h-5 min-h-0 w-9 items-center rounded-full border px-0 py-0 transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]',
|
||||
checked ? 'border-[var(--accent)] bg-[var(--accent)]' : 'border-[var(--border)] bg-[var(--muted)]'
|
||||
)}
|
||||
>
|
||||
<span className={`${checked ? 'translate-x-5 bg-white' : 'translate-x-1 bg-[var(--muted-foreground)]'} inline-block h-3 w-3 transform rounded-full transition-transform duration-200`} />
|
||||
</button>
|
||||
</Button>
|
||||
);
|
||||
|
||||
const Slider = ({ value, onChange, min, max, step, unit, label }: { value: number, onChange: (n: number) => void, min: number, max: number, step?: number, unit?: string, label: string }) => (
|
||||
@ -272,10 +276,11 @@ const Slider = ({ value, onChange, min, max, step, unit, label }: { value: numbe
|
||||
<span className={labelClass}>{label}</span>
|
||||
<span className="rounded-lg bg-[var(--accent-soft)] px-2.5 py-0.5 font-mono text-xs font-bold text-[var(--accent)]">{value}{unit}</span>
|
||||
</div>
|
||||
<input
|
||||
<Input
|
||||
type="range" min={min} max={max} step={step || 1} value={value}
|
||||
aria-label={label}
|
||||
onChange={(e) => onChange(Number(e.target.value))}
|
||||
className="h-1 w-full accent-[var(--accent)]"
|
||||
className="h-1 min-h-0 w-full px-0 py-0 accent-[var(--accent)]"
|
||||
/>
|
||||
<div className="flex justify-between font-mono text-[9px] text-[var(--muted-foreground)]">
|
||||
<span>{min}{unit}</span>
|
||||
@ -934,17 +939,20 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
{ id: 'logic' as const, label: 'Rules', icon: Cpu },
|
||||
{ id: 'advanced' as const, label: 'Risk & Execution', icon: Shield },
|
||||
]).map(t => (
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
key={t.id}
|
||||
onClick={() => setDrawerTab(t.id)}
|
||||
className={`flex-1 flex items-center justify-center gap-1.5 py-2 rounded-md text-[10px] font-bold uppercase tracking-wider transition-all ${drawerTab === t.id
|
||||
className={`flex-1 flex items-center justify-center gap-1.5 rounded-md py-2 text-[10px] font-bold uppercase tracking-wider transition-all ${drawerTab === t.id
|
||||
? 'bg-[var(--card)] text-[var(--foreground)] shadow-sm'
|
||||
: 'text-[var(--muted-foreground)] hover:text-[var(--foreground)]'
|
||||
}`}
|
||||
>
|
||||
<t.icon size={11} />
|
||||
{t.label}
|
||||
</button>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@ -979,10 +987,10 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
{/* Trading Symbols */}
|
||||
<div className="space-y-1.5">
|
||||
<label className={labelClass}>Trading Symbols</label>
|
||||
<textarea
|
||||
<Textarea
|
||||
value={editingProfile.symbols || ''}
|
||||
onChange={e => setEditingProfile({ ...editingProfile, symbols: e.target.value })}
|
||||
className="h-20 w-full resize-none rounded-xl border border-[var(--border)] bg-[var(--input)] px-4 py-2.5 font-mono text-sm text-[var(--foreground)] outline-none transition placeholder:text-[var(--muted-foreground)] focus:border-[var(--ring)] focus:ring-2 focus:ring-[var(--ring-soft)]"
|
||||
className="h-20 w-full resize-none font-mono text-sm"
|
||||
placeholder="BTC/USDT, ETH/USDT, SOL/USDT"
|
||||
/>
|
||||
<p className="text-[9px] text-[var(--muted-foreground)]">Comma-separated trading pairs</p>
|
||||
@ -1046,7 +1054,10 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
const isMandatory = currentType === 'mandatory';
|
||||
|
||||
return (
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
const newRules = editingProfile.strategy_config?.rules?.map(r =>
|
||||
@ -1058,13 +1069,13 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
});
|
||||
}}
|
||||
title="Click to toggle Mandatory/Voting"
|
||||
className={`px-1.5 py-0.5 rounded text-[8px] font-bold uppercase tracking-tighter border transition-all ${isMandatory
|
||||
className={`min-h-0 rounded border px-1.5 py-0.5 text-[8px] font-bold uppercase tracking-tighter transition-all ${isMandatory
|
||||
? 'bg-amber-500/10 text-amber-500 border-amber-500/20 hover:bg-amber-500/20'
|
||||
: 'bg-blue-500/10 text-blue-400 border-blue-500/20 hover:bg-blue-500/20'
|
||||
}`}
|
||||
>
|
||||
{isMandatory ? 'Mandatory' : 'Voting'}
|
||||
</button>
|
||||
</Button>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
@ -1231,7 +1242,10 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
<label className={labelClass}>Order Type</label>
|
||||
<div className="flex gap-2">
|
||||
{(['market', 'limit'] as const).map(t => (
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
key={t}
|
||||
onClick={() => setEditingProfile({
|
||||
...editingProfile,
|
||||
@ -1246,7 +1260,7 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
}`}
|
||||
>
|
||||
{t}
|
||||
</button>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@ -1257,7 +1271,10 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
{ value: 'both', label: 'Both Sides' },
|
||||
{ value: 'long_only', label: 'Long Only' }
|
||||
] as const).map(mode => (
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
key={mode.value}
|
||||
onClick={() => setEditingProfile({
|
||||
...editingProfile,
|
||||
@ -1272,7 +1289,7 @@ export const TradeProfileManager = ({ botState = DEFAULT_BOT_STATE }: TradeProfi
|
||||
}`}
|
||||
>
|
||||
{mode.label}
|
||||
</button>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<p className={helpTextClass}>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user