Henri Bonamy commited on
Commit
c1f951a
·
1 Parent(s): b7bfe6f

improved design

Browse files
frontend/index.html CHANGED
@@ -2,7 +2,7 @@
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
  <title>HF Agent</title>
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/png" href="/hf-log-only-white.png" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
  <title>HF Agent</title>
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
frontend/src/components/Chat/ApprovalFlow.tsx CHANGED
@@ -95,62 +95,104 @@ export default function ApprovalFlow({ sessionId }: ApprovalFlowProps) {
95
  const currentTool = pendingApprovals.tools[currentIndex];
96
 
97
  return (
98
- <Box sx={{
99
- mt: 0,
100
- mb: 4,
101
- px: 2,
102
- width: '100%',
103
- alignSelf: 'center'
104
- }}>
105
- <Typography variant="subtitle2" sx={{ fontFamily: 'monospace', mb: 2, fontWeight: 600 }}>
106
- ACTION REQUIRED ({currentIndex + 1}/{pendingApprovals.count}) : The agent wants to execute <Box component="span" sx={{ color: 'primary.main' }}>{currentTool.tool}</Box>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  </Typography>
108
 
109
  <Box component="pre" sx={{
110
- bgcolor: 'background.default',
111
- p: 1.5,
112
- borderRadius: 0.5,
113
- fontSize: '0.75rem',
114
- fontFamily: 'monospace',
115
  overflow: 'auto',
116
- maxHeight: 150,
117
- mb: 2,
118
- border: 1,
119
- borderColor: 'divider'
120
  }}>
121
  {JSON.stringify(currentTool.arguments, null, 2)}
122
  </Box>
123
 
124
- <Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
125
  <TextField
126
  fullWidth
127
  size="small"
128
- placeholder="Feedback for rejection (optional)"
129
  value={feedback}
130
  onChange={(e) => setFeedback(e.target.value)}
131
  variant="outlined"
132
  sx={{
133
- flex: 1,
134
- '& .MuiOutlinedInput-root': { fontFamily: 'monospace', fontSize: '0.8rem', height: '36px' }
 
 
 
135
  }}
136
  />
137
 
138
- <Button
139
- variant="outlined"
140
- color="error"
141
- onClick={() => handleResolve(false)}
142
- sx={{ fontFamily: 'monospace', height: '36px', px: 3 }}
143
- >
144
- REJECT
145
- </Button>
146
- <Button
147
- variant="contained"
148
- color="success"
149
- onClick={() => handleResolve(true)}
150
- sx={{ color: 'white', fontFamily: 'monospace', height: '36px', px: 3 }}
151
- >
152
- APPROVE
153
- </Button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  </Box>
155
  </Box>
156
  );
 
95
  const currentTool = pendingApprovals.tools[currentIndex];
96
 
97
  return (
98
+ <Box
99
+ className="action-card"
100
+ sx={{
101
+ mt: 2,
102
+ mb: 4,
103
+ width: '100%',
104
+ alignSelf: 'center',
105
+ padding: '18px',
106
+ borderRadius: 'var(--radius-md)',
107
+ background: 'linear-gradient(180deg, rgba(255,255,255,0.015), transparent)',
108
+ border: '1px solid rgba(255,255,255,0.03)',
109
+ display: 'flex',
110
+ flexDirection: 'column',
111
+ gap: '12px',
112
+ }}
113
+ >
114
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
115
+ <Typography variant="subtitle2" sx={{ fontWeight: 600, color: 'var(--text)' }}>
116
+ Approval Required
117
+ </Typography>
118
+ <Typography variant="caption" sx={{ color: 'var(--muted-text)' }}>
119
+ ({currentIndex + 1}/{pendingApprovals.count})
120
+ </Typography>
121
+ </Box>
122
+
123
+ <Typography variant="body2" sx={{ color: 'var(--muted-text)' }}>
124
+ The agent wants to execute <Box component="span" sx={{ color: 'var(--accent-yellow)', fontWeight: 500 }}>{currentTool.tool}</Box>
125
  </Typography>
126
 
127
  <Box component="pre" sx={{
128
+ bgcolor: 'rgba(0,0,0,0.3)',
129
+ p: 2,
130
+ borderRadius: '8px',
131
+ fontSize: '0.8rem',
132
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, monospace',
133
  overflow: 'auto',
134
+ maxHeight: 200,
135
+ border: '1px solid rgba(255,255,255,0.05)',
136
+ margin: 0
 
137
  }}>
138
  {JSON.stringify(currentTool.arguments, null, 2)}
139
  </Box>
140
 
141
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
142
  <TextField
143
  fullWidth
144
  size="small"
145
+ placeholder="Feedback (optional)"
146
  value={feedback}
147
  onChange={(e) => setFeedback(e.target.value)}
148
  variant="outlined"
149
  sx={{
150
+ '& .MuiOutlinedInput-root': {
151
+ bgcolor: 'rgba(0,0,0,0.2)',
152
+ fontFamily: 'inherit',
153
+ fontSize: '0.9rem'
154
+ }
155
  }}
156
  />
157
 
158
+ <Box className="action-buttons" sx={{ display: 'flex', gap: '10px' }}>
159
+ <Button
160
+ className="btn-reject"
161
+ onClick={() => handleResolve(false)}
162
+ sx={{
163
+ flex: 1,
164
+ background: 'transparent',
165
+ border: '1px solid rgba(255,255,255,0.05)',
166
+ color: 'var(--accent-red)',
167
+ padding: '10px 14px',
168
+ borderRadius: '10px',
169
+ '&:hover': {
170
+ bgcolor: 'rgba(224, 90, 79, 0.05)',
171
+ borderColor: 'var(--accent-red)',
172
+ }
173
+ }}
174
+ >
175
+ Reject
176
+ </Button>
177
+ <Button
178
+ className="btn-approve"
179
+ onClick={() => handleResolve(true)}
180
+ sx={{
181
+ flex: 1,
182
+ background: 'transparent',
183
+ border: '1px solid rgba(255,255,255,0.05)',
184
+ color: 'var(--accent-green)',
185
+ padding: '10px 14px',
186
+ borderRadius: '10px',
187
+ '&:hover': {
188
+ bgcolor: 'rgba(47, 204, 113, 0.05)',
189
+ borderColor: 'var(--accent-green)',
190
+ }
191
+ }}
192
+ >
193
+ Approve
194
+ </Button>
195
+ </Box>
196
  </Box>
197
  </Box>
198
  );
frontend/src/components/Chat/ChatInput.tsx CHANGED
@@ -36,26 +36,22 @@ export default function ChatInput({ onSend, disabled = false }: ChatInputProps)
36
  zIndex: 10,
37
  }}
