@gridland/demo 0.2.13 → 0.2.15
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/dist/chunk-R3ENBVV6.js +2140 -0
- package/dist/chunk-SQ5UVJ3G.js +2146 -0
- package/dist/demo-names.json +1 -1
- package/dist/landing.js +6 -0
- package/dist/run.js +412 -1688
- package/package.json +6 -1
package/dist/run.js
CHANGED
|
@@ -1,1589 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChatPanel,
|
|
3
|
+
GRADIENTS,
|
|
4
|
+
Gradient,
|
|
5
|
+
LandingApp,
|
|
6
|
+
LinkDemo,
|
|
7
|
+
Message,
|
|
8
|
+
Modal,
|
|
9
|
+
MultiSelect,
|
|
10
|
+
PromptInput,
|
|
11
|
+
SelectInput,
|
|
12
|
+
SpinnerPicker,
|
|
13
|
+
StatusBar,
|
|
14
|
+
TabBar,
|
|
15
|
+
Table,
|
|
16
|
+
TextInput,
|
|
17
|
+
Timeline,
|
|
18
|
+
textStyle
|
|
19
|
+
} from "./chunk-R3ENBVV6.js";
|
|
20
|
+
|
|
1
21
|
// src/run.tsx
|
|
2
22
|
import { createCliRenderer } from "@opentui/core";
|
|
3
23
|
import { createRoot, useKeyboard as useKeyboard2 } from "@opentui/react";
|
|
4
24
|
|
|
5
25
|
// ../ui/scripts/demo-apps.tsx
|
|
6
|
-
import { useState
|
|
26
|
+
import { useState, useCallback, useRef, useEffect } from "react";
|
|
7
27
|
import { useKeyboard } from "@opentui/react";
|
|
8
|
-
|
|
9
|
-
// ../ui/components/link/link.tsx
|
|
10
|
-
import { jsx } from "react/jsx-runtime";
|
|
11
|
-
var UNDERLINE = 1 << 3;
|
|
12
|
-
var UNDERLINE_DASHED = 1 << 4;
|
|
13
|
-
var UNDERLINE_DOTTED = 1 << 6;
|
|
14
|
-
function Link({ children, url, underline = "solid" }) {
|
|
15
|
-
let attributes = 0;
|
|
16
|
-
if (underline === "solid") {
|
|
17
|
-
attributes = UNDERLINE;
|
|
18
|
-
} else if (underline === "dashed") {
|
|
19
|
-
attributes = UNDERLINE | UNDERLINE_DASHED;
|
|
20
|
-
} else if (underline === "dotted") {
|
|
21
|
-
attributes = UNDERLINE | UNDERLINE_DOTTED;
|
|
22
|
-
}
|
|
23
|
-
return /* @__PURE__ */ jsx("text", { children: /* @__PURE__ */ jsx("a", { href: url, style: { attributes }, children }) });
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// ../ui/components/link/link-demo.tsx
|
|
27
|
-
import { useState } from "react";
|
|
28
|
-
|
|
29
|
-
// ../ui/components/text-style.ts
|
|
30
|
-
var BOLD = 1 << 0;
|
|
31
|
-
var DIM = 1 << 1;
|
|
32
|
-
var ITALIC = 1 << 2;
|
|
33
|
-
var UNDERLINE2 = 1 << 3;
|
|
34
|
-
var INVERSE = 1 << 5;
|
|
35
|
-
function textStyle(opts) {
|
|
36
|
-
let attributes = 0;
|
|
37
|
-
if (opts.bold) attributes |= BOLD;
|
|
38
|
-
if (opts.dim) attributes |= DIM;
|
|
39
|
-
if (opts.italic) attributes |= ITALIC;
|
|
40
|
-
if (opts.underline) attributes |= UNDERLINE2;
|
|
41
|
-
if (opts.inverse) attributes |= INVERSE;
|
|
42
|
-
return {
|
|
43
|
-
...opts.fg ? { fg: opts.fg } : {},
|
|
44
|
-
...opts.bg ? { bg: opts.bg } : {},
|
|
45
|
-
...attributes ? { attributes } : {}
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ../ui/components/status-bar/status-bar.tsx
|
|
50
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
51
|
-
function StatusBar({ items, extra }) {
|
|
52
|
-
const parts = [];
|
|
53
|
-
if (extra !== void 0) {
|
|
54
|
-
parts.push(
|
|
55
|
-
/* @__PURE__ */ jsx2("span", { children: extra }, "extra")
|
|
56
|
-
);
|
|
57
|
-
parts.push(
|
|
58
|
-
/* @__PURE__ */ jsx2("span", { style: textStyle({ dim: true }), children: " \u2502 " }, "pipe")
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
items.forEach((item, i) => {
|
|
62
|
-
if (i > 0) {
|
|
63
|
-
parts.push(/* @__PURE__ */ jsx2("span", { children: " " }, `gap-${i}`));
|
|
64
|
-
}
|
|
65
|
-
parts.push(
|
|
66
|
-
/* @__PURE__ */ jsx2("span", { style: textStyle({ inverse: true, bold: true }), children: ` ${item.key} ` }, `key-${i}`)
|
|
67
|
-
);
|
|
68
|
-
parts.push(
|
|
69
|
-
/* @__PURE__ */ jsx2("span", { style: textStyle({ dim: true }), children: ` ${item.label}` }, `label-${i}`)
|
|
70
|
-
);
|
|
71
|
-
});
|
|
72
|
-
if (parts.length === 0) {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
return /* @__PURE__ */ jsx2("text", { children: parts });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ../ui/components/link/link-demo.tsx
|
|
79
|
-
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
80
|
-
var MODES = ["solid", "dashed", "dotted", "none"];
|
|
81
|
-
function LinkDemo({
|
|
82
|
-
url = "https://opentui.com",
|
|
83
|
-
label = "Visit opentui.com",
|
|
84
|
-
useKeyboard: useKeyboard3
|
|
85
|
-
}) {
|
|
86
|
-
const [modeIndex, setModeIndex] = useState(0);
|
|
87
|
-
const mode = MODES[modeIndex];
|
|
88
|
-
useKeyboard3?.((event) => {
|
|
89
|
-
if (event.name === "right") {
|
|
90
|
-
setModeIndex((i) => (i + 1) % MODES.length);
|
|
91
|
-
} else if (event.name === "left") {
|
|
92
|
-
setModeIndex((i) => (i - 1 + MODES.length) % MODES.length);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", gap: 1, children: [
|
|
96
|
-
/* @__PURE__ */ jsx3(Link, { url, underline: mode, children: label }),
|
|
97
|
-
/* @__PURE__ */ jsx3(
|
|
98
|
-
StatusBar,
|
|
99
|
-
{
|
|
100
|
-
extra: /* @__PURE__ */ jsx3("span", { style: textStyle({ bold: true }), children: mode.padEnd(6) }),
|
|
101
|
-
items: [
|
|
102
|
-
{ key: "\u2190\u2192", label: "underline style" }
|
|
103
|
-
]
|
|
104
|
-
}
|
|
105
|
-
)
|
|
106
|
-
] });
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ../ui/components/ascii/ascii.tsx
|
|
110
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
111
|
-
|
|
112
|
-
// ../ui/components/spinner/spinner.tsx
|
|
113
|
-
import { useEffect, useState as useState2 } from "react";
|
|
114
|
-
|
|
115
|
-
// ../ui/components/theme/themes.ts
|
|
116
|
-
var darkTheme = {
|
|
117
|
-
primary: "#FF71CE",
|
|
118
|
-
accent: "#01CDFE",
|
|
119
|
-
secondary: "#B967FF",
|
|
120
|
-
muted: "#7B6F8E",
|
|
121
|
-
border: "#B967FF",
|
|
122
|
-
text: "#F0E6FF",
|
|
123
|
-
success: "#05FFA1",
|
|
124
|
-
error: "#FF6B6B",
|
|
125
|
-
warning: "#FFC164"
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
// ../ui/components/theme/theme-context.tsx
|
|
129
|
-
import { createContext, useContext } from "react";
|
|
130
|
-
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
131
|
-
var ThemeContext = createContext(null);
|
|
132
|
-
function useTheme() {
|
|
133
|
-
return useContext(ThemeContext) ?? darkTheme;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// ../ui/components/spinner/spinner.tsx
|
|
137
|
-
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
138
|
-
var VARIANTS = {
|
|
139
|
-
dots: { frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"], interval: 83 },
|
|
140
|
-
pulse: { frames: ["\xB7", "\u2219", "\u25CF", "\u2219", "\xB7", "\xB7", "\xB7"], interval: 180 },
|
|
141
|
-
meter: { frames: ["\u25B1\u25B1\u25B1", "\u25B0\u25B1\u25B1", "\u25B0\u25B0\u25B1", "\u25B0\u25B0\u25B0", "\u25B0\u25B0\u25B1", "\u25B0\u25B1\u25B1", "\u25B1\u25B1\u25B1"], interval: 143 },
|
|
142
|
-
bloom: { frames: ["\xB7", "\u2726", "\u2727", "\u2739", "\u273A", "\u274B", "\u2738", "\u2735", "\u2738", "\u274B", "\u273A", "\u2739", "\u2727", "\u2726", "\xB7", "\xB7"], interval: 100 },
|
|
143
|
-
ellipsis: { frames: [" ", ". ", ".. ", "..."], interval: 333 }
|
|
144
|
-
};
|
|
145
|
-
var VARIANT_NAMES = Object.keys(VARIANTS);
|
|
146
|
-
function Spinner({ variant = "dots", text, color }) {
|
|
147
|
-
const theme = useTheme();
|
|
148
|
-
const resolvedColor = color ?? theme.accent;
|
|
149
|
-
const { frames, interval } = VARIANTS[variant];
|
|
150
|
-
const [frame, setFrame] = useState2(0);
|
|
151
|
-
useEffect(() => {
|
|
152
|
-
setFrame(0);
|
|
153
|
-
const timer = setInterval(() => {
|
|
154
|
-
setFrame((prev) => (prev + 1) % frames.length);
|
|
155
|
-
}, interval);
|
|
156
|
-
return () => clearInterval(timer);
|
|
157
|
-
}, [variant]);
|
|
158
|
-
return /* @__PURE__ */ jsxs2("text", { children: [
|
|
159
|
-
/* @__PURE__ */ jsx6("span", { style: { fg: resolvedColor }, children: frames[frame] }),
|
|
160
|
-
text ? /* @__PURE__ */ jsxs2("span", { children: [
|
|
161
|
-
" ",
|
|
162
|
-
text
|
|
163
|
-
] }) : null
|
|
164
|
-
] });
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// ../ui/components/spinner/spinner-showcase.tsx
|
|
168
|
-
import { useState as useState3 } from "react";
|
|
169
|
-
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
170
|
-
function SpinnerPicker({ useKeyboard: useKeyboard3 }) {
|
|
171
|
-
const theme = useTheme();
|
|
172
|
-
const [selected, setSelected] = useState3(0);
|
|
173
|
-
useKeyboard3?.((event) => {
|
|
174
|
-
if (event.name === "left") {
|
|
175
|
-
setSelected((s) => s > 0 ? s - 1 : VARIANT_NAMES.length - 1);
|
|
176
|
-
} else if (event.name === "right") {
|
|
177
|
-
setSelected((s) => s < VARIANT_NAMES.length - 1 ? s + 1 : 0);
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
const selectedName = VARIANT_NAMES[selected];
|
|
181
|
-
return /* @__PURE__ */ jsxs3("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
182
|
-
/* @__PURE__ */ jsx7("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: /* @__PURE__ */ jsx7(Spinner, { variant: selectedName, color: theme.accent }) }),
|
|
183
|
-
/* @__PURE__ */ jsx7(
|
|
184
|
-
StatusBar,
|
|
185
|
-
{
|
|
186
|
-
items: [{ key: "\u2190\u2192", label: "change spinner type" }],
|
|
187
|
-
extra: /* @__PURE__ */ jsx7("span", { style: textStyle({ fg: theme.accent, bold: true }), children: selectedName.padEnd(8) })
|
|
188
|
-
}
|
|
189
|
-
)
|
|
190
|
-
] });
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// ../ui/components/text-input/text-input.tsx
|
|
194
|
-
import { useState as useState4, useCallback } from "react";
|
|
195
|
-
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
196
|
-
function TextInput({
|
|
197
|
-
value: controlledValue,
|
|
198
|
-
onChange,
|
|
199
|
-
onSubmit,
|
|
200
|
-
placeholder = "",
|
|
201
|
-
prompt = "> ",
|
|
202
|
-
promptColor,
|
|
203
|
-
focus = true,
|
|
204
|
-
maxLength
|
|
205
|
-
}) {
|
|
206
|
-
const theme = useTheme();
|
|
207
|
-
const resolvedPromptColor = promptColor ?? theme.accent;
|
|
208
|
-
const [internalValue, setInternalValue] = useState4("");
|
|
209
|
-
const isControlled = controlledValue !== void 0;
|
|
210
|
-
const displayValue = isControlled ? controlledValue : internalValue;
|
|
211
|
-
const handleInput = useCallback(
|
|
212
|
-
(newValue) => {
|
|
213
|
-
if (!isControlled) setInternalValue(newValue);
|
|
214
|
-
onChange?.(newValue);
|
|
215
|
-
},
|
|
216
|
-
[isControlled, onChange]
|
|
217
|
-
);
|
|
218
|
-
const handleSubmit = useCallback(
|
|
219
|
-
(value) => {
|
|
220
|
-
onSubmit?.(value);
|
|
221
|
-
if (!isControlled) setInternalValue("");
|
|
222
|
-
},
|
|
223
|
-
[isControlled, onSubmit]
|
|
224
|
-
);
|
|
225
|
-
return /* @__PURE__ */ jsxs4("box", { children: [
|
|
226
|
-
prompt && /* @__PURE__ */ jsx8("text", { style: { fg: resolvedPromptColor }, children: prompt }),
|
|
227
|
-
/* @__PURE__ */ jsx8(
|
|
228
|
-
"input",
|
|
229
|
-
{
|
|
230
|
-
value: displayValue,
|
|
231
|
-
placeholder,
|
|
232
|
-
maxLength,
|
|
233
|
-
focused: focus,
|
|
234
|
-
onInput: handleInput,
|
|
235
|
-
onSubmit: handleSubmit
|
|
236
|
-
}
|
|
237
|
-
)
|
|
238
|
-
] });
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// ../ui/components/select-input/select-input.tsx
|
|
242
|
-
import { useReducer, useMemo, useRef } from "react";
|
|
243
|
-
import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
244
|
-
function reducer(state, action) {
|
|
245
|
-
switch (action.type) {
|
|
246
|
-
case "MOVE": {
|
|
247
|
-
let next = state.cursor + action.direction;
|
|
248
|
-
if (next < 0) next = action.max - 1;
|
|
249
|
-
if (next >= action.max) next = 0;
|
|
250
|
-
return { ...state, cursor: next };
|
|
251
|
-
}
|
|
252
|
-
case "SUBMIT":
|
|
253
|
-
return { ...state, submitted: true };
|
|
254
|
-
default:
|
|
255
|
-
return state;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
var VISIBLE = 12;
|
|
259
|
-
var BAR = "\u2502";
|
|
260
|
-
var RADIO = "\u25CB";
|
|
261
|
-
var CURSOR = "\u25B8";
|
|
262
|
-
var SEPARATOR = "\u2500";
|
|
263
|
-
function SelectInput({
|
|
264
|
-
items = [],
|
|
265
|
-
defaultValue,
|
|
266
|
-
value: controlledValue,
|
|
267
|
-
onChange,
|
|
268
|
-
disabled = false,
|
|
269
|
-
invalid = false,
|
|
270
|
-
required = false,
|
|
271
|
-
placeholder,
|
|
272
|
-
title = "Select",
|
|
273
|
-
submittedStatus = "submitted",
|
|
274
|
-
limit,
|
|
275
|
-
highlightColor,
|
|
276
|
-
onSubmit,
|
|
277
|
-
useKeyboard: useKeyboard3
|
|
278
|
-
}) {
|
|
279
|
-
const theme = useTheme();
|
|
280
|
-
const resolvedHighlight = highlightColor ?? theme.primary;
|
|
281
|
-
const isControlled = controlledValue !== void 0;
|
|
282
|
-
const controlledRef = useRef(isControlled);
|
|
283
|
-
if (controlledRef.current !== isControlled) {
|
|
284
|
-
console.warn("SelectInput: switching between controlled and uncontrolled is not supported.");
|
|
285
|
-
}
|
|
286
|
-
const initialIndex = items.findIndex((i) => i.value === (isControlled ? controlledValue : defaultValue));
|
|
287
|
-
const [state, dispatch] = useReducer(reducer, {
|
|
288
|
-
cursor: Math.max(0, initialIndex),
|
|
289
|
-
submitted: false
|
|
290
|
-
});
|
|
291
|
-
const { flatRows, selectableItems } = useMemo(() => {
|
|
292
|
-
const rows = [];
|
|
293
|
-
const selectable = [];
|
|
294
|
-
let index = 0;
|
|
295
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
296
|
-
for (const item of items) {
|
|
297
|
-
const group = item.group ?? "";
|
|
298
|
-
const list = grouped.get(group) ?? [];
|
|
299
|
-
list.push(item);
|
|
300
|
-
grouped.set(group, list);
|
|
301
|
-
}
|
|
302
|
-
let first = true;
|
|
303
|
-
for (const [group, groupItems] of grouped) {
|
|
304
|
-
if (!first) rows.push({ type: "separator" });
|
|
305
|
-
first = false;
|
|
306
|
-
if (group) {
|
|
307
|
-
rows.push({ type: "group", label: group });
|
|
308
|
-
}
|
|
309
|
-
for (const item of groupItems) {
|
|
310
|
-
rows.push({ type: "item", item, index });
|
|
311
|
-
selectable.push({ item, index });
|
|
312
|
-
index++;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
return { flatRows: rows, selectableItems: selectable };
|
|
316
|
-
}, [items]);
|
|
317
|
-
const visibleCount = limit ?? VISIBLE;
|
|
318
|
-
const cursorRowIndex = flatRows.findIndex((r) => r.type === "item" && r.index === state.cursor);
|
|
319
|
-
const scrollOffset = Math.max(0, Math.min(cursorRowIndex - Math.floor(visibleCount / 2), flatRows.length - visibleCount));
|
|
320
|
-
const visibleRows = flatRows.slice(scrollOffset, scrollOffset + visibleCount);
|
|
321
|
-
const diamondColor = invalid ? theme.error : disabled ? theme.muted : theme.accent;
|
|
322
|
-
useKeyboard3?.((event) => {
|
|
323
|
-
if (state.submitted || disabled) return;
|
|
324
|
-
if (event.name === "up" || event.name === "k") {
|
|
325
|
-
const direction = -1;
|
|
326
|
-
let next = state.cursor + direction;
|
|
327
|
-
if (next < 0) next = selectableItems.length - 1;
|
|
328
|
-
dispatch({ type: "MOVE", direction, max: selectableItems.length });
|
|
329
|
-
const nextItem = selectableItems[next];
|
|
330
|
-
if (nextItem && !nextItem.item.disabled) {
|
|
331
|
-
onChange?.(nextItem.item.value);
|
|
332
|
-
}
|
|
333
|
-
} else if (event.name === "down" || event.name === "j") {
|
|
334
|
-
const direction = 1;
|
|
335
|
-
let next = state.cursor + direction;
|
|
336
|
-
if (next >= selectableItems.length) next = 0;
|
|
337
|
-
dispatch({ type: "MOVE", direction, max: selectableItems.length });
|
|
338
|
-
const nextItem = selectableItems[next];
|
|
339
|
-
if (nextItem && !nextItem.item.disabled) {
|
|
340
|
-
onChange?.(nextItem.item.value);
|
|
341
|
-
}
|
|
342
|
-
} else if (event.name === "return") {
|
|
343
|
-
const current = selectableItems[state.cursor];
|
|
344
|
-
if (current && !current.item.disabled) {
|
|
345
|
-
dispatch({ type: "SUBMIT" });
|
|
346
|
-
onSubmit?.(isControlled ? controlledValue : current.item.value);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
if (state.submitted) {
|
|
351
|
-
const selectedItem = isControlled ? items.find((i) => i.value === controlledValue) : selectableItems[state.cursor]?.item;
|
|
352
|
-
return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", children: [
|
|
353
|
-
/* @__PURE__ */ jsxs5("text", { children: [
|
|
354
|
-
/* @__PURE__ */ jsx9("span", { style: textStyle({ fg: theme.success }), children: "\u25C6 " }),
|
|
355
|
-
/* @__PURE__ */ jsx9("span", { style: textStyle({ bold: true }), children: title })
|
|
356
|
-
] }),
|
|
357
|
-
selectedItem && /* @__PURE__ */ jsxs5("text", { children: [
|
|
358
|
-
/* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.success }), children: [
|
|
359
|
-
BAR,
|
|
360
|
-
" "
|
|
361
|
-
] }),
|
|
362
|
-
/* @__PURE__ */ jsx9("span", { children: " " }),
|
|
363
|
-
/* @__PURE__ */ jsx9("span", { style: textStyle({ fg: theme.success }), children: "\u25CF " }),
|
|
364
|
-
/* @__PURE__ */ jsx9("span", { children: selectedItem.label })
|
|
365
|
-
] }),
|
|
366
|
-
/* @__PURE__ */ jsx9("text", { children: " " }),
|
|
367
|
-
/* @__PURE__ */ jsx9("text", { children: /* @__PURE__ */ jsx9("span", { style: textStyle({ dim: true }), children: submittedStatus }) })
|
|
368
|
-
] });
|
|
369
|
-
}
|
|
370
|
-
const hasItems = selectableItems.length > 0;
|
|
371
|
-
return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", children: [
|
|
372
|
-
/* @__PURE__ */ jsxs5("text", { children: [
|
|
373
|
-
/* @__PURE__ */ jsx9("span", { style: textStyle({ fg: diamondColor, dim: disabled }), children: "\u25C6 " }),
|
|
374
|
-
/* @__PURE__ */ jsx9("span", { style: textStyle({ bold: true, dim: disabled }), children: title }),
|
|
375
|
-
required && /* @__PURE__ */ jsx9("span", { style: textStyle({ fg: theme.error }), children: " *" })
|
|
376
|
-
] }),
|
|
377
|
-
invalid && /* @__PURE__ */ jsxs5("text", { children: [
|
|
378
|
-
/* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
379
|
-
BAR,
|
|
380
|
-
" "
|
|
381
|
-
] }),
|
|
382
|
-
/* @__PURE__ */ jsx9("span", { style: textStyle({ fg: theme.error }), children: " Please select an option" })
|
|
383
|
-
] }),
|
|
384
|
-
!hasItems && placeholder && /* @__PURE__ */ jsxs5("text", { children: [
|
|
385
|
-
/* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
386
|
-
BAR,
|
|
387
|
-
" "
|
|
388
|
-
] }),
|
|
389
|
-
/* @__PURE__ */ jsxs5("span", { style: textStyle({ dim: true }), children: [
|
|
390
|
-
" ",
|
|
391
|
-
placeholder
|
|
392
|
-
] })
|
|
393
|
-
] }),
|
|
394
|
-
visibleRows.map((row, i) => {
|
|
395
|
-
if (row.type === "separator") {
|
|
396
|
-
return /* @__PURE__ */ jsxs5("text", { children: [
|
|
397
|
-
/* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
398
|
-
BAR,
|
|
399
|
-
" "
|
|
400
|
-
] }),
|
|
401
|
-
/* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
402
|
-
" ",
|
|
403
|
-
SEPARATOR.repeat(20)
|
|
404
|
-
] })
|
|
405
|
-
] }, `sep-${i}`);
|
|
406
|
-
}
|
|
407
|
-
if (row.type === "group") {
|
|
408
|
-
return /* @__PURE__ */ jsxs5("text", { children: [
|
|
409
|
-
/* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
410
|
-
BAR,
|
|
411
|
-
" "
|
|
412
|
-
] }),
|
|
413
|
-
/* @__PURE__ */ jsx9("span", { style: textStyle({ bold: true, fg: theme.muted }), children: ` ${row.label}` })
|
|
414
|
-
] }, `group-${row.label}`);
|
|
415
|
-
}
|
|
416
|
-
const { item, index: itemIndex } = row;
|
|
417
|
-
const isHighlighted = !disabled && itemIndex === state.cursor;
|
|
418
|
-
const isItemDisabled = disabled || !!item.disabled;
|
|
419
|
-
const itemColor = isItemDisabled ? theme.muted : isHighlighted ? resolvedHighlight : void 0;
|
|
420
|
-
return /* @__PURE__ */ jsxs5("text", { children: [
|
|
421
|
-
/* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
422
|
-
BAR,
|
|
423
|
-
" "
|
|
424
|
-
] }),
|
|
425
|
-
/* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: isHighlighted ? resolvedHighlight : void 0 }), children: [
|
|
426
|
-
isHighlighted ? CURSOR : " ",
|
|
427
|
-
" "
|
|
428
|
-
] }),
|
|
429
|
-
/* @__PURE__ */ jsxs5("span", { style: textStyle({ fg: theme.muted, dim: isItemDisabled }), children: [
|
|
430
|
-
RADIO,
|
|
431
|
-
" "
|
|
432
|
-
] }),
|
|
433
|
-
/* @__PURE__ */ jsx9("span", { style: textStyle({ fg: itemColor, dim: isItemDisabled }), children: item.label })
|
|
434
|
-
] }, item.key ?? String(item.value));
|
|
435
|
-
})
|
|
436
|
-
] });
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// ../ui/components/multi-select/multi-select.tsx
|
|
440
|
-
import { useReducer as useReducer2, useMemo as useMemo2, useRef as useRef2 } from "react";
|
|
441
|
-
import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
442
|
-
function reducer2(state, action) {
|
|
443
|
-
switch (action.type) {
|
|
444
|
-
case "MOVE": {
|
|
445
|
-
let next = state.cursor + action.direction;
|
|
446
|
-
if (next < 0) next = action.max - 1;
|
|
447
|
-
if (next >= action.max) next = 0;
|
|
448
|
-
return { ...state, cursor: next };
|
|
449
|
-
}
|
|
450
|
-
case "SET_SELECTED":
|
|
451
|
-
return { ...state, selected: new Set(action.values) };
|
|
452
|
-
case "SUBMIT":
|
|
453
|
-
return { ...state, submitted: true };
|
|
454
|
-
default:
|
|
455
|
-
return state;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
var VISIBLE2 = 12;
|
|
459
|
-
var BAR2 = "\u2502";
|
|
460
|
-
var CHECKED = "\u25CF";
|
|
461
|
-
var UNCHECKED = "\u25CB";
|
|
462
|
-
var CURSOR2 = "\u25B8";
|
|
463
|
-
var SEPARATOR2 = "\u2500";
|
|
464
|
-
function MultiSelect({
|
|
465
|
-
items = [],
|
|
466
|
-
defaultSelected = [],
|
|
467
|
-
selected: controlledSelected,
|
|
468
|
-
onChange,
|
|
469
|
-
disabled = false,
|
|
470
|
-
invalid = false,
|
|
471
|
-
required = false,
|
|
472
|
-
placeholder,
|
|
473
|
-
maxCount,
|
|
474
|
-
title = "Select",
|
|
475
|
-
submittedStatus = "submitted",
|
|
476
|
-
limit,
|
|
477
|
-
enableSelectAll = true,
|
|
478
|
-
enableClear = true,
|
|
479
|
-
highlightColor,
|
|
480
|
-
checkboxColor,
|
|
481
|
-
allowEmpty = false,
|
|
482
|
-
onSubmit,
|
|
483
|
-
useKeyboard: useKeyboard3
|
|
484
|
-
}) {
|
|
485
|
-
const theme = useTheme();
|
|
486
|
-
const resolvedHighlight = highlightColor ?? theme.primary;
|
|
487
|
-
const resolvedCheckbox = checkboxColor ?? theme.accent;
|
|
488
|
-
const isControlled = controlledSelected !== void 0;
|
|
489
|
-
const controlledRef = useRef2(isControlled);
|
|
490
|
-
if (controlledRef.current !== isControlled) {
|
|
491
|
-
console.warn("MultiSelect: switching between controlled and uncontrolled is not supported.");
|
|
492
|
-
}
|
|
493
|
-
const [state, dispatch] = useReducer2(reducer2, {
|
|
494
|
-
cursor: 0,
|
|
495
|
-
selected: new Set(isControlled ? controlledSelected : defaultSelected),
|
|
496
|
-
submitted: false
|
|
497
|
-
});
|
|
498
|
-
const cursorRef = useRef2(0);
|
|
499
|
-
const currentSelected = isControlled ? new Set(controlledSelected) : state.selected;
|
|
500
|
-
const { flatRows, selectableItems } = useMemo2(() => {
|
|
501
|
-
const rows = [];
|
|
502
|
-
const selectable = [];
|
|
503
|
-
let index = 0;
|
|
504
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
505
|
-
for (const item of items) {
|
|
506
|
-
const group = item.group ?? "";
|
|
507
|
-
const list = grouped.get(group) ?? [];
|
|
508
|
-
list.push(item);
|
|
509
|
-
grouped.set(group, list);
|
|
510
|
-
}
|
|
511
|
-
let first = true;
|
|
512
|
-
for (const [group, groupItems] of grouped) {
|
|
513
|
-
if (!first) rows.push({ type: "separator" });
|
|
514
|
-
first = false;
|
|
515
|
-
if (group) {
|
|
516
|
-
rows.push({ type: "group", label: group });
|
|
517
|
-
}
|
|
518
|
-
for (const item of groupItems) {
|
|
519
|
-
rows.push({ type: "item", item, index });
|
|
520
|
-
selectable.push({ item, index });
|
|
521
|
-
index++;
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
return { flatRows: rows, selectableItems: selectable };
|
|
525
|
-
}, [items]);
|
|
526
|
-
const hasSubmitRow = allowEmpty || currentSelected.size > 0;
|
|
527
|
-
const totalPositions = selectableItems.length + (hasSubmitRow ? 1 : 0);
|
|
528
|
-
const isOnSubmit = hasSubmitRow && state.cursor === selectableItems.length;
|
|
529
|
-
const visibleCount = limit ?? VISIBLE2;
|
|
530
|
-
const cursorRowIndex = flatRows.findIndex((r) => r.type === "item" && r.index === state.cursor);
|
|
531
|
-
const scrollOffset = Math.max(0, Math.min(cursorRowIndex - Math.floor(visibleCount / 2), flatRows.length - visibleCount));
|
|
532
|
-
const visibleRows = flatRows.slice(scrollOffset, scrollOffset + visibleCount);
|
|
533
|
-
const setSelected = (values) => {
|
|
534
|
-
if (isControlled) {
|
|
535
|
-
onChange?.(values);
|
|
536
|
-
} else {
|
|
537
|
-
dispatch({ type: "SET_SELECTED", values });
|
|
538
|
-
}
|
|
539
|
-
};
|
|
540
|
-
const diamondColor = invalid ? theme.error : disabled ? theme.muted : theme.accent;
|
|
541
|
-
useKeyboard3?.((event) => {
|
|
542
|
-
if (state.submitted || disabled) return;
|
|
543
|
-
const move = (direction) => {
|
|
544
|
-
let next = cursorRef.current + direction;
|
|
545
|
-
if (next < 0) next = totalPositions - 1;
|
|
546
|
-
if (next >= totalPositions) next = 0;
|
|
547
|
-
cursorRef.current = next;
|
|
548
|
-
dispatch({ type: "MOVE", direction, max: totalPositions });
|
|
549
|
-
};
|
|
550
|
-
if (event.name === "up" || event.name === "k") {
|
|
551
|
-
move(-1);
|
|
552
|
-
} else if (event.name === "down" || event.name === "j") {
|
|
553
|
-
move(1);
|
|
554
|
-
} else if (event.name === "return") {
|
|
555
|
-
const onSubmitRow = hasSubmitRow && cursorRef.current === selectableItems.length;
|
|
556
|
-
if (onSubmitRow) {
|
|
557
|
-
dispatch({ type: "SUBMIT" });
|
|
558
|
-
onSubmit?.(Array.from(currentSelected));
|
|
559
|
-
} else {
|
|
560
|
-
const current = selectableItems[cursorRef.current];
|
|
561
|
-
if (current && !current.item.disabled) {
|
|
562
|
-
const isDeselecting = currentSelected.has(current.item.value);
|
|
563
|
-
if (!isDeselecting && maxCount !== void 0 && currentSelected.size >= maxCount) return;
|
|
564
|
-
const next = new Set(currentSelected);
|
|
565
|
-
if (isDeselecting) next.delete(current.item.value);
|
|
566
|
-
else next.add(current.item.value);
|
|
567
|
-
setSelected(Array.from(next));
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
} else if (event.name === "a" && enableSelectAll) {
|
|
571
|
-
const enabledValues = items.filter((i) => !i.disabled).map((i) => i.value);
|
|
572
|
-
setSelected(maxCount !== void 0 ? enabledValues.slice(0, maxCount) : enabledValues);
|
|
573
|
-
} else if (event.name === "x" && enableClear) {
|
|
574
|
-
setSelected([]);
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
|
-
if (state.submitted) {
|
|
578
|
-
const selectedItems = items.filter((i) => currentSelected.has(i.value));
|
|
579
|
-
return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", children: [
|
|
580
|
-
/* @__PURE__ */ jsxs6("text", { children: [
|
|
581
|
-
/* @__PURE__ */ jsx10("span", { style: textStyle({ fg: theme.success }), children: "\u25C6 " }),
|
|
582
|
-
/* @__PURE__ */ jsx10("span", { style: textStyle({ bold: true }), children: title })
|
|
583
|
-
] }),
|
|
584
|
-
selectedItems.map((item) => /* @__PURE__ */ jsxs6("text", { children: [
|
|
585
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.success }), children: [
|
|
586
|
-
BAR2,
|
|
587
|
-
" "
|
|
588
|
-
] }),
|
|
589
|
-
/* @__PURE__ */ jsx10("span", { children: " " }),
|
|
590
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.success }), children: [
|
|
591
|
-
CHECKED,
|
|
592
|
-
" "
|
|
593
|
-
] }),
|
|
594
|
-
/* @__PURE__ */ jsx10("span", { children: item.label })
|
|
595
|
-
] }, item.key ?? String(item.value))),
|
|
596
|
-
/* @__PURE__ */ jsx10("text", { children: " " }),
|
|
597
|
-
/* @__PURE__ */ jsx10("text", { children: /* @__PURE__ */ jsxs6("span", { style: textStyle({ dim: true }), children: [
|
|
598
|
-
selectedItems.length,
|
|
599
|
-
" selected \u2014 ",
|
|
600
|
-
submittedStatus
|
|
601
|
-
] }) })
|
|
602
|
-
] });
|
|
603
|
-
}
|
|
604
|
-
const hasItems = selectableItems.length > 0;
|
|
605
|
-
return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", children: [
|
|
606
|
-
/* @__PURE__ */ jsxs6("text", { children: [
|
|
607
|
-
/* @__PURE__ */ jsx10("span", { style: textStyle({ fg: diamondColor, dim: disabled }), children: "\u25C6 " }),
|
|
608
|
-
/* @__PURE__ */ jsx10("span", { style: textStyle({ bold: true, dim: disabled }), children: title }),
|
|
609
|
-
required && /* @__PURE__ */ jsx10("span", { style: textStyle({ fg: theme.error }), children: " *" }),
|
|
610
|
-
maxCount !== void 0 && /* @__PURE__ */ jsx10("span", { style: textStyle({ dim: true }), children: ` (${currentSelected.size}/${maxCount})` })
|
|
611
|
-
] }),
|
|
612
|
-
invalid && /* @__PURE__ */ jsxs6("text", { children: [
|
|
613
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
614
|
-
BAR2,
|
|
615
|
-
" "
|
|
616
|
-
] }),
|
|
617
|
-
/* @__PURE__ */ jsx10("span", { style: textStyle({ fg: theme.error }), children: " Please select at least one option" })
|
|
618
|
-
] }),
|
|
619
|
-
!hasItems && placeholder && /* @__PURE__ */ jsxs6("text", { children: [
|
|
620
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
621
|
-
BAR2,
|
|
622
|
-
" "
|
|
623
|
-
] }),
|
|
624
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ dim: true }), children: [
|
|
625
|
-
" ",
|
|
626
|
-
placeholder
|
|
627
|
-
] })
|
|
628
|
-
] }),
|
|
629
|
-
visibleRows.map((row, i) => {
|
|
630
|
-
if (row.type === "separator") {
|
|
631
|
-
return /* @__PURE__ */ jsxs6("text", { children: [
|
|
632
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
633
|
-
BAR2,
|
|
634
|
-
" "
|
|
635
|
-
] }),
|
|
636
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
637
|
-
" ",
|
|
638
|
-
SEPARATOR2.repeat(20)
|
|
639
|
-
] })
|
|
640
|
-
] }, `sep-${i}`);
|
|
641
|
-
}
|
|
642
|
-
if (row.type === "group") {
|
|
643
|
-
return /* @__PURE__ */ jsxs6("text", { children: [
|
|
644
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
645
|
-
BAR2,
|
|
646
|
-
" "
|
|
647
|
-
] }),
|
|
648
|
-
/* @__PURE__ */ jsx10("span", { style: textStyle({ bold: true, fg: theme.muted }), children: ` ${row.label}` })
|
|
649
|
-
] }, `group-${row.label}`);
|
|
650
|
-
}
|
|
651
|
-
const { item, index: itemIndex } = row;
|
|
652
|
-
const isHighlighted = !disabled && itemIndex === state.cursor;
|
|
653
|
-
const isSelected = currentSelected.has(item.value);
|
|
654
|
-
const isItemDisabled = disabled || !!item.disabled;
|
|
655
|
-
const itemColor = isItemDisabled ? theme.muted : isHighlighted ? resolvedHighlight : isSelected ? resolvedCheckbox : void 0;
|
|
656
|
-
return /* @__PURE__ */ jsxs6("text", { children: [
|
|
657
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
658
|
-
BAR2,
|
|
659
|
-
" "
|
|
660
|
-
] }),
|
|
661
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: isHighlighted ? resolvedHighlight : void 0 }), children: [
|
|
662
|
-
isHighlighted ? CURSOR2 : " ",
|
|
663
|
-
" "
|
|
664
|
-
] }),
|
|
665
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: isSelected && !isItemDisabled ? resolvedCheckbox : theme.muted, dim: isItemDisabled }), children: [
|
|
666
|
-
isSelected ? CHECKED : UNCHECKED,
|
|
667
|
-
" "
|
|
668
|
-
] }),
|
|
669
|
-
/* @__PURE__ */ jsx10("span", { style: textStyle({ fg: itemColor, dim: isItemDisabled }), children: item.label })
|
|
670
|
-
] }, item.key ?? String(item.value));
|
|
671
|
-
}),
|
|
672
|
-
hasSubmitRow && /* @__PURE__ */ jsxs6("text", { children: [
|
|
673
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: theme.muted }), children: [
|
|
674
|
-
BAR2,
|
|
675
|
-
" "
|
|
676
|
-
] }),
|
|
677
|
-
/* @__PURE__ */ jsxs6("span", { style: textStyle({ fg: isOnSubmit ? resolvedHighlight : void 0 }), children: [
|
|
678
|
-
isOnSubmit ? CURSOR2 : " ",
|
|
679
|
-
" "
|
|
680
|
-
] }),
|
|
681
|
-
/* @__PURE__ */ jsx10("span", { style: textStyle({ fg: isOnSubmit ? resolvedHighlight : theme.muted }), children: "\u21B3 " }),
|
|
682
|
-
/* @__PURE__ */ jsx10("span", { style: textStyle({ fg: isOnSubmit ? resolvedHighlight : theme.text }), children: "Submit" })
|
|
683
|
-
] })
|
|
684
|
-
] });
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// ../ui/components/table/table.tsx
|
|
688
|
-
import { Fragment } from "react";
|
|
689
|
-
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
690
|
-
function getColumns(data, columnsProp) {
|
|
691
|
-
if (columnsProp) return columnsProp;
|
|
692
|
-
const keys = /* @__PURE__ */ new Set();
|
|
693
|
-
for (const row of data) {
|
|
694
|
-
for (const key in row) keys.add(key);
|
|
695
|
-
}
|
|
696
|
-
return Array.from(keys);
|
|
697
|
-
}
|
|
698
|
-
function calculateColumnWidths(columns, data, padding) {
|
|
699
|
-
return columns.map((field) => {
|
|
700
|
-
const headerWidth = String(field).length;
|
|
701
|
-
const maxDataWidth = data.reduce((max, row) => {
|
|
702
|
-
const val = row[field];
|
|
703
|
-
return Math.max(max, val == null ? 0 : String(val).length);
|
|
704
|
-
}, 0);
|
|
705
|
-
return { field, width: Math.max(headerWidth, maxDataWidth) + padding * 2 };
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
function padCell(value, width, padding) {
|
|
709
|
-
const rightPad = width - value.length - padding;
|
|
710
|
-
return " ".repeat(padding) + value + " ".repeat(Math.max(0, rightPad));
|
|
711
|
-
}
|
|
712
|
-
function Table({
|
|
713
|
-
data,
|
|
714
|
-
columns: columnsProp,
|
|
715
|
-
padding = 1,
|
|
716
|
-
headerColor,
|
|
717
|
-
borderColor
|
|
718
|
-
}) {
|
|
719
|
-
const theme = useTheme();
|
|
720
|
-
const resolvedHeaderColor = headerColor ?? theme.primary;
|
|
721
|
-
const resolvedBorderColor = borderColor ?? theme.border;
|
|
722
|
-
const columns = getColumns(data, columnsProp);
|
|
723
|
-
const colInfo = calculateColumnWidths(columns, data, padding);
|
|
724
|
-
const borderLine = (left, mid, right) => {
|
|
725
|
-
const inner = colInfo.map((c) => "\u2500".repeat(c.width)).join(mid);
|
|
726
|
-
return /* @__PURE__ */ jsx11("text", { children: /* @__PURE__ */ jsxs7("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: [
|
|
727
|
-
left,
|
|
728
|
-
inner,
|
|
729
|
-
right
|
|
730
|
-
] }) });
|
|
731
|
-
};
|
|
732
|
-
const contentRow = (rowData, isHeader) => {
|
|
733
|
-
const parts = [];
|
|
734
|
-
parts.push(
|
|
735
|
-
/* @__PURE__ */ jsx11("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: "\u2502" }, "left-border")
|
|
736
|
-
);
|
|
737
|
-
colInfo.forEach((col, i) => {
|
|
738
|
-
const val = rowData[col.field];
|
|
739
|
-
const str = val == null ? "" : String(val);
|
|
740
|
-
const padded = padCell(str, col.width, padding);
|
|
741
|
-
if (isHeader) {
|
|
742
|
-
parts.push(
|
|
743
|
-
/* @__PURE__ */ jsx11("span", { style: textStyle({ fg: resolvedHeaderColor, bold: true }), children: padded }, `cell-${i}`)
|
|
744
|
-
);
|
|
745
|
-
} else {
|
|
746
|
-
parts.push(/* @__PURE__ */ jsx11("span", { children: padded }, `cell-${i}`));
|
|
747
|
-
}
|
|
748
|
-
if (i < colInfo.length - 1) {
|
|
749
|
-
parts.push(
|
|
750
|
-
/* @__PURE__ */ jsx11("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: "\u2502" }, `sep-${i}`)
|
|
751
|
-
);
|
|
752
|
-
}
|
|
753
|
-
});
|
|
754
|
-
parts.push(
|
|
755
|
-
/* @__PURE__ */ jsx11("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: "\u2502" }, "right-border")
|
|
756
|
-
);
|
|
757
|
-
return /* @__PURE__ */ jsx11("text", { children: parts });
|
|
758
|
-
};
|
|
759
|
-
const headerData = columns.reduce(
|
|
760
|
-
(acc, col) => ({ ...acc, [col]: col }),
|
|
761
|
-
{}
|
|
762
|
-
);
|
|
763
|
-
return /* @__PURE__ */ jsxs7("box", { children: [
|
|
764
|
-
borderLine("\u250C", "\u252C", "\u2510"),
|
|
765
|
-
contentRow(headerData, true),
|
|
766
|
-
data.map((row, index) => /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
767
|
-
borderLine("\u251C", "\u253C", "\u2524"),
|
|
768
|
-
contentRow(row, false)
|
|
769
|
-
] }, index)),
|
|
770
|
-
borderLine("\u2514", "\u2534", "\u2518")
|
|
771
|
-
] });
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// ../ui/components/gradient/gradient.tsx
|
|
775
|
-
import { Fragment as Fragment2, jsx as jsx12 } from "react/jsx-runtime";
|
|
776
|
-
var GRADIENTS = {
|
|
777
|
-
cristal: ["#bdfff3", "#4ac29a"],
|
|
778
|
-
teen: ["#77a1d3", "#79cbca", "#e684ae"],
|
|
779
|
-
mind: ["#473b7b", "#3584a7", "#30d2be"],
|
|
780
|
-
morning: ["#ff5f6d", "#ffc371"],
|
|
781
|
-
vice: ["#5ee7df", "#b490ca"],
|
|
782
|
-
passion: ["#f43b47", "#453a94"],
|
|
783
|
-
fruit: ["#ff4e50", "#f9d423"],
|
|
784
|
-
instagram: ["#833ab4", "#fd1d1d", "#fcb045"],
|
|
785
|
-
atlas: ["#feac5e", "#c779d0", "#4bc0c8"],
|
|
786
|
-
retro: ["#3f51b1", "#5a55ae", "#7b5fac", "#8f6aae", "#a86aa4", "#cc6b8e", "#f18271", "#f3a469", "#f7c978"],
|
|
787
|
-
summer: ["#fdbb2d", "#22c1c3"],
|
|
788
|
-
rainbow: ["#ff0000", "#ffff00", "#00ff00", "#00ffff", "#0000ff", "#ff00ff", "#ff0000"],
|
|
789
|
-
pastel: ["#74ebd5", "#ACB6E5"]
|
|
790
|
-
};
|
|
791
|
-
function hexToRgb(hex) {
|
|
792
|
-
const normalized = hex.replace("#", "");
|
|
793
|
-
return {
|
|
794
|
-
r: parseInt(normalized.substring(0, 2), 16),
|
|
795
|
-
g: parseInt(normalized.substring(2, 4), 16),
|
|
796
|
-
b: parseInt(normalized.substring(4, 6), 16)
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
function rgbToHex(rgb) {
|
|
800
|
-
const r = rgb.r.toString(16).padStart(2, "0");
|
|
801
|
-
const g = rgb.g.toString(16).padStart(2, "0");
|
|
802
|
-
const b = rgb.b.toString(16).padStart(2, "0");
|
|
803
|
-
return `#${r}${g}${b}`;
|
|
804
|
-
}
|
|
805
|
-
function lerp(a, b, t) {
|
|
806
|
-
return a + (b - a) * t;
|
|
807
|
-
}
|
|
808
|
-
function interpolateColor(color1, color2, t) {
|
|
809
|
-
return {
|
|
810
|
-
r: Math.round(lerp(color1.r, color2.r, t)),
|
|
811
|
-
g: Math.round(lerp(color1.g, color2.g, t)),
|
|
812
|
-
b: Math.round(lerp(color1.b, color2.b, t))
|
|
813
|
-
};
|
|
814
|
-
}
|
|
815
|
-
function generateGradient(colors, steps) {
|
|
816
|
-
if (colors.length === 0) throw new Error("At least one color is required");
|
|
817
|
-
if (colors.length === 1 || steps <= 1) return Array(steps).fill(colors[0]);
|
|
818
|
-
const rgbColors = colors.map(hexToRgb);
|
|
819
|
-
const result = [];
|
|
820
|
-
const segmentLength = (steps - 1) / (rgbColors.length - 1);
|
|
821
|
-
for (let i = 0; i < steps; i++) {
|
|
822
|
-
const segmentIndex = Math.min(Math.floor(i / segmentLength), rgbColors.length - 2);
|
|
823
|
-
const segmentProgress = segmentLength > 0 ? (i - segmentIndex * segmentLength) / segmentLength : 0;
|
|
824
|
-
const color = interpolateColor(rgbColors[segmentIndex], rgbColors[segmentIndex + 1], Math.min(segmentProgress, 1));
|
|
825
|
-
result.push(rgbToHex(color));
|
|
826
|
-
}
|
|
827
|
-
return result;
|
|
828
|
-
}
|
|
829
|
-
function Gradient({ children, name, colors }) {
|
|
830
|
-
if (name && colors) throw new Error("The `name` and `colors` props are mutually exclusive");
|
|
831
|
-
if (!name && !colors) throw new Error("Either `name` or `colors` prop must be provided");
|
|
832
|
-
const gradientColors = name ? GRADIENTS[name] : colors;
|
|
833
|
-
const lines = children.split("\n");
|
|
834
|
-
const maxLength = Math.max(...lines.map((l) => l.length));
|
|
835
|
-
if (maxLength === 0) return /* @__PURE__ */ jsx12("text", { children });
|
|
836
|
-
const hexColors = generateGradient(gradientColors, maxLength);
|
|
837
|
-
return /* @__PURE__ */ jsx12(Fragment2, { children: lines.map((line, lineIndex) => /* @__PURE__ */ jsx12("text", { children: line.split("").map((char, charIndex) => /* @__PURE__ */ jsx12("span", { style: { fg: hexColors[charIndex] }, children: char }, charIndex)) }, lineIndex)) });
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
// ../ui/components/tab-bar/tab-bar.tsx
|
|
841
|
-
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
842
|
-
function TabBar({
|
|
843
|
-
label,
|
|
844
|
-
options,
|
|
845
|
-
selectedIndex,
|
|
846
|
-
focused = true,
|
|
847
|
-
activeColor
|
|
848
|
-
}) {
|
|
849
|
-
const theme = useTheme();
|
|
850
|
-
const resolvedActiveColor = activeColor ?? theme.accent;
|
|
851
|
-
const parts = [];
|
|
852
|
-
if (label !== void 0) {
|
|
853
|
-
parts.push(
|
|
854
|
-
/* @__PURE__ */ jsx13(
|
|
855
|
-
"span",
|
|
856
|
-
{
|
|
857
|
-
style: focused ? textStyle({ bold: true }) : textStyle({ dim: true }),
|
|
858
|
-
children: label
|
|
859
|
-
},
|
|
860
|
-
"label"
|
|
861
|
-
)
|
|
862
|
-
);
|
|
863
|
-
}
|
|
864
|
-
parts.push(/* @__PURE__ */ jsx13("span", { children: " " }, "sep"));
|
|
865
|
-
options.forEach((option, i) => {
|
|
866
|
-
const isSelected = i === selectedIndex;
|
|
867
|
-
const padded = ` ${option} `;
|
|
868
|
-
if (isSelected && focused) {
|
|
869
|
-
parts.push(
|
|
870
|
-
/* @__PURE__ */ jsx13(
|
|
871
|
-
"span",
|
|
872
|
-
{
|
|
873
|
-
style: textStyle({ inverse: true, bold: true, fg: resolvedActiveColor }),
|
|
874
|
-
children: padded
|
|
875
|
-
},
|
|
876
|
-
`opt-${i}`
|
|
877
|
-
)
|
|
878
|
-
);
|
|
879
|
-
} else if (isSelected && !focused) {
|
|
880
|
-
parts.push(
|
|
881
|
-
/* @__PURE__ */ jsx13(
|
|
882
|
-
"span",
|
|
883
|
-
{
|
|
884
|
-
style: textStyle({ inverse: true, bold: true, dim: true }),
|
|
885
|
-
children: padded
|
|
886
|
-
},
|
|
887
|
-
`opt-${i}`
|
|
888
|
-
)
|
|
889
|
-
);
|
|
890
|
-
} else if (!focused) {
|
|
891
|
-
parts.push(
|
|
892
|
-
/* @__PURE__ */ jsx13("span", { style: textStyle({ dim: true }), children: padded }, `opt-${i}`)
|
|
893
|
-
);
|
|
894
|
-
} else {
|
|
895
|
-
parts.push(/* @__PURE__ */ jsx13("span", { children: padded }, `opt-${i}`));
|
|
896
|
-
}
|
|
897
|
-
});
|
|
898
|
-
return /* @__PURE__ */ jsx13("text", { children: parts });
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
// ../ui/components/modal/modal.tsx
|
|
902
|
-
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
903
|
-
function Modal({
|
|
904
|
-
children,
|
|
905
|
-
title,
|
|
906
|
-
borderColor,
|
|
907
|
-
borderStyle = "rounded",
|
|
908
|
-
onClose,
|
|
909
|
-
useKeyboard: useKeyboard3
|
|
910
|
-
}) {
|
|
911
|
-
const theme = useTheme();
|
|
912
|
-
const resolvedBorderColor = borderColor ?? theme.border;
|
|
913
|
-
useKeyboard3?.((event) => {
|
|
914
|
-
if (event.name === "escape" && onClose) {
|
|
915
|
-
onClose();
|
|
916
|
-
}
|
|
917
|
-
});
|
|
918
|
-
return /* @__PURE__ */ jsx14("box", { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx14(
|
|
919
|
-
"box",
|
|
920
|
-
{
|
|
921
|
-
flexDirection: "column",
|
|
922
|
-
flexGrow: 1,
|
|
923
|
-
border: true,
|
|
924
|
-
borderStyle,
|
|
925
|
-
borderColor: resolvedBorderColor,
|
|
926
|
-
children: title ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
927
|
-
/* @__PURE__ */ jsx14("box", { paddingX: 1, marginBottom: 1, children: /* @__PURE__ */ jsx14("text", { style: textStyle({ bold: true, fg: resolvedBorderColor }), children: title }) }),
|
|
928
|
-
children
|
|
929
|
-
] }) : children
|
|
930
|
-
}
|
|
931
|
-
) });
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
// ../ui/components/chat/chat.tsx
|
|
935
|
-
import { useState as useState5, useRef as useRef3 } from "react";
|
|
936
|
-
import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
937
|
-
var STATUS_ICONS = {
|
|
938
|
-
pending: "\u2022",
|
|
939
|
-
in_progress: "\u280B",
|
|
940
|
-
completed: "\u2713",
|
|
941
|
-
failed: "\u2717"
|
|
942
|
-
};
|
|
943
|
-
function getStatusColors(theme) {
|
|
944
|
-
return {
|
|
945
|
-
pending: theme.muted,
|
|
946
|
-
in_progress: theme.warning,
|
|
947
|
-
completed: theme.success,
|
|
948
|
-
failed: theme.error
|
|
949
|
-
};
|
|
950
|
-
}
|
|
951
|
-
function MessageBubble({
|
|
952
|
-
message,
|
|
953
|
-
userColor,
|
|
954
|
-
assistantColor
|
|
955
|
-
}) {
|
|
956
|
-
const isUser = message.role === "user";
|
|
957
|
-
const prefix = isUser ? "> " : "< ";
|
|
958
|
-
const color = isUser ? userColor : assistantColor;
|
|
959
|
-
return /* @__PURE__ */ jsxs9("text", { wrapMode: "word", children: [
|
|
960
|
-
/* @__PURE__ */ jsx15("span", { style: textStyle({ bold: true, fg: color }), children: prefix }),
|
|
961
|
-
/* @__PURE__ */ jsx15("span", { children: message.content })
|
|
962
|
-
] });
|
|
963
|
-
}
|
|
964
|
-
function StreamingTextDisplay({
|
|
965
|
-
text,
|
|
966
|
-
assistantColor,
|
|
967
|
-
cursorChar = "_"
|
|
968
|
-
}) {
|
|
969
|
-
if (!text) return null;
|
|
970
|
-
return /* @__PURE__ */ jsxs9("text", { wrapMode: "word", children: [
|
|
971
|
-
/* @__PURE__ */ jsx15("span", { style: textStyle({ bold: true, fg: assistantColor }), children: "< " }),
|
|
972
|
-
/* @__PURE__ */ jsx15("span", { children: text }),
|
|
973
|
-
/* @__PURE__ */ jsx15("span", { style: textStyle({ dim: true }), children: cursorChar })
|
|
974
|
-
] });
|
|
975
|
-
}
|
|
976
|
-
function ToolCallCard({ toolCall, statusColors }) {
|
|
977
|
-
const icon = STATUS_ICONS[toolCall.status] || "\u2022";
|
|
978
|
-
const color = statusColors[toolCall.status] || "gray";
|
|
979
|
-
const showEllipsis = toolCall.status === "pending" || toolCall.status === "in_progress";
|
|
980
|
-
return /* @__PURE__ */ jsxs9("text", { children: [
|
|
981
|
-
/* @__PURE__ */ jsx15("span", { children: " " }),
|
|
982
|
-
/* @__PURE__ */ jsx15("span", { style: textStyle({ fg: color }), children: icon }),
|
|
983
|
-
/* @__PURE__ */ jsx15("span", { children: " " }),
|
|
984
|
-
/* @__PURE__ */ jsx15("span", { style: textStyle({ fg: color }), children: toolCall.title }),
|
|
985
|
-
showEllipsis && /* @__PURE__ */ jsx15("span", { style: textStyle({ dim: true }), children: " ..." })
|
|
986
|
-
] });
|
|
987
|
-
}
|
|
988
|
-
function ChatInput({
|
|
989
|
-
onSubmit,
|
|
990
|
-
placeholder = "Type a message...",
|
|
991
|
-
prompt = "> ",
|
|
992
|
-
promptColor,
|
|
993
|
-
disabled = false,
|
|
994
|
-
useKeyboard: useKeyboard3
|
|
995
|
-
}) {
|
|
996
|
-
const [value, setValue] = useState5("");
|
|
997
|
-
const valueRef = useRef3("");
|
|
998
|
-
const updateValue = (newValue) => {
|
|
999
|
-
valueRef.current = newValue;
|
|
1000
|
-
setValue(newValue);
|
|
1001
|
-
};
|
|
1002
|
-
useKeyboard3?.((event) => {
|
|
1003
|
-
if (disabled) return;
|
|
1004
|
-
if (event.name === "return") {
|
|
1005
|
-
const trimmed = valueRef.current.trim();
|
|
1006
|
-
if (trimmed) {
|
|
1007
|
-
onSubmit(trimmed);
|
|
1008
|
-
updateValue("");
|
|
1009
|
-
}
|
|
1010
|
-
return;
|
|
1011
|
-
}
|
|
1012
|
-
if (event.name === "backspace" || event.name === "delete") {
|
|
1013
|
-
updateValue(valueRef.current.slice(0, -1));
|
|
1014
|
-
return;
|
|
1015
|
-
}
|
|
1016
|
-
if (event.ctrl || event.meta) return;
|
|
1017
|
-
if (event.name && event.name.length === 1) {
|
|
1018
|
-
updateValue(valueRef.current + event.name);
|
|
1019
|
-
return;
|
|
1020
|
-
}
|
|
1021
|
-
if (event.name === "space") {
|
|
1022
|
-
updateValue(valueRef.current + " ");
|
|
1023
|
-
return;
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
|
-
const showPlaceholder = value.length === 0;
|
|
1027
|
-
return /* @__PURE__ */ jsxs9("text", { children: [
|
|
1028
|
-
/* @__PURE__ */ jsx15("span", { style: textStyle({ fg: promptColor }), children: prompt }),
|
|
1029
|
-
showPlaceholder ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
1030
|
-
/* @__PURE__ */ jsx15("span", { style: textStyle({ dim: true }), children: placeholder }),
|
|
1031
|
-
!disabled && /* @__PURE__ */ jsx15("span", { style: textStyle({ inverse: true }), children: " " })
|
|
1032
|
-
] }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
1033
|
-
/* @__PURE__ */ jsx15("span", { children: value }),
|
|
1034
|
-
!disabled && /* @__PURE__ */ jsx15("span", { style: textStyle({ inverse: true }), children: " " })
|
|
1035
|
-
] })
|
|
1036
|
-
] });
|
|
1037
|
-
}
|
|
1038
|
-
function ChatPanel({
|
|
1039
|
-
messages,
|
|
1040
|
-
streamingText = "",
|
|
1041
|
-
isLoading = false,
|
|
1042
|
-
activeToolCalls = [],
|
|
1043
|
-
onSendMessage,
|
|
1044
|
-
onCancel,
|
|
1045
|
-
placeholder = "Type a message...",
|
|
1046
|
-
promptChar = "> ",
|
|
1047
|
-
promptColor,
|
|
1048
|
-
userColor,
|
|
1049
|
-
assistantColor,
|
|
1050
|
-
loadingText = "Thinking...",
|
|
1051
|
-
useKeyboard: useKeyboard3
|
|
1052
|
-
}) {
|
|
1053
|
-
const theme = useTheme();
|
|
1054
|
-
const resolvedUserColor = userColor ?? theme.secondary;
|
|
1055
|
-
const resolvedAssistantColor = assistantColor ?? theme.primary;
|
|
1056
|
-
const resolvedPromptColor = promptColor ?? theme.secondary;
|
|
1057
|
-
const statusColors = getStatusColors(theme);
|
|
1058
|
-
const inputDisabled = isLoading || !!streamingText;
|
|
1059
|
-
const wrappedUseKeyboard = useKeyboard3 ? (handler) => {
|
|
1060
|
-
useKeyboard3((event) => {
|
|
1061
|
-
if (event.name === "escape" && inputDisabled && onCancel) {
|
|
1062
|
-
onCancel();
|
|
1063
|
-
return;
|
|
1064
|
-
}
|
|
1065
|
-
handler(event);
|
|
1066
|
-
});
|
|
1067
|
-
} : void 0;
|
|
1068
|
-
return /* @__PURE__ */ jsxs9("box", { flexDirection: "column", paddingX: 1, children: [
|
|
1069
|
-
messages.map((msg) => /* @__PURE__ */ jsx15(
|
|
1070
|
-
MessageBubble,
|
|
1071
|
-
{
|
|
1072
|
-
message: msg,
|
|
1073
|
-
userColor: resolvedUserColor,
|
|
1074
|
-
assistantColor: resolvedAssistantColor
|
|
1075
|
-
},
|
|
1076
|
-
msg.id
|
|
1077
|
-
)),
|
|
1078
|
-
activeToolCalls.map((tc) => /* @__PURE__ */ jsx15(ToolCallCard, { toolCall: tc, statusColors }, tc.id)),
|
|
1079
|
-
streamingText ? /* @__PURE__ */ jsx15(
|
|
1080
|
-
StreamingTextDisplay,
|
|
1081
|
-
{
|
|
1082
|
-
text: streamingText,
|
|
1083
|
-
assistantColor: resolvedAssistantColor
|
|
1084
|
-
}
|
|
1085
|
-
) : isLoading ? /* @__PURE__ */ jsxs9("text", { style: textStyle({ dim: true }), children: [
|
|
1086
|
-
" ",
|
|
1087
|
-
loadingText
|
|
1088
|
-
] }) : null,
|
|
1089
|
-
/* @__PURE__ */ jsx15("box", { marginTop: 1, children: /* @__PURE__ */ jsx15(
|
|
1090
|
-
ChatInput,
|
|
1091
|
-
{
|
|
1092
|
-
onSubmit: onSendMessage,
|
|
1093
|
-
placeholder,
|
|
1094
|
-
prompt: promptChar,
|
|
1095
|
-
promptColor: resolvedPromptColor,
|
|
1096
|
-
disabled: inputDisabled,
|
|
1097
|
-
useKeyboard: wrappedUseKeyboard
|
|
1098
|
-
}
|
|
1099
|
-
) })
|
|
1100
|
-
] });
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
// ../ui/components/terminal-window/terminal-window.tsx
|
|
1104
|
-
import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1105
|
-
|
|
1106
|
-
// ../ui/components/made-with-opentui/made-with-opentui.tsx
|
|
1107
|
-
import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1108
|
-
|
|
1109
|
-
// ../ui/components/made-with-gridland/made-with-gridland.tsx
|
|
1110
|
-
import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1111
|
-
|
|
1112
|
-
// ../ui/components/breakpoints/use-breakpoints.ts
|
|
1113
|
-
import { useTerminalDimensions } from "@opentui/react";
|
|
1114
|
-
var BREAKPOINTS = {
|
|
1115
|
-
tiny: 40,
|
|
1116
|
-
narrow: 60,
|
|
1117
|
-
mobile: 70
|
|
1118
|
-
};
|
|
1119
|
-
function useBreakpoints() {
|
|
1120
|
-
const { width, height } = useTerminalDimensions();
|
|
1121
|
-
return {
|
|
1122
|
-
isTiny: width < BREAKPOINTS.tiny,
|
|
1123
|
-
isNarrow: width < BREAKPOINTS.narrow,
|
|
1124
|
-
isMobile: width < BREAKPOINTS.mobile,
|
|
1125
|
-
isDesktop: width >= BREAKPOINTS.mobile,
|
|
1126
|
-
width,
|
|
1127
|
-
height
|
|
1128
|
-
};
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
// ../docs/components/landing/landing-app.tsx
|
|
1132
|
-
import { useState as useState8 } from "react";
|
|
1133
|
-
|
|
1134
|
-
// ../docs/components/landing/logo.tsx
|
|
1135
|
-
import { useState as useState6, useEffect as useEffect2, useRef as useRef4, useMemo as useMemo3 } from "react";
|
|
1136
28
|
import figlet from "figlet";
|
|
1137
29
|
import ansiShadow from "figlet/importable-fonts/ANSI Shadow.js";
|
|
1138
|
-
import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1139
|
-
figlet.parseFont("ANSI Shadow", ansiShadow);
|
|
1140
|
-
function makeArt(text) {
|
|
1141
|
-
return figlet.textSync(text, { font: "ANSI Shadow" }).split("\n").filter((l) => l.trimEnd().length > 0).join("\n");
|
|
1142
|
-
}
|
|
1143
|
-
var fullArt = makeArt("gridland");
|
|
1144
|
-
var gridArt = makeArt("grid");
|
|
1145
|
-
var landArt = makeArt("land");
|
|
1146
|
-
var ART_HEIGHT = 6;
|
|
1147
|
-
function useAnimation(duration = 1e3) {
|
|
1148
|
-
const isBrowser = typeof document !== "undefined";
|
|
1149
|
-
const [progress, setProgress] = useState6(isBrowser ? 0 : 1);
|
|
1150
|
-
const startTime = useRef4(null);
|
|
1151
|
-
useEffect2(() => {
|
|
1152
|
-
if (!isBrowser) return;
|
|
1153
|
-
let raf;
|
|
1154
|
-
const tick = (time) => {
|
|
1155
|
-
if (startTime.current === null) startTime.current = time;
|
|
1156
|
-
const elapsed = time - startTime.current;
|
|
1157
|
-
const t = Math.min(1, elapsed / duration);
|
|
1158
|
-
const eased = 1 - Math.pow(1 - t, 3);
|
|
1159
|
-
setProgress(eased);
|
|
1160
|
-
if (t < 1) raf = requestAnimationFrame(tick);
|
|
1161
|
-
};
|
|
1162
|
-
raf = requestAnimationFrame(tick);
|
|
1163
|
-
return () => cancelAnimationFrame(raf);
|
|
1164
|
-
}, []);
|
|
1165
|
-
return progress;
|
|
1166
|
-
}
|
|
1167
|
-
function RevealGradient({ children, revealCol }) {
|
|
1168
|
-
const gradientColors = GRADIENTS.instagram;
|
|
1169
|
-
const lines = children.split("\n");
|
|
1170
|
-
const maxLength = Math.max(...lines.map((l) => l.length));
|
|
1171
|
-
if (maxLength === 0) return /* @__PURE__ */ jsx19("text", { children });
|
|
1172
|
-
const hexColors = useMemo3(() => generateGradient(gradientColors, maxLength), [maxLength]);
|
|
1173
|
-
return /* @__PURE__ */ jsx19("box", { position: "relative", width: maxLength, height: lines.length, shouldFill: false, children: lines.map((line, lineIndex) => {
|
|
1174
|
-
const runs = [];
|
|
1175
|
-
let current = null;
|
|
1176
|
-
for (let i = 0; i < line.length; i++) {
|
|
1177
|
-
const revealed = i <= revealCol;
|
|
1178
|
-
const char = line[i];
|
|
1179
|
-
const isVisible = revealed && char !== " ";
|
|
1180
|
-
if (isVisible) {
|
|
1181
|
-
if (!current) {
|
|
1182
|
-
current = { start: i, chars: [] };
|
|
1183
|
-
}
|
|
1184
|
-
current.chars.push(char);
|
|
1185
|
-
} else {
|
|
1186
|
-
if (current) {
|
|
1187
|
-
runs.push(current);
|
|
1188
|
-
current = null;
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
if (current) runs.push(current);
|
|
1193
|
-
return runs.map((run, runIndex) => /* @__PURE__ */ jsx19(
|
|
1194
|
-
"box",
|
|
1195
|
-
{
|
|
1196
|
-
position: "absolute",
|
|
1197
|
-
top: lineIndex,
|
|
1198
|
-
left: run.start,
|
|
1199
|
-
shouldFill: false,
|
|
1200
|
-
children: /* @__PURE__ */ jsx19("text", { shouldFill: false, children: run.chars.map((char, ci) => /* @__PURE__ */ jsx19(
|
|
1201
|
-
"span",
|
|
1202
|
-
{
|
|
1203
|
-
style: { fg: hexColors[run.start + ci] },
|
|
1204
|
-
children: char
|
|
1205
|
-
},
|
|
1206
|
-
ci
|
|
1207
|
-
)) })
|
|
1208
|
-
},
|
|
1209
|
-
`${lineIndex}-${runIndex}`
|
|
1210
|
-
));
|
|
1211
|
-
}) });
|
|
1212
|
-
}
|
|
1213
|
-
function Logo({ compact, narrow, mobile }) {
|
|
1214
|
-
const isBrowser = typeof document !== "undefined";
|
|
1215
|
-
const progress = useAnimation(900);
|
|
1216
|
-
const artHeight = compact ? 1 : narrow ? ART_HEIGHT * 2 : ART_HEIGHT;
|
|
1217
|
-
const dropOffset = Math.round((1 - progress) * -artHeight);
|
|
1218
|
-
const revealProgress = Math.max(0, Math.min(1, (progress - 0.1) / 0.7));
|
|
1219
|
-
const maxWidth = compact ? 8 : narrow ? 40 : 62;
|
|
1220
|
-
const revealCol = Math.round(revealProgress * (maxWidth + 4)) - 2;
|
|
1221
|
-
const taglineOpacity = Math.max(0, Math.min(1, (progress - 0.7) / 0.3));
|
|
1222
|
-
const subtitle = /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
1223
|
-
/* @__PURE__ */ jsx19("text", { children: " " }),
|
|
1224
|
-
/* @__PURE__ */ jsx19("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs13("text", { style: textStyle({ fg: "#d4b0e8" }), opacity: taglineOpacity, wrapMode: "word", textAlign: "center", width: "100%", shouldFill: false, children: [
|
|
1225
|
-
"A framework for building terminal apps, built on ",
|
|
1226
|
-
/* @__PURE__ */ jsx19("a", { href: "https://opentui.com", style: { attributes: 72, fg: "#d4b0e8" }, children: "OpenTUI" }),
|
|
1227
|
-
" + React." + (mobile ? " " : "\n") + "(Gridland apps, like this website, work in the browser and terminal.)"
|
|
1228
|
-
] }) })
|
|
1229
|
-
] });
|
|
1230
|
-
if (!isBrowser) {
|
|
1231
|
-
const art = compact ? "gridland" : narrow ? gridArt + "\n" + landArt : fullArt;
|
|
1232
|
-
return /* @__PURE__ */ jsxs13("box", { flexDirection: "column", flexShrink: 0, width: "100%", alignItems: "center", children: [
|
|
1233
|
-
/* @__PURE__ */ jsx19(Gradient, { name: "instagram", children: art }),
|
|
1234
|
-
/* @__PURE__ */ jsx19("text", { children: " " }),
|
|
1235
|
-
/* @__PURE__ */ jsx19("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs13("text", { style: textStyle({ fg: "#d4b0e8" }), shouldFill: false, children: [
|
|
1236
|
-
"A framework for building terminal apps, built on OpenTUI + React.",
|
|
1237
|
-
"\n",
|
|
1238
|
-
"(Gridland apps, like this website, work in the browser and terminal.)"
|
|
1239
|
-
] }) })
|
|
1240
|
-
] });
|
|
1241
|
-
}
|
|
1242
|
-
if (compact) {
|
|
1243
|
-
return /* @__PURE__ */ jsxs13("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
1244
|
-
/* @__PURE__ */ jsx19("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx19("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: /* @__PURE__ */ jsx19(RevealGradient, { revealCol, children: "gridland" }) }) }),
|
|
1245
|
-
subtitle
|
|
1246
|
-
] });
|
|
1247
|
-
}
|
|
1248
|
-
if (narrow) {
|
|
1249
|
-
return /* @__PURE__ */ jsxs13("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
1250
|
-
/* @__PURE__ */ jsx19("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsxs13("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: [
|
|
1251
|
-
/* @__PURE__ */ jsx19(RevealGradient, { revealCol, children: gridArt }),
|
|
1252
|
-
/* @__PURE__ */ jsx19(RevealGradient, { revealCol, children: landArt })
|
|
1253
|
-
] }) }),
|
|
1254
|
-
subtitle
|
|
1255
|
-
] });
|
|
1256
|
-
}
|
|
1257
|
-
return /* @__PURE__ */ jsxs13("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
1258
|
-
/* @__PURE__ */ jsx19("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx19("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: /* @__PURE__ */ jsx19(RevealGradient, { revealCol, children: fullArt }) }) }),
|
|
1259
|
-
subtitle
|
|
1260
|
-
] });
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
// ../docs/components/landing/install-box.tsx
|
|
1264
|
-
import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1265
|
-
function InstallBox() {
|
|
1266
|
-
const theme = useTheme();
|
|
1267
|
-
return /* @__PURE__ */ jsx20(
|
|
1268
|
-
"box",
|
|
1269
|
-
{
|
|
1270
|
-
border: true,
|
|
1271
|
-
borderStyle: "rounded",
|
|
1272
|
-
borderColor: theme.border,
|
|
1273
|
-
paddingX: 1,
|
|
1274
|
-
flexDirection: "column",
|
|
1275
|
-
flexShrink: 0,
|
|
1276
|
-
children: /* @__PURE__ */ jsxs14("text", { children: [
|
|
1277
|
-
/* @__PURE__ */ jsx20("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
1278
|
-
/* @__PURE__ */ jsx20("span", { style: textStyle({ bold: true }), children: "bun create " }),
|
|
1279
|
-
/* @__PURE__ */ jsx20("span", { style: textStyle({ fg: theme.accent }), children: "gridland" })
|
|
1280
|
-
] })
|
|
1281
|
-
}
|
|
1282
|
-
);
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
// ../docs/components/landing/links-box.tsx
|
|
1286
|
-
import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1287
|
-
var UNDERLINE3 = 1 << 3;
|
|
1288
|
-
function LinksBox() {
|
|
1289
|
-
const theme = useTheme();
|
|
1290
|
-
return /* @__PURE__ */ jsx21(
|
|
1291
|
-
"box",
|
|
1292
|
-
{
|
|
1293
|
-
border: true,
|
|
1294
|
-
borderStyle: "rounded",
|
|
1295
|
-
borderColor: theme.border,
|
|
1296
|
-
paddingX: 1,
|
|
1297
|
-
flexDirection: "column",
|
|
1298
|
-
flexShrink: 0,
|
|
1299
|
-
children: /* @__PURE__ */ jsxs15("text", { children: [
|
|
1300
|
-
/* @__PURE__ */ jsx21("span", { children: "\u{1F431}" }),
|
|
1301
|
-
/* @__PURE__ */ jsx21("a", { href: "https://github.com/cjroth/gridland", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " GitHub" }),
|
|
1302
|
-
/* @__PURE__ */ jsx21("span", { children: " " }),
|
|
1303
|
-
/* @__PURE__ */ jsx21("span", { children: "\u{1F4D6}" }),
|
|
1304
|
-
/* @__PURE__ */ jsx21("a", { href: "/docs", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " Docs" })
|
|
1305
|
-
] })
|
|
1306
|
-
}
|
|
1307
|
-
);
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
// ../docs/components/landing/matrix-background.tsx
|
|
1311
|
-
import { useMemo as useMemo4 } from "react";
|
|
1312
|
-
|
|
1313
|
-
// ../docs/components/landing/use-matrix.ts
|
|
1314
|
-
import { useState as useState7, useEffect as useEffect3, useRef as useRef5 } from "react";
|
|
1315
|
-
var CHARS = "abcdefghijklmnopqrstuvwxyz0123456789@#$%^&*(){}[]|;:<>,.?/~`";
|
|
1316
|
-
function randomChar() {
|
|
1317
|
-
return CHARS[Math.floor(Math.random() * CHARS.length)];
|
|
1318
|
-
}
|
|
1319
|
-
function createDrop(height, seeded = false) {
|
|
1320
|
-
const length = Math.floor(Math.random() * Math.floor(height * 0.6)) + 4;
|
|
1321
|
-
return {
|
|
1322
|
-
y: seeded ? Math.floor(Math.random() * (height + length)) : -Math.floor(Math.random() * height),
|
|
1323
|
-
speed: 1,
|
|
1324
|
-
length,
|
|
1325
|
-
chars: Array.from({ length }, randomChar)
|
|
1326
|
-
};
|
|
1327
|
-
}
|
|
1328
|
-
function buildGrid(columns, width, height) {
|
|
1329
|
-
const grid = Array.from({ length: height }, () => Array(width).fill(" "));
|
|
1330
|
-
const brightness = Array.from({ length: height }, () => Array(width).fill(0));
|
|
1331
|
-
for (let x = 0; x < width; x++) {
|
|
1332
|
-
const drop = columns[x];
|
|
1333
|
-
if (!drop) continue;
|
|
1334
|
-
for (let i = 0; i < drop.length; i++) {
|
|
1335
|
-
const row = Math.floor(drop.y) - i;
|
|
1336
|
-
if (row < 0 || row >= height) continue;
|
|
1337
|
-
grid[row][x] = drop.chars[i];
|
|
1338
|
-
if (i === 0) {
|
|
1339
|
-
brightness[row][x] = 1;
|
|
1340
|
-
} else {
|
|
1341
|
-
brightness[row][x] = Math.max(0.15, 1 - i / drop.length);
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
}
|
|
1345
|
-
return { grid, brightness };
|
|
1346
|
-
}
|
|
1347
|
-
function useMatrix(width, height) {
|
|
1348
|
-
const columnsRef = useRef5([]);
|
|
1349
|
-
const [state, setState] = useState7(() => {
|
|
1350
|
-
const columns = Array.from(
|
|
1351
|
-
{ length: width },
|
|
1352
|
-
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
1353
|
-
);
|
|
1354
|
-
columnsRef.current = columns;
|
|
1355
|
-
return buildGrid(columns, width, height);
|
|
1356
|
-
});
|
|
1357
|
-
useEffect3(() => {
|
|
1358
|
-
if (width < 2 || height < 2) return;
|
|
1359
|
-
const id = setInterval(() => {
|
|
1360
|
-
const columns = columnsRef.current;
|
|
1361
|
-
for (let x = 0; x < width; x++) {
|
|
1362
|
-
if (columns[x] === null || columns[x] === void 0) {
|
|
1363
|
-
if (Math.random() < 0.03) {
|
|
1364
|
-
columns[x] = createDrop(height);
|
|
1365
|
-
}
|
|
1366
|
-
continue;
|
|
1367
|
-
}
|
|
1368
|
-
const drop = columns[x];
|
|
1369
|
-
drop.y += drop.speed;
|
|
1370
|
-
if (Math.random() < 0.1) {
|
|
1371
|
-
const idx = Math.floor(Math.random() * drop.chars.length);
|
|
1372
|
-
drop.chars[idx] = randomChar();
|
|
1373
|
-
}
|
|
1374
|
-
if (drop.y - drop.length > height) {
|
|
1375
|
-
columns[x] = null;
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
setState(buildGrid(columns, width, height));
|
|
1379
|
-
}, 80);
|
|
1380
|
-
return () => clearInterval(id);
|
|
1381
|
-
}, [width, height]);
|
|
1382
|
-
useEffect3(() => {
|
|
1383
|
-
columnsRef.current = Array.from(
|
|
1384
|
-
{ length: width },
|
|
1385
|
-
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
1386
|
-
);
|
|
1387
|
-
setState(buildGrid(columnsRef.current, width, height));
|
|
1388
|
-
}, [width, height]);
|
|
1389
|
-
return state;
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
// ../docs/components/landing/matrix-background.tsx
|
|
1393
|
-
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
1394
|
-
var MUTE_LEVELS = [0.12, 0.18, 0.24, 0.3, 0.38];
|
|
1395
|
-
var BG = hexToRgb("#1a1a2e");
|
|
1396
|
-
function buildMutedColors(baseHex) {
|
|
1397
|
-
const fg = hexToRgb(baseHex);
|
|
1398
|
-
return MUTE_LEVELS.map((factor) => rgbToHex({
|
|
1399
|
-
r: Math.round(BG.r + (fg.r - BG.r) * factor),
|
|
1400
|
-
g: Math.round(BG.g + (fg.g - BG.g) * factor),
|
|
1401
|
-
b: Math.round(BG.b + (fg.b - BG.b) * factor)
|
|
1402
|
-
}));
|
|
1403
|
-
}
|
|
1404
|
-
function colorForCell(mutedColors, b) {
|
|
1405
|
-
if (b >= 1) return mutedColors[4];
|
|
1406
|
-
const idx = Math.min(Math.floor(b * (MUTE_LEVELS.length - 1)), MUTE_LEVELS.length - 2);
|
|
1407
|
-
return mutedColors[idx];
|
|
1408
|
-
}
|
|
1409
|
-
function MatrixBackground({ width, height, clearRect, clearRects }) {
|
|
1410
|
-
const { grid, brightness } = useMatrix(width, height);
|
|
1411
|
-
const theme = useTheme();
|
|
1412
|
-
const columnColors = useMemo4(
|
|
1413
|
-
() => width > 0 ? generateGradient([theme.accent, theme.secondary, theme.primary], width) : [],
|
|
1414
|
-
[width, theme.accent, theme.secondary, theme.primary]
|
|
1415
|
-
);
|
|
1416
|
-
const columnMutedColors = useMemo4(
|
|
1417
|
-
() => columnColors.map(buildMutedColors),
|
|
1418
|
-
[columnColors]
|
|
1419
|
-
);
|
|
1420
|
-
return /* @__PURE__ */ jsx22("box", { flexDirection: "column", children: grid.map((row, y) => /* @__PURE__ */ jsx22("text", { children: row.map((cell, x) => {
|
|
1421
|
-
const inClearRect = clearRect && y >= clearRect.top && y < clearRect.top + clearRect.height && x >= clearRect.left && x < clearRect.left + clearRect.width || clearRects && clearRects.some(
|
|
1422
|
-
(r) => y >= r.top && y < r.top + r.height && x >= r.left && x < r.left + r.width
|
|
1423
|
-
);
|
|
1424
|
-
const mutedColors = columnMutedColors[x];
|
|
1425
|
-
if (cell === " " || inClearRect || !mutedColors) {
|
|
1426
|
-
return /* @__PURE__ */ jsx22("span", { children: " " }, x);
|
|
1427
|
-
}
|
|
1428
|
-
return /* @__PURE__ */ jsx22(
|
|
1429
|
-
"span",
|
|
1430
|
-
{
|
|
1431
|
-
style: {
|
|
1432
|
-
fg: colorForCell(mutedColors, brightness[y][x])
|
|
1433
|
-
},
|
|
1434
|
-
children: cell
|
|
1435
|
-
},
|
|
1436
|
-
x
|
|
1437
|
-
);
|
|
1438
|
-
}) }, y)) });
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
// ../docs/components/landing/about-modal.tsx
|
|
1442
|
-
import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1443
|
-
function AboutModal({ onClose, useKeyboard: useKeyboard3 }) {
|
|
1444
|
-
const theme = useTheme();
|
|
1445
|
-
return /* @__PURE__ */ jsx23(Modal, { title: "About Gridland", useKeyboard: useKeyboard3, onClose, children: /* @__PURE__ */ jsxs16("box", { paddingX: 1, flexDirection: "column", gap: 1, children: [
|
|
1446
|
-
/* @__PURE__ */ jsx23("text", { style: textStyle({ bold: true, fg: theme.accent }), children: "What is Gridland?" }),
|
|
1447
|
-
/* @__PURE__ */ jsx23("text", { children: "Gridland renders terminal UIs to HTML5 Canvas with React." }),
|
|
1448
|
-
/* @__PURE__ */ jsx23("text", { children: "No xterm.js. No terminal emulator. Just pixels." }),
|
|
1449
|
-
/* @__PURE__ */ jsx23("text", { style: textStyle({ bold: true, fg: theme.accent }), children: "Features" }),
|
|
1450
|
-
/* @__PURE__ */ jsxs16("text", { children: [
|
|
1451
|
-
/* @__PURE__ */ jsxs16("span", { style: textStyle({ dim: true }), children: [
|
|
1452
|
-
"\u2022",
|
|
1453
|
-
" "
|
|
1454
|
-
] }),
|
|
1455
|
-
"Canvas-rendered TUI components"
|
|
1456
|
-
] }),
|
|
1457
|
-
/* @__PURE__ */ jsxs16("text", { children: [
|
|
1458
|
-
/* @__PURE__ */ jsxs16("span", { style: textStyle({ dim: true }), children: [
|
|
1459
|
-
"\u2022",
|
|
1460
|
-
" "
|
|
1461
|
-
] }),
|
|
1462
|
-
"React reconciler with JSX"
|
|
1463
|
-
] }),
|
|
1464
|
-
/* @__PURE__ */ jsxs16("text", { children: [
|
|
1465
|
-
/* @__PURE__ */ jsxs16("span", { style: textStyle({ dim: true }), children: [
|
|
1466
|
-
"\u2022",
|
|
1467
|
-
" "
|
|
1468
|
-
] }),
|
|
1469
|
-
"Yoga flexbox layout engine"
|
|
1470
|
-
] }),
|
|
1471
|
-
/* @__PURE__ */ jsxs16("text", { children: [
|
|
1472
|
-
/* @__PURE__ */ jsxs16("span", { style: textStyle({ dim: true }), children: [
|
|
1473
|
-
"\u2022",
|
|
1474
|
-
" "
|
|
1475
|
-
] }),
|
|
1476
|
-
"Keyboard, mouse, and clipboard support"
|
|
1477
|
-
] }),
|
|
1478
|
-
/* @__PURE__ */ jsxs16("text", { children: [
|
|
1479
|
-
/* @__PURE__ */ jsxs16("span", { style: textStyle({ dim: true }), children: [
|
|
1480
|
-
"\u2022",
|
|
1481
|
-
" "
|
|
1482
|
-
] }),
|
|
1483
|
-
"Next.js and Vite plugins"
|
|
1484
|
-
] }),
|
|
1485
|
-
/* @__PURE__ */ jsx23("text", { style: textStyle({ bold: true, fg: theme.accent }), children: "Tech Stack" }),
|
|
1486
|
-
/* @__PURE__ */ jsx23("text", { children: "React + opentui engine + yoga-layout + HTML5 Canvas" }),
|
|
1487
|
-
/* @__PURE__ */ jsx23("text", { style: textStyle({ dim: true }), children: "Press q to close" })
|
|
1488
|
-
] }) });
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
// ../docs/components/landing/landing-app.tsx
|
|
1492
|
-
import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1493
|
-
function LandingApp({ useKeyboard: useKeyboard3 }) {
|
|
1494
|
-
const theme = useTheme();
|
|
1495
|
-
const { width, height, isNarrow, isTiny, isMobile } = useBreakpoints();
|
|
1496
|
-
const [showAbout, setShowAbout] = useState8(false);
|
|
1497
|
-
useKeyboard3((event) => {
|
|
1498
|
-
if (event.name === "a" && !showAbout) {
|
|
1499
|
-
setShowAbout(true);
|
|
1500
|
-
}
|
|
1501
|
-
if (event.name === "q" && showAbout) {
|
|
1502
|
-
setShowAbout(false);
|
|
1503
|
-
}
|
|
1504
|
-
});
|
|
1505
|
-
if (showAbout) {
|
|
1506
|
-
return /* @__PURE__ */ jsxs17("box", { flexDirection: "column", width: "100%", height: "100%", children: [
|
|
1507
|
-
/* @__PURE__ */ jsx24("box", { flexGrow: 1, children: /* @__PURE__ */ jsx24(AboutModal, { onClose: () => setShowAbout(false), useKeyboard: useKeyboard3 }) }),
|
|
1508
|
-
/* @__PURE__ */ jsx24(StatusBar, { items: [{ key: "q", label: "close" }] })
|
|
1509
|
-
] });
|
|
1510
|
-
}
|
|
1511
|
-
const isBrowser = typeof document !== "undefined";
|
|
1512
|
-
const logoHeight = isTiny ? 2 : isNarrow ? 13 : 7;
|
|
1513
|
-
const logoExtra = isBrowser ? 1 : 0;
|
|
1514
|
-
const gap = isMobile ? 0 : 1;
|
|
1515
|
-
const installLinksTop = 3 + logoHeight + logoExtra + gap;
|
|
1516
|
-
const installLinksHeight = 3;
|
|
1517
|
-
const boxTop = installLinksTop + installLinksHeight + gap + 1;
|
|
1518
|
-
const boxHeight = height - boxTop - 1 - 1;
|
|
1519
|
-
const clearRect = { top: boxTop, left: 1, width: width - 2, height: boxHeight };
|
|
1520
|
-
const installLinksClearRect = { top: installLinksTop, left: 1, width: width - 2, height: installLinksHeight };
|
|
1521
|
-
return /* @__PURE__ */ jsxs17("box", { width: "100%", height: "100%", position: "relative", children: [
|
|
1522
|
-
/* @__PURE__ */ jsx24(MatrixBackground, { width, height, clearRect, clearRects: [installLinksClearRect] }),
|
|
1523
|
-
/* @__PURE__ */ jsxs17(
|
|
1524
|
-
"box",
|
|
1525
|
-
{
|
|
1526
|
-
position: "absolute",
|
|
1527
|
-
top: 0,
|
|
1528
|
-
left: 0,
|
|
1529
|
-
width,
|
|
1530
|
-
height,
|
|
1531
|
-
zIndex: 1,
|
|
1532
|
-
flexDirection: "column",
|
|
1533
|
-
shouldFill: false,
|
|
1534
|
-
children: [
|
|
1535
|
-
/* @__PURE__ */ jsxs17("box", { flexGrow: 1, flexDirection: "column", paddingTop: 3, paddingLeft: 1, paddingRight: 1, paddingBottom: 1, gap: isMobile ? 0 : 1, shouldFill: false, children: [
|
|
1536
|
-
/* @__PURE__ */ jsx24("box", { flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx24(Logo, { compact: isTiny, narrow: isNarrow, mobile: isMobile }) }),
|
|
1537
|
-
/* @__PURE__ */ jsxs17("box", { flexDirection: "row", flexWrap: "wrap", justifyContent: "center", gap: isMobile ? 0 : 1, flexShrink: 0, shouldFill: false, children: [
|
|
1538
|
-
/* @__PURE__ */ jsx24(
|
|
1539
|
-
"box",
|
|
1540
|
-
{
|
|
1541
|
-
border: true,
|
|
1542
|
-
borderStyle: "rounded",
|
|
1543
|
-
borderColor: theme.border,
|
|
1544
|
-
paddingX: 1,
|
|
1545
|
-
flexDirection: "column",
|
|
1546
|
-
flexShrink: 0,
|
|
1547
|
-
children: /* @__PURE__ */ jsxs17("text", { children: [
|
|
1548
|
-
/* @__PURE__ */ jsx24("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
1549
|
-
/* @__PURE__ */ jsx24("span", { style: textStyle({ bold: true }), children: "bunx " }),
|
|
1550
|
-
/* @__PURE__ */ jsx24("span", { style: textStyle({ fg: theme.accent }), children: "@gridland/demo landing" })
|
|
1551
|
-
] })
|
|
1552
|
-
}
|
|
1553
|
-
),
|
|
1554
|
-
/* @__PURE__ */ jsx24(InstallBox, {}),
|
|
1555
|
-
/* @__PURE__ */ jsx24(LinksBox, {})
|
|
1556
|
-
] }),
|
|
1557
|
-
/* @__PURE__ */ jsx24(
|
|
1558
|
-
"box",
|
|
1559
|
-
{
|
|
1560
|
-
flexGrow: 1,
|
|
1561
|
-
border: true,
|
|
1562
|
-
borderStyle: "rounded",
|
|
1563
|
-
borderColor: theme.border
|
|
1564
|
-
}
|
|
1565
|
-
)
|
|
1566
|
-
] }),
|
|
1567
|
-
/* @__PURE__ */ jsx24(
|
|
1568
|
-
StatusBar,
|
|
1569
|
-
{
|
|
1570
|
-
items: [
|
|
1571
|
-
{ key: "a", label: "about" }
|
|
1572
|
-
]
|
|
1573
|
-
}
|
|
1574
|
-
)
|
|
1575
|
-
]
|
|
1576
|
-
}
|
|
1577
|
-
)
|
|
1578
|
-
] });
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
// ../docs/components/landing/matrix-rain.tsx
|
|
1582
|
-
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1583
|
-
|
|
1584
|
-
// ../ui/scripts/demo-apps.tsx
|
|
1585
|
-
import figlet2 from "figlet";
|
|
1586
|
-
import ansiShadow2 from "figlet/importable-fonts/ANSI Shadow.js";
|
|
1587
30
|
import big from "figlet/importable-fonts/Big.js";
|
|
1588
31
|
import doom from "figlet/importable-fonts/Doom.js";
|
|
1589
32
|
import slant from "figlet/importable-fonts/Slant.js";
|
|
@@ -1591,9 +34,9 @@ import speed from "figlet/importable-fonts/Speed.js";
|
|
|
1591
34
|
import standard from "figlet/importable-fonts/Standard.js";
|
|
1592
35
|
import block from "figlet/importable-fonts/Block.js";
|
|
1593
36
|
import colossal from "figlet/importable-fonts/Colossal.js";
|
|
1594
|
-
import { jsx
|
|
37
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1595
38
|
var fonts = [
|
|
1596
|
-
{ name: "ANSI Shadow", data:
|
|
39
|
+
{ name: "ANSI Shadow", data: ansiShadow },
|
|
1597
40
|
{ name: "Standard", data: standard },
|
|
1598
41
|
{ name: "Big", data: big },
|
|
1599
42
|
{ name: "Doom", data: doom },
|
|
@@ -1603,49 +46,49 @@ var fonts = [
|
|
|
1603
46
|
{ name: "Colossal", data: colossal }
|
|
1604
47
|
];
|
|
1605
48
|
for (const f of fonts) {
|
|
1606
|
-
|
|
49
|
+
figlet.parseFont(f.name, f.data);
|
|
1607
50
|
}
|
|
1608
51
|
function getFigletLines(fontName, text = "gridland") {
|
|
1609
|
-
const art =
|
|
52
|
+
const art = figlet.textSync(text, { font: fontName });
|
|
1610
53
|
return art.split("\n").filter((l) => l.trimEnd().length > 0);
|
|
1611
54
|
}
|
|
1612
55
|
var gradientNames = Object.keys(GRADIENTS);
|
|
1613
56
|
function GradientApp() {
|
|
1614
|
-
const [index, setIndex] =
|
|
57
|
+
const [index, setIndex] = useState(0);
|
|
1615
58
|
const name = gradientNames[index];
|
|
1616
59
|
const lines = getFigletLines("ANSI Shadow");
|
|
1617
60
|
useKeyboard((event) => {
|
|
1618
61
|
if (event.name === "left") setIndex((i) => i > 0 ? i - 1 : gradientNames.length - 1);
|
|
1619
62
|
if (event.name === "right") setIndex((i) => i < gradientNames.length - 1 ? i + 1 : 0);
|
|
1620
63
|
});
|
|
1621
|
-
return /* @__PURE__ */
|
|
1622
|
-
/* @__PURE__ */
|
|
1623
|
-
/* @__PURE__ */
|
|
64
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
65
|
+
/* @__PURE__ */ jsx("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: /* @__PURE__ */ jsx(Gradient, { name, children: lines.join("\n") }) }),
|
|
66
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(
|
|
1624
67
|
StatusBar,
|
|
1625
68
|
{
|
|
1626
69
|
items: [{ key: "\u2190\u2192", label: "gradient" }, { key: "q", label: "quit" }],
|
|
1627
|
-
extra: /* @__PURE__ */
|
|
70
|
+
extra: /* @__PURE__ */ jsx("span", { style: textStyle({ fg: "cyan", bold: true }), children: name.padEnd(11) })
|
|
1628
71
|
}
|
|
1629
|
-
)
|
|
72
|
+
) })
|
|
1630
73
|
] });
|
|
1631
74
|
}
|
|
1632
75
|
function AsciiApp() {
|
|
1633
|
-
const [fontIndex, setFontIndex] =
|
|
76
|
+
const [fontIndex, setFontIndex] = useState(0);
|
|
1634
77
|
const font = fonts[fontIndex];
|
|
1635
78
|
const lines = getFigletLines(font.name);
|
|
1636
79
|
useKeyboard((event) => {
|
|
1637
80
|
if (event.name === "left") setFontIndex((i) => i > 0 ? i - 1 : fonts.length - 1);
|
|
1638
81
|
if (event.name === "right") setFontIndex((i) => i < fonts.length - 1 ? i + 1 : 0);
|
|
1639
82
|
});
|
|
1640
|
-
return /* @__PURE__ */
|
|
1641
|
-
/* @__PURE__ */
|
|
1642
|
-
/* @__PURE__ */
|
|
83
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
84
|
+
/* @__PURE__ */ jsx("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx("text", { fg: "#88c0d0", bold: true, children: line }, i)) }),
|
|
85
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(
|
|
1643
86
|
StatusBar,
|
|
1644
87
|
{
|
|
1645
88
|
items: [{ key: "\u2190\u2192", label: "change font" }, { key: "q", label: "quit" }],
|
|
1646
|
-
extra: /* @__PURE__ */
|
|
89
|
+
extra: /* @__PURE__ */ jsx("span", { style: textStyle({ fg: "cyan", bold: true }), children: font.name.padEnd(11) })
|
|
1647
90
|
}
|
|
1648
|
-
)
|
|
91
|
+
) })
|
|
1649
92
|
] });
|
|
1650
93
|
}
|
|
1651
94
|
function TableApp() {
|
|
@@ -1654,81 +97,201 @@ function TableApp() {
|
|
|
1654
97
|
{ name: "Bob", role: "Designer", status: "Active" },
|
|
1655
98
|
{ name: "Charlie", role: "PM", status: "Away" }
|
|
1656
99
|
];
|
|
1657
|
-
return /* @__PURE__ */
|
|
1658
|
-
/* @__PURE__ */
|
|
1659
|
-
/* @__PURE__ */
|
|
100
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
101
|
+
/* @__PURE__ */ jsx("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx(Table, { data, headerColor: "cyan", borderColor: "#5e81ac" }) }),
|
|
102
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
1660
103
|
] });
|
|
1661
104
|
}
|
|
1662
105
|
function SpinnerApp() {
|
|
1663
|
-
return /* @__PURE__ */
|
|
1664
|
-
/* @__PURE__ */
|
|
1665
|
-
/* @__PURE__ */
|
|
106
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
107
|
+
/* @__PURE__ */ jsx("box", { flexGrow: 1, children: /* @__PURE__ */ jsx(SpinnerPicker, { useKeyboard }) }),
|
|
108
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "\u2190\u2192", label: "change variant" }, { key: "q", label: "quit" }] }) })
|
|
1666
109
|
] });
|
|
1667
110
|
}
|
|
1668
111
|
function SelectInputApp() {
|
|
1669
|
-
const [submitted, setSubmitted] =
|
|
112
|
+
const [submitted, setSubmitted] = useState(false);
|
|
1670
113
|
const items = [
|
|
1671
114
|
{ label: "TypeScript", value: "ts" },
|
|
1672
115
|
{ label: "JavaScript", value: "js" },
|
|
1673
116
|
{ label: "Python", value: "py" },
|
|
1674
117
|
{ label: "Rust", value: "rs" }
|
|
1675
118
|
];
|
|
1676
|
-
return /* @__PURE__ */
|
|
1677
|
-
/* @__PURE__ */
|
|
1678
|
-
/* @__PURE__ */
|
|
119
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
120
|
+
/* @__PURE__ */ jsx("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx(SelectInput, { items, title: "Choose a language", useKeyboard, onSubmit: () => setSubmitted(true) }) }),
|
|
121
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: submitted ? [{ key: "q", label: "quit" }] : [
|
|
1679
122
|
{ key: "\u2191\u2193", label: "select" },
|
|
1680
123
|
{ key: "enter", label: "submit" },
|
|
1681
124
|
{ key: "q", label: "quit" }
|
|
1682
|
-
] })
|
|
125
|
+
] }) })
|
|
1683
126
|
] });
|
|
1684
127
|
}
|
|
1685
128
|
function MultiSelectApp() {
|
|
1686
|
-
const [submitted, setSubmitted] =
|
|
129
|
+
const [submitted, setSubmitted] = useState(false);
|
|
1687
130
|
const items = [
|
|
1688
131
|
{ label: "TypeScript", value: "ts" },
|
|
1689
132
|
{ label: "JavaScript", value: "js" },
|
|
1690
133
|
{ label: "Python", value: "py" },
|
|
1691
134
|
{ label: "Rust", value: "rs" }
|
|
1692
135
|
];
|
|
1693
|
-
return /* @__PURE__ */
|
|
1694
|
-
/* @__PURE__ */
|
|
1695
|
-
/* @__PURE__ */
|
|
136
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
137
|
+
/* @__PURE__ */ jsx("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx(MultiSelect, { items, title: "Select languages", useKeyboard, onSubmit: () => setSubmitted(true) }) }),
|
|
138
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: submitted ? [{ key: "q", label: "quit" }] : [
|
|
1696
139
|
{ key: "\u2191\u2193", label: "move" },
|
|
1697
140
|
{ key: "enter", label: "select" },
|
|
1698
141
|
{ key: "a", label: "all" },
|
|
1699
142
|
{ key: "x", label: "clear" },
|
|
1700
143
|
{ key: "q", label: "quit" }
|
|
1701
|
-
] })
|
|
144
|
+
] }) })
|
|
145
|
+
] });
|
|
146
|
+
}
|
|
147
|
+
function PromptInputApp() {
|
|
148
|
+
const [lastMessage, setLastMessage] = useState("");
|
|
149
|
+
const [model, setModel] = useState("opus");
|
|
150
|
+
const [showModelPicker, setShowModelPicker] = useState(false);
|
|
151
|
+
const [resetKey, setResetKey] = useState(0);
|
|
152
|
+
const commands = [
|
|
153
|
+
{ cmd: "/help", desc: "Show commands" },
|
|
154
|
+
{ cmd: "/model", desc: "Switch model" },
|
|
155
|
+
{ cmd: "/clear", desc: "Clear conversation" }
|
|
156
|
+
];
|
|
157
|
+
const files = ["src/index.ts", "src/routes.ts", "src/auth.ts", "package.json"];
|
|
158
|
+
const models = [
|
|
159
|
+
{ label: "Claude Opus", value: "opus" },
|
|
160
|
+
{ label: "Claude Sonnet", value: "sonnet" },
|
|
161
|
+
{ label: "Claude Haiku", value: "haiku" }
|
|
162
|
+
];
|
|
163
|
+
const handleSubmit = (msg) => {
|
|
164
|
+
if (msg.text === "/model") {
|
|
165
|
+
setShowModelPicker(true);
|
|
166
|
+
setResetKey((k) => k + 1);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (msg.text === "/clear") {
|
|
170
|
+
setLastMessage("");
|
|
171
|
+
setResetKey((k) => k + 1);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
setLastMessage(msg.text);
|
|
175
|
+
};
|
|
176
|
+
if (showModelPicker) {
|
|
177
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
178
|
+
/* @__PURE__ */ jsx(
|
|
179
|
+
Modal,
|
|
180
|
+
{
|
|
181
|
+
title: "Select Model",
|
|
182
|
+
useKeyboard,
|
|
183
|
+
onClose: () => setShowModelPicker(false),
|
|
184
|
+
children: /* @__PURE__ */ jsx("box", { paddingX: 1, children: /* @__PURE__ */ jsx(
|
|
185
|
+
SelectInput,
|
|
186
|
+
{
|
|
187
|
+
items: models,
|
|
188
|
+
defaultValue: model,
|
|
189
|
+
useKeyboard,
|
|
190
|
+
onSubmit: (value) => {
|
|
191
|
+
setModel(value);
|
|
192
|
+
setShowModelPicker(false);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
) })
|
|
196
|
+
}
|
|
197
|
+
),
|
|
198
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [
|
|
199
|
+
{ key: "\u23CE", label: "select" },
|
|
200
|
+
{ key: "esc", label: "cancel" },
|
|
201
|
+
{ key: "q", label: "quit" }
|
|
202
|
+
] }) })
|
|
203
|
+
] });
|
|
204
|
+
}
|
|
205
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
206
|
+
/* @__PURE__ */ jsx("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: lastMessage ? /* @__PURE__ */ jsxs("text", { children: [
|
|
207
|
+
/* @__PURE__ */ jsx("span", { children: "Sent: " }),
|
|
208
|
+
/* @__PURE__ */ jsx("span", { children: lastMessage })
|
|
209
|
+
] }) : /* @__PURE__ */ jsx("text", { style: textStyle({ dim: true }), children: "Type a message and press enter" }) }),
|
|
210
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, children: /* @__PURE__ */ jsx(
|
|
211
|
+
PromptInput,
|
|
212
|
+
{
|
|
213
|
+
commands,
|
|
214
|
+
files,
|
|
215
|
+
placeholder: "Message Claude...",
|
|
216
|
+
showDividers: true,
|
|
217
|
+
useKeyboard,
|
|
218
|
+
onSubmit: handleSubmit
|
|
219
|
+
},
|
|
220
|
+
resetKey
|
|
221
|
+
) }),
|
|
222
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, children: /* @__PURE__ */ jsxs("text", { children: [
|
|
223
|
+
/* @__PURE__ */ jsx("span", { style: textStyle({ fg: "#C4A8FF" }), children: "[\u22A1_\u22A1]" }),
|
|
224
|
+
/* @__PURE__ */ jsx("span", { style: textStyle({ dim: true }), children: " " + model })
|
|
225
|
+
] }) }),
|
|
226
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [
|
|
227
|
+
{ key: "\u23CE", label: "send" },
|
|
228
|
+
{ key: "/", label: "commands" },
|
|
229
|
+
{ key: "@", label: "files" },
|
|
230
|
+
{ key: "\u2191", label: "history" },
|
|
231
|
+
{ key: "q", label: "quit" }
|
|
232
|
+
] }) })
|
|
1702
233
|
] });
|
|
1703
234
|
}
|
|
235
|
+
var TEXT_INPUT_FIELDS = [
|
|
236
|
+
{ label: "Username", placeholder: "enter your name", maxLength: 30, required: true },
|
|
237
|
+
{ label: "Email", placeholder: "user@example.com", maxLength: 50, required: true, description: "We'll never share your email" },
|
|
238
|
+
{ label: "Password", placeholder: "enter password", maxLength: 40 },
|
|
239
|
+
{ label: "API Key", placeholder: "sk-...", maxLength: 60, disabled: true }
|
|
240
|
+
];
|
|
1704
241
|
function TextInputApp() {
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
242
|
+
const [activeField, setActiveField] = useState(0);
|
|
243
|
+
const [values, setValues] = useState(TEXT_INPUT_FIELDS.map(() => ""));
|
|
244
|
+
useKeyboard((event) => {
|
|
245
|
+
if (event.name === "up") setActiveField((i) => Math.max(0, i - 1));
|
|
246
|
+
if (event.name === "down" || event.name === "tab") setActiveField((i) => Math.min(TEXT_INPUT_FIELDS.length - 1, i + 1));
|
|
247
|
+
});
|
|
248
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
249
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingTop: 1, children: /* @__PURE__ */ jsxs("text", { children: [
|
|
250
|
+
/* @__PURE__ */ jsx("span", { style: textStyle({ fg: "#FF71CE", bold: true }), children: "TextInput" }),
|
|
251
|
+
/* @__PURE__ */ jsx("span", { style: textStyle({ dim: true }), children: " Form with multiple input types" })
|
|
252
|
+
] }) }),
|
|
253
|
+
/* @__PURE__ */ jsx("box", { flexDirection: "column", paddingX: 1, paddingTop: 1, flexGrow: 1, children: TEXT_INPUT_FIELDS.map((field, i) => /* @__PURE__ */ jsx("box", { marginBottom: 1, children: /* @__PURE__ */ jsx(
|
|
254
|
+
TextInput,
|
|
255
|
+
{
|
|
256
|
+
label: field.label,
|
|
257
|
+
placeholder: field.placeholder,
|
|
258
|
+
prompt: "> ",
|
|
259
|
+
focus: i === activeField,
|
|
260
|
+
maxLength: field.maxLength,
|
|
261
|
+
value: values[i],
|
|
262
|
+
onChange: (v) => setValues((prev) => prev.map((old, j) => j === i ? v : old)),
|
|
263
|
+
required: field.required,
|
|
264
|
+
disabled: field.disabled,
|
|
265
|
+
description: field.description
|
|
266
|
+
}
|
|
267
|
+
) }, field.label)) }),
|
|
268
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [
|
|
269
|
+
{ key: "\u2191\u2193", label: "field" },
|
|
270
|
+
{ key: "\u2190\u2192", label: "cursor" },
|
|
271
|
+
{ key: "tab", label: "complete" },
|
|
272
|
+
{ key: "^k/^u", label: "kill" }
|
|
273
|
+
] }) })
|
|
1711
274
|
] });
|
|
1712
275
|
}
|
|
1713
276
|
function LinkApp() {
|
|
1714
|
-
return /* @__PURE__ */
|
|
1715
|
-
/* @__PURE__ */
|
|
1716
|
-
/* @__PURE__ */
|
|
277
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
278
|
+
/* @__PURE__ */ jsx("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx(LinkDemo, { useKeyboard }) }),
|
|
279
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
1717
280
|
] });
|
|
1718
281
|
}
|
|
1719
282
|
function TabBarApp() {
|
|
1720
283
|
const tabs = ["Files", "Search", "Git", "Debug"];
|
|
1721
|
-
const [selectedIndex, setSelectedIndex] =
|
|
284
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
1722
285
|
useKeyboard((event) => {
|
|
1723
286
|
if (event.name === "left") setSelectedIndex((i) => i > 0 ? i - 1 : tabs.length - 1);
|
|
1724
287
|
if (event.name === "right") setSelectedIndex((i) => i < tabs.length - 1 ? i + 1 : 0);
|
|
1725
288
|
});
|
|
1726
|
-
return /* @__PURE__ */
|
|
1727
|
-
/* @__PURE__ */
|
|
1728
|
-
/* @__PURE__ */
|
|
1729
|
-
/* @__PURE__ */
|
|
289
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
290
|
+
/* @__PURE__ */ jsxs("box", { flexDirection: "column", gap: 1, padding: 1, flexGrow: 1, children: [
|
|
291
|
+
/* @__PURE__ */ jsx(TabBar, { label: "View", options: tabs, selectedIndex }),
|
|
292
|
+
/* @__PURE__ */ jsx("text", { style: textStyle({ dim: true }), children: "Use \u2190/\u2192 arrow keys to switch tabs" })
|
|
1730
293
|
] }),
|
|
1731
|
-
/* @__PURE__ */
|
|
294
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "\u2190\u2192", label: "switch tab" }, { key: "q", label: "quit" }] }) })
|
|
1732
295
|
] });
|
|
1733
296
|
}
|
|
1734
297
|
function StatusBarApp() {
|
|
@@ -1738,7 +301,7 @@ function StatusBarApp() {
|
|
|
1738
301
|
{ key: "b", label: "back" },
|
|
1739
302
|
{ key: "z", label: "reset" }
|
|
1740
303
|
];
|
|
1741
|
-
const [lastKey, setLastKey] =
|
|
304
|
+
const [lastKey, setLastKey] = useState(null);
|
|
1742
305
|
useKeyboard((event) => {
|
|
1743
306
|
if (event.name === "tab") setLastKey("switch focus (Tab)");
|
|
1744
307
|
else if (event.name === "left") setLastKey("cycle (\u2190)");
|
|
@@ -1746,66 +309,224 @@ function StatusBarApp() {
|
|
|
1746
309
|
else if (event.name === "b") setLastKey("back (b)");
|
|
1747
310
|
else if (event.name === "z") setLastKey("reset (z)");
|
|
1748
311
|
});
|
|
1749
|
-
return /* @__PURE__ */
|
|
1750
|
-
lastKey ? /* @__PURE__ */
|
|
1751
|
-
/* @__PURE__ */
|
|
1752
|
-
/* @__PURE__ */
|
|
1753
|
-
] }) : /* @__PURE__ */
|
|
1754
|
-
/* @__PURE__ */
|
|
312
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", gap: 1, padding: 1, children: [
|
|
313
|
+
lastKey ? /* @__PURE__ */ jsxs("text", { children: [
|
|
314
|
+
/* @__PURE__ */ jsx("span", { children: "Pressed: " }),
|
|
315
|
+
/* @__PURE__ */ jsx("span", { style: textStyle({ bold: true, fg: "cyan" }), children: lastKey })
|
|
316
|
+
] }) : /* @__PURE__ */ jsx("text", { style: textStyle({ dim: true }), children: "Press a key to trigger an action" }),
|
|
317
|
+
/* @__PURE__ */ jsx(
|
|
1755
318
|
StatusBar,
|
|
1756
319
|
{
|
|
1757
320
|
items: [...shortcuts, { key: "q", label: "quit" }],
|
|
1758
|
-
extra: /* @__PURE__ */
|
|
321
|
+
extra: /* @__PURE__ */ jsx("span", { style: textStyle({ fg: "green" }), children: "\u25CF Ready" })
|
|
1759
322
|
}
|
|
1760
323
|
)
|
|
1761
324
|
] });
|
|
1762
325
|
}
|
|
1763
326
|
function ModalApp() {
|
|
1764
|
-
const [isOpen, setIsOpen] =
|
|
327
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1765
328
|
useKeyboard((event) => {
|
|
1766
329
|
if (!isOpen && event.name === "m") setIsOpen(true);
|
|
1767
330
|
if (isOpen && (event.name === "q" || event.name === "escape")) setIsOpen(false);
|
|
1768
331
|
});
|
|
1769
332
|
if (isOpen) {
|
|
1770
|
-
return /* @__PURE__ */
|
|
1771
|
-
/* @__PURE__ */
|
|
1772
|
-
/* @__PURE__ */
|
|
1773
|
-
/* @__PURE__ */
|
|
1774
|
-
/* @__PURE__ */
|
|
333
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
334
|
+
/* @__PURE__ */ jsx(Modal, { title: "Example Modal", borderColor: "blue", useKeyboard, onClose: () => setIsOpen(false), children: /* @__PURE__ */ jsxs("box", { paddingX: 1, flexDirection: "column", children: [
|
|
335
|
+
/* @__PURE__ */ jsx("text", { children: "This is a modal overlay component." }),
|
|
336
|
+
/* @__PURE__ */ jsx("text", { children: " " }),
|
|
337
|
+
/* @__PURE__ */ jsx("text", { style: textStyle({ dim: true }), children: "It stretches to fill the full terminal height." })
|
|
1775
338
|
] }) }),
|
|
1776
|
-
/* @__PURE__ */
|
|
339
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "close" }, { key: "Esc", label: "quit" }] }) })
|
|
1777
340
|
] });
|
|
1778
341
|
}
|
|
1779
|
-
return /* @__PURE__ */
|
|
1780
|
-
/* @__PURE__ */
|
|
1781
|
-
/* @__PURE__ */
|
|
1782
|
-
/* @__PURE__ */
|
|
1783
|
-
/* @__PURE__ */
|
|
342
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
343
|
+
/* @__PURE__ */ jsx("box", { flexDirection: "column", flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsxs("text", { children: [
|
|
344
|
+
/* @__PURE__ */ jsx("span", { style: textStyle({ dim: true }), children: "Press " }),
|
|
345
|
+
/* @__PURE__ */ jsx("span", { style: textStyle({ inverse: true, bold: true }), children: " m " }),
|
|
346
|
+
/* @__PURE__ */ jsx("span", { style: textStyle({ dim: true }), children: " to open modal" })
|
|
1784
347
|
] }) }),
|
|
1785
|
-
/* @__PURE__ */
|
|
348
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "m", label: "open modal" }, { key: "q", label: "quit" }] }) })
|
|
1786
349
|
] });
|
|
1787
350
|
}
|
|
1788
351
|
function PrimitivesApp() {
|
|
1789
|
-
return /* @__PURE__ */
|
|
1790
|
-
/* @__PURE__ */
|
|
1791
|
-
/* @__PURE__ */
|
|
1792
|
-
/* @__PURE__ */
|
|
1793
|
-
/* @__PURE__ */
|
|
1794
|
-
/* @__PURE__ */
|
|
352
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
353
|
+
/* @__PURE__ */ jsxs("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: [
|
|
354
|
+
/* @__PURE__ */ jsx("box", { border: true, borderStyle: "rounded", borderColor: "#5e81ac", title: "Layout", titleAlignment: "center", padding: 1, children: /* @__PURE__ */ jsxs("box", { flexDirection: "row", gap: 2, children: [
|
|
355
|
+
/* @__PURE__ */ jsx("box", { border: true, borderStyle: "single", borderColor: "#a3be8c", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx("text", { fg: "#a3be8c", bold: true, children: "Box 1" }) }),
|
|
356
|
+
/* @__PURE__ */ jsx("box", { border: true, borderStyle: "single", borderColor: "#ebcb8b", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx("text", { fg: "#ebcb8b", bold: true, children: "Box 2" }) }),
|
|
357
|
+
/* @__PURE__ */ jsx("box", { border: true, borderStyle: "single", borderColor: "#b48ead", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx("text", { fg: "#b48ead", bold: true, children: "Box 3" }) })
|
|
1795
358
|
] }) }),
|
|
1796
|
-
/* @__PURE__ */
|
|
359
|
+
/* @__PURE__ */ jsx("text", { fg: "#d8dee9", dim: true, children: " Nested boxes with borders, colors & flexbox layout" })
|
|
1797
360
|
] }),
|
|
1798
|
-
/* @__PURE__ */
|
|
361
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
1799
362
|
] });
|
|
1800
363
|
}
|
|
1801
364
|
function TerminalWindowApp() {
|
|
1802
|
-
return /* @__PURE__ */
|
|
1803
|
-
/* @__PURE__ */
|
|
1804
|
-
/* @__PURE__ */
|
|
1805
|
-
/* @__PURE__ */
|
|
1806
|
-
/* @__PURE__ */
|
|
365
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
366
|
+
/* @__PURE__ */ jsxs("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: [
|
|
367
|
+
/* @__PURE__ */ jsx("text", { style: textStyle({ fg: "green" }), children: '$ echo "Hello from OpenTUI"' }),
|
|
368
|
+
/* @__PURE__ */ jsx("text", { children: "Hello from OpenTUI" }),
|
|
369
|
+
/* @__PURE__ */ jsx("text", { style: textStyle({ fg: "green" }), children: "$ _" })
|
|
1807
370
|
] }),
|
|
1808
|
-
/* @__PURE__ */
|
|
371
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
372
|
+
] });
|
|
373
|
+
}
|
|
374
|
+
var TIMELINE_STEPS = [
|
|
375
|
+
{ tool: "Read", label: "Reading codebase \u2014 src/", status: "done", delay: 1800 },
|
|
376
|
+
{ tool: "Think", label: "Planning changes \u2014 auth module", status: "done", delay: 2500 },
|
|
377
|
+
{ tool: "Edit", label: "Editing files \u2014 4 files", status: "done", delay: 3200 },
|
|
378
|
+
{ tool: "Bash", label: "Running tests \u2014 vitest", status: "done", delay: 2e3 },
|
|
379
|
+
{ tool: "Edit", label: "Fixing test \u2014 routes.test.ts", status: "done", delay: 1500 }
|
|
380
|
+
];
|
|
381
|
+
function TimelineApp() {
|
|
382
|
+
const [expanded, setExpanded] = useState(true);
|
|
383
|
+
const [phase, setPhase] = useState("running");
|
|
384
|
+
const [stepIndex, setStepIndex] = useState(0);
|
|
385
|
+
const timerRef = useRef(null);
|
|
386
|
+
useKeyboard((event) => {
|
|
387
|
+
if (event.name === "E" && event.ctrl && event.shift) setExpanded((v) => !v);
|
|
388
|
+
if (event.name === "r") timelineRestart();
|
|
389
|
+
});
|
|
390
|
+
function timelineRestart() {
|
|
391
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
392
|
+
setPhase("running");
|
|
393
|
+
setStepIndex(0);
|
|
394
|
+
}
|
|
395
|
+
useEffect(() => {
|
|
396
|
+
if (phase !== "running") return;
|
|
397
|
+
if (stepIndex < TIMELINE_STEPS.length) {
|
|
398
|
+
const delay = TIMELINE_STEPS[stepIndex].delay;
|
|
399
|
+
timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
|
|
400
|
+
} else {
|
|
401
|
+
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
402
|
+
}
|
|
403
|
+
return () => {
|
|
404
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
405
|
+
};
|
|
406
|
+
}, [phase, stepIndex]);
|
|
407
|
+
useEffect(() => {
|
|
408
|
+
if (phase === "done") {
|
|
409
|
+
timerRef.current = setTimeout(() => timelineRestart(), 3e3);
|
|
410
|
+
}
|
|
411
|
+
return () => {
|
|
412
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
413
|
+
};
|
|
414
|
+
}, [phase]);
|
|
415
|
+
const steps = TIMELINE_STEPS.map((s, i) => {
|
|
416
|
+
if (i < stepIndex) return { ...s, status: "done" };
|
|
417
|
+
if (i === stepIndex && phase === "running") return { ...s, status: "running" };
|
|
418
|
+
return { ...s, status: phase === "done" ? "done" : "pending" };
|
|
419
|
+
});
|
|
420
|
+
const elapsedMs = TIMELINE_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
|
|
421
|
+
const totalMs = TIMELINE_STEPS.reduce((sum, s) => sum + s.delay, 0);
|
|
422
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
423
|
+
/* @__PURE__ */ jsx("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx(
|
|
424
|
+
Timeline,
|
|
425
|
+
{
|
|
426
|
+
steps,
|
|
427
|
+
duration: phase === "done" ? `${(totalMs / 1e3).toFixed(1)}s` : `${(elapsedMs / 1e3).toFixed(1)}s`,
|
|
428
|
+
collapsed: !expanded
|
|
429
|
+
}
|
|
430
|
+
) }),
|
|
431
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [
|
|
432
|
+
{ key: "ctrl+shift+e", label: "toggle" },
|
|
433
|
+
{ key: "r", label: "restart" },
|
|
434
|
+
{ key: "q", label: "quit" }
|
|
435
|
+
] }) })
|
|
436
|
+
] });
|
|
437
|
+
}
|
|
438
|
+
var BUBBLE_STEPS = [
|
|
439
|
+
{ tool: "Read", label: "Reading codebase \u2014 src/", status: "done", delay: 1800 },
|
|
440
|
+
{ tool: "Think", label: "Planning changes \u2014 auth module", status: "done", delay: 2500 },
|
|
441
|
+
{ tool: "Edit", label: "Editing files \u2014 4 files", status: "done", delay: 3200 },
|
|
442
|
+
{ tool: "Bash", label: "Running tests \u2014 vitest", status: "done", delay: 2e3 },
|
|
443
|
+
{ tool: "Edit", label: "Fixing test \u2014 routes.test.ts", status: "done", delay: 1500 }
|
|
444
|
+
];
|
|
445
|
+
var BUBBLE_RESPONSE = "I've refactored the auth module. The changes include extracting the token validation into a shared helper, consolidating the middleware chain, and updating the test suite to match.";
|
|
446
|
+
var BUBBLE_TOTAL_MS = BUBBLE_STEPS.reduce((sum, s) => sum + s.delay, 0);
|
|
447
|
+
function MessageApp() {
|
|
448
|
+
const [expanded, setExpanded] = useState(true);
|
|
449
|
+
const [phase, setPhase] = useState("idle");
|
|
450
|
+
const [stepIndex, setStepIndex] = useState(0);
|
|
451
|
+
const [streamedText, setStreamedText] = useState("");
|
|
452
|
+
const timerRef = useRef(null);
|
|
453
|
+
useKeyboard((event) => {
|
|
454
|
+
if (event.name === "E" && event.ctrl && event.shift) setExpanded((v) => !v);
|
|
455
|
+
if (event.name === "r") bubbleRestart();
|
|
456
|
+
});
|
|
457
|
+
function bubbleRestart() {
|
|
458
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
459
|
+
setPhase("idle");
|
|
460
|
+
setStepIndex(0);
|
|
461
|
+
setStreamedText("");
|
|
462
|
+
}
|
|
463
|
+
useEffect(() => {
|
|
464
|
+
if (phase === "idle") {
|
|
465
|
+
timerRef.current = setTimeout(() => setPhase("thinking"), 800);
|
|
466
|
+
}
|
|
467
|
+
return () => {
|
|
468
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
469
|
+
};
|
|
470
|
+
}, [phase]);
|
|
471
|
+
useEffect(() => {
|
|
472
|
+
if (phase !== "thinking") return;
|
|
473
|
+
if (stepIndex < BUBBLE_STEPS.length) {
|
|
474
|
+
const delay = BUBBLE_STEPS[stepIndex].delay;
|
|
475
|
+
timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
|
|
476
|
+
} else {
|
|
477
|
+
timerRef.current = setTimeout(() => setPhase("streaming"), 500);
|
|
478
|
+
}
|
|
479
|
+
return () => {
|
|
480
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
481
|
+
};
|
|
482
|
+
}, [phase, stepIndex]);
|
|
483
|
+
useEffect(() => {
|
|
484
|
+
if (phase !== "streaming") return;
|
|
485
|
+
if (streamedText.length < BUBBLE_RESPONSE.length) {
|
|
486
|
+
timerRef.current = setTimeout(() => {
|
|
487
|
+
setStreamedText(BUBBLE_RESPONSE.slice(0, streamedText.length + 2));
|
|
488
|
+
}, 25);
|
|
489
|
+
} else {
|
|
490
|
+
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
491
|
+
}
|
|
492
|
+
return () => {
|
|
493
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
494
|
+
};
|
|
495
|
+
}, [phase, streamedText]);
|
|
496
|
+
useEffect(() => {
|
|
497
|
+
if (phase === "done") {
|
|
498
|
+
timerRef.current = setTimeout(() => bubbleRestart(), 3e3);
|
|
499
|
+
}
|
|
500
|
+
return () => {
|
|
501
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
502
|
+
};
|
|
503
|
+
}, [phase]);
|
|
504
|
+
const steps = BUBBLE_STEPS.map((s, i) => {
|
|
505
|
+
if (i < stepIndex) return { ...s, status: "done" };
|
|
506
|
+
if (i === stepIndex) return { ...s, status: "running" };
|
|
507
|
+
return { ...s, status: "pending" };
|
|
508
|
+
});
|
|
509
|
+
const isThinking = phase === "thinking";
|
|
510
|
+
const isStreaming = phase === "streaming";
|
|
511
|
+
const isDone = phase === "done";
|
|
512
|
+
const showAssistant = phase !== "idle";
|
|
513
|
+
const elapsedMs = BUBBLE_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
|
|
514
|
+
const reasoningDuration = isThinking ? `${(elapsedMs / 1e3).toFixed(1)}s` : `${(BUBBLE_TOTAL_MS / 1e3).toFixed(1)}s`;
|
|
515
|
+
const reasoningSteps = isThinking ? steps : BUBBLE_STEPS.map((s) => ({ ...s, status: "done" }));
|
|
516
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
517
|
+
/* @__PURE__ */ jsxs("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1, children: [
|
|
518
|
+
/* @__PURE__ */ jsx(Message, { role: "user", children: /* @__PURE__ */ jsx(Message.Content, { children: /* @__PURE__ */ jsx(Message.Text, { children: "Can you refactor the auth module?" }) }) }),
|
|
519
|
+
showAssistant && /* @__PURE__ */ jsxs(Message, { role: "assistant", isStreaming, children: [
|
|
520
|
+
/* @__PURE__ */ jsx(Message.Reasoning, { part: {
|
|
521
|
+
type: "reasoning",
|
|
522
|
+
duration: reasoningDuration,
|
|
523
|
+
collapsed: !expanded,
|
|
524
|
+
steps: reasoningSteps
|
|
525
|
+
} }),
|
|
526
|
+
(isStreaming || isDone) && /* @__PURE__ */ jsx(Message.Content, { children: /* @__PURE__ */ jsx(Message.Text, { isLast: true, children: isDone ? BUBBLE_RESPONSE : streamedText }) })
|
|
527
|
+
] })
|
|
528
|
+
] }),
|
|
529
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "ctrl+shift+e", label: "toggle timeline" }, { key: "r", label: "restart" }, { key: "q", label: "quit" }] }) })
|
|
1809
530
|
] });
|
|
1810
531
|
}
|
|
1811
532
|
var initialChatMessages = [
|
|
@@ -1816,12 +537,12 @@ var initialChatMessages = [
|
|
|
1816
537
|
];
|
|
1817
538
|
var chatNextId = 5;
|
|
1818
539
|
function ChatApp() {
|
|
1819
|
-
const [messages, setMessages] =
|
|
1820
|
-
const [isLoading, setIsLoading] =
|
|
1821
|
-
const [streamingText, setStreamingText] =
|
|
1822
|
-
const [activeToolCalls, setActiveToolCalls] =
|
|
1823
|
-
const intervalRef =
|
|
1824
|
-
const handleSend =
|
|
540
|
+
const [messages, setMessages] = useState(initialChatMessages);
|
|
541
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
542
|
+
const [streamingText, setStreamingText] = useState("");
|
|
543
|
+
const [activeToolCalls, setActiveToolCalls] = useState([]);
|
|
544
|
+
const intervalRef = useRef(null);
|
|
545
|
+
const handleSend = useCallback((text) => {
|
|
1825
546
|
const userMsg = { id: String(chatNextId++), role: "user", content: text };
|
|
1826
547
|
setMessages((prev) => [...prev, userMsg]);
|
|
1827
548
|
setIsLoading(true);
|
|
@@ -1852,14 +573,14 @@ function ChatApp() {
|
|
|
1852
573
|
}, 50);
|
|
1853
574
|
}, 1400);
|
|
1854
575
|
}, []);
|
|
1855
|
-
const handleCancel =
|
|
576
|
+
const handleCancel = useCallback(() => {
|
|
1856
577
|
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
1857
578
|
setIsLoading(false);
|
|
1858
579
|
setStreamingText("");
|
|
1859
580
|
setActiveToolCalls([]);
|
|
1860
581
|
}, []);
|
|
1861
|
-
return /* @__PURE__ */
|
|
1862
|
-
/* @__PURE__ */
|
|
582
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
583
|
+
/* @__PURE__ */ jsx(
|
|
1863
584
|
ChatPanel,
|
|
1864
585
|
{
|
|
1865
586
|
messages,
|
|
@@ -1872,29 +593,32 @@ function ChatApp() {
|
|
|
1872
593
|
useKeyboard
|
|
1873
594
|
}
|
|
1874
595
|
),
|
|
1875
|
-
/* @__PURE__ */
|
|
596
|
+
/* @__PURE__ */ jsx("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
1876
597
|
] });
|
|
1877
598
|
}
|
|
1878
599
|
var demos = [
|
|
1879
|
-
{ name: "gradient", app: () => /* @__PURE__ */
|
|
1880
|
-
{ name: "ascii", app: () => /* @__PURE__ */
|
|
1881
|
-
{ name: "table", app: () => /* @__PURE__ */
|
|
1882
|
-
{ name: "spinner", app: () => /* @__PURE__ */
|
|
1883
|
-
{ name: "select-input", app: () => /* @__PURE__ */
|
|
1884
|
-
{ name: "multi-select", app: () => /* @__PURE__ */
|
|
1885
|
-
{ name: "
|
|
1886
|
-
{ name: "
|
|
1887
|
-
{ name: "
|
|
1888
|
-
{ name: "
|
|
1889
|
-
{ name: "
|
|
1890
|
-
{ name: "
|
|
1891
|
-
{ name: "
|
|
1892
|
-
{ name: "
|
|
1893
|
-
{ name: "
|
|
600
|
+
{ name: "gradient", app: () => /* @__PURE__ */ jsx(GradientApp, {}) },
|
|
601
|
+
{ name: "ascii", app: () => /* @__PURE__ */ jsx(AsciiApp, {}) },
|
|
602
|
+
{ name: "table", app: () => /* @__PURE__ */ jsx(TableApp, {}) },
|
|
603
|
+
{ name: "spinner", app: () => /* @__PURE__ */ jsx(SpinnerApp, {}) },
|
|
604
|
+
{ name: "select-input", app: () => /* @__PURE__ */ jsx(SelectInputApp, {}) },
|
|
605
|
+
{ name: "multi-select", app: () => /* @__PURE__ */ jsx(MultiSelectApp, {}) },
|
|
606
|
+
{ name: "prompt-input", app: () => /* @__PURE__ */ jsx(PromptInputApp, {}) },
|
|
607
|
+
{ name: "text-input", app: () => /* @__PURE__ */ jsx(TextInputApp, {}) },
|
|
608
|
+
{ name: "link", app: () => /* @__PURE__ */ jsx(LinkApp, {}) },
|
|
609
|
+
{ name: "tabs", app: () => /* @__PURE__ */ jsx(TabBarApp, {}) },
|
|
610
|
+
{ name: "status-bar", app: () => /* @__PURE__ */ jsx(StatusBarApp, {}) },
|
|
611
|
+
{ name: "modal", app: () => /* @__PURE__ */ jsx(ModalApp, {}) },
|
|
612
|
+
{ name: "primitives", app: () => /* @__PURE__ */ jsx(PrimitivesApp, {}) },
|
|
613
|
+
{ name: "chat", app: () => /* @__PURE__ */ jsx(ChatApp, {}) },
|
|
614
|
+
{ name: "timeline", app: () => /* @__PURE__ */ jsx(TimelineApp, {}) },
|
|
615
|
+
{ name: "message", app: () => /* @__PURE__ */ jsx(MessageApp, {}) },
|
|
616
|
+
{ name: "terminal-window", app: () => /* @__PURE__ */ jsx(TerminalWindowApp, {}) },
|
|
617
|
+
{ name: "landing", app: () => /* @__PURE__ */ jsx(LandingApp, { useKeyboard }) }
|
|
1894
618
|
];
|
|
1895
619
|
|
|
1896
620
|
// src/run.tsx
|
|
1897
|
-
import { jsx as
|
|
621
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1898
622
|
var _renderer;
|
|
1899
623
|
function DemoShell({ children }) {
|
|
1900
624
|
useKeyboard2((event) => {
|
|
@@ -1902,7 +626,7 @@ function DemoShell({ children }) {
|
|
|
1902
626
|
_renderer.destroy();
|
|
1903
627
|
}
|
|
1904
628
|
});
|
|
1905
|
-
return /* @__PURE__ */
|
|
629
|
+
return /* @__PURE__ */ jsx2("box", { flexDirection: "column", flexGrow: 1, children });
|
|
1906
630
|
}
|
|
1907
631
|
async function runDemo(name) {
|
|
1908
632
|
const demo = demos.find((d) => d.name === name);
|
|
@@ -1912,7 +636,7 @@ async function runDemo(name) {
|
|
|
1912
636
|
process.exit(1);
|
|
1913
637
|
}
|
|
1914
638
|
_renderer = await createCliRenderer({ exitOnCtrlC: true });
|
|
1915
|
-
createRoot(_renderer).render(/* @__PURE__ */
|
|
639
|
+
createRoot(_renderer).render(/* @__PURE__ */ jsx2(DemoShell, { children: demo.app() }));
|
|
1916
640
|
}
|
|
1917
641
|
export {
|
|
1918
642
|
demos,
|