@supaku/agentfactory-dashboard 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,7 +21,7 @@ export function SessionList({ onSelect, className }: SessionListProps) {
21
21
 
22
22
  if (isLoading) {
23
23
  return (
24
- <div className={cn('space-y-2 p-5', className)}>
24
+ <div className={cn('space-y-2 p-6', className)}>
25
25
  {Array.from({ length: 6 }).map((_, i) => (
26
26
  <Skeleton key={i} className="h-14 rounded-lg" />
27
27
  ))}
@@ -31,7 +31,7 @@ export function SessionList({ onSelect, className }: SessionListProps) {
31
31
 
32
32
  if (sessions.length === 0) {
33
33
  return (
34
- <div className="p-5">
34
+ <div className="p-6">
35
35
  <EmptyState
36
36
  title="No sessions"
37
37
  description="Agent sessions will appear here once they start."
@@ -41,60 +41,76 @@ export function SessionList({ onSelect, className }: SessionListProps) {
41
41
  }
42
42
 
43
43
  return (
44
- <div className={cn('p-5', className)}>
45
- <div className="rounded-lg border border-af-surface-border overflow-hidden">
46
- <table className="w-full text-sm">
44
+ <div className={cn('p-6', className)}>
45
+ <div className="mb-5 flex items-center gap-3">
46
+ <h2 className="font-display text-lg font-bold text-af-text-primary tracking-tight">
47
+ Sessions
48
+ </h2>
49
+ <span className="rounded-full bg-af-surface/60 px-2 py-0.5 text-2xs font-body font-medium tabular-nums text-af-text-secondary">
50
+ {sessions.length}
51
+ </span>
52
+ </div>
53
+
54
+ <div className="rounded-xl border border-af-surface-border/40 overflow-hidden">
55
+ <table className="w-full text-sm font-body">
47
56
  <thead>
48
- <tr className="border-b border-af-surface-border bg-af-bg-secondary">
49
- <th className="px-4 py-2.5 text-left text-xs font-medium text-af-text-secondary">Issue</th>
50
- <th className="px-4 py-2.5 text-left text-xs font-medium text-af-text-secondary">Status</th>
51
- <th className="px-4 py-2.5 text-left text-xs font-medium text-af-text-secondary">Type</th>
52
- <th className="px-4 py-2.5 text-left text-xs font-medium text-af-text-secondary">Duration</th>
53
- <th className="px-4 py-2.5 text-left text-xs font-medium text-af-text-secondary">Cost</th>
54
- <th className="px-4 py-2.5 text-left text-xs font-medium text-af-text-secondary">Started</th>
57
+ <tr className="border-b border-af-surface-border/40 bg-af-bg-secondary/50">
58
+ <th className="px-4 py-3 text-left text-2xs font-semibold uppercase tracking-wider text-af-text-tertiary">Issue</th>
59
+ <th className="px-4 py-3 text-left text-2xs font-semibold uppercase tracking-wider text-af-text-tertiary">Status</th>
60
+ <th className="px-4 py-3 text-left text-2xs font-semibold uppercase tracking-wider text-af-text-tertiary">Type</th>
61
+ <th className="px-4 py-3 text-left text-2xs font-semibold uppercase tracking-wider text-af-text-tertiary">Duration</th>
62
+ <th className="px-4 py-3 text-left text-2xs font-semibold uppercase tracking-wider text-af-text-tertiary">Cost</th>
63
+ <th className="px-4 py-3 text-left text-2xs font-semibold uppercase tracking-wider text-af-text-tertiary">Started</th>
55
64
  </tr>
56
65
  </thead>
57
66
  <tbody>
58
- {sessions.map((session) => {
67
+ {sessions.map((session, i) => {
59
68
  const statusConfig = getStatusConfig(session.status)
60
69
  const workTypeConfig = getWorkTypeConfig(session.workType)
61
70
  return (
62
71
  <tr
63
72
  key={session.id}
64
- className="border-b border-af-surface-border last:border-0 hover:bg-af-surface/50 cursor-pointer transition-colors"
73
+ className={cn(
74
+ 'border-b border-af-surface-border/20 last:border-0 cursor-pointer transition-all duration-200',
75
+ 'hover:bg-af-surface/30'
76
+ )}
65
77
  onClick={() => onSelect?.(session.id)}
78
+ style={{ animationDelay: `${i * 30}ms` }}
66
79
  >
67
- <td className="px-4 py-2.5">
80
+ <td className="px-4 py-3">
68
81
  <span className="font-mono text-sm text-af-text-primary">{session.identifier}</span>
69
82
  </td>
70
- <td className="px-4 py-2.5">
71
- <div className="flex items-center gap-1.5">
83
+ <td className="px-4 py-3">
84
+ <div className="flex items-center gap-2">
72
85
  <StatusDot status={session.status} />
73
86
  <span className={cn('text-xs', statusConfig.textColor)}>
74
87
  {statusConfig.label}
75
88
  </span>
76
89
  </div>
77
90
  </td>
78
- <td className="px-4 py-2.5">
91
+ <td className="px-4 py-3">
79
92
  <Badge
80
93
  variant="outline"
81
- className={cn('text-xs', workTypeConfig.bgColor, workTypeConfig.color, 'border-transparent')}
94
+ className={cn(
95
+ 'text-2xs border',
96
+ workTypeConfig.bgColor, workTypeConfig.color, workTypeConfig.borderColor
97
+ )}
82
98
  >
83
99
  {workTypeConfig.label}
84
100
  </Badge>
85
101
  </td>
86
- <td className="px-4 py-2.5">
102
+ <td className="px-4 py-3">
87
103
  <span className="text-xs text-af-text-secondary tabular-nums">
88
104
  {formatDuration(session.duration)}
89
105
  </span>
90
106
  </td>
91
- <td className="px-4 py-2.5">
107
+ <td className="px-4 py-3">
92
108
  <span className="text-xs text-af-text-secondary tabular-nums font-mono">
93
109
  {formatCost(session.costUsd)}
94
110
  </span>
95
111
  </td>
96
- <td className="px-4 py-2.5">
97
- <span className="text-xs text-af-text-secondary">
112
+ <td className="px-4 py-3">
113
+ <span className="text-xs text-af-text-tertiary">
98
114
  {formatRelativeTime(session.startedAt)}
99
115
  </span>
100
116
  </td>
@@ -13,42 +13,64 @@ interface SessionTimelineProps {
13
13
  className?: string
14
14
  }
15
15
 
16
- const typeColors = {
17
- info: 'bg-blue-400',
18
- success: 'bg-af-status-success',
19
- warning: 'bg-af-status-warning',
20
- error: 'bg-af-status-error',
16
+ const typeStyles = {
17
+ info: {
18
+ dot: 'bg-af-blue',
19
+ glow: 'shadow-[0_0_8px_2px_rgba(75,139,245,0.3)]',
20
+ line: 'bg-af-blue/20',
21
+ },
22
+ success: {
23
+ dot: 'bg-af-status-success',
24
+ glow: 'shadow-[0_0_8px_2px_rgba(34,197,94,0.3)]',
25
+ line: 'bg-af-status-success/20',
26
+ },
27
+ warning: {
28
+ dot: 'bg-af-status-warning',
29
+ glow: 'shadow-[0_0_8px_2px_rgba(245,158,11,0.3)]',
30
+ line: 'bg-af-status-warning/20',
31
+ },
32
+ error: {
33
+ dot: 'bg-af-status-error',
34
+ glow: 'shadow-[0_0_8px_2px_rgba(239,68,68,0.3)]',
35
+ line: 'bg-af-status-error/20',
36
+ },
21
37
  }
22
38
 
23
39
  export function SessionTimeline({ events, className }: SessionTimelineProps) {
24
40
  return (
25
41
  <div className={cn('relative space-y-0', className)}>
26
- {/* Vertical line */}
27
- <div className="absolute left-[7px] top-2 bottom-2 w-px bg-af-surface-border" />
42
+ {/* Vertical connector line */}
43
+ {events.length > 1 && (
44
+ <div className="absolute left-[5px] top-3 bottom-3 w-px bg-af-surface-border/40" />
45
+ )}
28
46
 
29
- {events.map((event, i) => (
30
- <div key={event.id} className="relative flex gap-3 py-2">
31
- {/* Dot */}
32
- <span
33
- className={cn(
34
- 'relative z-10 mt-1 h-[14px] w-[14px] shrink-0 rounded-full border-2 border-af-bg-primary',
35
- typeColors[event.type ?? 'info']
36
- )}
37
- />
47
+ {events.map((event) => {
48
+ const styles = typeStyles[event.type ?? 'info']
49
+ return (
50
+ <div key={event.id} className="relative flex gap-3.5 py-2.5">
51
+ {/* Glowing dot */}
52
+ <span
53
+ className={cn(
54
+ 'relative z-10 mt-1.5 h-[10px] w-[10px] shrink-0 rounded-full',
55
+ styles.dot,
56
+ styles.glow
57
+ )}
58
+ />
38
59
 
39
- <div className="flex-1 min-w-0">
40
- <div className="flex items-baseline justify-between gap-2">
41
- <span className="text-sm text-af-text-primary">{event.label}</span>
42
- <span className="text-xs text-af-text-secondary whitespace-nowrap">
43
- {new Date(event.timestamp).toLocaleTimeString()}
44
- </span>
60
+ <div className="flex-1 min-w-0">
61
+ <div className="flex items-baseline justify-between gap-2">
62
+ <span className="text-sm font-body text-af-text-primary">{event.label}</span>
63
+ <span className="text-2xs font-body text-af-text-tertiary whitespace-nowrap tabular-nums">
64
+ {new Date(event.timestamp).toLocaleTimeString()}
65
+ </span>
66
+ </div>
67
+ {event.detail && (
68
+ <p className="mt-0.5 text-xs font-body text-af-text-tertiary">{event.detail}</p>
69
+ )}
45
70
  </div>
46
- {event.detail && (
47
- <p className="mt-0.5 text-xs text-af-text-secondary">{event.detail}</p>
48
- )}
49
71
  </div>
50
- </div>
51
- ))}
72
+ )
73
+ })}
52
74
  </div>
53
75
  )
54
76
  }
@@ -15,35 +15,35 @@ export function TokenChart({ inputTokens = 0, outputTokens = 0, className }: Tok
15
15
  const outputPct = (outputTokens / total) * 100
16
16
 
17
17
  return (
18
- <div className={cn('space-y-2', className)}>
19
- <div className="flex items-center justify-between text-xs text-af-text-secondary">
20
- <span>Token Usage</span>
21
- <span className="tabular-nums font-mono">{formatTokens(total)} total</span>
18
+ <div className={cn('space-y-3', className)}>
19
+ <div className="flex items-center justify-between text-2xs font-body">
20
+ <span className="uppercase tracking-wider text-af-text-tertiary">Token Usage</span>
21
+ <span className="tabular-nums font-mono text-af-text-secondary">{formatTokens(total)} total</span>
22
22
  </div>
23
23
 
24
24
  {/* Bar */}
25
- <div className="flex h-3 w-full overflow-hidden rounded-full bg-af-bg-primary">
25
+ <div className="flex h-2.5 w-full overflow-hidden rounded-full bg-af-bg-primary/60">
26
26
  <div
27
- className="bg-blue-400 transition-all"
27
+ className="bg-af-blue rounded-l-full transition-all duration-500"
28
28
  style={{ width: `${inputPct}%` }}
29
29
  />
30
30
  <div
31
- className="bg-af-accent transition-all"
31
+ className="bg-af-accent transition-all duration-500"
32
32
  style={{ width: `${outputPct}%` }}
33
33
  />
34
34
  </div>
35
35
 
36
36
  {/* Legend */}
37
- <div className="flex items-center gap-4 text-xs">
37
+ <div className="flex items-center gap-5 text-2xs font-body">
38
38
  <div className="flex items-center gap-1.5">
39
- <span className="h-2 w-2 rounded-full bg-blue-400" />
40
- <span className="text-af-text-secondary">Input</span>
41
- <span className="tabular-nums font-mono text-af-text-primary">{formatTokens(inputTokens)}</span>
39
+ <span className="h-2 w-2 rounded-full bg-af-blue shadow-[0_0_6px_1px_rgba(75,139,245,0.3)]" />
40
+ <span className="text-af-text-tertiary">Input</span>
41
+ <span className="tabular-nums font-mono text-af-text-secondary">{formatTokens(inputTokens)}</span>
42
42
  </div>
43
43
  <div className="flex items-center gap-1.5">
44
- <span className="h-2 w-2 rounded-full bg-af-accent" />
45
- <span className="text-af-text-secondary">Output</span>
46
- <span className="tabular-nums font-mono text-af-text-primary">{formatTokens(outputTokens)}</span>
44
+ <span className="h-2 w-2 rounded-full bg-af-accent shadow-[0_0_6px_1px_rgba(255,107,53,0.3)]" />
45
+ <span className="text-af-text-tertiary">Output</span>
46
+ <span className="tabular-nums font-mono text-af-text-secondary">{formatTokens(outputTokens)}</span>
47
47
  </div>
48
48
  </div>
49
49
  </div>
@@ -1,14 +1,13 @@
1
1
  'use client'
2
2
 
3
3
  import { cn } from '../../lib/utils'
4
- import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '../../components/ui/card'
5
4
  import { Badge } from '../../components/ui/badge'
6
5
  import { Separator } from '../../components/ui/separator'
7
6
  import { useStats } from '../../hooks/use-stats'
8
7
  import { useWorkers } from '../../hooks/use-workers'
9
8
  import { ProviderIcon } from '../../components/fleet/provider-icon'
10
9
  import { StatusDot } from '../../components/fleet/status-dot'
11
- import { CheckCircle2, AlertCircle, Settings2 } from 'lucide-react'
10
+ import { CheckCircle2, AlertCircle, Settings2, Webhook, Server, Shield } from 'lucide-react'
12
11
 
13
12
  interface SettingsViewProps {
14
13
  className?: string
@@ -22,97 +21,106 @@ export function SettingsView({ className }: SettingsViewProps) {
22
21
  const hasWorkerAuth = workersData !== null
23
22
 
24
23
  return (
25
- <div className={cn('space-y-6 p-5 max-w-3xl', className)}>
24
+ <div className={cn('space-y-6 p-6 max-w-3xl', className)}>
25
+ {/* Page header */}
26
26
  <div>
27
- <h1 className="text-lg font-semibold text-af-text-primary">Settings</h1>
28
- <p className="text-sm text-af-text-secondary">
27
+ <h1 className="font-display text-xl font-bold text-af-text-primary tracking-tight">Settings</h1>
28
+ <p className="mt-1 text-sm font-body text-af-text-secondary">
29
29
  Configuration and integration status for your AgentFactory instance.
30
30
  </p>
31
31
  </div>
32
32
 
33
33
  {/* Integration Status */}
34
- <Card>
35
- <CardHeader>
36
- <CardTitle>Integration Status</CardTitle>
37
- <CardDescription>Connected services and API endpoints</CardDescription>
38
- </CardHeader>
39
- <CardContent className="space-y-4">
34
+ <div className="rounded-xl border border-af-surface-border/40 bg-af-surface/30 overflow-hidden">
35
+ <div className="px-6 py-4 border-b border-af-surface-border/30">
36
+ <h3 className="flex items-center gap-2 font-display text-sm font-semibold text-af-text-primary tracking-tight">
37
+ <Webhook className="h-4 w-4 text-af-text-tertiary" />
38
+ Integration Status
39
+ </h3>
40
+ <p className="mt-0.5 text-xs font-body text-af-text-tertiary">Connected services and API endpoints</p>
41
+ </div>
42
+
43
+ <div className="px-6 py-4 space-y-4">
40
44
  <div className="flex items-center justify-between">
41
45
  <div className="flex items-center gap-3">
42
46
  <CheckCircle2 className="h-4 w-4 text-af-status-success" />
43
47
  <div>
44
- <p className="text-sm text-af-text-primary">Linear Webhook</p>
45
- <p className="text-xs text-af-text-secondary font-mono">/webhook</p>
48
+ <p className="text-sm font-body text-af-text-primary">Linear Webhook</p>
49
+ <p className="text-2xs font-mono text-af-text-tertiary">/webhook</p>
46
50
  </div>
47
51
  </div>
48
52
  <Badge variant="success">Connected</Badge>
49
53
  </div>
50
54
 
51
- <Separator />
55
+ <Separator className="bg-af-surface-border/30" />
52
56
 
53
57
  <div className="flex items-center justify-between">
54
58
  <div className="flex items-center gap-3">
55
59
  <CheckCircle2 className="h-4 w-4 text-af-status-success" />
56
60
  <div>
57
- <p className="text-sm text-af-text-primary">Public API</p>
58
- <p className="text-xs text-af-text-secondary font-mono">/api/public/stats</p>
61
+ <p className="text-sm font-body text-af-text-primary">Public API</p>
62
+ <p className="text-2xs font-mono text-af-text-tertiary">/api/public/stats</p>
59
63
  </div>
60
64
  </div>
61
65
  <Badge variant="success">Active</Badge>
62
66
  </div>
63
67
 
64
- <Separator />
68
+ <Separator className="bg-af-surface-border/30" />
65
69
 
66
70
  <div className="flex items-center justify-between">
67
71
  <div className="flex items-center gap-3">
68
72
  {hasWorkerAuth ? (
69
73
  <CheckCircle2 className="h-4 w-4 text-af-status-success" />
70
74
  ) : (
71
- <AlertCircle className="h-4 w-4 text-af-text-secondary" />
75
+ <AlertCircle className="h-4 w-4 text-af-text-tertiary" />
72
76
  )}
73
77
  <div>
74
- <p className="text-sm text-af-text-primary">Worker API</p>
75
- <p className="text-xs text-af-text-secondary font-mono">/api/workers</p>
78
+ <p className="text-sm font-body text-af-text-primary">Worker API</p>
79
+ <p className="text-2xs font-mono text-af-text-tertiary">/api/workers</p>
76
80
  </div>
77
81
  </div>
78
82
  <Badge variant={hasWorkerAuth ? 'success' : 'secondary'}>
79
83
  {hasWorkerAuth ? 'Authenticated' : 'No Auth Key'}
80
84
  </Badge>
81
85
  </div>
82
- </CardContent>
83
- </Card>
86
+ </div>
87
+ </div>
84
88
 
85
89
  {/* Workers */}
86
- <Card>
87
- <CardHeader>
88
- <CardTitle>Workers</CardTitle>
89
- <CardDescription>
90
+ <div className="rounded-xl border border-af-surface-border/40 bg-af-surface/30 overflow-hidden">
91
+ <div className="px-6 py-4 border-b border-af-surface-border/30">
92
+ <h3 className="flex items-center gap-2 font-display text-sm font-semibold text-af-text-primary tracking-tight">
93
+ <Server className="h-4 w-4 text-af-text-tertiary" />
94
+ Workers
95
+ </h3>
96
+ <p className="mt-0.5 text-xs font-body text-af-text-tertiary">
90
97
  {workers.length > 0
91
98
  ? `${workers.length} worker${workers.length !== 1 ? 's' : ''} registered`
92
99
  : 'No workers connected'}
93
- </CardDescription>
94
- </CardHeader>
95
- <CardContent>
100
+ </p>
101
+ </div>
102
+
103
+ <div className="px-6 py-4">
96
104
  {workers.length === 0 ? (
97
- <p className="text-sm text-af-text-secondary">
105
+ <p className="text-sm font-body text-af-text-tertiary">
98
106
  Workers will appear here once they register with the server.
99
107
  </p>
100
108
  ) : (
101
109
  <div className="space-y-3">
102
110
  {workers.map((worker) => (
103
- <div key={worker.id} className="flex items-center justify-between">
111
+ <div key={worker.id} className="flex items-center justify-between py-1">
104
112
  <div className="flex items-center gap-3">
105
113
  <StatusDot status={worker.status === 'active' ? 'working' : 'stopped'} />
106
114
  <div>
107
115
  <p className="text-sm font-mono text-af-text-primary">
108
116
  {worker.hostname ?? worker.id.slice(0, 8)}
109
117
  </p>
110
- <p className="text-xs text-af-text-secondary">
118
+ <p className="text-2xs font-body text-af-text-tertiary">
111
119
  {worker.activeSessions}/{worker.capacity} slots
112
120
  </p>
113
121
  </div>
114
122
  </div>
115
- <div className="flex items-center gap-2">
123
+ <div className="flex items-center gap-2.5">
116
124
  <ProviderIcon provider={worker.provider} size={14} />
117
125
  <Badge variant={worker.status === 'active' ? 'success' : 'secondary'}>
118
126
  {worker.status}
@@ -122,34 +130,35 @@ export function SettingsView({ className }: SettingsViewProps) {
122
130
  ))}
123
131
  </div>
124
132
  )}
125
- </CardContent>
126
- </Card>
133
+ </div>
134
+ </div>
127
135
 
128
136
  {/* Fleet Stats */}
129
- <Card>
130
- <CardHeader>
131
- <CardTitle className="flex items-center gap-2">
132
- <Settings2 className="h-4 w-4" />
137
+ <div className="rounded-xl border border-af-surface-border/40 bg-af-surface/30 overflow-hidden">
138
+ <div className="px-6 py-4 border-b border-af-surface-border/30">
139
+ <h3 className="flex items-center gap-2 font-display text-sm font-semibold text-af-text-primary tracking-tight">
140
+ <Shield className="h-4 w-4 text-af-text-tertiary" />
133
141
  Fleet Configuration
134
- </CardTitle>
135
- </CardHeader>
136
- <CardContent>
137
- <dl className="grid grid-cols-2 gap-4 text-sm">
138
- <div>
139
- <dt className="text-af-text-secondary">Total Capacity</dt>
140
- <dd className="mt-0.5 text-af-text-primary font-medium">
142
+ </h3>
143
+ </div>
144
+
145
+ <div className="px-6 py-4">
146
+ <div className="grid grid-cols-2 gap-6">
147
+ <div className="space-y-1">
148
+ <dt className="text-2xs font-body uppercase tracking-wider text-af-text-tertiary">Total Capacity</dt>
149
+ <dd className="font-display text-lg font-bold tabular-nums text-af-text-primary">
141
150
  {stats?.availableCapacity ?? '—'}
142
151
  </dd>
143
152
  </div>
144
- <div>
145
- <dt className="text-af-text-secondary">Workers Online</dt>
146
- <dd className="mt-0.5 text-af-text-primary font-medium">
153
+ <div className="space-y-1">
154
+ <dt className="text-2xs font-body uppercase tracking-wider text-af-text-tertiary">Workers Online</dt>
155
+ <dd className="font-display text-lg font-bold tabular-nums text-af-text-primary">
147
156
  {stats?.workersOnline ?? '—'}
148
157
  </dd>
149
158
  </div>
150
- </dl>
151
- </CardContent>
152
- </Card>
159
+ </div>
160
+ </div>
161
+ </div>
153
162
  </div>
154
163
  )
155
164
  }
@@ -17,13 +17,18 @@ export function EmptyState({
17
17
  children,
18
18
  }: EmptyStateProps) {
19
19
  return (
20
- <div className={cn('flex flex-col items-center justify-center py-12 text-center', className)}>
21
- <div className="mb-4 text-af-text-secondary">
22
- {icon ?? <Inbox className="h-10 w-10" />}
20
+ <div className={cn(
21
+ 'flex flex-col items-center justify-center py-16 text-center',
22
+ className
23
+ )}>
24
+ <div className="mb-4 rounded-xl border border-af-surface-border/30 bg-af-surface/20 p-4">
25
+ <div className="text-af-text-tertiary">
26
+ {icon ?? <Inbox className="h-8 w-8" />}
27
+ </div>
23
28
  </div>
24
- <h3 className="text-sm font-medium text-af-text-primary">{title}</h3>
25
- <p className="mt-1 text-sm text-af-text-secondary">{description}</p>
26
- {children && <div className="mt-4">{children}</div>}
29
+ <h3 className="font-display text-sm font-semibold text-af-text-primary tracking-tight">{title}</h3>
30
+ <p className="mt-1.5 max-w-xs text-xs font-body text-af-text-tertiary">{description}</p>
31
+ {children && <div className="mt-5">{children}</div>}
27
32
  </div>
28
33
  )
29
34
  }
@@ -3,17 +3,17 @@ import { cva, type VariantProps } from 'class-variance-authority'
3
3
  import { cn } from '../../lib/utils'
4
4
 
5
5
  const badgeVariants = cva(
6
- 'inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
6
+ 'inline-flex items-center rounded-full border px-2 py-0.5 text-2xs font-medium font-body transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
7
7
  {
8
8
  variants: {
9
9
  variant: {
10
10
  default: 'border-transparent bg-primary text-primary-foreground',
11
- secondary: 'border-transparent bg-secondary text-secondary-foreground',
11
+ secondary: 'border-af-surface-border/40 bg-af-surface/40 text-af-text-secondary',
12
12
  destructive: 'border-transparent bg-destructive text-destructive-foreground',
13
13
  outline: 'text-foreground',
14
- success: 'border-transparent bg-af-status-success/10 text-af-status-success',
15
- warning: 'border-transparent bg-af-status-warning/10 text-af-status-warning',
16
- error: 'border-transparent bg-af-status-error/10 text-af-status-error',
14
+ success: 'border-af-status-success/20 bg-af-status-success/10 text-af-status-success',
15
+ warning: 'border-af-status-warning/20 bg-af-status-warning/10 text-af-status-warning',
16
+ error: 'border-af-status-error/20 bg-af-status-error/10 text-af-status-error',
17
17
  },
18
18
  },
19
19
  defaultVariants: {
@@ -6,21 +6,21 @@ import { cva, type VariantProps } from 'class-variance-authority'
6
6
  import { cn } from '../../lib/utils'
7
7
 
8
8
  const buttonVariants = cva(
9
- 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
9
+ 'inline-flex items-center justify-center whitespace-nowrap rounded-lg text-sm font-medium font-body ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
10
10
  {
11
11
  variants: {
12
12
  variant: {
13
- default: 'bg-primary text-primary-foreground hover:bg-primary/90',
13
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90 glow-soft',
14
14
  destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
15
- outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
16
- secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
17
- ghost: 'hover:bg-accent hover:text-accent-foreground',
15
+ outline: 'border border-af-surface-border/50 bg-transparent hover:bg-af-surface/40 hover:text-accent-foreground',
16
+ secondary: 'bg-af-surface/60 text-secondary-foreground hover:bg-af-surface/80',
17
+ ghost: 'hover:bg-af-surface/40 hover:text-accent-foreground',
18
18
  link: 'text-primary underline-offset-4 hover:underline',
19
19
  },
20
20
  size: {
21
21
  default: 'h-9 px-4 py-2',
22
- sm: 'h-8 rounded-md px-3',
23
- lg: 'h-10 rounded-md px-8',
22
+ sm: 'h-8 rounded-lg px-3',
23
+ lg: 'h-10 rounded-lg px-8',
24
24
  icon: 'h-9 w-9',
25
25
  },
26
26
  },
@@ -5,7 +5,10 @@ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElemen
5
5
  ({ className, ...props }, ref) => (
6
6
  <div
7
7
  ref={ref}
8
- className={cn('rounded-lg border border-af-surface-border bg-af-surface text-card-foreground', className)}
8
+ className={cn(
9
+ 'rounded-xl border border-af-surface-border/40 bg-af-surface/40 text-card-foreground',
10
+ className
11
+ )}
9
12
  {...props}
10
13
  />
11
14
  )
@@ -14,35 +17,39 @@ Card.displayName = 'Card'
14
17
 
15
18
  const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
16
19
  ({ className, ...props }, ref) => (
17
- <div ref={ref} className={cn('flex flex-col space-y-1.5 p-5', className)} {...props} />
20
+ <div ref={ref} className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />
18
21
  )
19
22
  )
20
23
  CardHeader.displayName = 'CardHeader'
21
24
 
22
25
  const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
23
26
  ({ className, ...props }, ref) => (
24
- <h3 ref={ref} className={cn('text-sm font-medium leading-none tracking-tight', className)} {...props} />
27
+ <h3
28
+ ref={ref}
29
+ className={cn('font-display text-sm font-semibold leading-none tracking-tight', className)}
30
+ {...props}
31
+ />
25
32
  )
26
33
  )
27
34
  CardTitle.displayName = 'CardTitle'
28
35
 
29
36
  const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
30
37
  ({ className, ...props }, ref) => (
31
- <p ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
38
+ <p ref={ref} className={cn('text-xs font-body text-muted-foreground', className)} {...props} />
32
39
  )
33
40
  )
34
41
  CardDescription.displayName = 'CardDescription'
35
42
 
36
43
  const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
37
44
  ({ className, ...props }, ref) => (
38
- <div ref={ref} className={cn('p-5 pt-0', className)} {...props} />
45
+ <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
39
46
  )
40
47
  )
41
48
  CardContent.displayName = 'CardContent'
42
49
 
43
50
  const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
44
51
  ({ className, ...props }, ref) => (
45
- <div ref={ref} className={cn('flex items-center p-5 pt-0', className)} {...props} />
52
+ <div ref={ref} className={cn('flex items-center p-6 pt-0', className)} {...props} />
46
53
  )
47
54
  )
48
55
  CardFooter.displayName = 'CardFooter'
@@ -3,7 +3,10 @@ import { cn } from '../../lib/utils'
3
3
  function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
4
4
  return (
5
5
  <div
6
- className={cn('animate-pulse rounded-md bg-muted', className)}
6
+ className={cn(
7
+ 'animate-pulse rounded-lg bg-af-surface/60',
8
+ className
9
+ )}
7
10
  {...props}
8
11
  />
9
12
  )