38
  >
39
- <Box sx={{ maxWidth: 'md', mx: 'auto', width: '100%', px: 2 }}>
40
- {/* Input Label and Divider */}
41
- <Box sx={{ display: 'flex', alignItems: 'center', mb: 1, gap: 2 }}>
42
- <Typography variant="caption" sx={{ fontFamily: 'monospace', fontWeight: 600, color: 'text.secondary', letterSpacing: '0.05em' }}>
43
- INPUT
44
- </Typography>
45
- <Box sx={{ flex: 1, height: '1px', bgcolor: 'divider' }} />
46
- </Box>
47
-
48
  <Box
 
49
  sx={{
50
  display: 'flex',
51
- gap: 1,
52
- alignItems: 'center',
53
- bgcolor: 'background.paper',
54
- borderRadius: 1,
55
- boxShadow: 4,
56
- p: 1,
57
- border: 1,
58
- borderColor: 'divider',
 
 
 
59
  }}
60
  >
61
  <TextField
@@ -65,47 +61,65 @@ export default function ChatInput({ onSend, disabled = false }: ChatInputProps)
65
  value={input}
66
  onChange={(e) => setInput(e.target.value)}
67
  onKeyDown={handleKeyDown}
68
- placeholder="Ask anything"
69
  disabled={disabled}
70
- variant="outlined"
71
- size="small"
 
 
 
 
 
 
 
 
 
 
 
72
  sx={{
73
- '& .MuiOutlinedInput-root': {
74
- padding: '9px 12px',
75
- lineHeight: '1.4',
76
- fontFamily: 'monospace',
77
- },
78
- '& .MuiInputBase-input': {
79
- fontFamily: 'monospace',
80
- },
81
- '& .MuiOutlinedInput-notchedOutline': {
82
- border: 'none',
83
- },
84
  }}
85
  />
86
  <IconButton
87
  onClick={handleSend}
88
  disabled={disabled || !input.trim()}
89
  sx={{
90
- border: 1,
91
- borderColor: 'divider',
92
- borderRadius: 1,
93
- color: 'text.secondary',
94
  transition: 'all 0.2s',
95
  '&:hover': {
96
- borderColor: 'primary.main',
97
- color: 'primary.main',
98
- bgcolor: 'transparent',
99
  },
100
  '&.Mui-disabled': {
101
- borderColor: 'divider',
102
- opacity: 0.5,
103
  },
104
  }}
105
  >
106
- {disabled ? <CircularProgress size={24} color="inherit" /> : <ArrowUpwardIcon fontSize="small" />}
107
  </IconButton>
108
  </Box>
 
 
 
 
 
 
 
 
 
 
 
109
  </Box>
110
  </Box>
111
  );
 
36
  zIndex: 10,
37
  }}
38
  >
39
+ <Box sx={{ maxWidth: '880px', mx: 'auto', width: '100%', px: 2 }}>
 
 
 
 
 
 
 
 
40
  <Box
41
+ className="composer"
42
  sx={{
43
  display: 'flex',
44
+ gap: '10px',
45
+ alignItems: 'flex-start',
46
+ bgcolor: 'rgba(255,255,255,0.01)',
47
+ borderRadius: 'var(--radius-md)',
48
+ p: '12px',
49
+ border: '1px solid rgba(255,255,255,0.03)',
50
+ transition: 'box-shadow 0.2s ease, border-color 0.2s ease',
51
+ '&:focus-within': {
52
+ borderColor: 'var(--accent-yellow)',
53
+ boxShadow: 'var(--focus)',
54
+ }
55
  }}
56
  >
57
  <TextField
 
61
  value={input}
62
  onChange={(e) => setInput(e.target.value)}
63
  onKeyDown={handleKeyDown}
64
+ placeholder="Ask anything..."
65
  disabled={disabled}
66
+ variant="standard"
67
+ InputProps={{
68
+ disableUnderline: true,
69
+ sx: {
70
+ color: 'var(--text)',
71
+ fontSize: '15px',
72
+ fontFamily: 'inherit',
73
+ padding: 0,
74
+ lineHeight: 1.5,
75
+ minHeight: '56px',
76
+ alignItems: 'flex-start',
77
+ }
78
+ }}
79
  sx={{
80
+ flex: 1,
81
+ '& .MuiInputBase-root': {
82
+ p: 0,
83
+ backgroundColor: 'transparent',
84
+ },
85
+ '& textarea': {
86
+ resize: 'none',
87
+ padding: '0 !important',
88
+ }
 
 
89
  }}
90
  />
91
  <IconButton
92
  onClick={handleSend}
93
  disabled={disabled || !input.trim()}
94
  sx={{
95
+ mt: 1,
96
+ p: 1,
97
+ borderRadius: '10px',
98
+ color: 'var(--muted-text)',
99
  transition: 'all 0.2s',
100
  '&:hover': {
101
+ color: 'var(--accent-yellow)',
102
+ bgcolor: 'rgba(255,255,255,0.05)',
 
103
  },
104
  '&.Mui-disabled': {
105
+ opacity: 0.3,
 
106
  },
107
  }}
108
  >
109
+ {disabled ? <CircularProgress size={20} color="inherit" /> : <ArrowUpwardIcon fontSize="small" />}
110
  </IconButton>
111
  </Box>
112
+
113
+ {/* Powered By Badge */}
114
+ <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', mt: 1.5, gap: 0.8, opacity: 0.5 }}>
115
+ <Typography variant="caption" sx={{ fontSize: '10px', color: 'var(--muted-text)', textTransform: 'uppercase', letterSpacing: '0.05em', fontWeight: 500 }}>
116
+ powered by
117
+ </Typography>
118
+ <img src="/claude-logo.png" alt="Claude" style={{ height: '12px', objectFit: 'contain' }} />
119
+ <Typography variant="caption" sx={{ fontSize: '10px', color: 'var(--text)', fontWeight: 600, letterSpacing: '0.02em' }}>
120
+ claude-opus-4-5-20251101
121
+ </Typography>
122
+ </Box>
123
  </Box>
