fix(ui): declutter device page header — compact tool buttons
- WinBox/RemoteWinBox/SSH: replace big accent CTAs with compact bordered tool buttons (text-[10px], h-3 icons, border-default) - SimpleModeToggle: shrink from pill-button group to inline segmented control (text-[10px], accent-soft active state) - Edit/Delete already icon-only ghost from previous commit - All tool buttons now visually consistent — small, bordered, receding - Result: header reads as a compact control strip, not a CTA row Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -162,26 +162,26 @@ export function RemoteWinBoxButton({ tenantId, deviceId }: RemoteWinBoxButtonPro
|
|||||||
if (state === 'idle' || state === 'failed' || state === 'terminated') {
|
if (state === 'idle' || state === 'failed' || state === 'terminated') {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-1">
|
||||||
<button
|
<button
|
||||||
onClick={handleOpen}
|
onClick={handleOpen}
|
||||||
disabled={createMutation.isPending}
|
disabled={createMutation.isPending}
|
||||||
className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-accent text-white hover:bg-accent/90 disabled:opacity-50"
|
className="inline-flex items-center gap-1 px-2 py-1 rounded-[var(--radius-control)] text-[10px] text-text-secondary border border-border-default hover:border-accent transition-[border-color,color] duration-[50ms] disabled:opacity-50"
|
||||||
|
title="Open Remote WinBox (browser)"
|
||||||
>
|
>
|
||||||
{createMutation.isPending ? (
|
{createMutation.isPending ? (
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
<Loader2 className="h-3 w-3 animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
<Globe className="h-4 w-4" />
|
<Globe className="h-3 w-3" />
|
||||||
)}
|
)}
|
||||||
{createMutation.isPending ? 'Starting...' : 'Remote WinBox'}
|
{createMutation.isPending ? 'Starting' : 'Remote'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleReset}
|
onClick={handleReset}
|
||||||
className="inline-flex items-center gap-2 px-4 py-2 rounded-md border border-input bg-background hover:bg-accent hover:text-accent-foreground"
|
className="inline-flex items-center px-1.5 py-1 rounded-[var(--radius-control)] text-text-muted border border-border-default hover:border-accent transition-[border-color] duration-[50ms]"
|
||||||
title="Reset all remote WinBox sessions for this device"
|
title="Reset remote sessions"
|
||||||
>
|
>
|
||||||
<RefreshCw className="h-4 w-4" />
|
<RefreshCw className="h-3 w-3" />
|
||||||
Reset
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{state === 'failed' && error && (
|
{state === 'failed' && error && (
|
||||||
|
|||||||
@@ -162,10 +162,11 @@ export function SSHTerminal({ tenantId, deviceId, deviceName }: SSHTerminalProps
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
onClick={handleOpen}
|
onClick={handleOpen}
|
||||||
className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-accent text-white hover:bg-accent/90"
|
className="inline-flex items-center gap-1 px-2 py-1 rounded-[var(--radius-control)] text-[10px] text-text-secondary border border-border-default hover:border-accent transition-[border-color,color] duration-[50ms]"
|
||||||
|
title="Open SSH Terminal"
|
||||||
>
|
>
|
||||||
<TerminalIcon className="h-4 w-4" />
|
<TerminalIcon className="h-3 w-3" />
|
||||||
SSH Terminal
|
SSH
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,14 +78,15 @@ export function WinBoxButton({ tenantId, deviceId }: WinBoxButtonProps) {
|
|||||||
openMutation.mutate()
|
openMutation.mutate()
|
||||||
}}
|
}}
|
||||||
disabled={openMutation.isPending}
|
disabled={openMutation.isPending}
|
||||||
className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-accent text-white hover:bg-accent/90 disabled:opacity-50"
|
className="inline-flex items-center gap-1 px-2 py-1 rounded-[var(--radius-control)] text-[10px] text-text-secondary border border-border-default hover:border-accent transition-[border-color,color] duration-[50ms] disabled:opacity-50"
|
||||||
|
title="Open WinBox tunnel"
|
||||||
>
|
>
|
||||||
{openMutation.isPending ? (
|
{openMutation.isPending ? (
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
<Loader2 className="h-3 w-3 animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
<Monitor className="h-4 w-4" />
|
<Monitor className="h-3 w-3" />
|
||||||
)}
|
)}
|
||||||
{openMutation.isPending ? 'Connecting...' : 'Open WinBox'}
|
{openMutation.isPending ? 'Connecting' : 'WinBox'}
|
||||||
</button>
|
</button>
|
||||||
{error && <p className="mt-2 text-sm text-error">{error}</p>}
|
{error && <p className="mt-2 text-sm text-error">{error}</p>}
|
||||||
</div>
|
</div>
|
||||||
@@ -94,18 +95,17 @@ export function WinBoxButton({ tenantId, deviceId }: WinBoxButtonProps) {
|
|||||||
|
|
||||||
if (state === 'ready' && tunnelInfo) {
|
if (state === 'ready' && tunnelInfo) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-md border p-4 space-y-3">
|
<div className="rounded-sm border border-border-default bg-panel p-2.5 space-y-2">
|
||||||
<p className="font-medium text-sm">WinBox tunnel ready</p>
|
<p className="text-xs text-text-primary">
|
||||||
<p className="text-sm text-text-muted">
|
Tunnel ready: <code className="font-mono text-[10px] text-text-secondary">{tunnelInfo.host}:{tunnelInfo.port}</code>
|
||||||
Connect to: <code className="font-mono">{tunnelInfo.host}:{tunnelInfo.port}</code>
|
|
||||||
</p>
|
</p>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-1">
|
||||||
<button
|
<button
|
||||||
onClick={copyAddress}
|
onClick={copyAddress}
|
||||||
className="inline-flex items-center gap-2 px-3 py-1.5 text-sm rounded-md border hover:bg-accent"
|
className="inline-flex items-center gap-1 px-2 py-0.5 text-[10px] rounded-[var(--radius-control)] border border-border-default text-text-secondary hover:border-accent transition-[border-color] duration-[50ms]"
|
||||||
>
|
>
|
||||||
<Copy className="h-3 w-3" />
|
<Copy className="h-2.5 w-2.5" />
|
||||||
{copied ? 'Copied!' : 'Copy Address'}
|
{copied ? 'Copied' : 'Copy'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -113,15 +113,13 @@ export function WinBoxButton({ tenantId, deviceId }: WinBoxButtonProps) {
|
|||||||
closeMutation.mutate()
|
closeMutation.mutate()
|
||||||
}}
|
}}
|
||||||
disabled={closeMutation.isPending}
|
disabled={closeMutation.isPending}
|
||||||
className="inline-flex items-center gap-2 px-3 py-1.5 text-sm rounded-md border hover:bg-accent disabled:opacity-50"
|
className="inline-flex items-center gap-1 px-2 py-0.5 text-[10px] rounded-[var(--radius-control)] border border-border-default text-text-muted hover:border-accent disabled:opacity-50 transition-[border-color] duration-[50ms]"
|
||||||
>
|
>
|
||||||
<X className="h-3 w-3" />
|
<X className="h-2.5 w-2.5" />
|
||||||
Close Tunnel
|
Close
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-text-muted">
|
<p className="text-[9px] text-text-muted">Closes after 5 min idle</p>
|
||||||
Tunnel closes after 5 min of inactivity
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,31 +14,31 @@ interface SimpleModeToggleProps {
|
|||||||
|
|
||||||
export function SimpleModeToggle({ mode, onModeChange }: SimpleModeToggleProps) {
|
export function SimpleModeToggle({ mode, onModeChange }: SimpleModeToggleProps) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-1 rounded-lg border border-border bg-elevated/50 p-1">
|
<div className="flex items-center gap-px rounded-[var(--radius-control)] border border-border-default overflow-hidden">
|
||||||
<Button
|
<button
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => onModeChange('simple')}
|
onClick={() => onModeChange('simple')}
|
||||||
className={cn(
|
className={cn(
|
||||||
'gap-1.5 h-7 px-2.5 text-xs',
|
'flex items-center gap-1 px-1.5 py-0.5 text-[10px] transition-[background-color,color] duration-[50ms]',
|
||||||
mode === 'simple' && 'bg-accent/20 text-accent',
|
mode === 'simple'
|
||||||
|
? 'bg-accent-soft text-text-primary font-medium'
|
||||||
|
: 'text-text-muted hover:text-text-secondary',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<LayoutGrid className="h-3.5 w-3.5" />
|
<LayoutGrid className="h-2.5 w-2.5" />
|
||||||
Simple
|
Simple
|
||||||
</Button>
|
</button>
|
||||||
<Button
|
<button
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => onModeChange('standard')}
|
onClick={() => onModeChange('standard')}
|
||||||
className={cn(
|
className={cn(
|
||||||
'gap-1.5 h-7 px-2.5 text-xs',
|
'flex items-center gap-1 px-1.5 py-0.5 text-[10px] transition-[background-color,color] duration-[50ms]',
|
||||||
mode === 'standard' && 'bg-accent/20 text-accent',
|
mode === 'standard'
|
||||||
|
? 'bg-accent-soft text-text-primary font-medium'
|
||||||
|
: 'text-text-muted hover:text-text-secondary',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Sliders className="h-3.5 w-3.5" />
|
<Sliders className="h-2.5 w-2.5" />
|
||||||
Standard
|
Standard
|
||||||
</Button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user