Skip to content

Commit d130ceb

Browse files
committed
move to radix themed ui
1 parent 2462b6a commit d130ceb

File tree

16 files changed

+2171
-657
lines changed

16 files changed

+2171
-657
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,12 @@
5252
},
5353
"dependencies": {
5454
"@posthog/code-agent": "^0.2.0",
55-
"@radix-ui/react-tabs": "^1.0.4",
55+
"@radix-ui/react-icons": "^1.3.2",
56+
"@radix-ui/themes": "^3.2.1",
5657
"axios": "^1.6.7",
5758
"clsx": "^2.1.0",
5859
"date-fns": "^3.3.1",
60+
"radix-themes-tw": "0.2.3",
5961
"react": "^18.2.0",
6062
"react-dom": "^18.2.0",
6163
"react-hotkeys-hook": "^4.4.4",

pnpm-lock.yaml

Lines changed: 1615 additions & 178 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/renderer/App.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useEffect, useState } from 'react';
2+
import { Flex, Text, Spinner } from '@radix-ui/themes';
23
import { AuthScreen } from './components/AuthScreen';
34
import { MainLayout } from './components/MainLayout';
45
import { useAuthStore } from './stores/authStore';
@@ -13,9 +14,12 @@ function App() {
1314

1415
if (isLoading) {
1516
return (
16-
<div className="flex items-center justify-center h-screen bg-dark-bg">
17-
<div className="text-dark-text-muted">Loading...</div>
18-
</div>
17+
<Flex align="center" justify="center" minHeight="100vh">
18+
<Flex align="center" gap="3">
19+
<Spinner size="3" />
20+
<Text color="gray">Loading...</Text>
21+
</Flex>
22+
</Flex>
1923
);
2024
}
2125

Lines changed: 62 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useState } from 'react';
2+
import { Container, Flex, Card, Heading, Text, TextField, Button, Callout } from '@radix-ui/themes';
23
import { useAuthStore } from '../stores/authStore';
34