124
  </Box>
125
  );
frontend/src/components/Chat/MessageBubble.tsx CHANGED
@@ -10,12 +10,7 @@ interface MessageBubbleProps {
10
  export default function MessageBubble({ message }: MessageBubbleProps) {
11
  const isUser = message.role === 'user';
12
  const isTool = message.role === 'tool';
13
-
14
- const getBgColor = () => {
15
- if (isUser) return 'background.paper';
16
- if (isTool) return 'background.default';
17
- return 'transparent';
18
- };
19
 
20
  return (
21
  <Box
@@ -23,18 +18,24 @@ export default function MessageBubble({ message }: MessageBubbleProps) {
23
  display: 'flex',
24
  justifyContent: isUser ? 'flex-end' : 'flex-start',
25
  width: '100%',
 
 
26
  }}
27
  >
28
  <Paper
29
  elevation={0}
 
30
  sx={{
31
- p: isTool ? 2 : isUser ? 1.5 : 1,
32
- maxWidth: isTool ? '100%' : '80%',
33
  width: isTool ? '100%' : 'auto',
34
- bgcolor: getBgColor(),
35
- border: (!isUser && !isTool) ? 0 : 1,
36
- borderColor: 'divider',
37
- borderRadius: isUser ? 2 : undefined,
 
 
 
38
  }}
39
  >
40
  {isTool && (
@@ -57,11 +58,11 @@ export default function MessageBubble({ message }: MessageBubbleProps) {
57
  {message.trace && message.trace.length > 0 && (
58
  <Box
59
  sx={{
60
- bgcolor: 'background.default',
61
  borderRadius: 1,
62
  p: 1.5,
63
  border: 1,
64
- borderColor: 'divider',
65
  width: '100%',
66
  mb: 2,
67
  }}
@@ -72,7 +73,7 @@ export default function MessageBubble({ message }: MessageBubbleProps) {
72
  key={log.id}
73
  variant="caption"
74
  component="div"
75
- sx={{ color: 'common.white', fontFamily: 'monospace', fontSize: '0.75rem' }}
76
  >
77
  &gt; {log.text}
78
  </Typography>
@@ -83,16 +84,17 @@ export default function MessageBubble({ message }: MessageBubbleProps) {
83
 
84
  <Box
85
  sx={{
86
- '& p': { m: 0 },
87
  '& pre': {
88
- bgcolor: 'background.default',
89
  p: 1.5,
90
  borderRadius: 1,
91
  overflow: 'auto',
92
  fontSize: '0.85rem',
 
93
  },
94
  '& code': {
95
- bgcolor: 'background.default',
96
  px: 0.5,
97
  py: 0.25,
98
  borderRadius: 0.5,
@@ -104,8 +106,11 @@ export default function MessageBubble({ message }: MessageBubbleProps) {
104
  p: 0,
105
  },
106
  '& a': {
107
- color: 'inherit',
108
- textDecoration: 'underline',
 
 
 
109
  },
110
  '& ul, & ol': {
111
  pl: 2,
@@ -119,20 +124,24 @@ export default function MessageBubble({ message }: MessageBubbleProps) {
119
  },
120
  '& th': {
121
  borderBottom: '1px solid',
122
- borderColor: 'divider',
123
  textAlign: 'left',
124
  p: 1,
125
- bgcolor: 'action.hover',
126
  },
127
  '& td': {
128
  borderBottom: '1px solid',
129
- borderColor: 'divider',
130
  p: 1,
131
  },
132
  }}
133
  >
134
  <ReactMarkdown remarkPlugins={[remarkGfm]}>{message.content}</ReactMarkdown>
135
  </Box>
 
 
 
 
136
  </Paper>
137
  </Box>
138
  );
 
10
  export default function MessageBubble({ message }: MessageBubbleProps) {
11
  const isUser = message.role === 'user';
12
  const isTool = message.role === 'tool';
13
+ const isAssistant = message.role === 'assistant';
 
 
 
 
 
14
 
15
  return (
16
  <Box
 
18
  display: 'flex',
19
  justifyContent: isUser ? 'flex-end' : 'flex-start',
20
  width: '100%',
21
+ maxWidth: '880px',
22
+ mx: 'auto',
23
  }}
24
  >
25
  <Paper
26
  elevation={0}
27
+ className={`message ${isUser ? 'user' : isAssistant ? 'assistant' : ''}`}
28
  sx={{
29
+ p: '14px 18px',
30
+ margin: '10px 0',
31
  width: isTool ? '100%' : 'auto',
32
+ maxWidth: '100%',
33
+ borderRadius: 'var(--radius-lg)',
34
+ borderTopLeftRadius: isAssistant ? '6px' : undefined,
35
+ lineHeight: 1.45,
36
+ boxShadow: 'var(--shadow-1)',
37
+ border: '1px solid rgba(255,255,255,0.03)',
38
+ background: 'linear-gradient(180deg, rgba(255,255,255,0.015), transparent)',
39
  }}
40
  >
41
  {isTool && (
 
58
  {message.trace && message.trace.length > 0 && (
59
  <Box
60
  sx={{
61
+ bgcolor: 'rgba(0,0,0,0.3)',
62
  borderRadius: 1,
63
  p: 1.5,
64
  border: 1,
65
+ borderColor: 'rgba(255,255,255,0.05)',
66
  width: '100%',
67
  mb: 2,
68
  }}
 
73
  key={log.id}
74
  variant="caption"
75
  component="div"
76
+ sx={{ color: 'var(--muted-text)', fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, monospace', fontSize: '0.75rem' }}
77
  >
78
  &gt; {log.text}
79
  </Typography>
 
84
 
85
  <Box
86
  sx={{
87
+ '& p': { m: 0, color: isUser ? 'var(--text)' : 'var(--text)' }, // User might want different text color? Defaults to --text
88
  '& pre': {
89
+ bgcolor: 'rgba(0,0,0,0.5)',
90
  p: 1.5,
91
  borderRadius: 1,
92
  overflow: 'auto',
93
  fontSize: '0.85rem',
94
+ border: '1px solid rgba(255,255,255,0.05)',
95
  },
96
  '& code': {
97
+ bgcolor: 'rgba(255,255,255,0.05)',
98
  px: 0.5,
99
  py: 0.25,
100
  borderRadius: 0.5,
 
106
  p: 0,
107
  },
108
  '& a': {
109
+ color: 'var(--accent-yellow)',
110
+ textDecoration: 'none',
111
+ '&:hover': {
112
+ textDecoration: 'underline',
113
+ },
114
  },
115
  '& ul, & ol': {
116
  pl: 2,
 
124
  },
125
  '& th': {
126
  borderBottom: '1px solid',
127
+ borderColor: 'rgba(255,255,255,0.1)',
128
  textAlign: 'left',
129
  p: 1,
130
+ bgcolor: 'rgba(255,255,255,0.02)',
131
  },
132
  '& td': {
133
  borderBottom: '1px solid',
134
+ borderColor: 'rgba(255,255,255,0.05)',
135
  p: 1,
136
  },
137
  }}
138
  >
139
  <ReactMarkdown remarkPlugins={[remarkGfm]}>{message.content}</ReactMarkdown>
140
  </Box>
141
+
142
+ <Typography className="meta" variant="caption" sx={{ display: 'block', textAlign: 'right', mt: 1, fontSize: '11px', opacity: 0.5 }}>
143
+ {new Date(message.timestamp).toLocaleTimeString()}
144
+ </Typography>
145
  </Paper>
146
  </Box>
147
  );
frontend/src/components/CodePanel/CodePanel.tsx CHANGED
@@ -10,63 +10,82 @@ export default function CodePanel() {
10
  const { setRightPanelOpen } = useLayoutStore();
11
 
12
  return (
13
- <Box sx={{ height: '100%', display: 'flex', flexDirection: 'column', bgcolor: 'background.paper' }}>
14
- {/* Header - Always Visible */}
15
- <Box sx={{ p: 2, borderBottom: 1, borderColor: 'divider', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
16
- <Typography variant="caption" sx={{ fontFamily: 'monospace', fontWeight: 600, color: 'text.secondary', textTransform: 'uppercase', letterSpacing: '0.05em' }}>
 
 
 
 
 
 
 
17
  {panelContent?.title || 'Code Panel'}
18
  </Typography>
19
- <IconButton size="small" onClick={() => setRightPanelOpen(false)}>
20
  <CloseIcon fontSize="small" />
21
  </IconButton>
22
  </Box>
23
 
24
  {!panelContent ? (
25
  <Box sx={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', p: 4 }}>
26
- <Typography variant="body2" color="text.secondary" sx={{ fontFamily: 'monospace', opacity: 0.5 }}>
27
  NO DATA LOADED
28
  </Typography>
29
  </Box>
30
  ) : (
31
- <Box sx={{ flex: 1, overflow: 'auto', bgcolor: 'background.default' }}>
32
- {panelContent.content ? (
33
- panelContent.language === 'python' ? (
34
- <SyntaxHighlighter
35
- language="python"
36
- style={vscDarkPlus}
37
- customStyle={{
38
- margin: 0,
39
- padding: '16px',
40
- background: 'transparent',
41
- fontSize: '0.8rem',
42
- fontFamily: '"JetBrains Mono", monospace',
43
- }}
44
- wrapLines={true}
45
- wrapLongLines={true}
46
- >
47
- {panelContent.content}
48
- </SyntaxHighlighter>
49
- ) : (
50
- <Box sx={{ p: 2 }}>
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  <Box component="pre" sx={{
52
- m: 0,
53
- fontFamily: 'monospace',
54
- fontSize: '0.8rem',
55
- color: 'text.primary',
56
- whiteSpace: 'pre-wrap',
57
- wordBreak: 'break-all'
58
  }}>
59
- <code>{panelContent.content}</code>
 
 
 
 
 
 
 
60
  </Box>
61
- </Box>
62
- )
63
- ) : (
64
- <Box sx={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', p: 4, opacity: 0.5 }}>
65
- <Typography variant="caption" sx={{ fontFamily: 'monospace' }}>
66
- NO CONTENT TO DISPLAY
67
- </Typography>
68
- </Box>
69
- )}
70
  </Box>
71
  )}
72
  </Box>
 
10
  const { setRightPanelOpen } = useLayoutStore();
11
 
12
  return (
13
+ <Box sx={{ height: '100%', display: 'flex', flexDirection: 'column', bgcolor: 'var(--panel)' }}>
14
+ {/* Header - Fixed 60px to align */}
15
+ <Box sx={{
16
+ height: '60px',
17
+ display: 'flex',
18
+ alignItems: 'center',
19
+ justifyContent: 'space-between',
20
+ px: 2,
21
+ borderBottom: '1px solid rgba(255,255,255,0.03)'
22
+ }}>
23
+ <Typography variant="caption" sx={{ fontWeight: 600, color: 'var(--muted-text)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>
24
  {panelContent?.title || 'Code Panel'}
25
  </Typography>
26
+ <IconButton size="small" onClick={() => setRightPanelOpen(false)} sx={{ color: 'var(--muted-text)' }}>
27
  <CloseIcon fontSize="small" />
28
  </IconButton>
29
  </Box>
30
 
31
  {!panelContent ? (
32
  <Box sx={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', p: 4 }}>
33
+ <Typography variant="body2" color="text.secondary" sx={{ opacity: 0.5 }}>
34
  NO DATA LOADED
35
  </Typography>
36
  </Box>
37
  ) : (
38
+ <Box sx={{ flex: 1, overflow: 'auto', p: 2 }}>
39
+ <Box
40
+ className="code-panel"
41
+ sx={{
42
+ background: '#0A0B0C',
43
+ borderRadius: 'var(--radius-md)',
44
+ padding: '18px',
45
+ border: '1px solid rgba(255,255,255,0.03)',
46
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Roboto Mono", monospace',
47
+ fontSize: '13px',
48
+ lineHeight: 1.55,
49
+ height: '100%',
50
+ overflow: 'auto',
51
+ }}
52
+ >
53
+ {panelContent.content ? (
54
+ panelContent.language === 'python' ? (
55
+ <SyntaxHighlighter
56
+ language="python"
57
+ style={vscDarkPlus}
58
+ customStyle={{
59
+ margin: 0,
60
+ padding: 0,
61
+ background: 'transparent',
62
+ fontSize: '13px',
63
+ fontFamily: 'inherit',
64
+ }}
65
+ wrapLines={true}
66
+ wrapLongLines={true}
67
+ >
68
+ {panelContent.content}
69
+ </SyntaxHighlighter>
70
+ ) : (
71
  <Box component="pre" sx={{
72
+ m: 0,
73
+ fontFamily: 'inherit',
74
+ color: 'var(--text)',
75
+ whiteSpace: 'pre-wrap',
76
+ wordBreak: 'break-all'
 
77
  }}>
78
+ <code>{panelContent.content}</code>
79
+ </Box>
80
+ )
81
+ ) : (
82
+ <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%', opacity: 0.5 }}>
83
+ <Typography variant="caption">
84
+ NO CONTENT TO DISPLAY
85
+ </Typography>
86
  </Box>
87
+ )}
88
+ </Box>
 
 
 
 
 
 
 
89
  </Box>
90
  )}
91
  </Box>
frontend/src/components/Layout/AppLayout.tsx CHANGED
@@ -20,7 +20,7 @@ import ChatInput from '@/components/Chat/ChatInput';
20
  import MessageList from '@/components/Chat/MessageList';
21
  import type { Message } from '@/types/agent';
22
 
23
- const DRAWER_WIDTH = 280;
24
 
25
  export default function AppLayout() {
26
  const { activeSessionId } = useSessionStore();
@@ -125,8 +125,9 @@ export default function AppLayout() {
125
  width: DRAWER_WIDTH,
126
  borderRight: '1px solid',
127
  borderColor: 'divider',
128
- top: '40px', // Below logo bar
129
- height: 'calc(100% - 40px)',
 
130
  },
131
  }}
132
  open={isLeftSidebarOpen}
@@ -181,11 +182,14 @@ export default function AppLayout() {
181
 
182
  <Box
183
  component="main"
 
184
  sx={{
185
  flexGrow: 1,
186
  display: 'flex',
187
  flexDirection: 'column',
188
  overflow: 'hidden',
 
 
189
  }}
190
  >
191
  {activeSessionId ? (
@@ -266,8 +270,9 @@ export default function AppLayout() {
266
  boxSizing: 'border-box',
267
  width: rightPanelWidth,
268
  borderLeft: 'none',
269
- top: '40px', // Below logo bar
270
- height: 'calc(100% - 40px)',
 
271
  },
272
  }}
273
  open={isRightPanelOpen}
 
20
  import MessageList from '@/components/Chat/MessageList';
21
  import type { Message } from '@/types/agent';
22
 
23
+ const DRAWER_WIDTH = 260;
24
 
25
  export default function AppLayout() {
26
  const { activeSessionId } = useSessionStore();
 
125
  width: DRAWER_WIDTH,
126
  borderRight: '1px solid',
127
  borderColor: 'divider',
128
+ top: 0,
129
+ height: '100%',
130
+ bgcolor: 'var(--panel)', // Ensure correct background matches sidebar
131
  },
132
  }}
133
  open={isLeftSidebarOpen}
 
182
 
183
  <Box
184
  component="main"
185
+ className="chat-pane"
186
  sx={{
187
  flexGrow: 1,
188
  display: 'flex',
189
  flexDirection: 'column',
190
  overflow: 'hidden',
191
+ background: 'linear-gradient(180deg, var(--bg), var(--panel))',
192
+ padding: '24px',
193
  }}
194
  >
195
  {activeSessionId ? (
 
270
  boxSizing: 'border-box',
271
  width: rightPanelWidth,
272
  borderLeft: 'none',
273
+ top: 0,
274
+ height: '100%',
275
+ bgcolor: 'var(--panel)',
276
  },
277
  }}
278
  open={isRightPanelOpen}
frontend/src/components/SessionSidebar/SessionSidebar.tsx CHANGED
@@ -3,19 +3,14 @@ import {
3
  Box,
4
  List,
5
  ListItem,
6
- ListItemButton,
7
- ListItemText,
8
- ListItemSecondaryAction,
9
  IconButton,
10
  Typography,
11
  Button,
12
  Divider,
13
- Chip,
14
  Tooltip,
15
  } from '@mui/material';
16
  import DeleteIcon from '@mui/icons-material/Delete';
17
  import UndoIcon from '@mui/icons-material/Undo';
18
- import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord';
19
  import { useSessionStore } from '@/store/sessionStore';
20
  import { useAgentStore } from '@/store/agentStore';
21
 
@@ -26,30 +21,29 @@ interface SessionSidebarProps {
26
  const StatusDiode = ({ connected }: { connected: boolean }) => (
27
  <Box
28
  sx={{
29
- width: 8,
30
- height: 8,
31
  borderRadius: '50%',
32
- bgcolor: connected ? 'success.main' : 'error.main',
33
- boxShadow: connected ? '0 0 0 0 rgba(46, 160, 67, 0.7)' : 'none',
34
- animation: connected ? 'pulse 2s infinite' : 'none',
35
- '@keyframes pulse': {
36
- '0%': {
37
- transform: 'scale(0.95)',
38
- boxShadow: '0 0 0 0 rgba(46, 160, 67, 0.7)',
39
- },
40
- '70%': {
41
- transform: 'scale(1)',
42
- boxShadow: '0 0 0 4px rgba(46, 160, 67, 0)',
43
- },
44
- '100%': {
45
- transform: 'scale(0.95)',
46
- boxShadow: '0 0 0 0 rgba(46, 160, 67, 0)',
47
- },
48
- },
49
  }}
50
  />
51
  );
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  export default function SessionSidebar({ onClose }: SessionSidebarProps) {
54
  const { sessions, activeSessionId, createSession, deleteSession, switchSession } =
55
  useSessionStore();
@@ -102,114 +96,147 @@ export default function SessionSidebar({ onClose }: SessionSidebarProps) {
102
  };
103
 
104
  return (
105
- <Box sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
106
- {/* Header */}
107
- <Box sx={{ p: 2, borderBottom: 1, borderColor: 'divider', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
108
- <Box sx={{ mb: 2 }}>
109
- <img
110
- src="/hf-log-only-white.png"
111
- alt="HF Agent"
112
- style={{ height: '32px', objectFit: 'contain' }}
113
- />
 
 
 
 
 
 
114
  </Box>
 
115
 
 
 
116
  {/* System Info / Status */}
117
  <Box sx={{ mb: 2, display: 'flex', alignItems: 'center', gap: 1 }}>
118
- <Typography variant="caption" color="text.secondary" sx={{ fontFamily: 'monospace' }}>
119
- {isConnected ? 'Connected' : 'Disconnected'}
120
- </Typography>
121
  <StatusDiode connected={isConnected} />
 
 
 
122
  </Box>
123
 
124
  <Button
125
  fullWidth
126
- variant="outlined"
127
  onClick={handleNewSession}
128
- sx={{ justifyContent: 'center' }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  >
130
- Create Session
131
  </Button>
132
- </Box>
133
 
134
- {/* Session List */}
135
- <Box sx={{ flex: 1, overflow: 'auto' }}>
136
- {sessions.length === 0 ? (
137
- <Box sx={{ p: 3, textAlign: 'center' }}>
138
- <Typography variant="body2" color="text.secondary" sx={{ fontFamily: 'monospace' }}>
139
- NO ACTIVE SESSIONS
140
- </Typography>
141
- <Typography variant="caption" color="text.secondary">
142
- Initialize a new session to begin
143
- </Typography>
144
- </Box>
145
- ) : (
146
- <List disablePadding>
147
  {[...sessions].reverse().map((session, index) => {
148
- const sessionNumber = sessions.length - index;
149
- return (
150
- <ListItem key={session.id} disablePadding divider>
151
- <ListItemButton
152
- selected={session.id === activeSessionId}
 
 
153
  onClick={() => handleSelectSession(session.id)}
154
  sx={{
155
- '&.Mui-selected': {
156
- bgcolor: 'action.selected',
 
 
 
 
 
 
157
  '&:hover': {
158
- bgcolor: 'action.selected',
 
 
 
 
 
159
  },
160
- },
 
 
161
  }}
162
- >
163
- <ListItemText
164
- primary={
165
- <Typography variant="body2" sx={{ fontFamily: 'monospace', fontWeight: 600 }}>
166
- SESSION {String(sessionNumber).padStart(3, '0')}
167
- </Typography>
168
- }
169
- secondary={
170
- <Typography variant="caption" sx={{ fontFamily: 'monospace', display: 'flex', alignItems: 'center', gap: 1 }}>
171
- <span style={{ color: session.isActive ? 'var(--mui-palette-success-main)' : 'var(--mui-palette-text-secondary)' }}>
172
- {session.isActive ? 'RUNNING' : 'STOPPED'}
173
- </span>
174
- <span>·</span>
175
- <span>{formatTime(session.createdAt)}</span>
176
  </Typography>
177
- }
178
- />
179
- <ListItemSecondaryAction>
180
- <IconButton
181
- edge="end"
 
 
 
 
 
182
  size="small"
183
  onClick={(e) => handleDeleteSession(session.id, e)}
184
- >
 
185
  <DeleteIcon fontSize="small" />
186
- </IconButton>
187
- </ListItemSecondaryAction>
188
- </ListItemButton>
189
  </ListItem>
190
- );
191
  })}
192
- </List>
193
- )}
194
  </Box>
195
 
196
  {/* Footer */}
197
- <Divider />
198
- <Box sx={{ p: 2, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
199
- <Typography variant="caption" color="text.secondary" sx={{ fontFamily: 'monospace' }}>
200
- {sessions.length} SESSION{sessions.length !== 1 ? 'S' : ''}
201
- </Typography>
202
- <Tooltip title="Undo last turn">
203
- <span>
204
- <IconButton
205
- onClick={handleUndo}
206
- disabled={!activeSessionId || isProcessing}
207
- size="small"
208
- >
209
- <UndoIcon fontSize="small" />
210
- </IconButton>
211
- </span>
212
- </Tooltip>
 
 
213
  </Box>
214
  </Box>
215
  );
 
3
  Box,
4
  List,
5
  ListItem,
 
 
 
6
  IconButton,
7
  Typography,
8
  Button,
9
  Divider,
 
10
  Tooltip,
11
  } from '@mui/material';
12
  import DeleteIcon from '@mui/icons-material/Delete';
13
  import UndoIcon from '@mui/icons-material/Undo';
 
14
  import { useSessionStore } from '@/store/sessionStore';
15
  import { useAgentStore } from '@/store/agentStore';
16
 
 
21
  const StatusDiode = ({ connected }: { connected: boolean }) => (
22
  <Box
23
  sx={{
24
+ width: 10,
25
+ height: 10,
26
  borderRadius: '50%',
27
+ bgcolor: connected ? 'var(--accent-green)' : 'var(--accent-red)', // Use green/red for connection status
28
+ boxShadow: connected ? '0 0 6px rgba(47, 204, 113, 0.4)' : 'none',
29
+ transition: 'all 0.3s ease',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  }}
31
  />
32
  );
33
 
34
+ const RunningIndicator = () => (
35
+ <Box
36
+ className="running-indicator"
37
+ sx={{
38
+ width: 10,
39
+ height: 10,
40
+ borderRadius: '50%',
41
+ bgcolor: 'var(--accent-yellow)',
42
+ boxShadow: '0 0 6px rgba(199,165,0,0.18)',
43
+ }}
44
+ />
45
+ );
46
+
47
  export default function SessionSidebar({ onClose }: SessionSidebarProps) {
48
  const { sessions, activeSessionId, createSession, deleteSession, switchSession } =
49
  useSessionStore();
 
96
  };
97
 
98
  return (
99
+ <Box className="sidebar" sx={{ height: '100%', display: 'flex', flexDirection: 'column', bgcolor: 'var(--panel)' }}>
100
+ {/* Header - Aligned with AppLayout 60px */}
101
+ <Box sx={{
102
+ height: '60px',
103
+ display: 'flex',
104
+ alignItems: 'center',
105
+ px: 2,
106
+ borderBottom: '1px solid rgba(255,255,255,0.03)'
107
+ }}>
108
+ <Box className="brand-logo" sx={{ display: 'flex' }}>
109
+ <img
110
+ src="/hf-log-only-white.png"
111
+ alt="HF Agent"
112
+ style={{ height: '24px', objectFit: 'contain' }}
113
+ />
114
  </Box>
115
+ </Box>
116
 
117
+ {/* Content */}
118
+ <Box sx={{ flex: 1, display: 'flex', flexDirection: 'column', p: 2, overflow: 'hidden' }}>
119
  {/* System Info / Status */}
120
  <Box sx={{ mb: 2, display: 'flex', alignItems: 'center', gap: 1 }}>
 
 
 
121
  <StatusDiode connected={isConnected} />
122
+ <Typography variant="caption" sx={{ color: 'var(--muted-text)', fontFamily: 'inherit' }}>
123
+ {isConnected ? 'System Online' : 'Disconnected'}
124
+ </Typography>
125
  </Box>
126
 
127
  <Button
128
  fullWidth
129
+ className="create-session"
130
  onClick={handleNewSession}
131
+ sx={{
132
+ display: 'inline-flex',
133
+ alignItems: 'center',
134
+ justifyContent: 'flex-start',
135
+ gap: '10px',
136
+ padding: '10px 14px',
137
+ borderRadius: 'var(--radius-md)',
138
+ border: '1px solid rgba(255,255,255,0.06)',
139
+ bgcolor: 'transparent',
140
+ color: 'var(--text)',
141
+ fontWeight: 600,
142
+ textTransform: 'none',
143
+ mb: 3,
144
+ '&:hover': {
145
+ bgcolor: 'rgba(255,255,255,0.02)',
146
+ border: '1px solid rgba(255,255,255,0.1)',
147
+ },
148
+ '&::before': {
149
+ content: '""',
150
+ width: '4px',
151
+ height: '20px',
152
+ background: 'linear-gradient(180deg, var(--accent-yellow), rgba(199,165,0,0.9))',
153
+ borderRadius: '4px',
154
+ }
155
+ }}
156
  >
157
+ New Session
158
  </Button>
 
159
 
160
+ {/* Session List */}
161
+ <Box sx={{ flex: 1, overflow: 'auto', mx: -1, px: 1 }}>
162
+ <List disablePadding sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
 
 
 
 
 
 
 
 
 
 
163
  {[...sessions].reverse().map((session, index) => {
164
+ const sessionNumber = sessions.length - index;
165
+ const isSelected = session.id === activeSessionId;
166
+ return (
167
+ <ListItem
168
+ key={session.id}
169
+ disablePadding
170
+ className="session-item"
171
  onClick={() => handleSelectSession(session.id)}
172
  sx={{
173
+ display: 'flex',
174
+ alignItems: 'center',
175
+ gap: '12px',
176
+ padding: '10px',
177
+ borderRadius: 'var(--radius-md)',
178
+ bgcolor: isSelected ? 'rgba(255,255,255,0.05)' : 'transparent',
179
+ cursor: 'pointer',
180
+ transition: 'background 0.18s ease, transform 0.08s ease',
181
  '&:hover': {
182
+ bgcolor: 'rgba(255,255,255,0.02)',
183
+ transform: 'translateY(-1px)',
184
+ },
185
+ '& .delete-btn': {
186
+ opacity: 0,
187
+ transition: 'opacity 0.2s',
188
  },
189
+ '&:hover .delete-btn': {
190
+ opacity: 1,
191
+ }
192
  }}
193
+ >
194
+ <Box sx={{ flex: 1, overflow: 'hidden' }}>
195
+ <Typography variant="body2" sx={{ fontWeight: 500, color: 'var(--text)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
196
+ Session {String(sessionNumber).padStart(2, '0')}
 
 
 
 
 
 
 
 
 
 
197
  </Typography>
198
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mt: 0.5 }}>
199
+ {session.isActive && <RunningIndicator />}
200
+ <Typography className="time" variant="caption" sx={{ fontSize: '12px', color: 'var(--muted-text)' }}>
201
+ {formatTime(session.createdAt)}
202
+ </Typography>
203
+ </Box>
204
+ </Box>
205
+
206
+ <IconButton
207
+ className="delete-btn"
208
  size="small"
209
  onClick={(e) => handleDeleteSession(session.id, e)}
210
+ sx={{ color: 'var(--muted-text)', '&:hover': { color: 'var(--accent-red)' } }}
211
+ >
212
  <DeleteIcon fontSize="small" />
213
+ </IconButton>
 
 
214
  </ListItem>
215
+ );
216
  })}
217
+ </List>
218
+ </Box>
219
  </Box>
220
 
221
  {/* Footer */}
222
+ <Box sx={{ p: 2, borderTop: '1px solid rgba(255,255,255,0.03)' }}>
223
+ <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
224
+ <Typography variant="caption" className="small-note" sx={{ fontSize: '12px', color: 'var(--muted-text)' }}>
225
+ {sessions.length} active
226
+ </Typography>
227
+ <Tooltip title="Undo last turn">
228
+ <span>
229
+ <IconButton
230
+ onClick={handleUndo}
231
+ disabled={!activeSessionId || isProcessing}
232
+ size="small"
233
+ sx={{ color: 'var(--muted-text)', '&:hover': { color: 'var(--text)' } }}
234
+ >
235
+ <UndoIcon fontSize="small" />
236
+ </IconButton>
237
+ </span>
238
+ </Tooltip>
239
+ </Box>
240
  </Box>
241
  </Box>
242
  );
frontend/src/theme.ts CHANGED
@@ -4,69 +4,71 @@ const theme = createTheme({
4
  palette: {
5
  mode: 'dark',
6
  primary: {
7
- main: '#FEE133',
8
- light: '#FFF066',
9
- dark: '#B29F24',
10
  },
11
  secondary: {
12
  main: '#FF9D00',
13
  },
14
  background: {
15
- default: '#0D1117',
16
- paper: '#161B22',
17
  },
18
  text: {
19
- primary: '#E6EDF3',
20
- secondary: '#8B949E',
21
  },
22
- divider: '#30363D',
23
  success: {
24
- main: '#2EA043', // Muted green
25
  },
26
  error: {
27
- main: '#F85149',
28
  },
29
  warning: {
30
- main: '#D29922',
31
  },
32
  info: {
33
  main: '#58A6FF',
34
  },
35
  },
36
  typography: {
37
- fontFamily: '"IBM Plex Sans", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
38
- h1: {
39
- fontWeight: 600,
40
- },
41
- h2: {
42
- fontWeight: 600,
43
- },
44
- h3: {
45
- fontWeight: 600,
46
- },
47
- h4: {
48
- fontWeight: 600,
49
- },
50
- h5: {
51
- fontWeight: 600,
52
- },
53
- h6: {
54
- fontWeight: 600,
55
- },
56
- body1: {
57
- fontSize: '0.9375rem',
58
- },
59
- body2: {
60
- fontSize: '0.875rem',
61
- },
62
  button: {
63
- fontFamily: '"JetBrains Mono", "IBM Plex Sans", monospace',
 
 
64
  },
65
  },
66
  components: {
67
  MuiCssBaseline: {
68
  styleOverrides: {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  body: {
 
 
70
  scrollbarWidth: 'thin',
71
  '&::-webkit-scrollbar': {
72
  width: '8px',
@@ -81,17 +83,33 @@ const theme = createTheme({
81
  },
82
  },
83
  'code, pre': {
84
- fontFamily: '"JetBrains Mono", "Fira Code", monospace',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  },
86
  },
87
  },
88
  MuiButton: {
89
  styleOverrides: {
90
  root: {
91
- textTransform: 'uppercase',
92
  fontWeight: 600,
93
- letterSpacing: '0.05em',
94
- fontSize: '0.75rem',
 
 
95
  },
96
  },
97
  },
@@ -99,20 +117,42 @@ const theme = createTheme({
99
  styleOverrides: {
100
  root: {
101
  backgroundImage: 'none',
 
102
  },
103
  },
104
  },
105
  MuiDrawer: {
106
  styleOverrides: {
107
  paper: {
108
- borderRight: '1px solid #30363D',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  },
110
  },
111
  },
112
  },
113
  shape: {
114
- borderRadius: 2,
115
  },
116
  });
117
 
118
- export default theme;
 
4
  palette: {
5
  mode: 'dark',
6
  primary: {
7
+ main: '#C7A500', // --accent-yellow
 
 
8
  },
9
  secondary: {
10
  main: '#FF9D00',
11
  },
12
  background: {
13
+ default: '#0B0D10', // --bg
14
+ paper: '#0F1316', // --panel
15
  },
16
  text: {
17
+ primary: '#E6EEF8', // --text
18
+ secondary: '#98A0AA', // --muted-text
19
  },
20
+ divider: 'rgba(255,255,255,0.03)',
21
  success: {
22
+ main: '#2FCC71', // --accent-green
23
  },
24
  error: {
25
+ main: '#E05A4F', // --accent-red
26
  },
27
  warning: {
28
+ main: '#C7A500',
29
  },
30
  info: {
31
  main: '#58A6FF',
32
  },
33
  },
34
  typography: {
35
+ fontFamily: 'Inter, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif',
36
+ fontSize: 15,
37
+ h1: { fontWeight: 600, color: '#E6EEF8' },
38
+ h2: { fontWeight: 600, color: '#E6EEF8' },
39
+ h3: { fontWeight: 600, color: '#E6EEF8' },
40
+ h4: { fontWeight: 600, color: '#E6EEF8' },
41
+ h5: { fontWeight: 600, color: '#E6EEF8' },
42
+ h6: { fontWeight: 600, color: '#E6EEF8' },
43
+ body1: { fontSize: '15px', color: '#E6EEF8' },
44
+ body2: { fontSize: '0.875rem', color: '#98A0AA' },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  button: {
46
+ fontFamily: 'Inter, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif',
47
+ textTransform: 'none',
48
+ fontWeight: 600,
49
  },
50
  },
51
  components: {
52
  MuiCssBaseline: {
53
  styleOverrides: {
54
+ ':root': {
55
+ '--bg': '#0B0D10',
56
+ '--panel': '#0F1316',
57
+ '--surface': '#121416',
58
+ '--text': '#E6EEF8',
59
+ '--muted-text': '#98A0AA',
60
+ '--accent-yellow': '#C7A500',
61
+ '--accent-yellow-weak': 'rgba(199,165,0,0.08)',
62
+ '--accent-green': '#2FCC71',
63
+ '--accent-red': '#E05A4F',
64
+ '--shadow-1': '0 6px 18px rgba(2,6,12,0.55)',
65
+ '--radius-lg': '20px',
66
+ '--radius-md': '12px',
67
+ '--focus': '0 0 0 3px rgba(199,165,0,0.12)',
68
+ },
69
  body: {
70
+ background: 'linear-gradient(180deg, var(--bg), #090B0D)',
71
+ color: 'var(--text)',
72
  scrollbarWidth: 'thin',
73
  '&::-webkit-scrollbar': {
74
  width: '8px',
 
83
  },
84
  },
85
  'code, pre': {
86
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, "Roboto Mono", monospace',
87
+ },
88
+ '.brand-logo': {
89
+ position: 'relative',
90
+ padding: '6px',
91
+ borderRadius: '8px',
92
+ '&::after': {
93
+ content: '""',
94
+ position: 'absolute',
95
+ inset: '-6px',
96
+ borderRadius: '10px',
97
+ background: 'var(--accent-yellow-weak)',
98
+ zIndex: -1,
99
+ pointerEvents: 'none',
100
+ },
101
  },
102
  },
103
  },
104
  MuiButton: {
105
  styleOverrides: {
106
  root: {
107
+ borderRadius: '10px',
108
  fontWeight: 600,
109
+ transition: 'transform 0.06s ease, background 0.12s ease, box-shadow 0.12s ease',
110
+ '&:hover': {
111
+ transform: 'translateY(-1px)',
112
+ },
113
  },
114
  },
115
  },
 
117
  styleOverrides: {
118
  root: {
119
  backgroundImage: 'none',
120
+ backgroundColor: 'transparent', // Default to transparent for gradients
121
  },
122
  },
123
  },
124
  MuiDrawer: {
125
  styleOverrides: {
126
  paper: {
127
+ backgroundColor: 'var(--panel)',
128
+ borderRight: '1px solid rgba(255,255,255,0.03)',
129
+ },
130
+ },
131
+ },
132
+ MuiTextField: {
133
+ styleOverrides: {
134
+ root: {
135
+ '& .MuiOutlinedInput-root': {
136
+ borderRadius: 'var(--radius-md)',
137
+ '& fieldset': {
138
+ borderColor: 'rgba(255,255,255,0.03)',
139
+ },
140
+ '&:hover fieldset': {
141
+ borderColor: 'rgba(255,255,255,0.1)',
142
+ },
143
+ '&.Mui-focused fieldset': {
144
+ borderColor: 'var(--accent-yellow)',
145
+ borderWidth: '1px',
146
+ boxShadow: 'var(--focus)',
147
+ },
148
+ },
149
  },
150
  },
151
  },
152
  },
153
  shape: {
154
+ borderRadius: 12,
155
  },
156
  });
157
 
158
+ export default theme;