create-theokit 1.0.4 → 1.0.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-theokit",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "type": "module",
5
5
  "description": "Scaffold a new TheoKit project",
6
6
  "license": "Apache-2.0",
@@ -1,10 +1,11 @@
1
- /* TheoKit — global design tokens + reset */
1
+ /* TheoKit — design system */
2
2
 
3
3
  :root {
4
4
  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
5
5
  --font-mono: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas, monospace;
6
- --bg: #ffffff;
7
- --bg-secondary: #fafafa;
6
+
7
+ --bg: #fafafa;
8
+ --bg-content: #ffffff;
8
9
  --card: #ffffff;
9
10
  --border: #e5e5e5;
10
11
  --text: #171717;
@@ -12,6 +13,10 @@
12
13
  --text-muted: #999999;
13
14
  --accent: #6366f1;
14
15
  --accent-hover: #4f46e5;
16
+ --btn-primary-bg: #171717;
17
+ --btn-primary-hover: #383838;
18
+ --btn-secondary-hover: #f2f2f2;
19
+ --btn-secondary-border: #ebebeb;
15
20
  --green: #22c55e;
16
21
  --red: #ef4444;
17
22
  --yellow: #eab308;
@@ -20,7 +25,7 @@
20
25
  @media (prefers-color-scheme: dark) {
21
26
  :root {
22
27
  --bg: #0a0a0a;
23
- --bg-secondary: #111111;
28
+ --bg-content: #0a0a0a;
24
29
  --card: #141414;
25
30
  --border: #2a2a2a;
26
31
  --text: #ededed;
@@ -28,11 +33,14 @@
28
33
  --text-muted: #666666;
29
34
  --accent: #818cf8;
30
35
  --accent-hover: #6366f1;
36
+ --btn-primary-bg: #ededed;
37
+ --btn-primary-hover: #cccccc;
38
+ --btn-secondary-hover: #1a1a1a;
39
+ --btn-secondary-border: #2a2a2a;
31
40
  --green: #22c55e;
32
41
  --red: #ef4444;
33
42
  --yellow: #eab308;
34
43
  }
35
-
36
44
  html { color-scheme: dark; }
37
45
  }
38
46
 
@@ -50,31 +58,146 @@ body {
50
58
  min-height: 100vh;
51
59
  display: flex;
52
60
  flex-direction: column;
61
+ align-items: center;
53
62
  -webkit-font-smoothing: antialiased;
54
63
  -moz-osx-font-smoothing: grayscale;
55
64
  }
56
65
 
66
+ a { color: inherit; text-decoration: none; }
57
67
  code, pre { font-family: var(--font-mono); }
58
68
 
59
- a { color: inherit; text-decoration: none; }
69
+ /* ─── Page container ────────────────────────────────── */
60
70
 
61
- /* ─── Layout ────────────────────────────────────────── */
71
+ .page {
72
+ display: flex;
73
+ flex: 1;
74
+ flex-direction: column;
75
+ align-items: center;
76
+ width: 100%;
77
+ }
62
78
 
63
- .container {
64
- max-width: 1200px;
65
- margin: 0 auto;
66
- padding: 24px;
79
+ .main {
80
+ display: flex;
67
81
  flex: 1;
82
+ flex-direction: column;
68
83
  width: 100%;
84
+ max-width: 900px;
85
+ background: var(--bg-content);
86
+ padding: 80px 48px 48px;
69
87
  }
70
88
 
71
- /* ─── Cards ─────────────────────────────────────────── */
89
+ @media (max-width: 768px) {
90
+ .main { padding: 48px 20px 32px; }
91
+ }
72
92
 
73
- .card {
93
+ /* ─── Hero ──────────────────────────────────────────── */
94
+
95
+ .hero {
96
+ display: flex;
97
+ flex-direction: column;
98
+ align-items: center;
99
+ text-align: center;
100
+ gap: 16px;
101
+ margin-bottom: 48px;
102
+ }
103
+
104
+ .hero-logo {
105
+ border-radius: 16px;
106
+ margin-bottom: 8px;
107
+ }
108
+
109
+ .hero h1 {
110
+ font-size: 40px;
111
+ font-weight: 700;
112
+ letter-spacing: -2.4px;
113
+ line-height: 48px;
114
+ text-wrap: balance;
115
+ }
116
+
117
+ .hero .tagline {
118
+ font-size: 18px;
119
+ line-height: 28px;
120
+ color: var(--text-secondary);
121
+ max-width: 440px;
122
+ text-wrap: balance;
123
+ }
124
+
125
+ .hero .hint {
126
+ font-size: 14px;
127
+ color: var(--text-muted);
128
+ margin-top: 8px;
129
+ }
130
+
131
+ .hero .hint code {
74
132
  background: var(--card);
75
133
  border: 1px solid var(--border);
76
- border-radius: 12px;
77
- padding: 24px;
134
+ padding: 2px 8px;
135
+ border-radius: 6px;
136
+ font-size: 13px;
137
+ }
138
+
139
+ @media (max-width: 768px) {
140
+ .hero h1 { font-size: 32px; line-height: 40px; letter-spacing: -1.92px; }
141
+ .hero .tagline { font-size: 16px; }
142
+ }
143
+
144
+ /* ─── CTA Buttons ───────────────────────────────────── */
145
+
146
+ .ctas {
147
+ display: flex;
148
+ gap: 12px;
149
+ margin-top: 8px;
150
+ }
151
+
152
+ .btn {
153
+ display: inline-flex;
154
+ justify-content: center;
155
+ align-items: center;
156
+ height: 40px;
157
+ padding: 0 20px;
158
+ border-radius: 128px;
159
+ border: 1px solid transparent;
160
+ font-size: 14px;
161
+ font-weight: 500;
162
+ cursor: pointer;
163
+ transition: background 0.2s, border-color 0.2s;
164
+ text-decoration: none;
165
+ }
166
+
167
+ .btn.primary {
168
+ background: var(--btn-primary-bg);
169
+ color: var(--bg);
170
+ }
171
+
172
+ .btn.secondary {
173
+ border-color: var(--btn-secondary-border);
174
+ color: var(--text);
175
+ }
176
+
177
+ @media (hover: hover) and (pointer: fine) {
178
+ .btn.primary:hover { background: var(--btn-primary-hover); }
179
+ .btn.secondary:hover { background: var(--btn-secondary-hover); border-color: transparent; }
180
+ }
181
+
182
+ /* ─── Role selector ─────────────────────────────────── */
183
+
184
+ .role-bar {
185
+ display: flex;
186
+ justify-content: center;
187
+ align-items: center;
188
+ gap: 8px;
189
+ margin-bottom: 32px;
190
+ font-size: 14px;
191
+ color: var(--text-muted);
192
+ }
193
+
194
+ .role-bar select {
195
+ padding: 6px 12px;
196
+ background: var(--card);
197
+ border: 1px solid var(--border);
198
+ border-radius: 6px;
199
+ color: var(--text);
200
+ font-size: 13px;
78
201
  }
79
202
 
80
203
  /* ─── Grid ──────────────────────────────────────────── */
@@ -83,24 +206,35 @@ a { color: inherit; text-decoration: none; }
83
206
  display: grid;
84
207
  grid-template-columns: 1fr 1fr;
85
208
  gap: 24px;
209
+ width: 100%;
86
210
  }
87
211
 
88
212
  @media (max-width: 768px) {
89
213
  .grid { grid-template-columns: 1fr; }
90
214
  }
91
215
 
92
- /* ─── Typography ────────────────────────────────────── */
216
+ /* ─── Cards ─────────────────────────────────────────── */
93
217
 
94
- h1 { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
95
- h2 { font-size: 1rem; font-weight: 600; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }
218
+ .card {
219
+ background: var(--card);
220
+ border: 1px solid var(--border);
221
+ border-radius: 12px;
222
+ padding: 24px;
223
+ }
96
224
 
97
- .accent { color: var(--accent); }
98
- .subtitle { color: var(--text-secondary); font-size: 0.9rem; margin-top: 4px; line-height: 1.5; }
225
+ .card h2 {
226
+ font-size: 15px;
227
+ font-weight: 600;
228
+ margin-bottom: 16px;
229
+ display: flex;
230
+ align-items: center;
231
+ gap: 8px;
232
+ }
99
233
 
100
234
  /* ─── Badges ────────────────────────────────────────── */
101
235
 
102
236
  .badge {
103
- font-size: 0.65rem;
237
+ font-size: 11px;
104
238
  padding: 2px 10px;
105
239
  border-radius: 99px;
106
240
  font-weight: 500;
@@ -115,87 +249,88 @@ h2 { font-size: 1rem; font-weight: 600; margin-bottom: 16px; display: flex; alig
115
249
 
116
250
  /* ─── Table ─────────────────────────────────────────── */
117
251
 
118
- table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
119
- th { text-align: left; padding: 10px 8px; color: var(--text-muted); border-bottom: 1px solid var(--border); font-weight: 500; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; }
120
- td { padding: 10px 8px; border-bottom: 1px solid var(--border); }
121
- tr.done td { opacity: 0.45; text-decoration: line-through; }
252
+ table { width: 100%; border-collapse: collapse; font-size: 13px; }
253
+ th {
254
+ text-align: left; padding: 8px 6px;
255
+ color: var(--text-muted); border-bottom: 1px solid var(--border);
256
+ font-weight: 500; font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em;
257
+ }
258
+ td { padding: 8px 6px; border-bottom: 1px solid var(--border); }
259
+ tr.done td { opacity: 0.4; text-decoration: line-through; }
122
260
 
123
- .prio { font-size: 0.7rem; padding: 2px 10px; border-radius: 99px; font-weight: 500; }
261
+ .prio { font-size: 11px; padding: 2px 8px; border-radius: 99px; font-weight: 500; }
124
262
  .prio-high { background: color-mix(in srgb, var(--red) 12%, transparent); color: var(--red); }
125
- .prio-med { background: color-mix(in srgb, var(--yellow) 12%, transparent); color: var(--yellow); }
263
+ .prio-medium { background: color-mix(in srgb, var(--yellow) 12%, transparent); color: var(--yellow); }
126
264
  .prio-low { background: color-mix(in srgb, var(--green) 12%, transparent); color: var(--green); }
127
265
 
128
266
  /* ─── Forms ─────────────────────────────────────────── */
129
267
 
130
268
  .create-bar { display: flex; gap: 8px; margin-top: 16px; }
131
269
  .create-bar input {
132
- flex: 1; padding: 10px 14px;
133
- background: var(--bg-secondary); border: 1px solid var(--border);
134
- border-radius: 8px; color: var(--text); font-size: 0.85rem;
270
+ flex: 1; padding: 8px 12px;
271
+ background: var(--bg); border: 1px solid var(--border);
272
+ border-radius: 8px; color: var(--text); font-size: 13px;
135
273
  outline: none; transition: border-color 0.2s;
136
274
  }
137
275
  .create-bar input:focus { border-color: var(--accent); }
138
276
  .create-bar select {
139
- padding: 10px 12px; background: var(--bg-secondary);
277
+ padding: 8px 10px; background: var(--bg);
140
278
  border: 1px solid var(--border); border-radius: 8px;
141
- color: var(--text); font-size: 0.8rem;
279
+ color: var(--text); font-size: 13px;
142
280
  }
143
281
  .create-bar button, .chat-bar button {
144
- padding: 10px 20px; background: var(--accent); color: white;
282
+ padding: 8px 16px; background: var(--accent); color: white;
145
283
  border: none; border-radius: 8px; cursor: pointer;
146
- font-weight: 600; font-size: 0.85rem; transition: background 0.2s;
284
+ font-weight: 600; font-size: 13px; transition: background 0.2s;
147
285
  }
148
-
149
286
  @media (hover: hover) and (pointer: fine) {
150
287
  .create-bar button:hover, .chat-bar button:hover { background: var(--accent-hover); }
151
288
  }
152
-
153
289
  .create-bar button:disabled, .chat-bar button:disabled { opacity: 0.4; cursor: not-allowed; }
154
- .error { color: var(--red); font-size: 0.8rem; margin-top: 4px; }
155
-
156
- /* ─── Role selector ─────────────────────────────────── */
157
-
158
- .role-bar { margin-top: 14px; display: flex; align-items: center; gap: 8px; }
159
- .role-bar label { font-size: 0.8rem; color: var(--text-muted); }
160
- .role-bar select {
161
- padding: 6px 12px; background: var(--bg-secondary);
162
- border: 1px solid var(--border); border-radius: 6px;
163
- color: var(--text); font-size: 0.8rem;
164
- }
290
+ .error { color: var(--red); font-size: 13px; margin-top: 6px; }
165
291
 
166
292
  /* ─── Chat ──────────────────────────────────────────── */
167
293
 
168
294
  .chat-box {
169
- height: 420px; overflow-y: auto; padding: 16px;
170
- background: var(--bg-secondary); border: 1px solid var(--border);
295
+ height: 320px; overflow-y: auto; padding: 14px;
296
+ background: var(--bg); border: 1px solid var(--border);
171
297
  border-radius: 10px; margin-bottom: 12px;
172
- font-size: 0.85rem; line-height: 1.7;
298
+ font-size: 13px; line-height: 1.6;
173
299
  }
174
300
 
175
- .msg { margin-bottom: 10px; padding: 10px 14px; border-radius: 10px; }
301
+ .msg { margin-bottom: 8px; padding: 8px 12px; border-radius: 8px; }
176
302
  .msg.user { background: color-mix(in srgb, var(--accent) 10%, transparent); color: var(--accent); }
177
303
  .msg.agent { background: var(--card); border: 1px solid var(--border); }
178
- .msg.tool { background: color-mix(in srgb, var(--yellow) 8%, transparent); color: var(--yellow); font-size: 0.78rem; font-family: var(--font-mono); }
179
- .msg.system { color: var(--text-muted); font-size: 0.78rem; font-style: italic; }
180
- .msg.error { color: var(--red); font-size: 0.8rem; }
304
+ .msg.tool { background: color-mix(in srgb, var(--yellow) 8%, transparent); color: var(--yellow); font-size: 12px; font-family: var(--font-mono); }
305
+ .msg.system { color: var(--text-muted); font-size: 12px; font-style: italic; }
306
+ .msg.error { color: var(--red); font-size: 13px; }
181
307
 
182
308
  .chat-bar { display: flex; gap: 8px; }
183
309
  .chat-bar input {
184
- flex: 1; padding: 12px 16px;
185
- background: var(--bg-secondary); border: 1px solid var(--border);
186
- border-radius: 10px; color: var(--text); font-size: 0.9rem;
310
+ flex: 1; padding: 10px 14px;
311
+ background: var(--bg); border: 1px solid var(--border);
312
+ border-radius: 10px; color: var(--text); font-size: 14px;
187
313
  outline: none; transition: border-color 0.2s;
188
314
  }
189
315
  .chat-bar input:focus { border-color: var(--accent); }
190
316
 
191
- .cost { color: var(--text-muted); font-size: 0.75rem; margin-top: 8px; text-align: right; }
317
+ /* ─── Footer ────────────────────────────────────────── */
318
+
319
+ .footer {
320
+ text-align: center;
321
+ padding: 40px 24px 32px;
322
+ font-size: 13px;
323
+ color: var(--text-muted);
324
+ }
325
+
326
+ .footer a { color: var(--text-secondary); transition: color 0.2s; }
327
+ .footer a:hover { color: var(--accent); }
192
328
 
193
329
  /* ─── Loading ───────────────────────────────────────── */
194
330
 
195
331
  .loading-spinner {
196
- width: 40px;
197
- height: 40px;
198
- border: 3px solid var(--border);
332
+ width: 24px; height: 24px;
333
+ border: 2px solid var(--border);
199
334
  border-top-color: var(--accent);
200
335
  border-radius: 50%;
201
336
  animation: spin 0.8s linear infinite;
@@ -204,93 +339,3 @@ tr.done td { opacity: 0.45; text-decoration: line-through; }
204
339
  @keyframes spin {
205
340
  to { transform: rotate(360deg); }
206
341
  }
207
-
208
- /* ─── Hero ──────────────────────────────────────────── */
209
-
210
- .hero {
211
- text-align: center;
212
- padding: 48px 24px 32px;
213
- }
214
-
215
- .hero img {
216
- margin-bottom: 16px;
217
- border-radius: 16px;
218
- }
219
-
220
- .hero h1 {
221
- font-size: 2.5rem;
222
- font-weight: 800;
223
- letter-spacing: -0.03em;
224
- margin-bottom: 4px;
225
- }
226
-
227
- .hero .tagline {
228
- color: var(--text-secondary);
229
- font-size: 1.1rem;
230
- margin-bottom: 24px;
231
- }
232
-
233
- .hero-links {
234
- display: flex;
235
- justify-content: center;
236
- gap: 12px;
237
- margin-bottom: 24px;
238
- }
239
-
240
- .btn {
241
- display: inline-flex;
242
- align-items: center;
243
- padding: 10px 24px;
244
- border-radius: 99px;
245
- font-weight: 600;
246
- font-size: 0.9rem;
247
- text-decoration: none;
248
- transition: background 0.2s, border-color 0.2s;
249
- }
250
-
251
- .btn.primary {
252
- background: var(--accent);
253
- color: white;
254
- }
255
-
256
- .btn.secondary {
257
- background: transparent;
258
- border: 1px solid var(--border);
259
- color: var(--text);
260
- }
261
-
262
- @media (hover: hover) and (pointer: fine) {
263
- .btn.primary:hover { background: var(--accent-hover); }
264
- .btn.secondary:hover { background: var(--bg-secondary); }
265
- }
266
-
267
- .hero .hint {
268
- color: var(--text-muted);
269
- font-size: 0.8rem;
270
- }
271
-
272
- .hero .hint code {
273
- font-family: var(--font-mono);
274
- background: var(--bg-secondary);
275
- padding: 2px 6px;
276
- border-radius: 4px;
277
- font-size: 0.75rem;
278
- }
279
-
280
- /* ─── Footer ────────────────────────────────────────── */
281
-
282
- .footer {
283
- text-align: center;
284
- padding: 32px 24px;
285
- color: var(--text-muted);
286
- font-size: 0.8rem;
287
- }
288
-
289
- .footer a {
290
- color: var(--accent);
291
- text-decoration: none;
292
- }
293
-
294
- .footer a:hover {
295
- text-decoration: underline;
296
- }
@@ -2,23 +2,9 @@
2
2
 
3
3
  import { useState, useEffect, useCallback, useRef, type FormEvent } from 'react'
4
4
 
5
- // ── Types ──
6
-
7
- interface Task {
8
- id: number
9
- title: string
10
- priority: 'high' | 'medium' | 'low'
11
- done: boolean
12
- }
13
-
5
+ interface Task { id: number; title: string; priority: 'high' | 'medium' | 'low'; done: boolean }
14
6
  type Role = '' | 'user' | 'admin'
15
-
16
- interface ChatMsg {
17
- role: 'user' | 'agent' | 'tool' | 'system' | 'error'
18
- text: string
19
- }
20
-
21
- // ── Page ──
7
+ interface ChatMsg { role: 'user' | 'agent' | 'tool' | 'system' | 'error'; text: string }
22
8
 
23
9
  export default function Page() {
24
10
  const [tasks, setTasks] = useState<Task[]>([])
@@ -31,13 +17,12 @@ export default function Page() {
31
17
  const [chatBusy, setChatBusy] = useState(false)
32
18
  const chatRef = useRef<HTMLDivElement>(null)
33
19
 
34
- const headers = useCallback((): Record<string, string> => {
20
+ const hdrs = useCallback((): Record<string, string> => {
35
21
  const h: Record<string, string> = { 'Content-Type': 'application/json' }
36
22
  if (role) h['x-role'] = role
37
23
  return h
38
24
  }, [role])
39
25
 
40
- // Fetch tasks on mount + when role changes
41
26
  const loadTasks = useCallback(async () => {
42
27
  const res = await fetch('/api/tasks')
43
28
  if (res.ok) setTasks(await res.json())
@@ -45,38 +30,33 @@ export default function Page() {
45
30
 
46
31
  useEffect(() => { loadTasks() }, [loadTasks])
47
32
 
48
- // Create task
49
33
  const createTask = async (e: FormEvent) => {
50
34
  e.preventDefault()
51
35
  setFormError('')
52
36
  if (!title.trim()) return
53
- const res = await fetch('/api/tasks', { method: 'POST', headers: headers(), body: JSON.stringify({ title, priority }) })
37
+ const res = await fetch('/api/tasks', { method: 'POST', headers: hdrs(), body: JSON.stringify({ title, priority }) })
54
38
  if (res.status === 403) { setFormError('403 — Need User role'); return }
55
39
  if (!res.ok) { const b = await res.json(); setFormError(b.error?.issues?.[0]?.message ?? `Error ${res.status}`); return }
56
40
  setTitle('')
57
41
  loadTasks()
58
42
  }
59
43
 
60
- // AI Chat
61
44
  const sendChat = async () => {
62
45
  const msg = chatInput.trim()
63
46
  if (!msg || chatBusy) return
64
47
  setChatInput('')
65
48
  setChat(c => [...c, { role: 'user', text: msg }])
66
49
  setChatBusy(true)
67
-
68
50
  try {
69
51
  const res = await fetch('/api/agents/assistant/chat', {
70
- method: 'POST', headers: headers(),
52
+ method: 'POST', headers: hdrs(),
71
53
  body: JSON.stringify({ message: msg, sessionId: 'session-' + Date.now() }),
72
54
  })
73
55
  if (res.status === 403) { setChat(c => [...c, { role: 'error', text: '403 — Need User role' }]); return }
74
-
75
56
  const reader = res.body?.getReader()
76
57
  if (!reader) return
77
58
  const decoder = new TextDecoder()
78
59
  let buf = '', agentText = ''
79
-
80
60
  while (true) {
81
61
  const { done, value } = await reader.read()
82
62
  if (done) break
@@ -90,111 +70,100 @@ export default function Page() {
90
70
  else if (ev.type === 'tool_call') setChat(c => [...c, { role: 'tool', text: `🔧 ${ev.toolName}` }])
91
71
  else if (ev.type === 'tool_result') setChat(c => [...c, { role: 'tool', text: `✅ ${(ev.output ?? '').slice(0, 80)}` }])
92
72
  else if (ev.type === 'error') setChat(c => [...c, { role: 'error', text: ev.message }])
93
- } catch { /* partial JSON */ }
73
+ } catch { /* partial */ }
94
74
  }
95
75
  }
96
76
  if (agentText) setChat(c => [...c, { role: 'agent', text: agentText }])
97
77
  loadTasks()
98
78
  } catch (err) {
99
79
  setChat(c => [...c, { role: 'error', text: `Error: ${err instanceof Error ? err.message : String(err)}` }])
100
- } finally {
101
- setChatBusy(false)
102
- }
80
+ } finally { setChatBusy(false) }
103
81
  }
104
82
 
105
83
  useEffect(() => { chatRef.current?.scrollTo(0, chatRef.current.scrollHeight) }, [chat])
106
84
 
107
85
  return (
108
- <>
109
- {/* Hero */}
110
- <header className="hero">
111
- <img src="/logo.png" alt="TheoKit" width={80} height={80} />
112
- <h1>TheoKit</h1>
113
- <p className="tagline">Build the app your agent lives in.</p>
114
- <nav className="hero-links">
115
- <a href="https://usetheo.dev" target="_blank" rel="noopener noreferrer" className="btn primary">
116
- usetheo.dev
117
- </a>
118
- <a href="https://github.com/usetheodev/theokit" target="_blank" rel="noopener noreferrer" className="btn secondary">
119
- Documentation
120
- </a>
121
- </nav>
122
- <p className="hint">
123
- Edit <code>app/page.tsx</code> to get started. Changes hot-reload instantly.
124
- </p>
125
- </header>
126
-
127
- {/* Role selector */}
128
- <div className="role-bar">
129
- <label htmlFor="role">Role:</label>
130
- <select id="role" value={role} onChange={e => setRole(e.target.value as Role)}>
131
- <option value="">None (public only)</option>
132
- <option value="user">User</option>
133
- <option value="admin">Admin</option>
134
- </select>
135
- </div>
136
-
137
- {/* Main grid */}
138
- <main className="grid">
139
- {/* Tasks CRUD */}
140
- <section className="card">
141
- <h2>Tasks <span className="badge">@Controller</span></h2>
142
- <table>
143
- <thead><tr><th>Task</th><th>Priority</th><th>Status</th></tr></thead>
144
- <tbody>
145
- {tasks.map(t => (
146
- <tr key={t.id} className={t.done ? 'done' : ''}>
147
- <td>{t.done ? '✅ ' : '○ '}{t.title}</td>
148
- <td><span className={`prio prio-${t.priority}`}>{t.priority}</span></td>
149
- <td>{t.done ? 'Done' : 'To do'}</td>
150
- </tr>
86
+ <div className="page">
87
+ <div className="main">
88
+ {/* Hero */}
89
+ <header className="hero">
90
+ <img src="/logo.png" alt="TheoKit" width={72} height={72} className="hero-logo" />
91
+ <h1>TheoKit</h1>
92
+ <p className="tagline">Build the app your agent lives in.</p>
93
+ <nav className="ctas">
94
+ <a href="https://usetheo.dev" target="_blank" rel="noopener noreferrer" className="btn primary">
95
+ Get Started
96
+ </a>
97
+ <a href="https://github.com/usetheodev/theokit" target="_blank" rel="noopener noreferrer" className="btn secondary">
98
+ Documentation
99
+ </a>
100
+ </nav>
101
+ <p className="hint">
102
+ Edit <code>app/page.tsx</code> to get started.
103
+ </p>
104
+ </header>
105
+
106
+ {/* Role */}
107
+ <div className="role-bar">
108
+ <label htmlFor="role">Role:</label>
109
+ <select id="role" value={role} onChange={e => setRole(e.target.value as Role)}>
110
+ <option value="">None (public)</option>
111
+ <option value="user">User</option>
112
+ <option value="admin">Admin</option>
113
+ </select>
114
+ </div>
115
+
116
+ {/* Content */}
117
+ <div className="grid">
118
+ <section className="card">
119
+ <h2>Tasks <span className="badge">@Controller</span></h2>
120
+ <table>
121
+ <thead><tr><th>Task</th><th>Priority</th><th>Status</th></tr></thead>
122
+ <tbody>
123
+ {tasks.map(t => (
124
+ <tr key={t.id} className={t.done ? 'done' : ''}>
125
+ <td>{t.done ? '✅ ' : '○ '}{t.title}</td>
126
+ <td><span className={`prio prio-${t.priority}`}>{t.priority}</span></td>
127
+ <td>{t.done ? 'Done' : 'To do'}</td>
128
+ </tr>
129
+ ))}
130
+ </tbody>
131
+ </table>
132
+ <form onSubmit={createTask} className="create-bar">
133
+ <input value={title} onChange={e => setTitle(e.target.value)} placeholder="New task..." required minLength={3} />
134
+ <select value={priority} onChange={e => setPriority(e.target.value as Task['priority'])}>
135
+ <option value="medium">Medium</option>
136
+ <option value="high">High</option>
137
+ <option value="low">Low</option>
138
+ </select>
139
+ <button type="submit">Add</button>
140
+ </form>
141
+ {formError && <p className="error">{formError}</p>}
142
+ </section>
143
+
144
+ <section className="card">
145
+ <h2>AI Assistant <span className="badge badge-ai">@Agent + SSE</span></h2>
146
+ <div ref={chatRef} className="chat-box">
147
+ {chat.map((m, i) => (
148
+ <div key={i} className={`msg ${m.role}`}>{m.role === 'user' ? `You: ${m.text}` : m.text}</div>
151
149
  ))}
152
- </tbody>
153
- </table>
154
- <form onSubmit={createTask} className="create-bar">
155
- <input value={title} onChange={e => setTitle(e.target.value)} placeholder="New task..." required minLength={3} />
156
- <select value={priority} onChange={e => setPriority(e.target.value as Task['priority'])}>
157
- <option value="medium">Medium</option>
158
- <option value="high">High</option>
159
- <option value="low">Low</option>
160
- </select>
161
- <button type="submit">Add</button>
162
- </form>
163
- {formError && <p className="error">{formError}</p>}
164
- </section>
165
-
166
- {/* AI Chat */}
167
- <section className="card">
168
- <h2>AI Assistant <span className="badge badge-ai">@Agent + SSE</span></h2>
169
- <div ref={chatRef} className="chat-box">
170
- {chat.map((m, i) => (
171
- <div key={i} className={`msg ${m.role}`}>{m.role === 'user' ? `You: ${m.text}` : m.text}</div>
172
- ))}
173
- </div>
174
- <div className="chat-bar">
175
- <input
176
- value={chatInput}
177
- onChange={e => setChatInput(e.target.value)}
178
- onKeyDown={e => e.key === 'Enter' && sendChat()}
179
- placeholder="Message the AI assistant..."
180
- disabled={chatBusy}
181
- />
182
- <button type="button" onClick={sendChat} disabled={chatBusy}>Send</button>
183
- </div>
184
- </section>
185
- </main>
186
-
187
- {/* Footer */}
188
- <footer className="footer">
189
- <p>
190
- Powered by{' '}
191
- <a href="https://usetheo.dev" target="_blank" rel="noopener noreferrer">TheoKit</a>
150
+ </div>
151
+ <div className="chat-bar">
152
+ <input value={chatInput} onChange={e => setChatInput(e.target.value)} onKeyDown={e => e.key === 'Enter' && sendChat()} placeholder="Message the AI assistant..." disabled={chatBusy} />
153
+ <button type="button" onClick={sendChat} disabled={chatBusy}>Send</button>
154
+ </div>
155
+ </section>
156
+ </div>
157
+
158
+ {/* Footer */}
159
+ <footer className="footer">
160
+ Powered by <a href="https://usetheo.dev" target="_blank" rel="noopener noreferrer">TheoKit</a>
192
161
  {' · '}
193
162
  <a href="https://github.com/usetheodev/theokit" target="_blank" rel="noopener noreferrer">GitHub</a>
194
163
  {' · '}
195
164
  <a href="https://discord.usetheo.dev" target="_blank" rel="noopener noreferrer">Discord</a>
196
- </p>
197
- </footer>
198
- </>
165
+ </footer>
166
+ </div>
167
+ </div>
199
168
  )
200
169
  }
@@ -14,7 +14,7 @@
14
14
  "typecheck": "tsc --noEmit"
15
15
  },
16
16
  "dependencies": {
17
- "theokit": "^0.5.2",
17
+ "theokit": "^0.5.3",
18
18
  "react": "^19.0.0",
19
19
  "react-dom": "^19.0.0",
20
20
  "react-router": "^7.0.0",