45
export function AuthScreen() {
@@ -24,62 +25,66 @@ export function AuthScreen() {
2425
};
2526

2627
return (
27-
<div className="min-h-screen flex items-center justify-center bg-dark-bg">
28-
<div className="w-full max-w-md p-8">
29-
<div className="text-center mb-8">
30-
<h1 className="text-3xl font-bold text-dark-text mb-2">Mission Control</h1>
31-
<p className="text-dark-text-muted">Sign in to your PostHog account</p>
32-
</div>
33-
34-
<form onSubmit={handleSubmit} className="space-y-6">
35-
<div>
36-
<label htmlFor="apiKey" className="block text-sm font-medium text-dark-text mb-2">
37-
Personal API Key
38-
</label>
39-
<input
40-
id="apiKey"
41-
type="password"
42-
value={apiKey}
43-
onChange={(e) => setApiKey(e.target.value)}
44-
className="w-full px-3 py-2 bg-dark-surface border border-dark-border rounded-md text-dark-text focus:ring-2 focus:ring-posthog-500 focus:border-transparent"
45-
placeholder="phx_..."
46-
required
47-
/>
48-
<p className="mt-1 text-xs text-dark-text-muted">
49-
Get your API key from PostHog settings
50-
</p>
51-
</div>
52-
53-
<div>
54-
<label htmlFor="apiHost" className="block text-sm font-medium text-dark-text mb-2">
55-
PostHog Instance URL
56-
</label>
57-
<input
58-
id="apiHost"
59-
type="url"
60-
value={apiHost}
61-
onChange={(e) => setApiHost(e.target.value)}
62-
className="w-full px-3 py-2 bg-dark-surface border border-dark-border rounded-md text-dark-text focus:ring-2 focus:ring-posthog-500 focus:border-transparent"
63-
placeholder="https://app.posthog.com"
64-
required
65-
/>
66-
</div>
67-
68-
{error && (
69-
<div className="p-3 bg-red-900/20 border border-red-800 rounded-md text-red-400 text-sm">
70-
{error}
71-
</div>
72-
)}
73-
74-
<button
75-
type="submit"
76-
disabled={isLoading || !apiKey}
77-
className="w-full py-2 px-4 bg-posthog-500 hover:bg-posthog-600 disabled:bg-gray-700 disabled:cursor-not-allowed text-white font-medium rounded-md transition-colors"
78-
>
79-
{isLoading ? 'Connecting...' : 'Connect'}
80-
</button>
81-
</form>
82-
</div>
83-
</div>
28+
<Container size="1">
29+
<Flex direction="column" align="center" justify="center" minHeight="100vh">
30+
<Card size="3" maxWidth="400px" width="100%">
31+
<Flex direction="column" gap="6">
32+
<Flex direction="column" align="center" gap="2">
33+
<Heading size="8">Mission Control</Heading>
34+
<Text color="gray">Sign in to your PostHog account</Text>
35+
</Flex>
36+
37+
<form onSubmit={handleSubmit}>
38+
<Flex direction="column" gap="4">
39+
<Flex direction="column" gap="2">
40+
<Text as="label" htmlFor="apiKey" size="2" weight="medium">
41+
Personal API Key
42+
</Text>
43+
<TextField.Root
44+
id="apiKey"
45+
type="password"
46+
value={apiKey}
47+
onChange={(e) => setApiKey(e.target.value)}
48+
placeholder="phx_..."
49+
required
50+
/>
51+
<Text size="1" color="gray">
52+
Get your API key from PostHog settings
53+
</Text>
54+
</Flex>
55+
56+
<Flex direction="column" gap="2">
57+
<Text as="label" htmlFor="apiHost" size="2" weight="medium">
58+
PostHog Instance URL
59+
</Text>
60+
<TextField.Root
61+
id="apiHost"
62+
type="url"
63+
value={apiHost}
64+
onChange={(e) => setApiHost(e.target.value)}
65+
placeholder="https://app.posthog.com"
66+
required
67+
/>
68+
</Flex>
69+
70+
{error && (
71+
<Callout.Root color="red">
72+
<Callout.Text>{error}</Callout.Text>
73+
</Callout.Root>
74+
)}
75+
76+
<Button
77+
type="submit"
78+
size="3"
79+
disabled={isLoading || !apiKey}
80+
>
81+
{isLoading ? 'Connecting...' : 'Connect'}
82+
</Button>
83+
</Flex>
84+
</form>
85+
</Flex>
86+
</Card>
87+
</Flex>
88+
</Container>
8489
);
8590
}
Lines changed: 97 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useEffect, useRef } from 'react';
2-
import clsx from 'clsx';
2+
import { Flex, Box, Heading, Text } from '@radix-ui/themes';
33
import { LogEntry, formatTime } from '../types/log';
44
import { ToolCallView } from './log/ToolCallView';
55
import { DiffView } from './log/DiffView';
@@ -12,117 +12,153 @@ interface LogViewProps {
1212

1313
export function LogView({ logs, isRunning }: LogViewProps) {
1414
const scrollRef = useRef<HTMLDivElement>(null);
15-
15+
1616
// Auto-scroll to bottom when new logs arrive
1717
useEffect(() => {
1818
if (scrollRef.current) {
1919
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
2020
}
2121
}, [logs]);
22-
22+
2323
if (logs.length === 0 && !isRunning) {
2424
return (
25-
<div className="flex flex-col items-center justify-center h-full p-8">
26-
<div className="text-dark-text-muted text-center">
27-
<p className="mb-2">No activity yet</p>
28-
<p className="text-sm">Run the task to see logs here</p>
29-
</div>
30-
</div>
25+
<Flex direction="column" align="center" justify="center" height="100%" p="8">
26+
<Flex direction="column" align="center" gap="2">
27+
<Text color="gray">No activity yet</Text>
28+
<Text size="2" color="gray">Run the task to see logs here</Text>
29+
</Flex>
30+
</Flex>
3131
);
3232
}
33-
33+
3434
return (
35-
<div className="flex flex-col h-full">
36-
<div className="p-4 border-b border-dark-border flex items-center justify-between">
37-
<h2 className="font-medium text-dark-text">Activity Log</h2>
38-
{isRunning && (
39-
<div className="flex items-center gap-2">
40-
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse" />
41-
<span className="text-sm text-dark-text-muted">Running</span>
42-
</div>
43-
)}
44-
</div>
45-
46-
<div ref={scrollRef} className="flex-1 overflow-y-auto p-4 font-mono text-sm whitespace-pre-wrap">
35+
<Flex direction="column" height="100%">
36+
<Box p="4" className="border-b border-gray-6">
37+
<Flex align="center" justify="between">
38+
<Heading size="3">Activity Log</Heading>
39+
{isRunning && (
40+
<Flex align="center" gap="2">
41+
<Box
42+
width="8px"
43+
height="8px"
44+
className="bg-green-9 rounded-full animate-pulse"
45+
/>
46+
<Text size="2" color="gray">Running</Text>
47+
</Flex>
48+
)}
49+
</Flex>
50+
</Box>
51+
52+
<Box
53+
ref={scrollRef}
54+
flexGrow="1"
55+
overflowY="auto"
56+
p="4"
57+
className="font-mono text-sm whitespace-pre-wrap"
58+
>
4759
{logs.map((log, index) => {
4860
// Backward compat for plain strings
4961
if (typeof log === 'string') {
5062
return (
51-
<div key={index} className={clsx('mb-2 leading-relaxed text-dark-text')}>
52-
<span className="text-dark-text-muted mr-2">{new Date().toLocaleTimeString()}</span>
53-
{log}
54-
</div>
63+
<Box key={index} >
64+
<Text color="gray" >
65+
{new Date().toLocaleTimeString()}
66+
</Text>
67+
<Text>{log}</Text>
68+
</Box>
5569
);
5670
}
5771
// Structured entries
5872
switch (log.type) {
5973
case 'text':
6074
return (
61-
<div key={index} className={clsx('mb-2 leading-relaxed', log.level === 'error' ? 'text-red-400' : 'text-dark-text')}>
62-
<span className="text-dark-text-muted mr-2">{formatTime(log.ts)}</span>
63-
{log.content}
64-
</div>
75+
<Box key={index} mb="2">
76+
<Text color="gray" mr="2">
77+
{formatTime(log.ts)}
78+
</Text>
79+
<Text color={log.level === 'error' ? 'red' : undefined}>
80+
{log.content}
81+
</Text>
82+
</Box>
6583
);
6684
case 'status':
6785
return (
68-
<div key={index} className="mb-2 leading-relaxed text-dark-text">
69-
<span className="text-dark-text-muted mr-2">{formatTime(log.ts)}</span>
70-
status: {log.phase}
71-
</div>
86+
<Box key={index} mb="2">
87+
<Text color="gray" mr="2">
88+
{formatTime(log.ts)}
89+
</Text>
90+
<Text>status: {log.phase}</Text>
91+
</Box>
7292
);
7393
case 'tool_call':
7494
return (
75-
<div key={index} className="mb-4">
76-
<div className="text-xs text-dark-text-muted mb-1">{formatTime(log.ts)} tool_call</div>
95+
<Box key={index} mb="2">
96+
<Text size="1" color="gray" >
97+
{formatTime(log.ts)} tool_call
98+
</Text>
7799
<ToolCallView toolName={log.toolName} callId={log.callId} args={log.args} />
78-
</div>
100+
</Box>
79101
);
80102
case 'tool_result':
81103
return (
82-
<div key={index} className="mb-4">
83-
<div className="text-xs text-dark-text-muted mb-1">{formatTime(log.ts)} tool_result</div>
104+
<Box key={index} mb="2">
105+
<Text size="1" color="gray" >
106+
{formatTime(log.ts)} tool_result
107+
</Text>
84108
<ToolCallView toolName={log.toolName} callId={log.callId} args={log.result} />
85-
</div>
109+
</Box>
86110
);
87111
case 'diff':
88112
return (
89-
<div key={index} className="mb-4">
90-
<div className="text-xs text-dark-text-muted mb-1">{formatTime(log.ts)} diff</div>
113+
<Box key={index} mb="2">
114+
<Text size="1" color="gray" >
115+
{formatTime(log.ts)} diff
116+
</Text>
91117
<DiffView file={log.file} patch={log.patch} added={log.summary?.added} removed={log.summary?.removed} />
92-
</div>
118+
</Box>
93119
);
94120
case 'file_write':
95121
return (
96-
<div key={index} className="mb-2 leading-relaxed text-dark-text">
97-
<span className="text-dark-text-muted mr-2">{formatTime(log.ts)}</span>
98-
file_write: {log.path}
99-
{typeof log.bytes === 'number' ? <span className="text-dark-text-muted"> ({log.bytes} bytes)</span> : null}
100-
</div>
122+
<Box key={index} mb="2">
123+
<Text color="gray" mr="2">
124+
{formatTime(log.ts)}
125+
</Text>
126+
<Text>file_write: {log.path}</Text>
127+
{typeof log.bytes === 'number' && (
128+
<Text color="gray"> ({log.bytes} bytes)</Text>
129+
)}
130+
</Box>
101131
);
102132
case 'metric':
103133
return (
104-
<div key={index} className="mb-2">
105-
<div className="text-xs text-dark-text-muted mb-1">{formatTime(log.ts)} metric</div>
134+
<Box key={index} mb="2">
135+
<Text size="1" color="gray" >
136+
{formatTime(log.ts)} metric
137+
</Text>
106138
<MetricView keyName={log.key} value={log.value} unit={log.unit} />
107-
</div>
139+
</Box>
108140
);
109141
case 'artifact':
110142
return (
111-
<div key={index} className="mb-2 leading-relaxed text-dark-text">
112-
<span className="text-dark-text-muted mr-2">{formatTime(log.ts)}</span>
113-
artifact: {/* simple preview */}
114-
</div>
143+
<Box key={index} mb="2">
144+
<Text color="gray" mr="2">
145+
{formatTime(log.ts)}
146+
</Text>
147+
<Text>artifact: {/* simple preview */}</Text>
148+
</Box>
115149
);
116150
default:
117151
return (
118-
<div key={index} className="mb-2 leading-relaxed text-dark-text">
119-
<span className="text-dark-text-muted mr-2">{new Date().toLocaleTimeString()}</span>
120-
{JSON.stringify(log)}
121-
</div>
152+
<Box key={index} mb="2">
153+
<Text color="gray" mr="2">
154+
{new Date().toLocaleTimeString()}
155+
</Text>
156+
<Text>{JSON.stringify(log)}</Text>
157+
</Box>
122158
);
123159
}
124160
})}
125-
</div>
126-
</div>
161+
</Box>
162+
</Flex>
127163
);
128164
}

0 commit comments

Comments
 (0)