feat(ui): sweep remaining components for Deep Space consistency

Replace old design tokens and hardcoded colors across 29 files:
- bg-primary/text-primary-foreground -> bg-accent/text-white
- text-muted-foreground -> text-text-muted
- text-destructive/bg-destructive -> text-error/bg-error
- bg-muted -> bg-elevated (background usage)
- Hardcoded green/red/yellow/emerald/amber/slate -> semantic tokens
- Remove shadow-md/lg from cards, tooltips, topology nodes
- rounded-xl -> rounded-lg on cards/panels
- focus:ring-1 focus:ring-ring -> focus:border-accent on inputs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-16 19:00:36 -05:00
parent 25d4a80b73
commit c455fe4ed5
29 changed files with 107 additions and 107 deletions

View File

@@ -461,7 +461,7 @@ function ChannelFormDialog({
<select
value={smtpProvider}
onChange={(e) => handleProviderChange(e.target.value)}
className="w-full rounded-md bg-slate-700 border border-slate-600 text-white px-3 py-2 text-sm"
className="w-full rounded-md bg-elevated border border-border text-text-primary px-3 py-2 text-sm"
>
{SMTP_PRESETS.map((p) => (
<option key={p.id} value={p.id}>
@@ -544,12 +544,12 @@ function ChannelFormDialog({
type="button"
onClick={handleTestSmtp}
disabled={testing || !smtpHost || !toAddress}
className="px-4 py-2 rounded-md bg-slate-600 text-white text-sm hover:bg-slate-500 disabled:opacity-50"
className="px-4 py-2 rounded-md bg-elevated text-text-primary text-sm hover:bg-elevated/80 disabled:opacity-50"
>
{testing ? 'Testing...' : 'Test Connection'}
</button>
{testResult && (
<p className={`text-sm ${testResult.success ? 'text-green-400' : 'text-red-400'}`}>
<p className={`text-sm ${testResult.success ? 'text-success' : 'text-error'}`}>
{testResult.message}
</p>
)}

View File

@@ -224,7 +224,7 @@ export function EmergencyKitDialog({
>
{copied ? (
<>
<Check className="h-4 w-4 text-green-500" />
<Check className="h-4 w-4 text-success" />
Copied
</>
) : (

View File

@@ -56,18 +56,18 @@ const SCORE_CONFIG: Record<
},
2: {
label: 'Fair',
color: 'text-yellow-500',
barColor: 'bg-yellow-500',
color: 'text-warning',
barColor: 'bg-warning',
},
3: {
label: 'Strong',
color: 'text-green-500',
barColor: 'bg-green-500',
color: 'text-success',
barColor: 'bg-success',
},
4: {
label: 'Very Strong',
color: 'text-green-400',
barColor: 'bg-green-400',
color: 'text-success',
barColor: 'bg-success',
},
}

View File

@@ -168,7 +168,7 @@ export function BulkDeployDialog({
{availableDevices.length === 0 ? (
<div className="rounded-lg border border-border bg-elevated/50 p-4 text-center">
<CheckCircle className="h-6 w-6 text-green-500 mx-auto mb-2" />
<CheckCircle className="h-6 w-6 text-success mx-auto mb-2" />
<p className="text-sm font-medium text-text-primary">
All devices have certificates
</p>
@@ -222,7 +222,7 @@ export function BulkDeployDialog({
className={cn(
'text-[10px] uppercase px-1.5 py-0.5 rounded',
d.status === 'online'
? 'bg-green-500/10 text-green-500'
? 'bg-success/10 text-success'
: 'bg-text-muted/10 text-text-muted',
)}
>
@@ -263,9 +263,9 @@ export function BulkDeployDialog({
<div className="space-y-4">
{/* Summary */}
<div className="grid grid-cols-2 gap-3">
<div className="rounded-lg border border-green-500/30 bg-green-500/5 p-4 text-center">
<CheckCircle className="h-6 w-6 text-green-500 mx-auto mb-1" />
<p className="text-2xl font-bold text-green-500">
<div className="rounded-lg border border-success/30 bg-success/5 p-4 text-center">
<CheckCircle className="h-6 w-6 text-success mx-auto mb-1" />
<p className="text-2xl font-bold text-success">
{result.success}
</p>
<p className="text-xs text-text-muted">Succeeded</p>

View File

@@ -76,7 +76,7 @@ export function CAStatusCard({ ca, canWrite: writable, tenantId }: CAStatusCardP
if (!ca) {
return (
<div className="max-w-lg mx-auto">
<div className="rounded-xl border border-border bg-surface p-8 text-center space-y-6">
<div className="rounded-lg border border-border bg-surface p-8 text-center space-y-6">
<div className="mx-auto w-16 h-16 rounded-2xl bg-accent/10 flex items-center justify-center">
<Shield className="h-8 w-8 text-accent" />
</div>
@@ -118,8 +118,8 @@ export function CAStatusCard({ ca, canWrite: writable, tenantId }: CAStatusCardP
return (
<div
className={cn(
'rounded-xl border bg-surface p-6 space-y-4',
isExpired ? 'border-error/40' : 'border-green-500/30',
'rounded-lg border bg-surface p-6 space-y-4',
isExpired ? 'border-error/40' : 'border-success/30',
)}
>
<div className="flex items-center justify-between">
@@ -127,13 +127,13 @@ export function CAStatusCard({ ca, canWrite: writable, tenantId }: CAStatusCardP
<div
className={cn(
'w-10 h-10 rounded-xl flex items-center justify-center',
isExpired ? 'bg-error/10' : 'bg-green-500/10',
isExpired ? 'bg-error/10' : 'bg-success/10',
)}
>
<ShieldCheck
className={cn(
'h-5 w-5',
isExpired ? 'text-error' : 'text-green-500',
isExpired ? 'text-error' : 'text-success',
)}
/>
</div>
@@ -146,7 +146,7 @@ export function CAStatusCard({ ca, canWrite: writable, tenantId }: CAStatusCardP
'inline-flex items-center gap-1 text-[10px] font-medium uppercase px-1.5 py-0.5 rounded border mt-0.5',
isExpired
? 'bg-error/20 text-error border-error/40'
: 'bg-green-500/20 text-green-500 border-green-500/40',
: 'bg-success/20 text-success border-success/40',
)}
>
{isExpired ? 'Expired' : 'Active'}
@@ -175,7 +175,7 @@ export function CAStatusCard({ ca, canWrite: writable, tenantId }: CAStatusCardP
title="Copy fingerprint"
>
{copied ? (
<CheckCircle className="h-3.5 w-3.5 text-green-500" />
<CheckCircle className="h-3.5 w-3.5 text-success" />
) : (
<Copy className="h-3.5 w-3.5" />
)}

View File

@@ -148,7 +148,7 @@ export function DeployCertDialog({
{availableDevices.length === 0 ? (
<div className="rounded-lg border border-border bg-elevated/50 p-4 text-center">
<CheckCircle className="h-6 w-6 text-green-500 mx-auto mb-2" />
<CheckCircle className="h-6 w-6 text-success mx-auto mb-2" />
<p className="text-sm font-medium text-text-primary">
All devices have certificates
</p>
@@ -231,7 +231,7 @@ export function DeployCertDialog({
{step === 'done' && (
<div className="py-8 text-center space-y-3">
<CheckCircle className="h-8 w-8 text-green-500 mx-auto" />
<CheckCircle className="h-8 w-8 text-success mx-auto" />
<p className="text-sm font-medium text-text-primary">
Certificate deployed successfully
</p>

View File

@@ -54,11 +54,11 @@ const STATUS_CONFIG: Record<
},
deployed: {
label: 'Deployed',
className: 'bg-green-500/20 text-green-500 border-green-500/40',
className: 'bg-success/20 text-success border-success/40',
},
expiring: {
label: 'Expiring Soon',
className: 'bg-yellow-500/20 text-yellow-500 border-yellow-500/40',
className: 'bg-warning/20 text-warning border-warning/40',
},
expired: {
label: 'Expired',
@@ -236,7 +236,7 @@ export function DeviceCertTable({
{/* Empty state */}
{filteredCerts.length === 0 ? (
<div className="rounded-xl border border-dashed border-accent/30 bg-accent/5 p-8 text-center space-y-3">
<div className="rounded-lg border border-dashed border-accent/30 bg-accent/5 p-8 text-center space-y-3">
<ShieldCheck className="h-10 w-10 text-accent mx-auto" />
<h3 className="text-base font-semibold text-text-primary">
No device certificates yet

View File

@@ -25,7 +25,7 @@ function triggerBadgeClass(type: ConfigBackupEntry['trigger_type']) {
case 'config-change':
return 'border-orange-500/50 bg-orange-500/10 text-orange-500'
default:
return 'border-muted bg-muted/10 text-muted-foreground'
return 'border-muted bg-muted/10 text-text-muted'
}
}

View File

@@ -67,8 +67,8 @@ export function ConfigHistorySection({ tenantId, deviceId, deviceName }: ConfigH
return (
<div className="rounded-lg border border-border bg-surface p-4">
<div className="flex items-center gap-2 mb-3">
<History className="h-4 w-4 text-muted-foreground" />
<h3 className="text-sm font-medium text-muted-foreground">Configuration History</h3>
<History className="h-4 w-4 text-text-muted" />
<h3 className="text-sm font-medium text-text-muted">Configuration History</h3>
</div>
{selectedSnapshotId && (

View File

@@ -28,7 +28,7 @@ export function DiffViewer({ tenantId, deviceId, snapshotId, onClose }: DiffView
{/* Header */}
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-3">
<h3 className="text-sm font-medium text-muted-foreground">Config Diff</h3>
<h3 className="text-sm font-medium text-text-muted">Config Diff</h3>
{diff && (
<span className="text-xs font-mono">
<span className="text-success">+{diff.lines_added}</span>

View File

@@ -20,10 +20,10 @@ interface RestorePreviewProps {
}
const riskBadgeColors = {
none: 'bg-muted text-text-secondary',
none: 'bg-elevated text-text-secondary',
low: 'bg-success/10 text-success border-success/30',
medium: 'bg-warning/10 text-warning border-warning/30',
high: 'bg-destructive/10 text-destructive border-destructive/30',
high: 'bg-error/10 text-error border-error/30',
} as const
export function RestorePreview({
@@ -53,9 +53,9 @@ export function RestorePreview({
if (isLoading) {
return (
<div className="space-y-4 p-4">
<div className="h-12 rounded-lg bg-muted animate-pulse" />
<div className="h-32 rounded-lg bg-muted animate-pulse" />
<div className="h-16 rounded-lg bg-muted animate-pulse" />
<div className="h-12 rounded-lg bg-elevated animate-pulse" />
<div className="h-32 rounded-lg bg-elevated animate-pulse" />
<div className="h-16 rounded-lg bg-elevated animate-pulse" />
</div>
)
}
@@ -63,10 +63,10 @@ export function RestorePreview({
if (error || !preview) {
return (
<div className="p-4 space-y-4">
<div className="rounded-lg border border-destructive/30 bg-destructive/5 p-4 flex items-start gap-3">
<XCircle className="h-5 w-5 text-destructive shrink-0 mt-0.5" />
<div className="rounded-lg border border-error/30 bg-error/5 p-4 flex items-start gap-3">
<XCircle className="h-5 w-5 text-error shrink-0 mt-0.5" />
<div>
<p className="text-sm font-medium text-destructive">Preview failed</p>
<p className="text-sm font-medium text-error">Preview failed</p>
<p className="text-xs text-text-secondary mt-1">
Could not analyze the config. You may still proceed manually.
</p>
@@ -88,13 +88,13 @@ export function RestorePreview({
<div className="space-y-4 p-4">
{/* Validation errors */}
{!validation.valid && (
<div className="rounded-lg border border-destructive/30 bg-destructive/5 p-3 space-y-1">
<p className="text-sm font-medium text-destructive flex items-center gap-2">
<div className="rounded-lg border border-error/30 bg-error/5 p-3 space-y-1">
<p className="text-sm font-medium text-error flex items-center gap-2">
<XCircle className="h-4 w-4" />
Validation errors found
</p>
{validation.errors.map((err, i) => (
<p key={i} className="text-xs text-destructive/80 ml-6">{err}</p>
<p key={i} className="text-xs text-error/80 ml-6">{err}</p>
))}
</div>
)}
@@ -103,13 +103,13 @@ export function RestorePreview({
<div className="rounded-lg border border-border bg-surface-raised p-3 flex items-center justify-between">
<div className="flex items-center gap-4 text-sm">
<span className="text-success font-mono">+{diff.added}</span>
<span className="text-destructive font-mono">-{diff.removed}</span>
<span className="text-error font-mono">-{diff.removed}</span>
<span className="text-text-secondary">
across {changedCategories.length} categor{changedCategories.length === 1 ? 'y' : 'ies'}
</span>
</div>
{hasHighRisk ? (
<span className="text-xs font-medium text-destructive flex items-center gap-1">
<span className="text-xs font-medium text-error flex items-center gap-1">
<Shield className="h-3 w-3" /> High risk
</span>
) : (
@@ -138,7 +138,7 @@ export function RestorePreview({
</div>
<div className="flex items-center gap-3">
{cat.adds > 0 && <span className="text-xs text-success">+{cat.adds}</span>}
{cat.removes > 0 && <span className="text-xs text-destructive">-{cat.removes}</span>}
{cat.removes > 0 && <span className="text-xs text-error">-{cat.removes}</span>}
<span className={cn(
'text-xs px-1.5 py-0.5 rounded border',
riskBadgeColors[cat.risk],

View File

@@ -41,11 +41,11 @@ export function RollbackAlert({
}
return (
<div className="rounded-lg border border-destructive/30 bg-destructive/5 px-4 py-3 flex items-center justify-between">
<div className="rounded-lg border border-error/30 bg-error/5 px-4 py-3 flex items-center justify-between">
<div className="flex items-center gap-3">
<AlertTriangle className="h-5 w-5 text-destructive shrink-0" />
<AlertTriangle className="h-5 w-5 text-error shrink-0" />
<div>
<p className="text-sm font-medium text-destructive">
<p className="text-sm font-medium text-error">
Device went offline after config change
</p>
<p className="text-xs text-text-secondary mt-0.5">

View File

@@ -166,7 +166,7 @@ export function RemoteWinBoxButton({ tenantId, deviceId }: RemoteWinBoxButtonPro
<button
onClick={handleOpen}
disabled={createMutation.isPending}
className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-accent text-white hover:bg-accent/90 disabled:opacity-50"
>
{createMutation.isPending ? (
<Loader2 className="h-4 w-4 animate-spin" />
@@ -186,11 +186,11 @@ export function RemoteWinBoxButton({ tenantId, deviceId }: RemoteWinBoxButtonPro
</div>
{state === 'failed' && error && (
<div className="mt-2 flex items-center gap-2">
<p className="text-sm text-destructive">{error}</p>
<p className="text-sm text-error">{error}</p>
</div>
)}
{state === 'terminated' && (
<p className="mt-2 text-sm text-muted-foreground">Session ended</p>
<p className="mt-2 text-sm text-text-muted">Session ended</p>
)}
</div>
)
@@ -206,7 +206,7 @@ export function RemoteWinBoxButton({ tenantId, deviceId }: RemoteWinBoxButtonPro
{state === 'requesting' ? 'Requesting session...' : 'Provisioning WinBox container...'}
</p>
</div>
<p className="text-xs text-muted-foreground">This may take a few seconds</p>
<p className="text-xs text-text-muted">This may take a few seconds</p>
</div>
)
}
@@ -234,12 +234,12 @@ export function RemoteWinBoxButton({ tenantId, deviceId }: RemoteWinBoxButtonPro
}
>
{/* Header bar */}
<div className="flex items-center justify-between px-3 py-2 border-b bg-muted/50">
<div className="flex items-center justify-between px-3 py-2 border-b bg-elevated/50">
<div className="flex items-center gap-2">
<Globe className="h-4 w-4 text-primary" />
<Globe className="h-4 w-4 text-accent" />
<span className="text-sm font-medium">Remote WinBox</span>
{countdown && (
<span className="text-xs text-muted-foreground">
<span className="text-xs text-text-muted">
Expires in {countdown}
</span>
)}
@@ -281,7 +281,7 @@ export function RemoteWinBoxButton({ tenantId, deviceId }: RemoteWinBoxButtonPro
// Active but no iframe URL (missing xpra_ws_port) — show reset option
return (
<div className="rounded-md border p-4 space-y-2">
<p className="text-sm text-destructive">Session active but display unavailable</p>
<p className="text-sm text-error">Session active but display unavailable</p>
<button
onClick={handleReset}
className="inline-flex items-center gap-2 px-3 py-1.5 rounded-md border border-input bg-background hover:bg-accent text-sm"

View File

@@ -162,7 +162,7 @@ export function SSHTerminal({ tenantId, deviceId, deviceName }: SSHTerminalProps
return (
<button
onClick={handleOpen}
className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-primary text-primary-foreground hover:bg-primary/90"
className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-accent text-white hover:bg-accent/90"
>
<TerminalIcon className="h-4 w-4" />
SSH Terminal
@@ -172,14 +172,14 @@ export function SSHTerminal({ tenantId, deviceId, deviceName }: SSHTerminalProps
return (
<div className={`rounded-md border overflow-hidden ${expanded ? 'fixed inset-4 z-50 bg-background' : ''}`}>
<div className="flex items-center justify-between px-3 py-2 bg-muted/50 border-b">
<div className="flex items-center justify-between px-3 py-2 bg-elevated/50 border-b">
<span className="text-sm font-medium">SSH: {deviceName}</span>
<div className="flex gap-1">
<button onClick={() => setExpanded(!expanded)} className="p-1 hover:bg-accent rounded">
{expanded ? <Minimize2 className="h-4 w-4" /> : <Maximize2 className="h-4 w-4" />}
</button>
{state === 'disconnected' ? (
<button onClick={handleReconnect} className="px-2 py-1 text-xs rounded bg-primary text-primary-foreground">
<button onClick={handleReconnect} className="px-2 py-1 text-xs rounded bg-accent text-white">
Reconnect
</button>
) : (
@@ -191,7 +191,7 @@ export function SSHTerminal({ tenantId, deviceId, deviceName }: SSHTerminalProps
</div>
<div ref={termRef} className="h-80" tabIndex={0} style={expanded ? { height: 'calc(100% - 40px)' } : {}} />
{state === 'connected' && (
<div className="px-3 py-1 text-xs text-muted-foreground border-t">
<div className="px-3 py-1 text-xs text-text-muted border-t">
SSH session active idle timeout: 15 min
</div>
)}

View File

@@ -78,7 +78,7 @@ export function WinBoxButton({ tenantId, deviceId }: WinBoxButtonProps) {
openMutation.mutate()
}}
disabled={openMutation.isPending}
className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-accent text-white hover:bg-accent/90 disabled:opacity-50"
>
{openMutation.isPending ? (
<Loader2 className="h-4 w-4 animate-spin" />
@@ -87,7 +87,7 @@ export function WinBoxButton({ tenantId, deviceId }: WinBoxButtonProps) {
)}
{openMutation.isPending ? 'Connecting...' : 'Open WinBox'}
</button>
{error && <p className="mt-2 text-sm text-destructive">{error}</p>}
{error && <p className="mt-2 text-sm text-error">{error}</p>}
</div>
)
}
@@ -96,7 +96,7 @@ export function WinBoxButton({ tenantId, deviceId }: WinBoxButtonProps) {
return (
<div className="rounded-md border p-4 space-y-3">
<p className="font-medium text-sm">WinBox tunnel ready</p>
<p className="text-sm text-muted-foreground">
<p className="text-sm text-text-muted">
Connect to: <code className="font-mono">{tunnelInfo.host}:{tunnelInfo.port}</code>
</p>
<div className="flex gap-2">
@@ -119,7 +119,7 @@ export function WinBoxButton({ tenantId, deviceId }: WinBoxButtonProps) {
Close Tunnel
</button>
</div>
<p className="text-xs text-muted-foreground">
<p className="text-xs text-text-muted">
Tunnel closes after 5 min of inactivity
</p>
</div>

View File

@@ -36,8 +36,8 @@ const CONNECTION_LABELS: Record<ConnectionState, string> = {
// Generate a deterministic color from a string
function tenantColor(name: string): string {
const colors = [
'bg-blue-500', 'bg-emerald-500', 'bg-violet-500', 'bg-amber-500',
'bg-rose-500', 'bg-cyan-500', 'bg-pink-500', 'bg-teal-500',
'bg-info', 'bg-success', 'bg-accent', 'bg-warning',
'bg-error', 'bg-info', 'bg-accent', 'bg-success',
]
let hash = 0
for (let i = 0; i < name.length; i++) {

View File

@@ -298,7 +298,7 @@ export function Sidebar() {
role="dialog"
aria-modal="true"
aria-label="Navigation"
className="lg:hidden fixed inset-y-0 left-0 z-50 w-[180px] flex flex-col bg-sidebar border-r border-border shadow-xl"
className="lg:hidden fixed inset-y-0 left-0 z-50 w-[180px] flex flex-col bg-sidebar border-r border-border"
>
{sidebarContent(false)}
</aside>

View File

@@ -294,7 +294,7 @@ export function MaintenanceForm({
onChange={(e) => setNotes(e.target.value)}
placeholder="Reason for maintenance, ticket number, etc."
rows={2}
className="w-full rounded-md border border-border bg-elevated/50 px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-1 focus:ring-ring resize-none"
className="w-full rounded-md border border-border bg-elevated/50 px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:border-accent focus:outline-none resize-none"
/>
</div>

View File

@@ -33,7 +33,7 @@ function CustomTooltip({
}: { active?: boolean; payload?: Array<{ value?: number }>; label?: string; unit: string }) {
if (!active || !payload?.length) return null
return (
<div className="rounded border border-border bg-surface px-2 py-1.5 text-xs text-text-primary shadow-lg">
<div className="rounded border border-border bg-surface px-2 py-1.5 text-xs text-text-primary">
<div className="mb-1 text-text-muted">{label}</div>
<div>
{(payload[0].value ?? 0).toFixed(1)}

View File

@@ -36,7 +36,7 @@ function formatBucket(bucket: string, useDate: boolean): string {
function CustomTooltip({ active, payload, label }: { active?: boolean; payload?: Array<{ value?: number; dataKey?: string; name?: string; color?: string }>; label?: string }) {
if (!active || !payload?.length) return null
return (
<div className="rounded border border-border bg-surface px-2 py-1.5 text-xs text-text-primary shadow-lg">
<div className="rounded border border-border bg-surface px-2 py-1.5 text-xs text-text-primary">
<div className="mb-1 text-text-muted">{label}</div>
{payload.map((entry) => (
<div key={entry.dataKey} className="flex items-center gap-2">

View File

@@ -99,8 +99,8 @@ function DeviceNode({ data }: NodeProps<DeviceNodeData>) {
return (
<div
className={cn(
'rounded-lg border bg-surface shadow-md px-3 py-2 min-w-[180px]',
'transition-shadow hover:shadow-lg',
'rounded-lg border bg-surface px-3 py-2 min-w-[180px]',
'transition-colors',
isOnline ? 'border-border' : 'border-error/30',
)}
>
@@ -152,7 +152,7 @@ interface TooltipData {
function NodeTooltip({ data }: { data: TooltipData; onClose?: () => void }) {
return (
<div
className="absolute z-50 rounded-lg border border-border bg-elevated shadow-lg px-3 py-2 text-xs pointer-events-none"
className="absolute z-50 rounded-lg border border-border bg-elevated px-3 py-2 text-xs pointer-events-none"
style={{ left: data.x + 10, top: data.y - 10 }}
>
<div className="font-medium text-text-primary">{data.hostname}</div>
@@ -339,7 +339,7 @@ export function TopologyMap({ tenantId }: TopologyMapProps) {
>
<Background color="hsl(var(--muted))" gap={20} size={1} />
<Controls
className="!bg-surface !border-border !shadow-md [&>button]:!bg-surface [&>button]:!border-border [&>button]:!text-text-secondary [&>button:hover]:!bg-elevated"
className="!bg-surface !border-border [&>button]:!bg-surface [&>button]:!border-border [&>button]:!text-text-secondary [&>button:hover]:!bg-elevated"
/>
<MiniMap
nodeColor={(node) => {

View File

@@ -232,7 +232,7 @@ export function ReportsPage({ tenantId }: ReportsPageProps) {
disabled={generateMutation.isPending || !tenantId}
className={cn(
'inline-flex items-center gap-2 px-6 py-2.5 rounded-md text-sm font-medium transition-colors',
'bg-primary text-primary-foreground hover:bg-primary/90',
'bg-accent text-white hover:bg-accent/90',
'disabled:opacity-50 disabled:cursor-not-allowed',
)}
>

View File

@@ -264,7 +264,7 @@ export function ApiKeysPage({ tenantId }: ApiKeysPageProps) {
</label>
<input
type="text"
className="w-full rounded-md border border-border-bright bg-elevated/50 px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring"
className="w-full rounded-md border border-border-bright bg-elevated/50 px-3 py-2 text-sm focus:border-accent focus:outline-none"
placeholder="e.g. Monitoring Integration"
value={name}
onChange={(e) => setName(e.target.value)}
@@ -300,7 +300,7 @@ export function ApiKeysPage({ tenantId }: ApiKeysPageProps) {
</label>
<input
type="date"
className="w-full rounded-md border border-border-bright bg-elevated/50 px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring"
className="w-full rounded-md border border-border-bright bg-elevated/50 px-3 py-2 text-sm focus:border-accent focus:outline-none"
value={expiresAt}
onChange={(e) => setExpiresAt(e.target.value)}
min={new Date().toISOString().split('T')[0]}

View File

@@ -215,13 +215,13 @@ export function SettingsPage() {
{/* Delete Account */}
<div className="flex items-center justify-between py-2 border-t border-border/50">
<div>
<span className="text-sm text-destructive">Delete Account</span>
<span className="text-sm text-error">Delete Account</span>
<p className="text-xs text-text-muted">Permanently delete your account and all personal data</p>
</div>
<Button
variant="outline"
size="sm"
className="text-destructive border-destructive/30 hover:bg-destructive/10"
className="text-error border-error/30 hover:bg-error/10"
onClick={() => setShowDeleteDialog(true)}
>
<Trash2 className="h-3.5 w-3.5 mr-1.5" />
@@ -237,7 +237,7 @@ export function SettingsPage() {
}}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 text-destructive">
<DialogTitle className="flex items-center gap-2 text-error">
<AlertTriangle className="h-5 w-5" />
Delete Account
</DialogTitle>
@@ -247,8 +247,8 @@ export function SettingsPage() {
</DialogHeader>
<div className="space-y-4 py-4">
<div className="rounded-md bg-destructive/10 border border-destructive/20 p-3">
<p className="text-sm text-destructive font-medium">This will permanently:</p>
<div className="rounded-md bg-error/10 border border-error/20 p-3">
<p className="text-sm text-error font-medium">This will permanently:</p>
<ul className="text-sm text-text-secondary mt-1 space-y-1 list-disc pl-4">
<li>Delete your user account</li>
<li>Remove all your API keys</li>

View File

@@ -484,7 +484,7 @@ export function SetupWizard() {
<StepIndicator currentStep={step} />
{/* Card */}
<div className="bg-surface border border-border rounded-xl shadow-lg p-8">
<div className="bg-surface border border-border rounded-lg p-8">
{step === 1 && (
<CreateTenantStep
onComplete={(tenant) => {

View File

@@ -201,7 +201,7 @@ export function VpnPage() {
<div className="p-6 space-y-6">
<h1 className="text-2xl font-bold text-text-primary">VPN</h1>
<div className="max-w-lg mx-auto mt-12">
<div className="rounded-xl border border-border bg-surface p-8 text-center space-y-6">
<div className="rounded-lg border border-border bg-surface p-8 text-center space-y-6">
<div className="mx-auto w-16 h-16 rounded-2xl bg-accent/10 flex items-center justify-center">
<Shield className="h-8 w-8 text-accent" />
</div>
@@ -244,8 +244,8 @@ export function VpnPage() {
className={cn(
'inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium',
config.is_enabled
? 'bg-green-500/10 text-green-500'
: 'bg-yellow-500/10 text-yellow-500',
? 'bg-success/10 text-success'
: 'bg-warning/10 text-warning',
)}
>
{config.is_enabled ? (
@@ -271,7 +271,7 @@ export function VpnPage() {
<Button
variant="outline"
size="sm"
className="text-red-400 border-red-800 hover:bg-red-900/30"
className="text-error border-error/30 hover:bg-error/10"
onClick={() => {
if (confirm('Delete VPN configuration? All peers will be removed.')) {
deleteMutation.mutate()
@@ -310,7 +310,7 @@ export function VpnPage() {
{peersLoading ? (
<TableSkeleton rows={3} />
) : peers.length === 0 ? (
<div className="rounded-xl border border-dashed border-accent/30 bg-accent/5 p-8 text-center space-y-3">
<div className="rounded-lg border border-dashed border-accent/30 bg-accent/5 p-8 text-center space-y-3">
<ShieldCheck className="h-10 w-10 text-accent mx-auto" />
<h3 className="text-base font-semibold text-text-primary">VPN is ready</h3>
<p className="text-sm text-text-secondary max-w-md mx-auto">
@@ -346,7 +346,7 @@ export function VpnPage() {
</td>
<td className="px-4 py-3">
{peer.last_handshake ? (
<span className="inline-flex items-center gap-1 text-green-500 text-xs">
<span className="inline-flex items-center gap-1 text-success text-xs">
<Wifi className="h-3 w-3" /> Connected
</span>
) : (
@@ -373,7 +373,7 @@ export function VpnPage() {
variant="ghost"
size="sm"
onClick={() => removePeerMutation.mutate(peer.id)}
className="text-red-400 hover:text-red-300"
className="text-error hover:text-error/80"
title="Remove from VPN"
>
<Trash2 className="h-4 w-4" />
@@ -400,7 +400,7 @@ export function VpnPage() {
</p>
{availableDevices.length === 0 ? (
<div className="rounded-lg border border-border bg-elevated/50 p-4 text-center">
<CheckCircle className="h-6 w-6 text-green-500 mx-auto mb-2" />
<CheckCircle className="h-6 w-6 text-success mx-auto mb-2" />
<p className="text-sm font-medium text-text-primary">All devices are on VPN</p>
<p className="text-xs text-text-muted mt-1">
Every device in your fleet is already connected. Add more devices to your fleet first.
@@ -454,7 +454,7 @@ export function VpnPage() {
className="absolute top-2 right-2"
onClick={() => copyToClipboard(peerConfig.routeros_commands.join('\n'))}
>
{copied ? <CheckCircle className="h-4 w-4 text-green-500" /> : <Copy className="h-4 w-4" />}
{copied ? <CheckCircle className="h-4 w-4 text-success" /> : <Copy className="h-4 w-4" />}
</Button>
</div>
<div className="grid grid-cols-2 gap-3 text-sm">

View File

@@ -672,7 +672,7 @@ function DeviceDetailPage() {
{/* Interface Utilization */}
<div className="rounded-lg border border-border bg-surface p-4">
<h3 className="text-sm font-medium text-muted-foreground mb-3">Interface Utilization</h3>
<h3 className="text-sm font-medium text-text-muted mb-3">Interface Utilization</h3>
<InterfaceGauges tenantId={tenantId} deviceId={deviceId} active={activeTab === 'overview'} />
</div>

View File

@@ -13,25 +13,25 @@ export const Route = createFileRoute('/_authenticated/traffic')({
function cpuColor(cpu: number | null): string {
if (cpu === null) return 'text-text-muted'
if (cpu < 50) return 'text-emerald-400'
if (cpu < 80) return 'text-yellow-400'
return 'text-red-400'
if (cpu < 50) return 'text-success'
if (cpu < 80) return 'text-warning'
return 'text-error'
}
function memColor(mem: number | null): string {
if (mem === null) return 'text-text-muted'
if (mem < 60) return 'text-emerald-400'
if (mem < 85) return 'text-yellow-400'
return 'text-red-400'
if (mem < 60) return 'text-success'
if (mem < 85) return 'text-warning'
return 'text-error'
}
function statusDot(status: string) {
const color =
status === 'online'
? 'bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.6)]'
? 'bg-success'
: status === 'degraded'
? 'bg-yellow-400 shadow-[0_0_6px_rgba(250,204,21,0.6)]'
: 'bg-red-400 shadow-[0_0_6px_rgba(248,113,113,0.6)]'
? 'bg-warning'
: 'bg-error'
return <span className={cn('inline-block h-2 w-2 rounded-full', color)} />
}

View File

@@ -13,9 +13,9 @@ export const Route = createFileRoute('/_authenticated/wireless')({
function signalColor(signal: number | null): string {
if (signal === null) return 'text-text-muted'
if (signal > -60) return 'text-emerald-400'
if (signal > -70) return 'text-yellow-400'
return 'text-red-400'
if (signal > -60) return 'text-success'
if (signal > -70) return 'text-warning'
return 'text-error'
}
function WirelessPage() {
@@ -105,7 +105,7 @@ function WirelessPage() {
) : issues.length === 0 ? (
<Card className="border-border bg-surface">
<CardContent className="flex flex-col items-center justify-center gap-3 p-12">
<CheckCircle2 className="h-10 w-10 text-emerald-400" />
<CheckCircle2 className="h-10 w-10 text-success" />
<p className="text-sm font-medium text-text-secondary">
All Clear no wireless issues detected
</p>
@@ -153,7 +153,7 @@ function WirelessPage() {
>
<td className="px-4 py-3 text-sm text-text-secondary">
<div className="flex items-center gap-2">
<span className="inline-block h-2 w-2 rounded-full bg-red-400 shadow-[0_0_6px_rgba(248,113,113,0.6)]" />
<span className="inline-block h-2 w-2 rounded-full bg-error" />
{issue.hostname}
</div>
</td>