@gridland/demo 0.2.50 → 0.2.51
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-4VNS5WPM.js +42 -0
- package/dist/chunk-DTDQ3HF4.js +494 -0
- package/dist/demo-names.json +1 -1
- package/dist/landing.js +164 -286
- package/dist/run.js +1166 -1055
- package/dist/token-M3ULGZTY.js +62 -0
- package/dist/token-util-FKUIR5UM.js +5 -0
- package/package.json +4 -4
package/dist/run.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
// src/run.tsx
|
|
2
|
-
import { createCliRenderer, createRoot, useKeyboard as
|
|
2
|
+
import { createCliRenderer, createRoot, useKeyboard as useKeyboard19 } from "@gridland/bun";
|
|
3
3
|
|
|
4
|
-
//
|
|
5
|
-
import {
|
|
4
|
+
// demos/index.tsx
|
|
5
|
+
import { useKeyboard as useKeyboard18 } from "@gridland/utils";
|
|
6
|
+
|
|
7
|
+
// demos/gradient.tsx
|
|
8
|
+
import { useState as useState8 } from "react";
|
|
6
9
|
import { useKeyboard } from "@gridland/utils";
|
|
7
10
|
|
|
8
11
|
// ../ui/components/theme/themes.ts
|
|
@@ -33,19 +36,6 @@ import { jsx as jsx2 } from "react/jsx-runtime";
|
|
|
33
36
|
var UNDERLINE = 1 << 3;
|
|
34
37
|
var UNDERLINE_DASHED = 1 << 4;
|
|
35
38
|
var UNDERLINE_DOTTED = 1 << 6;
|
|
36
|
-
function Link({ children, url, underline = "solid", color }) {
|
|
37
|
-
const theme = useTheme();
|
|
38
|
-
const resolvedColor = color ?? theme.accent;
|
|
39
|
-
let attributes = 0;
|
|
40
|
-
if (underline === "solid") {
|
|
41
|
-
attributes = UNDERLINE;
|
|
42
|
-
} else if (underline === "dashed") {
|
|
43
|
-
attributes = UNDERLINE | UNDERLINE_DASHED;
|
|
44
|
-
} else if (underline === "dotted") {
|
|
45
|
-
attributes = UNDERLINE | UNDERLINE_DOTTED;
|
|
46
|
-
}
|
|
47
|
-
return /* @__PURE__ */ jsx2("text", { children: /* @__PURE__ */ jsx2("a", { href: url, style: { attributes, fg: resolvedColor }, children }) });
|
|
48
|
-
}
|
|
49
39
|
|
|
50
40
|
// ../ui/components/link/link-demo.tsx
|
|
51
41
|
import { useState } from "react";
|
|
@@ -72,7 +62,7 @@ function textStyle(opts) {
|
|
|
72
62
|
|
|
73
63
|
// ../ui/components/status-bar/status-bar.tsx
|
|
74
64
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
75
|
-
function StatusBar({ items, extra }) {
|
|
65
|
+
function StatusBar({ items: items3, extra }) {
|
|
76
66
|
const theme = useTheme();
|
|
77
67
|
const parts = [];
|
|
78
68
|
if (extra !== void 0) {
|
|
@@ -83,7 +73,7 @@ function StatusBar({ items, extra }) {
|
|
|
83
73
|
/* @__PURE__ */ jsx3("span", { style: textStyle({ dim: true, fg: theme.placeholder }), children: " \u2502 " }, "pipe")
|
|
84
74
|
);
|
|
85
75
|
}
|
|
86
|
-
|
|
76
|
+
items3.forEach((item, i) => {
|
|
87
77
|
if (i > 0) {
|
|
88
78
|
parts.push(/* @__PURE__ */ jsx3("span", { children: " " }, `gap-${i}`));
|
|
89
79
|
}
|
|
@@ -111,35 +101,6 @@ function useKeyboardContext(propOverride) {
|
|
|
111
101
|
|
|
112
102
|
// ../ui/components/link/link-demo.tsx
|
|
113
103
|
import { jsx as jsx5, jsxs } from "react/jsx-runtime";
|
|
114
|
-
var MODES = ["solid", "dashed", "dotted", "none"];
|
|
115
|
-
function LinkDemo({
|
|
116
|
-
url = "https://opentui.com",
|
|
117
|
-
label = "Visit opentui.com",
|
|
118
|
-
useKeyboard: useKeyboardProp
|
|
119
|
-
}) {
|
|
120
|
-
const useKeyboard3 = useKeyboardContext(useKeyboardProp);
|
|
121
|
-
const [modeIndex, setModeIndex] = useState(0);
|
|
122
|
-
const mode = MODES[modeIndex];
|
|
123
|
-
useKeyboard3?.((event) => {
|
|
124
|
-
if (event.name === "right") {
|
|
125
|
-
setModeIndex((i) => (i + 1) % MODES.length);
|
|
126
|
-
} else if (event.name === "left") {
|
|
127
|
-
setModeIndex((i) => (i - 1 + MODES.length) % MODES.length);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", gap: 1, children: [
|
|
131
|
-
/* @__PURE__ */ jsx5(Link, { url, underline: mode, children: label }),
|
|
132
|
-
/* @__PURE__ */ jsx5(
|
|
133
|
-
StatusBar,
|
|
134
|
-
{
|
|
135
|
-
extra: /* @__PURE__ */ jsx5("span", { style: textStyle({ bold: true }), children: mode.padEnd(6) }),
|
|
136
|
-
items: [
|
|
137
|
-
{ key: "\u2190\u2192", label: "underline style" }
|
|
138
|
-
]
|
|
139
|
-
}
|
|
140
|
-
)
|
|
141
|
-
] });
|
|
142
|
-
}
|
|
143
104
|
|
|
144
105
|
// ../ui/components/ascii/ascii.tsx
|
|
145
106
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
@@ -148,25 +109,43 @@ import { jsx as jsx6 } from "react/jsx-runtime";
|
|
|
148
109
|
import { useEffect, useState as useState2 } from "react";
|
|
149
110
|
import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
150
111
|
var VARIANTS = {
|
|
151
|
-
dots: { frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"], interval:
|
|
112
|
+
dots: { frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"], interval: 80 },
|
|
152
113
|
pulse: { frames: ["\xB7", "\u2219", "\u25CF", "\u2219", "\xB7", "\xB7", "\xB7"], interval: 180 },
|
|
153
114
|
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 },
|
|
154
115
|
bloom: { frames: ["\xB7", "\u2726", "\u2727", "\u2739", "\u273A", "\u274B", "\u2738", "\u2735", "\u2738", "\u274B", "\u273A", "\u2739", "\u2727", "\u2726", "\xB7", "\xB7"], interval: 100 },
|
|
155
116
|
ellipsis: { frames: [" ", ". ", ".. ", "..."], interval: 333 }
|
|
156
117
|
};
|
|
157
118
|
var VARIANT_NAMES = Object.keys(VARIANTS);
|
|
158
|
-
|
|
119
|
+
var STATUS_SYMBOLS = {
|
|
120
|
+
success: "\u2714",
|
|
121
|
+
error: "\u2716",
|
|
122
|
+
warning: "\u26A0",
|
|
123
|
+
info: "\u2139"
|
|
124
|
+
};
|
|
125
|
+
function Spinner({ variant = "dots", text, color, status = "spinning" }) {
|
|
159
126
|
const theme = useTheme();
|
|
160
|
-
const resolvedColor = color ?? theme.accent;
|
|
161
127
|
const { frames, interval } = VARIANTS[variant];
|
|
162
128
|
const [frame, setFrame] = useState2(0);
|
|
163
129
|
useEffect(() => {
|
|
130
|
+
if (status !== "spinning") return;
|
|
164
131
|
setFrame(0);
|
|
165
132
|
const timer = setInterval(() => {
|
|
166
133
|
setFrame((prev) => (prev + 1) % frames.length);
|
|
167
134
|
}, interval);
|
|
168
135
|
return () => clearInterval(timer);
|
|
169
|
-
}, [variant]);
|
|
136
|
+
}, [variant, status]);
|
|
137
|
+
if (status !== "spinning") {
|
|
138
|
+
const symbol = STATUS_SYMBOLS[status];
|
|
139
|
+
const statusColor = status === "success" ? theme.success : status === "error" ? theme.error : status === "warning" ? theme.warning : theme.accent;
|
|
140
|
+
return /* @__PURE__ */ jsxs2("text", { children: [
|
|
141
|
+
/* @__PURE__ */ jsx7("span", { style: { fg: statusColor }, children: symbol }),
|
|
142
|
+
text ? /* @__PURE__ */ jsxs2("span", { style: { fg: theme.foreground }, children: [
|
|
143
|
+
" ",
|
|
144
|
+
text
|
|
145
|
+
] }) : null
|
|
146
|
+
] });
|
|
147
|
+
}
|
|
148
|
+
const resolvedColor = color ?? theme.accent;
|
|
170
149
|
return /* @__PURE__ */ jsxs2("text", { children: [
|
|
171
150
|
/* @__PURE__ */ jsx7("span", { style: { fg: resolvedColor }, children: frames[frame] }),
|
|
172
151
|
text ? /* @__PURE__ */ jsxs2("span", { style: { fg: theme.foreground }, children: [
|
|
@@ -181,9 +160,9 @@ import { useState as useState3 } from "react";
|
|
|
181
160
|
import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
182
161
|
function SpinnerPicker({ useKeyboard: useKeyboardProp }) {
|
|
183
162
|
const theme = useTheme();
|
|
184
|
-
const
|
|
163
|
+
const useKeyboard20 = useKeyboardContext(useKeyboardProp);
|
|
185
164
|
const [selected, setSelected] = useState3(0);
|
|
186
|
-
|
|
165
|
+
useKeyboard20?.((event) => {
|
|
187
166
|
if (event.name === "left") {
|
|
188
167
|
setSelected((s) => s > 0 ? s - 1 : VARIANT_NAMES.length - 1);
|
|
189
168
|
} else if (event.name === "right") {
|
|
@@ -296,7 +275,7 @@ var RADIO = "\u25CB";
|
|
|
296
275
|
var CURSOR = "\u25B8";
|
|
297
276
|
var SEPARATOR = "\u2500";
|
|
298
277
|
function SelectInput({
|
|
299
|
-
items = [],
|
|
278
|
+
items: items3 = [],
|
|
300
279
|
defaultValue,
|
|
301
280
|
value: controlledValue,
|
|
302
281
|
onChange,
|
|
@@ -312,14 +291,14 @@ function SelectInput({
|
|
|
312
291
|
useKeyboard: useKeyboardProp
|
|
313
292
|
}) {
|
|
314
293
|
const theme = useTheme();
|
|
315
|
-
const
|
|
294
|
+
const useKeyboard20 = useKeyboardContext(useKeyboardProp);
|
|
316
295
|
const resolvedHighlight = highlightColor ?? theme.primary;
|
|
317
296
|
const isControlled = controlledValue !== void 0;
|
|
318
297
|
const controlledRef = useRef2(isControlled);
|
|
319
298
|
if (controlledRef.current !== isControlled) {
|
|
320
299
|
console.warn("SelectInput: switching between controlled and uncontrolled is not supported.");
|
|
321
300
|
}
|
|
322
|
-
const initialIndex =
|
|
301
|
+
const initialIndex = items3.findIndex((i) => i.value === (isControlled ? controlledValue : defaultValue));
|
|
323
302
|
const [state, dispatch] = useReducer(reducer, {
|
|
324
303
|
cursor: Math.max(0, initialIndex),
|
|
325
304
|
submitted: false
|
|
@@ -329,7 +308,7 @@ function SelectInput({
|
|
|
329
308
|
const selectable = [];
|
|
330
309
|
let index = 0;
|
|
331
310
|
const grouped = /* @__PURE__ */ new Map();
|
|
332
|
-
for (const item of
|
|
311
|
+
for (const item of items3) {
|
|
333
312
|
const group = item.group ?? "";
|
|
334
313
|
const list = grouped.get(group) ?? [];
|
|
335
314
|
list.push(item);
|
|
@@ -349,13 +328,13 @@ function SelectInput({
|
|
|
349
328
|
}
|
|
350
329
|
}
|
|
351
330
|
return { flatRows: rows, selectableItems: selectable };
|
|
352
|
-
}, [
|
|
331
|
+
}, [items3]);
|
|
353
332
|
const visibleCount = limit ?? VISIBLE;
|
|
354
333
|
const cursorRowIndex = flatRows.findIndex((r) => r.type === "item" && r.index === state.cursor);
|
|
355
334
|
const scrollOffset = Math.max(0, Math.min(cursorRowIndex - Math.floor(visibleCount / 2), flatRows.length - visibleCount));
|
|
356
335
|
const visibleRows = flatRows.slice(scrollOffset, scrollOffset + visibleCount);
|
|
357
336
|
const diamondColor = invalid ? theme.error : disabled ? theme.muted : theme.accent;
|
|
358
|
-
|
|
337
|
+
useKeyboard20?.((event) => {
|
|
359
338
|
if (state.submitted || disabled) return;
|
|
360
339
|
if (event.name === "up" || event.name === "k") {
|
|
361
340
|
const direction = -1;
|
|
@@ -384,7 +363,7 @@ function SelectInput({
|
|
|
384
363
|
}
|
|
385
364
|
});
|
|
386
365
|
if (state.submitted) {
|
|
387
|
-
const selectedItem = isControlled ?
|
|
366
|
+
const selectedItem = isControlled ? items3.find((i) => i.value === controlledValue) : selectableItems[state.cursor]?.item;
|
|
388
367
|
return /* @__PURE__ */ jsxs5("box", { flexDirection: "column", children: [
|
|
389
368
|
/* @__PURE__ */ jsxs5("text", { children: [
|
|
390
369
|
/* @__PURE__ */ jsx10("span", { style: textStyle({ fg: theme.success }), children: "\u25C6 " }),
|
|
@@ -498,7 +477,7 @@ var UNCHECKED = "\u25CB";
|
|
|
498
477
|
var CURSOR2 = "\u25B8";
|
|
499
478
|
var SEPARATOR2 = "\u2500";
|
|
500
479
|
function MultiSelect({
|
|
501
|
-
items = [],
|
|
480
|
+
items: items3 = [],
|
|
502
481
|
defaultSelected = [],
|
|
503
482
|
selected: controlledSelected,
|
|
504
483
|
onChange,
|
|
@@ -519,7 +498,7 @@ function MultiSelect({
|
|
|
519
498
|
useKeyboard: useKeyboardProp
|
|
520
499
|
}) {
|
|
521
500
|
const theme = useTheme();
|
|
522
|
-
const
|
|
501
|
+
const useKeyboard20 = useKeyboardContext(useKeyboardProp);
|
|
523
502
|
const resolvedHighlight = highlightColor ?? theme.primary;
|
|
524
503
|
const resolvedCheckbox = checkboxColor ?? theme.accent;
|
|
525
504
|
const isControlled = controlledSelected !== void 0;
|
|
@@ -539,7 +518,7 @@ function MultiSelect({
|
|
|
539
518
|
const selectable = [];
|
|
540
519
|
let index = 0;
|
|
541
520
|
const grouped = /* @__PURE__ */ new Map();
|
|
542
|
-
for (const item of
|
|
521
|
+
for (const item of items3) {
|
|
543
522
|
const group = item.group ?? "";
|
|
544
523
|
const list = grouped.get(group) ?? [];
|
|
545
524
|
list.push(item);
|
|
@@ -559,7 +538,7 @@ function MultiSelect({
|
|
|
559
538
|
}
|
|
560
539
|
}
|
|
561
540
|
return { flatRows: rows, selectableItems: selectable };
|
|
562
|
-
}, [
|
|
541
|
+
}, [items3]);
|
|
563
542
|
const hasSubmitRow = allowEmpty || currentSelected.size > 0;
|
|
564
543
|
const totalPositions = selectableItems.length + (hasSubmitRow ? 1 : 0);
|
|
565
544
|
const isOnSubmit = hasSubmitRow && state.cursor === selectableItems.length;
|
|
@@ -575,7 +554,7 @@ function MultiSelect({
|
|
|
575
554
|
}
|
|
576
555
|
};
|
|
577
556
|
const diamondColor = invalid ? theme.error : disabled ? theme.muted : theme.accent;
|
|
578
|
-
|
|
557
|
+
useKeyboard20?.((event) => {
|
|
579
558
|
if (state.submitted || disabled) return;
|
|
580
559
|
const move = (direction) => {
|
|
581
560
|
let next = cursorRef.current + direction;
|
|
@@ -605,14 +584,14 @@ function MultiSelect({
|
|
|
605
584
|
}
|
|
606
585
|
}
|
|
607
586
|
} else if (event.name === "a" && enableSelectAll) {
|
|
608
|
-
const enabledValues =
|
|
587
|
+
const enabledValues = items3.filter((i) => !i.disabled).map((i) => i.value);
|
|
609
588
|
setSelected(maxCount !== void 0 ? enabledValues.slice(0, maxCount) : enabledValues);
|
|
610
589
|
} else if (event.name === "x" && enableClear) {
|
|
611
590
|
setSelected([]);
|
|
612
591
|
}
|
|
613
592
|
});
|
|
614
593
|
if (state.submitted) {
|
|
615
|
-
const selectedItems =
|
|
594
|
+
const selectedItems = items3.filter((i) => currentSelected.has(i.value));
|
|
616
595
|
return /* @__PURE__ */ jsxs6("box", { flexDirection: "column", children: [
|
|
617
596
|
/* @__PURE__ */ jsxs6("text", { children: [
|
|
618
597
|
/* @__PURE__ */ jsx11("span", { style: textStyle({ fg: theme.success }), children: "\u25C6 " }),
|
|
@@ -722,91 +701,145 @@ function MultiSelect({
|
|
|
722
701
|
}
|
|
723
702
|
|
|
724
703
|
// ../ui/components/table/table.tsx
|
|
725
|
-
import { Fragment } from "react";
|
|
704
|
+
import { createContext as createContext3, useContext as useContext3, Children, isValidElement, Fragment } from "react";
|
|
726
705
|
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
727
|
-
|
|
706
|
+
var TableContext = createContext3(null);
|
|
707
|
+
function useTableContext() {
|
|
708
|
+
const ctx = useContext3(TableContext);
|
|
709
|
+
if (!ctx) throw new Error("Table compound components must be used within <TableRoot>");
|
|
710
|
+
return ctx;
|
|
711
|
+
}
|
|
712
|
+
function getColumns(data2, columnsProp) {
|
|
728
713
|
if (columnsProp) return columnsProp;
|
|
729
714
|
const keys = /* @__PURE__ */ new Set();
|
|
730
|
-
for (const row of
|
|
715
|
+
for (const row of data2) {
|
|
731
716
|
for (const key in row) keys.add(key);
|
|
732
717
|
}
|
|
733
718
|
return Array.from(keys);
|
|
734
719
|
}
|
|
735
|
-
function calculateColumnWidths(columns, data, padding) {
|
|
736
|
-
return columns.map((field) => {
|
|
737
|
-
const headerWidth = String(field).length;
|
|
738
|
-
const maxDataWidth = data.reduce((max, row) => {
|
|
739
|
-
const val = row[field];
|
|
740
|
-
return Math.max(max, val == null ? 0 : String(val).length);
|
|
741
|
-
}, 0);
|
|
742
|
-
return { field, width: Math.max(headerWidth, maxDataWidth) + padding * 2 };
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
720
|
function padCell(value, width, padding) {
|
|
746
721
|
const rightPad = width - value.length - padding;
|
|
747
722
|
return " ".repeat(padding) + value + " ".repeat(Math.max(0, rightPad));
|
|
748
723
|
}
|
|
724
|
+
function extractCellText(node) {
|
|
725
|
+
if (node == null) return "";
|
|
726
|
+
if (typeof node === "string") return node;
|
|
727
|
+
if (typeof node === "number" || typeof node === "boolean") return String(node);
|
|
728
|
+
if (Array.isArray(node)) return node.map(extractCellText).join("");
|
|
729
|
+
return "";
|
|
730
|
+
}
|
|
731
|
+
function collectColumnWidths(children, padding) {
|
|
732
|
+
const columnMaxWidths = [];
|
|
733
|
+
Children.forEach(children, (section) => {
|
|
734
|
+
if (!isValidElement(section)) return;
|
|
735
|
+
if (section.type === TableCaption) return;
|
|
736
|
+
Children.forEach(section.props.children, (row) => {
|
|
737
|
+
if (!isValidElement(row)) return;
|
|
738
|
+
let colIdx = 0;
|
|
739
|
+
Children.forEach(row.props.children, (cell) => {
|
|
740
|
+
if (!isValidElement(cell)) return;
|
|
741
|
+
const text = extractCellText(cell.props.children);
|
|
742
|
+
const width = text.length + padding * 2;
|
|
743
|
+
if (colIdx >= columnMaxWidths.length) {
|
|
744
|
+
columnMaxWidths.push(width);
|
|
745
|
+
} else {
|
|
746
|
+
columnMaxWidths[colIdx] = Math.max(columnMaxWidths[colIdx], width);
|
|
747
|
+
}
|
|
748
|
+
colIdx++;
|
|
749
|
+
});
|
|
750
|
+
});
|
|
751
|
+
});
|
|
752
|
+
return columnMaxWidths;
|
|
753
|
+
}
|
|
754
|
+
function getTotalWidth(columnWidths) {
|
|
755
|
+
if (columnWidths.length === 0) return 0;
|
|
756
|
+
return columnWidths.reduce((sum, w) => sum + w, 0) + (columnWidths.length - 1);
|
|
757
|
+
}
|
|
758
|
+
function TableRoot({ children, padding = 1, headerColor, borderColor }) {
|
|
759
|
+
const theme = useTheme();
|
|
760
|
+
const resolvedHeaderColor = headerColor ?? theme.foreground;
|
|
761
|
+
const resolvedBorderColor = borderColor ?? theme.muted;
|
|
762
|
+
const columnWidths = collectColumnWidths(children, padding);
|
|
763
|
+
return /* @__PURE__ */ jsx12(
|
|
764
|
+
TableContext.Provider,
|
|
765
|
+
{
|
|
766
|
+
value: {
|
|
767
|
+
columnWidths,
|
|
768
|
+
padding,
|
|
769
|
+
headerColor: resolvedHeaderColor,
|
|
770
|
+
borderColor: resolvedBorderColor,
|
|
771
|
+
foregroundColor: theme.foreground
|
|
772
|
+
},
|
|
773
|
+
children: /* @__PURE__ */ jsx12("box", { children })
|
|
774
|
+
}
|
|
775
|
+
);
|
|
776
|
+
}
|
|
777
|
+
function TableHeader({ children }) {
|
|
778
|
+
const ctx = useTableContext();
|
|
779
|
+
const totalWidth = getTotalWidth(ctx.columnWidths);
|
|
780
|
+
return /* @__PURE__ */ jsxs7("box", { children: [
|
|
781
|
+
children,
|
|
782
|
+
/* @__PURE__ */ jsx12("text", { children: /* @__PURE__ */ jsx12("span", { style: textStyle({ fg: ctx.borderColor }), children: "\u2500".repeat(totalWidth) }) })
|
|
783
|
+
] });
|
|
784
|
+
}
|
|
785
|
+
function TableBody({ children }) {
|
|
786
|
+
const ctx = useTableContext();
|
|
787
|
+
const totalWidth = getTotalWidth(ctx.columnWidths);
|
|
788
|
+
const rows = Children.toArray(children);
|
|
789
|
+
return /* @__PURE__ */ jsx12("box", { children: rows.map((row, index) => /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
790
|
+
row,
|
|
791
|
+
index < rows.length - 1 && /* @__PURE__ */ jsx12("text", { children: /* @__PURE__ */ jsx12("span", { style: textStyle({ fg: ctx.borderColor, dim: true }), children: "\u2500".repeat(totalWidth) }) })
|
|
792
|
+
] }, index)) });
|
|
793
|
+
}
|
|
794
|
+
function TableRow({ children }) {
|
|
795
|
+
const ctx = useTableContext();
|
|
796
|
+
const parts = [];
|
|
797
|
+
let colIdx = 0;
|
|
798
|
+
Children.forEach(children, (child) => {
|
|
799
|
+
if (!isValidElement(child)) return;
|
|
800
|
+
const text = extractCellText(child.props.children);
|
|
801
|
+
const width = ctx.columnWidths[colIdx] ?? text.length + ctx.padding * 2;
|
|
802
|
+
const padded = padCell(text, width, ctx.padding);
|
|
803
|
+
const isHead = child.type === TableHead;
|
|
804
|
+
if (colIdx > 0) {
|
|
805
|
+
parts.push(
|
|
806
|
+
/* @__PURE__ */ jsx12("span", { style: textStyle({ fg: ctx.borderColor, dim: true }), children: " " }, `sep-${colIdx}`)
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
if (isHead) {
|
|
810
|
+
parts.push(
|
|
811
|
+
/* @__PURE__ */ jsx12("span", { style: textStyle({ fg: ctx.headerColor }), children: padded }, `cell-${colIdx}`)
|
|
812
|
+
);
|
|
813
|
+
} else {
|
|
814
|
+
parts.push(
|
|
815
|
+
/* @__PURE__ */ jsx12("span", { style: textStyle({ fg: ctx.foregroundColor, dim: true }), children: padded }, `cell-${colIdx}`)
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
colIdx++;
|
|
819
|
+
});
|
|
820
|
+
return /* @__PURE__ */ jsx12("text", { children: parts });
|
|
821
|
+
}
|
|
822
|
+
function TableHead(_props) {
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
function TableCell(_props) {
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
828
|
+
function TableCaption({ children }) {
|
|
829
|
+
const ctx = useTableContext();
|
|
830
|
+
return /* @__PURE__ */ jsx12("text", { children: /* @__PURE__ */ jsx12("span", { style: textStyle({ fg: ctx.borderColor, dim: true }), children: extractCellText(children) }) });
|
|
831
|
+
}
|
|
749
832
|
function Table({
|
|
750
|
-
data,
|
|
833
|
+
data: data2,
|
|
751
834
|
columns: columnsProp,
|
|
752
835
|
padding = 1,
|
|
753
836
|
headerColor,
|
|
754
837
|
borderColor
|
|
755
838
|
}) {
|
|
756
|
-
const
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
const colInfo = calculateColumnWidths(columns, data, padding);
|
|
761
|
-
const borderLine = (left, mid, right) => {
|
|
762
|
-
const inner = colInfo.map((c) => "\u2500".repeat(c.width)).join(mid);
|
|
763
|
-
return /* @__PURE__ */ jsx12("text", { children: /* @__PURE__ */ jsxs7("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: [
|
|
764
|
-
left,
|
|
765
|
-
inner,
|
|
766
|
-
right
|
|
767
|
-
] }) });
|
|
768
|
-
};
|
|
769
|
-
const contentRow = (rowData, isHeader) => {
|
|
770
|
-
const parts = [];
|
|
771
|
-
parts.push(
|
|
772
|
-
/* @__PURE__ */ jsx12("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: "\u2502" }, "left-border")
|
|
773
|
-
);
|
|
774
|
-
colInfo.forEach((col, i) => {
|
|
775
|
-
const val = rowData[col.field];
|
|
776
|
-
const str = val == null ? "" : String(val);
|
|
777
|
-
const padded = padCell(str, col.width, padding);
|
|
778
|
-
if (isHeader) {
|
|
779
|
-
parts.push(
|
|
780
|
-
/* @__PURE__ */ jsx12("span", { style: textStyle({ fg: resolvedHeaderColor, bold: true }), children: padded }, `cell-${i}`)
|
|
781
|
-
);
|
|
782
|
-
} else {
|
|
783
|
-
parts.push(
|
|
784
|
-
/* @__PURE__ */ jsx12("span", { style: textStyle({ fg: theme.foreground }), children: padded }, `cell-${i}`)
|
|
785
|
-
);
|
|
786
|
-
}
|
|
787
|
-
if (i < colInfo.length - 1) {
|
|
788
|
-
parts.push(
|
|
789
|
-
/* @__PURE__ */ jsx12("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: "\u2502" }, `sep-${i}`)
|
|
790
|
-
);
|
|
791
|
-
}
|
|
792
|
-
});
|
|
793
|
-
parts.push(
|
|
794
|
-
/* @__PURE__ */ jsx12("span", { style: textStyle({ fg: resolvedBorderColor, bold: true }), children: "\u2502" }, "right-border")
|
|
795
|
-
);
|
|
796
|
-
return /* @__PURE__ */ jsx12("text", { children: parts });
|
|
797
|
-
};
|
|
798
|
-
const headerData = columns.reduce(
|
|
799
|
-
(acc, col) => ({ ...acc, [col]: col }),
|
|
800
|
-
{}
|
|
801
|
-
);
|
|
802
|
-
return /* @__PURE__ */ jsxs7("box", { children: [
|
|
803
|
-
borderLine("\u250C", "\u252C", "\u2510"),
|
|
804
|
-
contentRow(headerData, true),
|
|
805
|
-
data.map((row, index) => /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
806
|
-
borderLine("\u251C", "\u253C", "\u2524"),
|
|
807
|
-
contentRow(row, false)
|
|
808
|
-
] }, index)),
|
|
809
|
-
borderLine("\u2514", "\u2534", "\u2518")
|
|
839
|
+
const cols = getColumns(data2, columnsProp);
|
|
840
|
+
return /* @__PURE__ */ jsxs7(TableRoot, { padding, headerColor, borderColor, children: [
|
|
841
|
+
/* @__PURE__ */ jsx12(TableHeader, { children: /* @__PURE__ */ jsx12(TableRow, { children: cols.map((col) => /* @__PURE__ */ jsx12(TableHead, { children: String(col) }, String(col))) }) }),
|
|
842
|
+
/* @__PURE__ */ jsx12(TableBody, { children: data2.map((row, index) => /* @__PURE__ */ jsx12(TableRow, { children: cols.map((col) => /* @__PURE__ */ jsx12(TableCell, { children: row[col] == null ? "" : String(row[col]) }, String(col))) }, index)) })
|
|
810
843
|
] });
|
|
811
844
|
}
|
|
812
845
|
|
|
@@ -865,23 +898,23 @@ function generateGradient(colors, steps) {
|
|
|
865
898
|
}
|
|
866
899
|
return result;
|
|
867
900
|
}
|
|
868
|
-
function Gradient({ children, name, colors }) {
|
|
869
|
-
if (
|
|
870
|
-
if (!
|
|
871
|
-
const gradientColors =
|
|
872
|
-
const
|
|
873
|
-
const maxLength = Math.max(...
|
|
901
|
+
function Gradient({ children, name: name2, colors }) {
|
|
902
|
+
if (name2 && colors) throw new Error("The `name` and `colors` props are mutually exclusive");
|
|
903
|
+
if (!name2 && !colors) throw new Error("Either `name` or `colors` prop must be provided");
|
|
904
|
+
const gradientColors = name2 ? GRADIENTS[name2] : colors;
|
|
905
|
+
const lines2 = children.split("\n");
|
|
906
|
+
const maxLength = Math.max(...lines2.map((l) => l.length));
|
|
874
907
|
if (maxLength === 0) return /* @__PURE__ */ jsx13("text", { children });
|
|
875
908
|
const hexColors = generateGradient(gradientColors, maxLength);
|
|
876
|
-
return /* @__PURE__ */ jsx13(Fragment2, { children:
|
|
909
|
+
return /* @__PURE__ */ jsx13(Fragment2, { children: lines2.map((line, lineIndex) => /* @__PURE__ */ jsx13("text", { children: line.split("").map((char, charIndex) => /* @__PURE__ */ jsx13("span", { style: { fg: hexColors[charIndex] }, children: char }, charIndex)) }, lineIndex)) });
|
|
877
910
|
}
|
|
878
911
|
|
|
879
912
|
// ../ui/components/tab-bar/tab-bar.tsx
|
|
880
|
-
import { createContext as
|
|
913
|
+
import { createContext as createContext4, useContext as useContext4, useState as useState5, Children as Children2, isValidElement as isValidElement2 } from "react";
|
|
881
914
|
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
882
|
-
var TabsContext =
|
|
915
|
+
var TabsContext = createContext4(null);
|
|
883
916
|
function useTabsContext() {
|
|
884
|
-
const ctx =
|
|
917
|
+
const ctx = useContext4(TabsContext);
|
|
885
918
|
if (!ctx) throw new Error("Tabs compound components must be used within <Tabs>");
|
|
886
919
|
return ctx;
|
|
887
920
|
}
|
|
@@ -907,8 +940,8 @@ function TabsList({
|
|
|
907
940
|
const { value } = useTabsContext();
|
|
908
941
|
const color = activeColor ?? theme.accent;
|
|
909
942
|
const triggers = [];
|
|
910
|
-
|
|
911
|
-
if (
|
|
943
|
+
Children2.forEach(children, (child) => {
|
|
944
|
+
if (isValidElement2(child) && "value" in child.props) {
|
|
912
945
|
triggers.push({ value: child.props.value, label: child.props.children });
|
|
913
946
|
}
|
|
914
947
|
});
|
|
@@ -971,9 +1004,9 @@ function Modal({
|
|
|
971
1004
|
useKeyboard: useKeyboardProp
|
|
972
1005
|
}) {
|
|
973
1006
|
const theme = useTheme();
|
|
974
|
-
const
|
|
1007
|
+
const useKeyboard20 = useKeyboardContext(useKeyboardProp);
|
|
975
1008
|
const resolvedBorderColor = borderColor ?? theme.muted;
|
|
976
|
-
|
|
1009
|
+
useKeyboard20?.((event) => {
|
|
977
1010
|
if (event.name === "escape" && onClose) {
|
|
978
1011
|
onClose();
|
|
979
1012
|
}
|
|
@@ -999,28 +1032,29 @@ import {
|
|
|
999
1032
|
useState as useState6,
|
|
1000
1033
|
useRef as useRef4,
|
|
1001
1034
|
useCallback as useCallback2,
|
|
1035
|
+
useEffect as useEffect2,
|
|
1002
1036
|
useMemo as useMemo3,
|
|
1003
|
-
createContext as
|
|
1004
|
-
useContext as
|
|
1037
|
+
createContext as createContext5,
|
|
1038
|
+
useContext as useContext5
|
|
1005
1039
|
} from "react";
|
|
1006
1040
|
import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1007
|
-
var PromptInputControllerCtx =
|
|
1008
|
-
var useOptionalController = () =>
|
|
1009
|
-
var PromptInputContext =
|
|
1041
|
+
var PromptInputControllerCtx = createContext5(null);
|
|
1042
|
+
var useOptionalController = () => useContext5(PromptInputControllerCtx);
|
|
1043
|
+
var PromptInputContext = createContext5(null);
|
|
1010
1044
|
function usePromptInput() {
|
|
1011
|
-
const ctx =
|
|
1045
|
+
const ctx = useContext5(PromptInputContext);
|
|
1012
1046
|
if (!ctx) {
|
|
1013
1047
|
throw new Error("usePromptInput must be used within a <PromptInput> component");
|
|
1014
1048
|
}
|
|
1015
1049
|
return ctx;
|
|
1016
1050
|
}
|
|
1017
|
-
function computeDefaultSuggestions(input,
|
|
1018
|
-
if (input.startsWith("/") &&
|
|
1019
|
-
return
|
|
1051
|
+
function computeDefaultSuggestions(input, commands2, files2) {
|
|
1052
|
+
if (input.startsWith("/") && commands2.length > 0) {
|
|
1053
|
+
return commands2.filter((c) => c.cmd.startsWith(input)).map((c) => ({ text: c.cmd, desc: c.desc }));
|
|
1020
1054
|
}
|
|
1021
|
-
if (input.includes("@") &&
|
|
1055
|
+
if (input.includes("@") && files2.length > 0) {
|
|
1022
1056
|
const query = input.split("@").pop() ?? "";
|
|
1023
|
-
return
|
|
1057
|
+
return files2.filter((f) => f.toLowerCase().includes(query.toLowerCase())).map((f) => ({ text: "@" + f }));
|
|
1024
1058
|
}
|
|
1025
1059
|
return [];
|
|
1026
1060
|
}
|
|
@@ -1030,9 +1064,10 @@ function resolveStatusHintText(status, submittedText, streamingText, errorText,
|
|
|
1030
1064
|
if (status === "error") return errorText;
|
|
1031
1065
|
return disabledText;
|
|
1032
1066
|
}
|
|
1067
|
+
var DIVIDER_LINE = "\u2500".repeat(500);
|
|
1033
1068
|
function PromptInputDivider() {
|
|
1034
1069
|
const { theme } = usePromptInput();
|
|
1035
|
-
return /* @__PURE__ */ jsx16("text", { wrapMode: "none", children: /* @__PURE__ */ jsx16("span", { style: textStyle({ dim: true, fg: theme.muted }), children:
|
|
1070
|
+
return /* @__PURE__ */ jsx16("text", { wrapMode: "none", marginLeft: -1, marginRight: -1, children: /* @__PURE__ */ jsx16("span", { style: textStyle({ dim: true, fg: theme.muted }), children: DIVIDER_LINE }) });
|
|
1036
1071
|
}
|
|
1037
1072
|
function PromptInputSuggestions() {
|
|
1038
1073
|
const { suggestions, sugIdx, maxSuggestions, theme } = usePromptInput();
|
|
@@ -1099,18 +1134,27 @@ function PromptInput({
|
|
|
1099
1134
|
errorText = "An error occurred. Try again.",
|
|
1100
1135
|
disabled: disabledProp = false,
|
|
1101
1136
|
disabledText = "Generating...",
|
|
1102
|
-
commands = [],
|
|
1103
|
-
files = [],
|
|
1137
|
+
commands: commands2 = [],
|
|
1138
|
+
files: files2 = [],
|
|
1104
1139
|
getSuggestions: customGetSuggestions,
|
|
1105
1140
|
maxSuggestions = 5,
|
|
1106
1141
|
enableHistory = true,
|
|
1107
1142
|
model,
|
|
1108
1143
|
showDividers = true,
|
|
1144
|
+
autoFocus = false,
|
|
1109
1145
|
useKeyboard: useKeyboardProp,
|
|
1110
1146
|
children
|
|
1111
1147
|
}) {
|
|
1112
1148
|
const theme = useTheme();
|
|
1113
|
-
const
|
|
1149
|
+
const useKeyboard20 = useKeyboardContext(useKeyboardProp);
|
|
1150
|
+
useEffect2(() => {
|
|
1151
|
+
if (!autoFocus) return;
|
|
1152
|
+
if (typeof document === "undefined") return;
|
|
1153
|
+
const canvas = document.querySelector("canvas");
|
|
1154
|
+
if (canvas && document.activeElement !== canvas) {
|
|
1155
|
+
canvas.focus();
|
|
1156
|
+
}
|
|
1157
|
+
}, [autoFocus]);
|
|
1114
1158
|
const resolvedPromptColor = promptColor ?? theme.muted;
|
|
1115
1159
|
const disabled = status ? status === "submitted" || status === "streaming" : disabledProp;
|
|
1116
1160
|
const statusHintText = resolveStatusHintText(status, submittedText, streamingLabel, errorText, disabledText);
|
|
@@ -1167,8 +1211,8 @@ function PromptInput({
|
|
|
1167
1211
|
}, []);
|
|
1168
1212
|
const computeSuggestions = useCallback2((input) => {
|
|
1169
1213
|
if (customGetSuggestions) return customGetSuggestions(input);
|
|
1170
|
-
return computeDefaultSuggestions(input,
|
|
1171
|
-
}, [customGetSuggestions,
|
|
1214
|
+
return computeDefaultSuggestions(input, commands2, files2);
|
|
1215
|
+
}, [customGetSuggestions, commands2, files2]);
|
|
1172
1216
|
const updateValue = useCallback2((next) => {
|
|
1173
1217
|
valueRef.current = next;
|
|
1174
1218
|
if (isControlled) {
|
|
@@ -1203,7 +1247,7 @@ function PromptInput({
|
|
|
1203
1247
|
clearInput();
|
|
1204
1248
|
}
|
|
1205
1249
|
}, [onSubmit, clearInput]);
|
|
1206
|
-
|
|
1250
|
+
useKeyboard20?.((event) => {
|
|
1207
1251
|
if (event.name === "escape" && (status === "streaming" || status === "submitted") && onStop) {
|
|
1208
1252
|
onStop();
|
|
1209
1253
|
return;
|
|
@@ -1304,14 +1348,16 @@ function PromptInput({
|
|
|
1304
1348
|
theme
|
|
1305
1349
|
};
|
|
1306
1350
|
if (children) {
|
|
1307
|
-
return /* @__PURE__ */ jsx16(PromptInputContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx16("box", { flexDirection: "column", children }) });
|
|
1351
|
+
return /* @__PURE__ */ jsx16(PromptInputContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx16("box", { flexDirection: "column", flexShrink: 0, children }) });
|
|
1308
1352
|
}
|
|
1309
|
-
return /* @__PURE__ */ jsx16(PromptInputContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxs10("box", { flexDirection: "column", children: [
|
|
1353
|
+
return /* @__PURE__ */ jsx16(PromptInputContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxs10("box", { flexDirection: "column", flexShrink: 0, children: [
|
|
1310
1354
|
showDividers && /* @__PURE__ */ jsx16(PromptInputDivider, {}),
|
|
1311
|
-
/* @__PURE__ */
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1355
|
+
/* @__PURE__ */ jsxs10("box", { flexDirection: "column", paddingX: 1, children: [
|
|
1356
|
+
/* @__PURE__ */ jsx16(PromptInputSuggestions, {}),
|
|
1357
|
+
/* @__PURE__ */ jsx16(PromptInputTextarea, {}),
|
|
1358
|
+
/* @__PURE__ */ jsx16(PromptInputStatusText, {}),
|
|
1359
|
+
/* @__PURE__ */ jsx16(PromptInputModel, {})
|
|
1360
|
+
] }),
|
|
1315
1361
|
showDividers && /* @__PURE__ */ jsx16(PromptInputDivider, {})
|
|
1316
1362
|
] }) });
|
|
1317
1363
|
}
|
|
@@ -1444,13 +1490,13 @@ function ChatPanel({
|
|
|
1444
1490
|
}
|
|
1445
1491
|
|
|
1446
1492
|
// ../ui/components/chain-of-thought/chain-of-thought.tsx
|
|
1447
|
-
import { createContext as
|
|
1493
|
+
import { createContext as createContext6, memo, useContext as useContext6, useEffect as useEffect3, useMemo as useMemo4, useState as useState7 } from "react";
|
|
1448
1494
|
import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1449
1495
|
var DOTS = ["\u25CB", "\u25D4", "\u25D1", "\u25D5", "\u25CF"];
|
|
1450
1496
|
var SPINNER_INTERVAL = 150;
|
|
1451
|
-
var ChainOfThoughtContext =
|
|
1497
|
+
var ChainOfThoughtContext = createContext6(null);
|
|
1452
1498
|
var useChainOfThought = () => {
|
|
1453
|
-
const context =
|
|
1499
|
+
const context = useContext6(ChainOfThoughtContext);
|
|
1454
1500
|
if (!context) {
|
|
1455
1501
|
throw new Error("ChainOfThought components must be used within <ChainOfThought>");
|
|
1456
1502
|
}
|
|
@@ -1519,7 +1565,7 @@ var ChainOfThoughtStep = memo(({
|
|
|
1519
1565
|
const color = getStepColor(status, theme);
|
|
1520
1566
|
const pipe = "\u2502";
|
|
1521
1567
|
const [frame, setFrame] = useState7(0);
|
|
1522
|
-
|
|
1568
|
+
useEffect3(() => {
|
|
1523
1569
|
if (!isActive) {
|
|
1524
1570
|
setFrame(0);
|
|
1525
1571
|
return;
|
|
@@ -1548,11 +1594,11 @@ ChainOfThoughtContent.displayName = "ChainOfThoughtContent";
|
|
|
1548
1594
|
ChainOfThoughtStep.displayName = "ChainOfThoughtStep";
|
|
1549
1595
|
|
|
1550
1596
|
// ../ui/components/message/message.tsx
|
|
1551
|
-
import { createContext as
|
|
1597
|
+
import { createContext as createContext7, useContext as useContext7 } from "react";
|
|
1552
1598
|
import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1553
|
-
var MessageContext =
|
|
1599
|
+
var MessageContext = createContext7(null);
|
|
1554
1600
|
function useMessage() {
|
|
1555
|
-
const ctx =
|
|
1601
|
+
const ctx = useContext7(MessageContext);
|
|
1556
1602
|
if (!ctx) throw new Error("useMessage must be used within <Message>");
|
|
1557
1603
|
return ctx;
|
|
1558
1604
|
}
|
|
@@ -1561,23 +1607,25 @@ function getBubbleColors(theme) {
|
|
|
1561
1607
|
return isDark ? { assistantBg: "#2a2a4a", userBg: "#2a3a3a" } : { assistantBg: "#F1F5F9", userBg: "#E2E8F0" };
|
|
1562
1608
|
}
|
|
1563
1609
|
var TOOL_STATE_ICONS = {
|
|
1564
|
-
|
|
1610
|
+
pending: "\u2022",
|
|
1565
1611
|
// •
|
|
1566
|
-
|
|
1612
|
+
running: "\u280B",
|
|
1567
1613
|
// ⠋
|
|
1568
|
-
|
|
1614
|
+
completed: "\u2713",
|
|
1569
1615
|
// ✓
|
|
1616
|
+
error: "\u2715"
|
|
1617
|
+
// ✕
|
|
1570
1618
|
};
|
|
1571
1619
|
function getToolStateColor(state, theme) {
|
|
1572
1620
|
switch (state) {
|
|
1573
|
-
case "
|
|
1621
|
+
case "pending":
|
|
1574
1622
|
return theme.muted;
|
|
1575
|
-
case "
|
|
1623
|
+
case "running":
|
|
1576
1624
|
return theme.warning;
|
|
1577
|
-
case "
|
|
1625
|
+
case "completed":
|
|
1578
1626
|
return theme.success;
|
|
1579
|
-
|
|
1580
|
-
return theme.
|
|
1627
|
+
case "error":
|
|
1628
|
+
return theme.error;
|
|
1581
1629
|
}
|
|
1582
1630
|
}
|
|
1583
1631
|
function MessageContent({ children }) {
|
|
@@ -1602,51 +1650,57 @@ function MessageText({ children, isLast = false }) {
|
|
|
1602
1650
|
isLast && isStreaming && /* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: streamingCursor })
|
|
1603
1651
|
] });
|
|
1604
1652
|
}
|
|
1605
|
-
function MessageReasoning({
|
|
1606
|
-
return /* @__PURE__ */ jsxs13(ChainOfThought, { defaultOpen:
|
|
1607
|
-
/* @__PURE__ */ jsx19(ChainOfThoughtHeader, { duration
|
|
1608
|
-
/* @__PURE__ */
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1653
|
+
function MessageReasoning({ duration, steps, collapsed = true, children }) {
|
|
1654
|
+
return /* @__PURE__ */ jsxs13(ChainOfThought, { defaultOpen: !collapsed, children: [
|
|
1655
|
+
/* @__PURE__ */ jsx19(ChainOfThoughtHeader, { duration }),
|
|
1656
|
+
/* @__PURE__ */ jsxs13(ChainOfThoughtContent, { children: [
|
|
1657
|
+
steps?.map((step, i) => /* @__PURE__ */ jsx19(
|
|
1658
|
+
ChainOfThoughtStep,
|
|
1659
|
+
{
|
|
1660
|
+
label: step.label,
|
|
1661
|
+
description: step.description,
|
|
1662
|
+
status: step.status,
|
|
1663
|
+
isLast: i === (steps?.length ?? 0) - 1,
|
|
1664
|
+
children: step.output
|
|
1665
|
+
},
|
|
1666
|
+
i
|
|
1667
|
+
)),
|
|
1668
|
+
children
|
|
1669
|
+
] })
|
|
1619
1670
|
] });
|
|
1620
1671
|
}
|
|
1621
|
-
function
|
|
1672
|
+
function MessageToolCall({ name: name2, state = "pending", result, color }) {
|
|
1622
1673
|
const theme = useTheme();
|
|
1623
1674
|
const { backgroundColor, textColor } = useMessage();
|
|
1624
|
-
const
|
|
1625
|
-
const
|
|
1626
|
-
const
|
|
1627
|
-
const isActive = state === "partial-call" || state === "call";
|
|
1675
|
+
const icon = TOOL_STATE_ICONS[state];
|
|
1676
|
+
const stateColor = color ?? getToolStateColor(state, theme);
|
|
1677
|
+
const isActive = state === "pending" || state === "running";
|
|
1628
1678
|
return /* @__PURE__ */ jsxs13("box", { flexDirection: "column", children: [
|
|
1629
1679
|
/* @__PURE__ */ jsxs13("text", { children: [
|
|
1630
1680
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: stateColor, bg: backgroundColor }), children: icon }),
|
|
1631
1681
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, bg: backgroundColor }), children: " " }),
|
|
1632
|
-
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: stateColor, bold: isActive, bg: backgroundColor }), children:
|
|
1682
|
+
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: stateColor, bold: isActive, bg: backgroundColor }), children: name2 }),
|
|
1633
1683
|
isActive && /* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: " ..." })
|
|
1634
1684
|
] }),
|
|
1635
|
-
state === "
|
|
1685
|
+
state === "completed" && result !== void 0 && /* @__PURE__ */ jsxs13("text", { children: [
|
|
1636
1686
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: " \u2514\u2500 " }),
|
|
1637
1687
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: String(result).slice(0, 120) })
|
|
1688
|
+
] }),
|
|
1689
|
+
state === "error" && result !== void 0 && /* @__PURE__ */ jsxs13("text", { children: [
|
|
1690
|
+
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: theme.error, dim: true, bg: backgroundColor }), children: " \u2514\u2500 " }),
|
|
1691
|
+
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: theme.error, dim: true, bg: backgroundColor }), children: String(result).slice(0, 120) })
|
|
1638
1692
|
] })
|
|
1639
1693
|
] });
|
|
1640
1694
|
}
|
|
1641
|
-
function MessageSource({
|
|
1695
|
+
function MessageSource({ title, url, index }) {
|
|
1642
1696
|
const theme = useTheme();
|
|
1643
1697
|
const { backgroundColor, textColor } = useMessage();
|
|
1644
|
-
const
|
|
1698
|
+
const displayTitle = title || url || "source";
|
|
1645
1699
|
return /* @__PURE__ */ jsxs13("text", { children: [
|
|
1646
1700
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: "[" }),
|
|
1647
1701
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: theme.accent, bg: backgroundColor }), children: String(index + 1) }),
|
|
1648
1702
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: "] " }),
|
|
1649
|
-
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: theme.accent, bg: backgroundColor }), children:
|
|
1703
|
+
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: theme.accent, bg: backgroundColor }), children: displayTitle })
|
|
1650
1704
|
] });
|
|
1651
1705
|
}
|
|
1652
1706
|
function MessageFooter({ model, timestamp }) {
|
|
@@ -1682,7 +1736,7 @@ function Message({
|
|
|
1682
1736
|
Message.Content = MessageContent;
|
|
1683
1737
|
Message.Text = MessageText;
|
|
1684
1738
|
Message.Reasoning = MessageReasoning;
|
|
1685
|
-
Message.
|
|
1739
|
+
Message.ToolCall = MessageToolCall;
|
|
1686
1740
|
Message.Source = MessageSource;
|
|
1687
1741
|
Message.Footer = MessageFooter;
|
|
1688
1742
|
|
|
@@ -1708,124 +1762,836 @@ function useBreakpoints() {
|
|
|
1708
1762
|
};
|
|
1709
1763
|
}
|
|
1710
1764
|
|
|
1711
|
-
//
|
|
1712
|
-
import
|
|
1765
|
+
// demos/gradient.tsx
|
|
1766
|
+
import figlet from "figlet";
|
|
1767
|
+
import ansiShadow from "figlet/importable-fonts/ANSI Shadow.js";
|
|
1768
|
+
figlet.parseFont("ANSI Shadow", ansiShadow);
|
|
1769
|
+
var art = figlet.textSync("gridland", { font: "ANSI Shadow" });
|
|
1770
|
+
var lines = art.split("\n").filter((l) => l.trimEnd().length > 0);
|
|
1771
|
+
var gradientNames = Object.keys(GRADIENTS);
|
|
1772
|
+
function GradientApp() {
|
|
1773
|
+
const theme = useTheme();
|
|
1774
|
+
const [index, setIndex] = useState8(gradientNames.indexOf("instagram"));
|
|
1775
|
+
const name2 = gradientNames[index];
|
|
1776
|
+
useKeyboard((event) => {
|
|
1777
|
+
if (event.name === "left") setIndex((i) => i > 0 ? i - 1 : gradientNames.length - 1);
|
|
1778
|
+
if (event.name === "right") setIndex((i) => i < gradientNames.length - 1 ? i + 1 : 0);
|
|
1779
|
+
});
|
|
1780
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1 }, /* @__PURE__ */ React.createElement(Gradient, { name: name2 }, lines.join("\n"))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
1781
|
+
StatusBar,
|
|
1782
|
+
{
|
|
1783
|
+
items: [{ key: "\u2190\u2192", label: "gradient" }],
|
|
1784
|
+
extra: /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.accent, bold: true }) }, name2.padEnd(11))
|
|
1785
|
+
}
|
|
1786
|
+
)));
|
|
1787
|
+
}
|
|
1713
1788
|
|
|
1714
|
-
//
|
|
1715
|
-
import {
|
|
1716
|
-
|
|
1789
|
+
// demos/ascii.tsx
|
|
1790
|
+
import { useState as useState9 } from "react";
|
|
1791
|
+
import { useKeyboard as useKeyboard2 } from "@gridland/utils";
|
|
1792
|
+
import figlet2 from "figlet";
|
|
1793
|
+
import ansiShadow2 from "figlet/importable-fonts/ANSI Shadow.js";
|
|
1794
|
+
import big from "figlet/importable-fonts/Big.js";
|
|
1795
|
+
import doom from "figlet/importable-fonts/Doom.js";
|
|
1796
|
+
import slant from "figlet/importable-fonts/Slant.js";
|
|
1797
|
+
import speed from "figlet/importable-fonts/Speed.js";
|
|
1798
|
+
import standard from "figlet/importable-fonts/Standard.js";
|
|
1799
|
+
import block from "figlet/importable-fonts/Block.js";
|
|
1800
|
+
import colossal from "figlet/importable-fonts/Colossal.js";
|
|
1801
|
+
var fonts = [
|
|
1802
|
+
{ name: "ANSI Shadow", data: ansiShadow2 },
|
|
1803
|
+
{ name: "Standard", data: standard },
|
|
1804
|
+
{ name: "Big", data: big },
|
|
1805
|
+
{ name: "Doom", data: doom },
|
|
1806
|
+
{ name: "Slant", data: slant },
|
|
1807
|
+
{ name: "Speed", data: speed },
|
|
1808
|
+
{ name: "Block", data: block },
|
|
1809
|
+
{ name: "Colossal", data: colossal }
|
|
1810
|
+
];
|
|
1811
|
+
for (const f of fonts) {
|
|
1812
|
+
figlet2.parseFont(f.name, f.data);
|
|
1813
|
+
}
|
|
1814
|
+
function getLines(fontName) {
|
|
1815
|
+
const art2 = figlet2.textSync("gridland", { font: fontName });
|
|
1816
|
+
return art2.split("\n").filter((l) => l.trimEnd().length > 0);
|
|
1817
|
+
}
|
|
1818
|
+
function AsciiApp() {
|
|
1717
1819
|
const theme = useTheme();
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
"
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
"\u2022",
|
|
1733
|
-
" "
|
|
1734
|
-
] }),
|
|
1735
|
-
"React reconciler with JSX"
|
|
1736
|
-
] }),
|
|
1737
|
-
/* @__PURE__ */ jsxs15("text", { children: [
|
|
1738
|
-
/* @__PURE__ */ jsxs15("span", { style: textStyle({ dim: true }), children: [
|
|
1739
|
-
"\u2022",
|
|
1740
|
-
" "
|
|
1741
|
-
] }),
|
|
1742
|
-
"Yoga flexbox layout engine"
|
|
1743
|
-
] }),
|
|
1744
|
-
/* @__PURE__ */ jsxs15("text", { children: [
|
|
1745
|
-
/* @__PURE__ */ jsxs15("span", { style: textStyle({ dim: true }), children: [
|
|
1746
|
-
"\u2022",
|
|
1747
|
-
" "
|
|
1748
|
-
] }),
|
|
1749
|
-
"Keyboard, mouse, and clipboard support"
|
|
1750
|
-
] }),
|
|
1751
|
-
/* @__PURE__ */ jsxs15("text", { children: [
|
|
1752
|
-
/* @__PURE__ */ jsxs15("span", { style: textStyle({ dim: true }), children: [
|
|
1753
|
-
"\u2022",
|
|
1754
|
-
" "
|
|
1755
|
-
] }),
|
|
1756
|
-
"Next.js and Vite plugins"
|
|
1757
|
-
] }),
|
|
1758
|
-
/* @__PURE__ */ jsx21("text", { style: textStyle({ bold: true, fg: theme.accent }), children: "Tech Stack" }),
|
|
1759
|
-
/* @__PURE__ */ jsx21("text", { children: "React + opentui engine + yoga-layout + HTML5 Canvas" }),
|
|
1760
|
-
/* @__PURE__ */ jsx21("text", { style: textStyle({ dim: true }), children: "Press q to close" })
|
|
1761
|
-
] }) });
|
|
1820
|
+
const [fontIndex, setFontIndex] = useState9(fonts.findIndex((f) => f.name === "Colossal"));
|
|
1821
|
+
const font = fonts[fontIndex];
|
|
1822
|
+
const lines2 = getLines(font.name);
|
|
1823
|
+
useKeyboard2((event) => {
|
|
1824
|
+
if (event.name === "left") setFontIndex((i) => i > 0 ? i - 1 : fonts.length - 1);
|
|
1825
|
+
if (event.name === "right") setFontIndex((i) => i < fonts.length - 1 ? i + 1 : 0);
|
|
1826
|
+
});
|
|
1827
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1 }, lines2.map((line, i) => /* @__PURE__ */ React.createElement("text", { key: i, fg: theme.accent, bold: true }, line))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
1828
|
+
StatusBar,
|
|
1829
|
+
{
|
|
1830
|
+
items: [{ key: "\u2190\u2192", label: "change font" }],
|
|
1831
|
+
extra: /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.accent, bold: true }) }, font.name.padEnd(11))
|
|
1832
|
+
}
|
|
1833
|
+
)));
|
|
1762
1834
|
}
|
|
1763
1835
|
|
|
1764
|
-
//
|
|
1765
|
-
|
|
1766
|
-
|
|
1836
|
+
// demos/table.tsx
|
|
1837
|
+
function TableApp() {
|
|
1838
|
+
const data2 = [
|
|
1839
|
+
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
1840
|
+
{ name: "Bob", role: "Designer", status: "Active" },
|
|
1841
|
+
{ name: "Charlie", role: "PM", status: "Away" }
|
|
1842
|
+
];
|
|
1843
|
+
return /* @__PURE__ */ React.createElement("box", { padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement(Table, { data: data2, headerColor: "cyan", borderColor: "#5e81ac" }));
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
// demos/spinner.tsx
|
|
1847
|
+
import { useKeyboard as useKeyboard3 } from "@gridland/utils";
|
|
1848
|
+
function SpinnerApp() {
|
|
1849
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { flexGrow: 1 }, /* @__PURE__ */ React.createElement(SpinnerPicker, { useKeyboard: useKeyboard3 })), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [{ key: "\u2190\u2192", label: "change variant" }] })));
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
// demos/select-input.tsx
|
|
1853
|
+
import { useState as useState10 } from "react";
|
|
1854
|
+
import { useKeyboard as useKeyboard4 } from "@gridland/utils";
|
|
1855
|
+
var items = [
|
|
1856
|
+
{ label: "TypeScript", value: "ts" },
|
|
1857
|
+
{ label: "JavaScript", value: "js" },
|
|
1858
|
+
{ label: "Python", value: "py" },
|
|
1859
|
+
{ label: "Rust", value: "rs" }
|
|
1860
|
+
];
|
|
1861
|
+
function SelectInputApp() {
|
|
1862
|
+
const [submitted, setSubmitted] = useState10(false);
|
|
1863
|
+
const [resetKey, setResetKey] = useState10(0);
|
|
1864
|
+
useKeyboard4((event) => {
|
|
1865
|
+
if (submitted && event.name === "r") {
|
|
1866
|
+
setSubmitted(false);
|
|
1867
|
+
setResetKey((k) => k + 1);
|
|
1868
|
+
}
|
|
1869
|
+
});
|
|
1870
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement(
|
|
1871
|
+
SelectInput,
|
|
1872
|
+
{
|
|
1873
|
+
key: resetKey,
|
|
1874
|
+
items,
|
|
1875
|
+
title: "Choose a language",
|
|
1876
|
+
useKeyboard: useKeyboard4,
|
|
1877
|
+
onSubmit: () => setSubmitted(true)
|
|
1878
|
+
}
|
|
1879
|
+
)), /* @__PURE__ */ React.createElement(StatusBar, { items: submitted ? [{ key: "r", label: "reset demo" }] : [
|
|
1880
|
+
{ key: "\u2191\u2193", label: "select" },
|
|
1881
|
+
{ key: "enter", label: "submit" }
|
|
1882
|
+
] }));
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
// demos/multi-select.tsx
|
|
1886
|
+
import { useState as useState11 } from "react";
|
|
1887
|
+
import { useKeyboard as useKeyboard5 } from "@gridland/utils";
|
|
1888
|
+
var items2 = [
|
|
1889
|
+
{ label: "TypeScript", value: "ts" },
|
|
1890
|
+
{ label: "JavaScript", value: "js" },
|
|
1891
|
+
{ label: "Python", value: "py" },
|
|
1892
|
+
{ label: "Rust", value: "rs" }
|
|
1893
|
+
];
|
|
1894
|
+
function MultiSelectApp() {
|
|
1895
|
+
const [submitted, setSubmitted] = useState11(false);
|
|
1896
|
+
const [resetKey, setResetKey] = useState11(0);
|
|
1897
|
+
useKeyboard5((event) => {
|
|
1898
|
+
if (submitted && event.name === "r") {
|
|
1899
|
+
setSubmitted(false);
|
|
1900
|
+
setResetKey((k) => k + 1);
|
|
1901
|
+
}
|
|
1902
|
+
});
|
|
1903
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement(
|
|
1904
|
+
MultiSelect,
|
|
1905
|
+
{
|
|
1906
|
+
key: resetKey,
|
|
1907
|
+
items: items2,
|
|
1908
|
+
title: "Select languages",
|
|
1909
|
+
useKeyboard: useKeyboard5,
|
|
1910
|
+
onSubmit: () => setSubmitted(true)
|
|
1911
|
+
}
|
|
1912
|
+
)), /* @__PURE__ */ React.createElement(StatusBar, { items: submitted ? [{ key: "r", label: "reset demo" }] : [
|
|
1913
|
+
{ key: "\u2191\u2193", label: "move" },
|
|
1914
|
+
{ key: "enter", label: "select" },
|
|
1915
|
+
{ key: "a", label: "all" },
|
|
1916
|
+
{ key: "x", label: "clear" }
|
|
1917
|
+
] }));
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
// demos/prompt-input.tsx
|
|
1921
|
+
import { useState as useState12 } from "react";
|
|
1922
|
+
import { useKeyboard as useKeyboard6 } from "@gridland/utils";
|
|
1923
|
+
var commands = [{ cmd: "/model", desc: "Switch model" }];
|
|
1924
|
+
var files = ["src/index.ts", "src/routes.ts", "src/auth.ts", "package.json"];
|
|
1925
|
+
var models = [
|
|
1926
|
+
{ label: "Claude Opus", value: "opus" },
|
|
1927
|
+
{ label: "Claude Sonnet", value: "sonnet" },
|
|
1928
|
+
{ label: "Claude Haiku", value: "haiku" }
|
|
1929
|
+
];
|
|
1930
|
+
function PromptInputApp() {
|
|
1767
1931
|
const theme = useTheme();
|
|
1768
|
-
|
|
1769
|
-
|
|
1932
|
+
const [lastMessage, setLastMessage] = useState12("");
|
|
1933
|
+
const [model, setModel] = useState12("opus");
|
|
1934
|
+
const [showModelPicker, setShowModelPicker] = useState12(false);
|
|
1935
|
+
const [resetKey, setResetKey] = useState12(0);
|
|
1936
|
+
const handleSubmit = (msg) => {
|
|
1937
|
+
if (msg.text === "/model") {
|
|
1938
|
+
setShowModelPicker(true);
|
|
1939
|
+
setResetKey((k) => k + 1);
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
setLastMessage(msg.text);
|
|
1943
|
+
};
|
|
1944
|
+
if (showModelPicker) {
|
|
1945
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement(Modal, { title: "Select Model", useKeyboard: useKeyboard6, onClose: () => setShowModelPicker(false) }, /* @__PURE__ */ React.createElement("box", { paddingX: 1 }, /* @__PURE__ */ React.createElement(
|
|
1946
|
+
SelectInput,
|
|
1947
|
+
{
|
|
1948
|
+
items: models,
|
|
1949
|
+
defaultValue: model,
|
|
1950
|
+
useKeyboard: useKeyboard6,
|
|
1951
|
+
onSubmit: (value) => {
|
|
1952
|
+
setModel(value);
|
|
1953
|
+
setShowModelPicker(false);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
))));
|
|
1957
|
+
}
|
|
1958
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, lastMessage ? /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.muted }) }, "Sent: "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground }) }, lastMessage)) : /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", null, " "))), /* @__PURE__ */ React.createElement(
|
|
1959
|
+
PromptInput,
|
|
1770
1960
|
{
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
/* @__PURE__ */ jsx22("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
1779
|
-
/* @__PURE__ */ jsx22("span", { style: textStyle({ bold: true }), children: "bun create " }),
|
|
1780
|
-
/* @__PURE__ */ jsx22("span", { style: textStyle({ fg: theme.accent }), children: "gridland" })
|
|
1781
|
-
] })
|
|
1961
|
+
key: resetKey,
|
|
1962
|
+
commands,
|
|
1963
|
+
files,
|
|
1964
|
+
placeholder: "Message Claude...",
|
|
1965
|
+
showDividers: true,
|
|
1966
|
+
useKeyboard: useKeyboard6,
|
|
1967
|
+
onSubmit: handleSubmit
|
|
1782
1968
|
}
|
|
1783
|
-
)
|
|
1969
|
+
), /* @__PURE__ */ React.createElement("box", null, /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true }) }, "model: " + model))), /* @__PURE__ */ React.createElement("box", { paddingTop: 1, paddingLeft: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [
|
|
1970
|
+
{ key: "\u23CE enter", label: "send" },
|
|
1971
|
+
{ key: "/model", label: "change model" },
|
|
1972
|
+
{ key: "\u2191", label: "history" }
|
|
1973
|
+
] })));
|
|
1784
1974
|
}
|
|
1785
1975
|
|
|
1786
|
-
//
|
|
1787
|
-
import {
|
|
1788
|
-
|
|
1789
|
-
|
|
1976
|
+
// demos/text-input.tsx
|
|
1977
|
+
import { useState as useState13 } from "react";
|
|
1978
|
+
import { useKeyboard as useKeyboard7 } from "@gridland/utils";
|
|
1979
|
+
var FIELDS = [
|
|
1980
|
+
{ label: "Username", placeholder: "enter your name", maxLength: 30, required: true },
|
|
1981
|
+
{ label: "Email", placeholder: "user@example.com", maxLength: 50, required: true, description: "We'll never share your email" },
|
|
1982
|
+
{ label: "Password", placeholder: "enter password", maxLength: 40 },
|
|
1983
|
+
{ label: "API Key", placeholder: "sk-...", maxLength: 60, disabled: true }
|
|
1984
|
+
];
|
|
1985
|
+
function TextInputApp() {
|
|
1986
|
+
const [activeField, setActiveField] = useState13(0);
|
|
1987
|
+
const [values, setValues] = useState13(FIELDS.map(() => ""));
|
|
1988
|
+
useKeyboard7((event) => {
|
|
1989
|
+
if (event.name === "up") setActiveField((i) => Math.max(0, i - 1));
|
|
1990
|
+
if (event.name === "down") setActiveField((i) => Math.min(FIELDS.length - 1, i + 1));
|
|
1991
|
+
});
|
|
1992
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", paddingX: 1, paddingTop: 1, flexGrow: 1 }, FIELDS.map((field, i) => /* @__PURE__ */ React.createElement("box", { key: field.label, marginBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
1993
|
+
TextInput,
|
|
1994
|
+
{
|
|
1995
|
+
label: field.label,
|
|
1996
|
+
placeholder: field.placeholder,
|
|
1997
|
+
prompt: "> ",
|
|
1998
|
+
focus: i === activeField,
|
|
1999
|
+
maxLength: field.maxLength,
|
|
2000
|
+
value: values[i],
|
|
2001
|
+
onChange: (v) => setValues((prev) => prev.map((old, j) => j === i ? v : old)),
|
|
2002
|
+
required: field.required,
|
|
2003
|
+
disabled: field.disabled,
|
|
2004
|
+
description: field.description
|
|
2005
|
+
}
|
|
2006
|
+
)))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [{ key: "\u2191\u2193", label: "field" }] })));
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
// demos/link.tsx
|
|
2010
|
+
import { useState as useState14 } from "react";
|
|
2011
|
+
import { useKeyboard as useKeyboard8 } from "@gridland/utils";
|
|
2012
|
+
var MODES = ["solid", "dashed", "dotted", "none"];
|
|
2013
|
+
function LinkApp() {
|
|
1790
2014
|
const theme = useTheme();
|
|
1791
|
-
|
|
1792
|
-
|
|
2015
|
+
const [modeIndex, setModeIndex] = useState14(0);
|
|
2016
|
+
const mode = MODES[modeIndex];
|
|
2017
|
+
useKeyboard8((event) => {
|
|
2018
|
+
if (event.name === "right") setModeIndex((i) => (i + 1) % MODES.length);
|
|
2019
|
+
if (event.name === "left") setModeIndex((i) => (i - 1 + MODES.length) % MODES.length);
|
|
2020
|
+
});
|
|
2021
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: theme.foreground }) }, "Made by ", /* @__PURE__ */ React.createElement("a", { href: "https://cjroth.com", style: { attributes: mode === "solid" ? 8 : mode === "dashed" ? 24 : mode === "dotted" ? 72 : 0, fg: theme.accent } }, "Chris Roth"), " and ", /* @__PURE__ */ React.createElement("a", { href: "https://jessicacheng.studio", style: { attributes: mode === "solid" ? 8 : mode === "dashed" ? 24 : mode === "dotted" ? 72 : 0, fg: theme.accent } }, "Jessica Cheng"), ".")), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
2022
|
+
StatusBar,
|
|
1793
2023
|
{
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
borderColor: theme.border,
|
|
1797
|
-
paddingX: 1,
|
|
1798
|
-
flexDirection: "column",
|
|
1799
|
-
flexShrink: 0,
|
|
1800
|
-
children: /* @__PURE__ */ jsxs17("text", { children: [
|
|
1801
|
-
/* @__PURE__ */ jsx23("span", { children: "\u{1F431}" }),
|
|
1802
|
-
/* @__PURE__ */ jsx23("a", { href: "https://github.com/thoughtfulllc/gridland", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " GitHub" }),
|
|
1803
|
-
/* @__PURE__ */ jsx23("span", { children: " " }),
|
|
1804
|
-
/* @__PURE__ */ jsx23("span", { children: "\u{1F4D6}" }),
|
|
1805
|
-
/* @__PURE__ */ jsx23("a", { href: "https://gridland.io/docs", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " Docs" })
|
|
1806
|
-
] })
|
|
2024
|
+
extra: /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true, fg: theme.foreground }) }, mode.padEnd(6)),
|
|
2025
|
+
items: [{ key: "\u2190\u2192", label: "underline style" }]
|
|
1807
2026
|
}
|
|
1808
|
-
);
|
|
2027
|
+
)));
|
|
1809
2028
|
}
|
|
1810
2029
|
|
|
1811
|
-
//
|
|
1812
|
-
import { useState as
|
|
1813
|
-
import
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
2030
|
+
// demos/tabs.tsx
|
|
2031
|
+
import { useState as useState15 } from "react";
|
|
2032
|
+
import { useKeyboard as useKeyboard9 } from "@gridland/utils";
|
|
2033
|
+
var tabs = ["Files", "Search", "Git", "Debug"];
|
|
2034
|
+
function TabBarApp() {
|
|
2035
|
+
const [selectedIndex, setSelectedIndex] = useState15(0);
|
|
2036
|
+
useKeyboard9((event) => {
|
|
2037
|
+
if (event.name === "left") setSelectedIndex((i) => i > 0 ? i - 1 : tabs.length - 1);
|
|
2038
|
+
if (event.name === "right") setSelectedIndex((i) => i < tabs.length - 1 ? i + 1 : 0);
|
|
2039
|
+
});
|
|
2040
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { padding: 1 }, /* @__PURE__ */ React.createElement(TabBar, { options: tabs, selectedIndex })), /* @__PURE__ */ React.createElement("box", { flexGrow: 1 }), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [{ key: "\u2190\u2192", label: "switch tab" }] })));
|
|
1819
2041
|
}
|
|
1820
|
-
|
|
1821
|
-
|
|
2042
|
+
|
|
2043
|
+
// demos/status-bar.tsx
|
|
2044
|
+
import { useState as useState16 } from "react";
|
|
2045
|
+
import { useKeyboard as useKeyboard10 } from "@gridland/utils";
|
|
2046
|
+
var shortcuts = [
|
|
2047
|
+
{ key: "Tab", label: "switch focus" },
|
|
2048
|
+
{ key: "\u2190\u2192", label: "cycle" },
|
|
2049
|
+
{ key: "b", label: "back" },
|
|
2050
|
+
{ key: "z", label: "reset" }
|
|
2051
|
+
];
|
|
2052
|
+
function StatusBarApp() {
|
|
2053
|
+
const theme = useTheme();
|
|
2054
|
+
const [lastKey, setLastKey] = useState16(null);
|
|
2055
|
+
useKeyboard10((event) => {
|
|
2056
|
+
if (event.name === "tab") setLastKey("switch focus (Tab)");
|
|
2057
|
+
else if (event.name === "left") setLastKey("cycle (\u2190)");
|
|
2058
|
+
else if (event.name === "right") setLastKey("cycle (\u2192)");
|
|
2059
|
+
else if (event.name === "b") setLastKey("back (b)");
|
|
2060
|
+
else if (event.name === "z") setLastKey("reset (z)");
|
|
2061
|
+
});
|
|
2062
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", gap: 1, padding: 1 }, lastKey ? /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", null, "Pressed: "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true, fg: theme.accent }) }, lastKey)) : /* @__PURE__ */ React.createElement("text", { style: textStyle({ dim: true }) }, "Press a key to trigger an action"), /* @__PURE__ */ React.createElement(
|
|
2063
|
+
StatusBar,
|
|
2064
|
+
{
|
|
2065
|
+
items: shortcuts,
|
|
2066
|
+
extra: /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.success }) }, "\u25CF Ready")
|
|
2067
|
+
}
|
|
2068
|
+
));
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
// demos/modal.tsx
|
|
2072
|
+
import { useState as useState17 } from "react";
|
|
2073
|
+
import { useKeyboard as useKeyboard11 } from "@gridland/utils";
|
|
2074
|
+
function ModalApp() {
|
|
2075
|
+
const theme = useTheme();
|
|
2076
|
+
const [isOpen, setIsOpen] = useState17(false);
|
|
2077
|
+
useKeyboard11((event) => {
|
|
2078
|
+
if (!isOpen && event.name === "m") setIsOpen(true);
|
|
2079
|
+
if (isOpen && (event.name === "q" || event.name === "escape")) setIsOpen(false);
|
|
2080
|
+
});
|
|
2081
|
+
if (isOpen) {
|
|
2082
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement(Modal, { title: "Example Modal", useKeyboard: useKeyboard11, onClose: () => setIsOpen(false) }, /* @__PURE__ */ React.createElement("box", { paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: theme.foreground }) }, "This is a modal overlay component."), /* @__PURE__ */ React.createElement("text", null, " "), /* @__PURE__ */ React.createElement("text", { style: textStyle({ dim: true, fg: theme.muted }) }, "It stretches to fill the full terminal height."))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [{ key: "q", label: "close" }] })));
|
|
2083
|
+
}
|
|
2084
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true, fg: theme.muted }) }, "Press "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true, fg: theme.background, bg: theme.muted }) }, " m "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true, fg: theme.muted }) }, " to open modal")));
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
// demos/primitives.tsx
|
|
2088
|
+
function PrimitivesApp() {
|
|
2089
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(
|
|
2090
|
+
"box",
|
|
2091
|
+
{
|
|
2092
|
+
border: true,
|
|
2093
|
+
borderStyle: "rounded",
|
|
2094
|
+
borderColor: "#75715e",
|
|
2095
|
+
title: "Layout",
|
|
2096
|
+
titleAlignment: "center",
|
|
2097
|
+
padding: 1
|
|
2098
|
+
},
|
|
2099
|
+
/* @__PURE__ */ React.createElement("box", { flexDirection: "row", gap: 2 }, /* @__PURE__ */ React.createElement("box", { border: true, borderStyle: "single", borderColor: "#a6e22e", padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement("text", { fg: "#a6e22e", bold: true }, "Box 1")), /* @__PURE__ */ React.createElement("box", { border: true, borderStyle: "single", borderColor: "#f92672", padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement("text", { fg: "#f92672", bold: true }, "Box 2")), /* @__PURE__ */ React.createElement("box", { border: true, borderStyle: "single", borderColor: "#66d9ef", padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement("text", { fg: "#66d9ef", bold: true }, "Box 3")))
|
|
2100
|
+
), /* @__PURE__ */ React.createElement("text", { dim: true, fg: "#75715e" }, " Nested boxes with borders, colors & flexbox layout"));
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
// demos/chat.tsx
|
|
2104
|
+
import { useState as useState18, useCallback as useCallback3, useRef as useRef5 } from "react";
|
|
2105
|
+
import { useKeyboard as useKeyboard12 } from "@gridland/utils";
|
|
2106
|
+
var initialMessages = [
|
|
2107
|
+
{ id: "1", role: "user", content: "Show me my portfolio" },
|
|
2108
|
+
{ id: "2", role: "assistant", content: "Here's your current portfolio allocation:" },
|
|
2109
|
+
{ id: "3", role: "user", content: "Calculate rebalancing trades" },
|
|
2110
|
+
{ id: "4", role: "assistant", content: "I've calculated the optimal trades to rebalance your portfolio." }
|
|
2111
|
+
];
|
|
2112
|
+
var nextId = 5;
|
|
2113
|
+
function ChatApp() {
|
|
2114
|
+
const [messages, setMessages] = useState18(initialMessages);
|
|
2115
|
+
const [isLoading, setIsLoading] = useState18(false);
|
|
2116
|
+
const [streamingText, setStreamingText] = useState18("");
|
|
2117
|
+
const [activeToolCalls, setActiveToolCalls] = useState18([]);
|
|
2118
|
+
const intervalRef = useRef5(null);
|
|
2119
|
+
const handleSend = useCallback3((text) => {
|
|
2120
|
+
const userMsg = { id: String(nextId++), role: "user", content: text };
|
|
2121
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
2122
|
+
setIsLoading(true);
|
|
2123
|
+
const toolCallId = `tc-${nextId}`;
|
|
2124
|
+
setTimeout(() => {
|
|
2125
|
+
setIsLoading(false);
|
|
2126
|
+
setActiveToolCalls([{ id: toolCallId, title: "process_request", status: "in_progress" }]);
|
|
2127
|
+
}, 500);
|
|
2128
|
+
setTimeout(() => {
|
|
2129
|
+
setActiveToolCalls([{ id: toolCallId, title: "process_request", status: "completed" }]);
|
|
2130
|
+
}, 1200);
|
|
2131
|
+
const response = `You said: "${text}". This is a demo response.`;
|
|
2132
|
+
let charIndex = 0;
|
|
2133
|
+
setTimeout(() => {
|
|
2134
|
+
intervalRef.current = setInterval(() => {
|
|
2135
|
+
charIndex = Math.min(charIndex + 3, response.length);
|
|
2136
|
+
if (charIndex < response.length) {
|
|
2137
|
+
setStreamingText(response.slice(0, charIndex));
|
|
2138
|
+
} else {
|
|
2139
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
2140
|
+
setStreamingText("");
|
|
2141
|
+
setActiveToolCalls([]);
|
|
2142
|
+
setMessages((prev) => [
|
|
2143
|
+
...prev,
|
|
2144
|
+
{ id: String(nextId++), role: "assistant", content: response }
|
|
2145
|
+
]);
|
|
2146
|
+
}
|
|
2147
|
+
}, 50);
|
|
2148
|
+
}, 1400);
|
|
2149
|
+
}, []);
|
|
2150
|
+
const handleCancel = useCallback3(() => {
|
|
2151
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
2152
|
+
setIsLoading(false);
|
|
2153
|
+
setStreamingText("");
|
|
2154
|
+
setActiveToolCalls([]);
|
|
2155
|
+
}, []);
|
|
2156
|
+
return /* @__PURE__ */ React.createElement(
|
|
2157
|
+
ChatPanel,
|
|
2158
|
+
{
|
|
2159
|
+
messages,
|
|
2160
|
+
streamingText,
|
|
2161
|
+
isLoading,
|
|
2162
|
+
activeToolCalls,
|
|
2163
|
+
onSendMessage: handleSend,
|
|
2164
|
+
onCancel: handleCancel,
|
|
2165
|
+
placeholder: "Ask about your portfolio...",
|
|
2166
|
+
useKeyboard: useKeyboard12
|
|
2167
|
+
}
|
|
2168
|
+
);
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
// demos/chain-of-thought.tsx
|
|
2172
|
+
import { useState as useState19, useEffect as useEffect4, useRef as useRef6 } from "react";
|
|
2173
|
+
import { useKeyboard as useKeyboard13 } from "@gridland/utils";
|
|
2174
|
+
var ALL_STEPS = [
|
|
2175
|
+
{ tool: "Read", label: "Reading codebase", description: "src/", status: "done", delay: 1800 },
|
|
2176
|
+
{ tool: "Think", label: "Planning changes", description: "auth module", status: "done", delay: 2500 },
|
|
2177
|
+
{ tool: "Edit", label: "Editing files", description: "4 files", status: "done", delay: 3200 },
|
|
2178
|
+
{ tool: "Bash", label: "Running tests", description: "vitest", status: "done", delay: 2e3 },
|
|
2179
|
+
{ tool: "Edit", label: "Fixing test", description: "routes.test.ts", status: "done", delay: 1500 }
|
|
2180
|
+
];
|
|
2181
|
+
function ChainOfThoughtApp() {
|
|
2182
|
+
const [expanded, setExpanded] = useState19(true);
|
|
2183
|
+
const [phase, setPhase] = useState19("running");
|
|
2184
|
+
const [stepIndex, setStepIndex] = useState19(0);
|
|
2185
|
+
const timerRef = useRef6(null);
|
|
2186
|
+
useKeyboard13((event) => {
|
|
2187
|
+
if (event.name === "E" && event.ctrl && event.shift) setExpanded((v) => !v);
|
|
2188
|
+
if (event.name === "r") restart();
|
|
2189
|
+
});
|
|
2190
|
+
function restart() {
|
|
2191
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2192
|
+
setPhase("running");
|
|
2193
|
+
setStepIndex(0);
|
|
2194
|
+
}
|
|
2195
|
+
useEffect4(() => {
|
|
2196
|
+
if (phase !== "running") return;
|
|
2197
|
+
if (stepIndex < ALL_STEPS.length) {
|
|
2198
|
+
const delay = ALL_STEPS[stepIndex].delay;
|
|
2199
|
+
timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
|
|
2200
|
+
} else {
|
|
2201
|
+
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
2202
|
+
}
|
|
2203
|
+
return () => {
|
|
2204
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2205
|
+
};
|
|
2206
|
+
}, [phase, stepIndex]);
|
|
2207
|
+
useEffect4(() => {
|
|
2208
|
+
if (phase === "done") {
|
|
2209
|
+
timerRef.current = setTimeout(() => restart(), 3e3);
|
|
2210
|
+
}
|
|
2211
|
+
return () => {
|
|
2212
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2213
|
+
};
|
|
2214
|
+
}, [phase]);
|
|
2215
|
+
const steps = ALL_STEPS.map((s, i) => {
|
|
2216
|
+
if (i < stepIndex) return { ...s, status: "done" };
|
|
2217
|
+
if (i === stepIndex && phase === "running") return { ...s, status: "running" };
|
|
2218
|
+
return { ...s, status: phase === "done" ? "done" : "pending" };
|
|
2219
|
+
});
|
|
2220
|
+
const elapsedMs = ALL_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
|
|
2221
|
+
const totalMs = ALL_STEPS.reduce((sum, s) => sum + s.delay, 0);
|
|
2222
|
+
const durationStr = phase === "done" ? `${(totalMs / 1e3).toFixed(1)}s` : `${(elapsedMs / 1e3).toFixed(1)}s`;
|
|
2223
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement(ChainOfThought, { open: expanded, onOpenChange: setExpanded }, /* @__PURE__ */ React.createElement(ChainOfThoughtHeader, { duration: durationStr }), /* @__PURE__ */ React.createElement(ChainOfThoughtContent, null, steps.map((step, i) => /* @__PURE__ */ React.createElement(
|
|
2224
|
+
ChainOfThoughtStep,
|
|
2225
|
+
{
|
|
2226
|
+
key: i,
|
|
2227
|
+
label: step.label,
|
|
2228
|
+
description: step.description,
|
|
2229
|
+
status: step.status,
|
|
2230
|
+
isLast: i === steps.length - 1
|
|
2231
|
+
},
|
|
2232
|
+
step.output
|
|
2233
|
+
))))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [
|
|
2234
|
+
{ key: "ctrl+shift+e", label: "toggle" },
|
|
2235
|
+
{ key: "r", label: "restart" }
|
|
2236
|
+
] })));
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
// demos/message.tsx
|
|
2240
|
+
import { useState as useState20, useEffect as useEffect5, useRef as useRef7 } from "react";
|
|
2241
|
+
import { useKeyboard as useKeyboard14 } from "@gridland/utils";
|
|
2242
|
+
var 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.";
|
|
2243
|
+
function MessageApp() {
|
|
2244
|
+
const [phase, setPhase] = useState20("idle");
|
|
2245
|
+
const [streamedText, setStreamedText] = useState20("");
|
|
2246
|
+
const timerRef = useRef7(null);
|
|
2247
|
+
useKeyboard14((event) => {
|
|
2248
|
+
if (event.name === "r") restart();
|
|
2249
|
+
});
|
|
2250
|
+
function restart() {
|
|
2251
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2252
|
+
setPhase("idle");
|
|
2253
|
+
setStreamedText("");
|
|
2254
|
+
}
|
|
2255
|
+
useEffect5(() => {
|
|
2256
|
+
if (phase === "idle") {
|
|
2257
|
+
timerRef.current = setTimeout(() => setPhase("streaming"), 800);
|
|
2258
|
+
}
|
|
2259
|
+
return () => {
|
|
2260
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2261
|
+
};
|
|
2262
|
+
}, [phase]);
|
|
2263
|
+
useEffect5(() => {
|
|
2264
|
+
if (phase !== "streaming") return;
|
|
2265
|
+
if (streamedText.length < RESPONSE.length) {
|
|
2266
|
+
timerRef.current = setTimeout(() => {
|
|
2267
|
+
setStreamedText(RESPONSE.slice(0, streamedText.length + 2));
|
|
2268
|
+
}, 25);
|
|
2269
|
+
} else {
|
|
2270
|
+
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
2271
|
+
}
|
|
2272
|
+
return () => {
|
|
2273
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2274
|
+
};
|
|
2275
|
+
}, [phase, streamedText]);
|
|
2276
|
+
useEffect5(() => {
|
|
2277
|
+
if (phase === "done") {
|
|
2278
|
+
timerRef.current = setTimeout(() => restart(), 3e3);
|
|
2279
|
+
}
|
|
2280
|
+
return () => {
|
|
2281
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2282
|
+
};
|
|
2283
|
+
}, [phase]);
|
|
2284
|
+
const isStreaming = phase === "streaming";
|
|
2285
|
+
const isDone = phase === "done";
|
|
2286
|
+
const showAssistant = phase !== "idle";
|
|
2287
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement(Message, { role: "user" }, /* @__PURE__ */ React.createElement(Message.Content, null, /* @__PURE__ */ React.createElement(Message.Text, null, "Can you refactor the auth module?"))), showAssistant && /* @__PURE__ */ React.createElement(Message, { role: "assistant", isStreaming }, /* @__PURE__ */ React.createElement(Message.Content, null, /* @__PURE__ */ React.createElement(Message.Text, { isLast: true }, isDone ? RESPONSE : streamedText)))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [{ key: "r", label: "restart" }] })));
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
// demos/terminal-window.tsx
|
|
2291
|
+
function TerminalWindowApp() {
|
|
2292
|
+
const theme = useTheme();
|
|
2293
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: theme.secondary }) }, '$ echo "Hello from TerminalWindow"'), /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: theme.foreground }) }, "Hello from TerminalWindow"), /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: theme.secondary }) }, "$ _"));
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
// demos/focus.tsx
|
|
2297
|
+
import { useState as useState21, useRef as useRef8 } from "react";
|
|
2298
|
+
import { useKeyboard as useKeyboard15 } from "@gridland/utils";
|
|
2299
|
+
var focusPanels = [
|
|
2300
|
+
{
|
|
2301
|
+
label: "Language",
|
|
2302
|
+
items: [
|
|
2303
|
+
{ label: "TypeScript", value: "ts" },
|
|
2304
|
+
{ label: "JavaScript", value: "js" },
|
|
2305
|
+
{ label: "Python", value: "py" }
|
|
2306
|
+
]
|
|
2307
|
+
},
|
|
2308
|
+
{
|
|
2309
|
+
label: "Framework",
|
|
2310
|
+
items: [
|
|
2311
|
+
{ label: "React", value: "react" },
|
|
2312
|
+
{ label: "Vue", value: "vue" },
|
|
2313
|
+
{ label: "Svelte", value: "svelte" }
|
|
2314
|
+
]
|
|
2315
|
+
},
|
|
2316
|
+
{
|
|
2317
|
+
label: "Runtime",
|
|
2318
|
+
items: [
|
|
2319
|
+
{ label: "Bun", value: "bun" },
|
|
2320
|
+
{ label: "Node", value: "node" },
|
|
2321
|
+
{ label: "Deno", value: "deno" }
|
|
2322
|
+
]
|
|
2323
|
+
}
|
|
2324
|
+
];
|
|
2325
|
+
function FocusApp() {
|
|
2326
|
+
const [panelIndex, setPanelIndex] = useState21(0);
|
|
2327
|
+
const [entered, setEntered] = useState21(false);
|
|
2328
|
+
const [cursors, setCursors] = useState21([0, 0, 0]);
|
|
2329
|
+
const [selections, setSelections] = useState21([null, null, null]);
|
|
2330
|
+
const panelRef = useRef8(0);
|
|
2331
|
+
const enteredRef = useRef8(false);
|
|
2332
|
+
const cursorsRef = useRef8([0, 0, 0]);
|
|
2333
|
+
panelRef.current = panelIndex;
|
|
2334
|
+
enteredRef.current = entered;
|
|
2335
|
+
cursorsRef.current = cursors;
|
|
2336
|
+
useKeyboard15((event) => {
|
|
2337
|
+
const pi = panelRef.current;
|
|
2338
|
+
if (enteredRef.current) {
|
|
2339
|
+
const items3 = focusPanels[pi].items;
|
|
2340
|
+
const cur = cursorsRef.current[pi];
|
|
2341
|
+
if (event.name === "down" || event.name === "j") {
|
|
2342
|
+
const next = (cur + 1) % items3.length;
|
|
2343
|
+
cursorsRef.current = [...cursorsRef.current];
|
|
2344
|
+
cursorsRef.current[pi] = next;
|
|
2345
|
+
setCursors([...cursorsRef.current]);
|
|
2346
|
+
} else if (event.name === "up" || event.name === "k") {
|
|
2347
|
+
const next = (cur - 1 + items3.length) % items3.length;
|
|
2348
|
+
cursorsRef.current = [...cursorsRef.current];
|
|
2349
|
+
cursorsRef.current[pi] = next;
|
|
2350
|
+
setCursors([...cursorsRef.current]);
|
|
2351
|
+
} else if (event.name === "return") {
|
|
2352
|
+
const selected = items3[cursorsRef.current[pi]].label;
|
|
2353
|
+
setSelections((s) => {
|
|
2354
|
+
const n = [...s];
|
|
2355
|
+
n[pi] = selected;
|
|
2356
|
+
return n;
|
|
2357
|
+
});
|
|
2358
|
+
enteredRef.current = false;
|
|
2359
|
+
setEntered(false);
|
|
2360
|
+
} else if (event.name === "escape") {
|
|
2361
|
+
enteredRef.current = false;
|
|
2362
|
+
setEntered(false);
|
|
2363
|
+
}
|
|
2364
|
+
} else {
|
|
2365
|
+
if (event.name === "right" || event.name === "tab") {
|
|
2366
|
+
const next = (pi + 1) % focusPanels.length;
|
|
2367
|
+
panelRef.current = next;
|
|
2368
|
+
setPanelIndex(next);
|
|
2369
|
+
} else if (event.name === "left") {
|
|
2370
|
+
const next = (pi - 1 + focusPanels.length) % focusPanels.length;
|
|
2371
|
+
panelRef.current = next;
|
|
2372
|
+
setPanelIndex(next);
|
|
2373
|
+
} else if (event.name === "return") {
|
|
2374
|
+
enteredRef.current = true;
|
|
2375
|
+
setEntered(true);
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
event.preventDefault();
|
|
2379
|
+
});
|
|
2380
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "row", gap: 1, padding: 1, flexGrow: 1 }, focusPanels.map((panel, i) => {
|
|
2381
|
+
const focused = i === panelIndex;
|
|
2382
|
+
const active = focused && entered;
|
|
2383
|
+
const selected = selections[i];
|
|
2384
|
+
return /* @__PURE__ */ React.createElement(
|
|
2385
|
+
"box",
|
|
2386
|
+
{
|
|
2387
|
+
key: panel.label,
|
|
2388
|
+
border: true,
|
|
2389
|
+
borderStyle: "rounded",
|
|
2390
|
+
borderColor: active ? "#22c55e" : focused ? "#3b82f6" : "#555",
|
|
2391
|
+
flexGrow: 1
|
|
2392
|
+
},
|
|
2393
|
+
/* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement("text", { style: {
|
|
2394
|
+
fg: active ? "#22c55e" : focused ? "#3b82f6" : "#888",
|
|
2395
|
+
bold: focused
|
|
2396
|
+
} }, focused ? "\u25B8 " : " ", panel.label, selected ? `: ${selected}` : ""), (active || !entered && focused) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("box", { height: 1 }), /* @__PURE__ */ React.createElement("box", { flexDirection: "column" }, panel.items.map((item, j) => {
|
|
2397
|
+
const highlighted = active && j === cursors[i];
|
|
2398
|
+
return /* @__PURE__ */ React.createElement("text", { key: item.value, style: {
|
|
2399
|
+
fg: highlighted ? "#22c55e" : active ? "#ccc" : "#666",
|
|
2400
|
+
bold: highlighted
|
|
2401
|
+
} }, highlighted ? " \u25B8 " : " ", item.label);
|
|
2402
|
+
}))))
|
|
2403
|
+
);
|
|
2404
|
+
})), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
2405
|
+
StatusBar,
|
|
2406
|
+
{
|
|
2407
|
+
items: entered ? [{ key: "\u2191\u2193", label: "select" }, { key: "enter", label: "confirm" }, { key: "esc", label: "back" }] : [{ key: "\u2190\u2192", label: "navigate" }, { key: "enter", label: "select" }, { key: "tab", label: "next" }]
|
|
2408
|
+
}
|
|
2409
|
+
)));
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
// demos/pointer.tsx
|
|
2413
|
+
import { useState as useState22, useRef as useRef9 } from "react";
|
|
2414
|
+
import { useKeyboard as useKeyboard16 } from "@gridland/utils";
|
|
2415
|
+
var pointerColors = ["#ef4444", "#f97316", "#eab308", "#22c55e", "#3b82f6", "#8b5cf6"];
|
|
2416
|
+
var pointerColorNames = ["Red", "Orange", "Yellow", "Green", "Blue", "Purple"];
|
|
2417
|
+
function HoverBox() {
|
|
2418
|
+
const [hovering, setHovering] = useState22(false);
|
|
2419
|
+
return /* @__PURE__ */ React.createElement(
|
|
2420
|
+
"box",
|
|
2421
|
+
{
|
|
2422
|
+
border: true,
|
|
2423
|
+
borderStyle: "rounded",
|
|
2424
|
+
borderColor: hovering ? "#22c55e" : "#555",
|
|
2425
|
+
width: 20,
|
|
2426
|
+
height: 5,
|
|
2427
|
+
onMouseOver: () => setHovering(true),
|
|
2428
|
+
onMouseOut: () => setHovering(false)
|
|
2429
|
+
},
|
|
2430
|
+
/* @__PURE__ */ React.createElement("box", { padding: 1 }, /* @__PURE__ */ React.createElement("text", { style: { fg: hovering ? "#22c55e" : "#888", bold: hovering } }, hovering ? "Mouse inside!" : "Hover me"))
|
|
2431
|
+
);
|
|
2432
|
+
}
|
|
2433
|
+
function PointerApp() {
|
|
2434
|
+
const [selected, setSelected] = useState22(null);
|
|
2435
|
+
const [clickCount, setClickCount] = useState22(0);
|
|
2436
|
+
const [mousePos, setMousePos] = useState22(null);
|
|
2437
|
+
const selectedRef = useRef9(null);
|
|
2438
|
+
const clickCountRef = useRef9(0);
|
|
2439
|
+
selectedRef.current = selected;
|
|
2440
|
+
clickCountRef.current = clickCount;
|
|
2441
|
+
useKeyboard16((event) => {
|
|
2442
|
+
const cur = selectedRef.current ?? -1;
|
|
2443
|
+
if (event.name === "right" || event.name === "tab") {
|
|
2444
|
+
const next = (cur + 1) % pointerColors.length;
|
|
2445
|
+
selectedRef.current = next;
|
|
2446
|
+
setSelected(next);
|
|
2447
|
+
} else if (event.name === "left") {
|
|
2448
|
+
const next = (cur - 1 + pointerColors.length) % pointerColors.length;
|
|
2449
|
+
selectedRef.current = next;
|
|
2450
|
+
setSelected(next);
|
|
2451
|
+
}
|
|
2452
|
+
event.preventDefault();
|
|
2453
|
+
});
|
|
2454
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "row", gap: 1 }, pointerColors.map((color, i) => /* @__PURE__ */ React.createElement(
|
|
2455
|
+
"box",
|
|
2456
|
+
{
|
|
2457
|
+
key: color,
|
|
2458
|
+
flexGrow: 1,
|
|
2459
|
+
height: 3,
|
|
2460
|
+
border: true,
|
|
2461
|
+
borderStyle: "rounded",
|
|
2462
|
+
borderColor: i === selected ? color : "#555",
|
|
2463
|
+
onMouseDown: (e) => {
|
|
2464
|
+
clickCountRef.current++;
|
|
2465
|
+
setClickCount(clickCountRef.current);
|
|
2466
|
+
selectedRef.current = i;
|
|
2467
|
+
setSelected(i);
|
|
2468
|
+
setMousePos({ x: e.x, y: e.y });
|
|
2469
|
+
}
|
|
2470
|
+
},
|
|
2471
|
+
/* @__PURE__ */ React.createElement("text", { style: { fg: color, bold: i === selected } }, i === selected ? `\u25B8 ${pointerColorNames[i]}` : ` ${pointerColorNames[i]}`)
|
|
2472
|
+
))), /* @__PURE__ */ React.createElement("box", { height: 1 }), /* @__PURE__ */ React.createElement("box", { flexDirection: "row", gap: 2 }, /* @__PURE__ */ React.createElement(HoverBox, null), /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, paddingTop: 1 }, /* @__PURE__ */ React.createElement("text", { style: { fg: selected !== null ? pointerColors[selected] : "#888" } }, selected !== null ? `Clicked ${pointerColorNames[selected]}` : "Click a color", clickCount > 0 ? ` (${clickCount} clicks)` : ""), /* @__PURE__ */ React.createElement("text", { style: { dim: true, fg: "#888" } }, mousePos ? `mouse: ${mousePos.x}, ${mousePos.y}` : ""))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [
|
|
2473
|
+
{ key: "click", label: "select" },
|
|
2474
|
+
{ key: "\u2190\u2192", label: "keyboard nav" }
|
|
2475
|
+
] })));
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
// demos/cursor-highlight.tsx
|
|
2479
|
+
import { useState as useState23 } from "react";
|
|
2480
|
+
function CursorHighlightApp() {
|
|
2481
|
+
const [pos, setPos] = useState23(null);
|
|
2482
|
+
return /* @__PURE__ */ React.createElement(
|
|
2483
|
+
"box",
|
|
2484
|
+
{
|
|
2485
|
+
flexDirection: "column",
|
|
2486
|
+
flexGrow: 1,
|
|
2487
|
+
onMouseMove: (e) => {
|
|
2488
|
+
setPos({ x: e.x, y: e.y });
|
|
2489
|
+
}
|
|
2490
|
+
},
|
|
2491
|
+
/* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement("text", { style: { bold: true, fg: "#fff" } }, "Cursor Highlight"), /* @__PURE__ */ React.createElement("text", { style: { dim: true, fg: "#888" } }, "Move your mouse over the grid"), /* @__PURE__ */ React.createElement("box", { height: 1 }), /* @__PURE__ */ React.createElement("box", { flexDirection: "column" }, Array.from({ length: 6 }, (_, row) => /* @__PURE__ */ React.createElement("text", { key: row }, Array.from({ length: 40 }, (_2, col) => {
|
|
2492
|
+
const isEven = (row + col) % 2 === 0;
|
|
2493
|
+
return /* @__PURE__ */ React.createElement("span", { key: col, style: {
|
|
2494
|
+
fg: isEven ? "#3b82f6" : "#8b5cf6",
|
|
2495
|
+
dim: !isEven
|
|
2496
|
+
} }, isEven ? "\u2591\u2591" : "\u2593\u2593");
|
|
2497
|
+
}))))),
|
|
2498
|
+
/* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
2499
|
+
StatusBar,
|
|
2500
|
+
{
|
|
2501
|
+
items: [],
|
|
2502
|
+
extra: /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true, fg: "#1e1e2e", bg: "#888" }) }, " x "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true, fg: "#888" }) }, ` ${pos ? String(pos.x).padStart(3) : " -"} `), /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true, fg: "#1e1e2e", bg: "#888" }) }, " y "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true, fg: "#888" }) }, ` ${pos ? String(pos.y).padStart(3) : " -"}`))
|
|
2503
|
+
}
|
|
2504
|
+
))
|
|
2505
|
+
);
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
// demos/text-style.tsx
|
|
2509
|
+
function TextStyleApp() {
|
|
2510
|
+
const theme = useTheme();
|
|
2511
|
+
const desc = textStyle({ fg: theme.muted });
|
|
2512
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1, gap: 0 }, /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground, bold: true }) }, "bold "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " bold: true ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground, dim: true }) }, "dim "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " dim: true ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground, italic: true }) }, "italic "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " italic: true ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground, underline: true }) }, "underline "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " underline: true ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ inverse: true }) }, "inverse "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " inverse: true ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, " "), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.primary }) }, "fg color "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " fg: theme.primary ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground, bg: theme.secondary }) }, "bg color "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " fg: theme.foreground, bg: theme.secondary ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, " "), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.accent, bold: true, underline: true }) }, "combined "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " fg: theme.accent, bold: true, underline: true ", "}", ")")));
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
// demos/headless.tsx
|
|
2516
|
+
var data = [
|
|
2517
|
+
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
2518
|
+
{ name: "Bob", role: "Designer", status: "Active" },
|
|
2519
|
+
{ name: "Charlie", role: "PM", status: "Away" }
|
|
2520
|
+
];
|
|
2521
|
+
function HeadlessApp() {
|
|
2522
|
+
return /* @__PURE__ */ React.createElement("box", { padding: 1 }, /* @__PURE__ */ React.createElement(Table, { data }));
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
// demos/theming.tsx
|
|
2526
|
+
import { useKeyboard as useKeyboard17 } from "@gridland/utils";
|
|
2527
|
+
var tableData = [
|
|
2528
|
+
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
2529
|
+
{ name: "Bob", role: "Designer", status: "Away" }
|
|
2530
|
+
];
|
|
2531
|
+
var selectItems = [
|
|
2532
|
+
{ label: "TypeScript", value: "ts" },
|
|
2533
|
+
{ label: "JavaScript", value: "js" },
|
|
2534
|
+
{ label: "Python", value: "py" }
|
|
2535
|
+
];
|
|
2536
|
+
function ThemingApp() {
|
|
2537
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement(Spinner, { text: "Loading data..." }), /* @__PURE__ */ React.createElement(Table, { data: tableData }), /* @__PURE__ */ React.createElement(MultiSelect, { items: selectItems, useKeyboard: useKeyboard17 }));
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
// src/landing/landing-app.tsx
|
|
2541
|
+
import { useMemo as useMemo7 } from "react";
|
|
2542
|
+
|
|
2543
|
+
// src/landing/install-box.tsx
|
|
2544
|
+
function InstallBox() {
|
|
2545
|
+
const theme = useTheme();
|
|
2546
|
+
return /* @__PURE__ */ React.createElement(
|
|
2547
|
+
"box",
|
|
2548
|
+
{
|
|
2549
|
+
border: true,
|
|
2550
|
+
borderStyle: "rounded",
|
|
2551
|
+
borderColor: theme.border,
|
|
2552
|
+
paddingX: 1,
|
|
2553
|
+
flexDirection: "column",
|
|
2554
|
+
flexShrink: 0
|
|
2555
|
+
},
|
|
2556
|
+
/* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true }) }, "$ "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true }) }, "bun create "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.accent }) }, "gridland"))
|
|
2557
|
+
);
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
// src/landing/links-box.tsx
|
|
2561
|
+
var UNDERLINE3 = 1 << 3;
|
|
2562
|
+
function LinksBox() {
|
|
2563
|
+
const theme = useTheme();
|
|
2564
|
+
return /* @__PURE__ */ React.createElement(
|
|
2565
|
+
"box",
|
|
2566
|
+
{
|
|
2567
|
+
border: true,
|
|
2568
|
+
borderStyle: "rounded",
|
|
2569
|
+
borderColor: theme.border,
|
|
2570
|
+
paddingX: 1,
|
|
2571
|
+
flexDirection: "column",
|
|
2572
|
+
flexShrink: 0
|
|
2573
|
+
},
|
|
2574
|
+
/* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", null, "\u{1F431}"), /* @__PURE__ */ React.createElement("a", { href: "https://github.com/thoughtfulllc/gridland", style: { attributes: UNDERLINE3, fg: theme.accent } }, " GitHub"), /* @__PURE__ */ React.createElement("span", null, " "), /* @__PURE__ */ React.createElement("span", null, "\u{1F4D6}"), /* @__PURE__ */ React.createElement("a", { href: "https://gridland.io/docs", style: { attributes: UNDERLINE3, fg: theme.accent } }, " Docs"))
|
|
2575
|
+
);
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
// src/landing/logo.tsx
|
|
2579
|
+
import { useState as useState24, useEffect as useEffect6, useRef as useRef10, useMemo as useMemo5 } from "react";
|
|
2580
|
+
import figlet3 from "figlet";
|
|
2581
|
+
import ansiShadow3 from "figlet/importable-fonts/ANSI Shadow.js";
|
|
2582
|
+
figlet3.parseFont("ANSI Shadow", ansiShadow3);
|
|
2583
|
+
function makeArt(text) {
|
|
2584
|
+
return figlet3.textSync(text, { font: "ANSI Shadow" }).split("\n").filter((l) => l.trimEnd().length > 0).join("\n");
|
|
2585
|
+
}
|
|
2586
|
+
var fullArt = makeArt("gridland");
|
|
2587
|
+
var gridArt = makeArt("grid");
|
|
1822
2588
|
var landArt = makeArt("land");
|
|
1823
2589
|
var ART_HEIGHT = 6;
|
|
1824
2590
|
function useAnimation(duration = 1e3) {
|
|
1825
2591
|
const isBrowser = typeof document !== "undefined";
|
|
1826
|
-
const [progress, setProgress] =
|
|
1827
|
-
const startTime =
|
|
1828
|
-
|
|
2592
|
+
const [progress, setProgress] = useState24(isBrowser ? 0 : 1);
|
|
2593
|
+
const startTime = useRef10(null);
|
|
2594
|
+
useEffect6(() => {
|
|
1829
2595
|
if (!isBrowser) return;
|
|
1830
2596
|
let raf;
|
|
1831
2597
|
const tick = (time) => {
|
|
@@ -1843,11 +2609,11 @@ function useAnimation(duration = 1e3) {
|
|
|
1843
2609
|
}
|
|
1844
2610
|
function RevealGradient({ children, revealCol }) {
|
|
1845
2611
|
const gradientColors = GRADIENTS.instagram;
|
|
1846
|
-
const
|
|
1847
|
-
const maxLength = Math.max(...
|
|
1848
|
-
if (maxLength === 0) return /* @__PURE__ */
|
|
2612
|
+
const lines2 = children.split("\n");
|
|
2613
|
+
const maxLength = Math.max(...lines2.map((l) => l.length));
|
|
2614
|
+
if (maxLength === 0) return /* @__PURE__ */ React.createElement("text", null, children);
|
|
1849
2615
|
const hexColors = useMemo5(() => generateGradient(gradientColors, maxLength), [maxLength]);
|
|
1850
|
-
return /* @__PURE__ */
|
|
2616
|
+
return /* @__PURE__ */ React.createElement("box", { position: "relative", width: maxLength, height: lines2.length, shouldFill: false }, lines2.map((line, lineIndex) => {
|
|
1851
2617
|
const runs = [];
|
|
1852
2618
|
let current = null;
|
|
1853
2619
|
for (let i = 0; i < line.length; i++) {
|
|
@@ -1867,25 +2633,25 @@ function RevealGradient({ children, revealCol }) {
|
|
|
1867
2633
|
}
|
|
1868
2634
|
}
|
|
1869
2635
|
if (current) runs.push(current);
|
|
1870
|
-
return runs.map((run, runIndex) => /* @__PURE__ */
|
|
2636
|
+
return runs.map((run, runIndex) => /* @__PURE__ */ React.createElement(
|
|
1871
2637
|
"box",
|
|
1872
2638
|
{
|
|
2639
|
+
key: `${lineIndex}-${runIndex}`,
|
|
1873
2640
|
position: "absolute",
|
|
1874
2641
|
top: lineIndex,
|
|
1875
2642
|
left: run.start,
|
|
1876
|
-
shouldFill: false
|
|
1877
|
-
children: /* @__PURE__ */ jsx24("text", { shouldFill: false, children: run.chars.map((char, ci) => /* @__PURE__ */ jsx24(
|
|
1878
|
-
"span",
|
|
1879
|
-
{
|
|
1880
|
-
style: { fg: hexColors[run.start + ci] },
|
|
1881
|
-
children: char
|
|
1882
|
-
},
|
|
1883
|
-
ci
|
|
1884
|
-
)) })
|
|
2643
|
+
shouldFill: false
|
|
1885
2644
|
},
|
|
1886
|
-
|
|
2645
|
+
/* @__PURE__ */ React.createElement("text", { shouldFill: false }, run.chars.map((char, ci) => /* @__PURE__ */ React.createElement(
|
|
2646
|
+
"span",
|
|
2647
|
+
{
|
|
2648
|
+
key: ci,
|
|
2649
|
+
style: { fg: hexColors[run.start + ci] }
|
|
2650
|
+
},
|
|
2651
|
+
char
|
|
2652
|
+
)))
|
|
1887
2653
|
));
|
|
1888
|
-
})
|
|
2654
|
+
}));
|
|
1889
2655
|
}
|
|
1890
2656
|
function Logo({ compact, narrow, mobile }) {
|
|
1891
2657
|
const isBrowser = typeof document !== "undefined";
|
|
@@ -1896,52 +2662,25 @@ function Logo({ compact, narrow, mobile }) {
|
|
|
1896
2662
|
const maxWidth = compact ? 8 : narrow ? 40 : 62;
|
|
1897
2663
|
const revealCol = Math.round(revealProgress * (maxWidth + 4)) - 2;
|
|
1898
2664
|
const taglineOpacity = Math.max(0, Math.min(1, (progress - 0.7) / 0.3));
|
|
1899
|
-
const subtitle = /* @__PURE__ */
|
|
1900
|
-
/* @__PURE__ */ jsx24("text", { children: " " }),
|
|
1901
|
-
/* @__PURE__ */ jsx24("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs18("text", { style: textStyle({ fg: "#d4b0e8" }), opacity: taglineOpacity, wrapMode: "word", textAlign: "center", width: "100%", shouldFill: false, children: [
|
|
1902
|
-
"A framework for building terminal apps, built on ",
|
|
1903
|
-
/* @__PURE__ */ jsx24("a", { href: "https://opentui.com", style: { attributes: 72, fg: "#d4b0e8" }, children: "OpenTUI" }),
|
|
1904
|
-
" + React." + (mobile ? " " : "\n") + "(Gridland apps, like this website, work in the browser and terminal.)"
|
|
1905
|
-
] }) })
|
|
1906
|
-
] });
|
|
2665
|
+
const subtitle = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("text", null, " "), /* @__PURE__ */ React.createElement("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false }, /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: "#d4b0e8" }), opacity: taglineOpacity, wrapMode: "word", textAlign: "center", width: "100%", shouldFill: false }, "A framework for building terminal apps, built on ", /* @__PURE__ */ React.createElement("a", { href: "https://opentui.com", style: { attributes: 72, fg: "#d4b0e8" } }, "OpenTUI"), " + React." + (mobile ? " " : "\n") + "(Gridland apps, like this website, work in the browser and terminal.)")));
|
|
1907
2666
|
if (!isBrowser) {
|
|
1908
|
-
const
|
|
1909
|
-
return /* @__PURE__ */
|
|
1910
|
-
/* @__PURE__ */ jsx24(Gradient, { name: "instagram", children: art }),
|
|
1911
|
-
/* @__PURE__ */ jsx24("text", { children: " " }),
|
|
1912
|
-
/* @__PURE__ */ jsx24("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs18("text", { style: textStyle({ fg: "#d4b0e8" }), shouldFill: false, children: [
|
|
1913
|
-
"A framework for building terminal apps, built on OpenTUI + React.",
|
|
1914
|
-
"\n",
|
|
1915
|
-
"(Gridland apps, like this website, work in the browser and terminal.)"
|
|
1916
|
-
] }) })
|
|
1917
|
-
] });
|
|
2667
|
+
const art2 = compact ? "gridland" : narrow ? gridArt + "\n" + landArt : fullArt;
|
|
2668
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexShrink: 0, width: "100%", alignItems: "center", shouldFill: false }, /* @__PURE__ */ React.createElement(Gradient, { name: "instagram" }, art2), /* @__PURE__ */ React.createElement("text", null, " "), /* @__PURE__ */ React.createElement("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false }, /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: "#d4b0e8" }), shouldFill: false }, "A framework for building terminal apps, built on OpenTUI + React.", "\n", "(Gridland apps, like this website, work in the browser and terminal.)")));
|
|
1918
2669
|
}
|
|
1919
2670
|
if (compact) {
|
|
1920
|
-
return /* @__PURE__ */
|
|
1921
|
-
/* @__PURE__ */ jsx24("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx24("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: /* @__PURE__ */ jsx24(RevealGradient, { revealCol, children: "gridland" }) }) }),
|
|
1922
|
-
subtitle
|
|
1923
|
-
] });
|
|
2671
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false }, /* @__PURE__ */ React.createElement("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false }, /* @__PURE__ */ React.createElement("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false }, /* @__PURE__ */ React.createElement(RevealGradient, { revealCol }, "gridland"))), subtitle);
|
|
1924
2672
|
}
|
|
1925
2673
|
if (narrow) {
|
|
1926
|
-
return /* @__PURE__ */
|
|
1927
|
-
/* @__PURE__ */ jsx24("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsxs18("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: [
|
|
1928
|
-
/* @__PURE__ */ jsx24(RevealGradient, { revealCol, children: gridArt }),
|
|
1929
|
-
/* @__PURE__ */ jsx24(RevealGradient, { revealCol, children: landArt })
|
|
1930
|
-
] }) }),
|
|
1931
|
-
subtitle
|
|
1932
|
-
] });
|
|
2674
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false }, /* @__PURE__ */ React.createElement("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false }, /* @__PURE__ */ React.createElement("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false }, /* @__PURE__ */ React.createElement(RevealGradient, { revealCol }, gridArt), /* @__PURE__ */ React.createElement(RevealGradient, { revealCol }, landArt))), subtitle);
|
|
1933
2675
|
}
|
|
1934
|
-
return /* @__PURE__ */
|
|
1935
|
-
/* @__PURE__ */ jsx24("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx24("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: /* @__PURE__ */ jsx24(RevealGradient, { revealCol, children: fullArt }) }) }),
|
|
1936
|
-
subtitle
|
|
1937
|
-
] });
|
|
2676
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false }, /* @__PURE__ */ React.createElement("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false }, /* @__PURE__ */ React.createElement("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false }, /* @__PURE__ */ React.createElement(RevealGradient, { revealCol }, fullArt))), subtitle);
|
|
1938
2677
|
}
|
|
1939
2678
|
|
|
1940
|
-
//
|
|
2679
|
+
// src/landing/matrix-background.tsx
|
|
1941
2680
|
import { useMemo as useMemo6 } from "react";
|
|
1942
2681
|
|
|
1943
|
-
//
|
|
1944
|
-
import { useState as
|
|
2682
|
+
// src/landing/use-matrix.ts
|
|
2683
|
+
import { useState as useState25, useEffect as useEffect7, useRef as useRef11 } from "react";
|
|
1945
2684
|
var CHARS = "abcdefghijklmnopqrstuvwxyz0123456789@#$%^&*(){}[]|;:<>,.?/~`";
|
|
1946
2685
|
function randomChar() {
|
|
1947
2686
|
return CHARS[Math.floor(Math.random() * CHARS.length)];
|
|
@@ -1975,8 +2714,8 @@ function buildGrid(columns, width, height) {
|
|
|
1975
2714
|
return { grid, brightness };
|
|
1976
2715
|
}
|
|
1977
2716
|
function useMatrix(width, height) {
|
|
1978
|
-
const columnsRef =
|
|
1979
|
-
const [state, setState] =
|
|
2717
|
+
const columnsRef = useRef11([]);
|
|
2718
|
+
const [state, setState] = useState25(() => {
|
|
1980
2719
|
const columns = Array.from(
|
|
1981
2720
|
{ length: width },
|
|
1982
2721
|
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
@@ -1984,7 +2723,7 @@ function useMatrix(width, height) {
|
|
|
1984
2723
|
columnsRef.current = columns;
|
|
1985
2724
|
return buildGrid(columns, width, height);
|
|
1986
2725
|
});
|
|
1987
|
-
|
|
2726
|
+
useEffect7(() => {
|
|
1988
2727
|
if (width < 2 || height < 2) return;
|
|
1989
2728
|
const id = setInterval(() => {
|
|
1990
2729
|
const columns = columnsRef.current;
|
|
@@ -2009,7 +2748,7 @@ function useMatrix(width, height) {
|
|
|
2009
2748
|
}, 80);
|
|
2010
2749
|
return () => clearInterval(id);
|
|
2011
2750
|
}, [width, height]);
|
|
2012
|
-
|
|
2751
|
+
useEffect7(() => {
|
|
2013
2752
|
columnsRef.current = Array.from(
|
|
2014
2753
|
{ length: width },
|
|
2015
2754
|
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
@@ -2019,8 +2758,7 @@ function useMatrix(width, height) {
|
|
|
2019
2758
|
return state;
|
|
2020
2759
|
}
|
|
2021
2760
|
|
|
2022
|
-
//
|
|
2023
|
-
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
2761
|
+
// src/landing/matrix-background.tsx
|
|
2024
2762
|
var MUTE_LEVELS = [0.12, 0.18, 0.24, 0.3, 0.38];
|
|
2025
2763
|
var BG = hexToRgb("#1a1a2e");
|
|
2026
2764
|
function buildMutedColors(baseHex) {
|
|
@@ -2047,726 +2785,99 @@ function MatrixBackground({ width, height, clearRect, clearRects }) {
|
|
|
2047
2785
|
() => columnColors.map(buildMutedColors),
|
|
2048
2786
|
[columnColors]
|
|
2049
2787
|
);
|
|
2050
|
-
return /* @__PURE__ */
|
|
2788
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column" }, grid.map((row, y) => /* @__PURE__ */ React.createElement("text", { key: y }, row.map((cell, x) => {
|
|
2051
2789
|
const inClearRect = clearRect && y >= clearRect.top && y < clearRect.top + clearRect.height && x >= clearRect.left && x < clearRect.left + clearRect.width || clearRects && clearRects.some(
|
|
2052
2790
|
(r) => y >= r.top && y < r.top + r.height && x >= r.left && x < r.left + r.width
|
|
2053
2791
|
);
|
|
2054
2792
|
const mutedColors = columnMutedColors[x];
|
|
2055
2793
|
if (cell === " " || inClearRect || !mutedColors) {
|
|
2056
|
-
return /* @__PURE__ */
|
|
2794
|
+
return /* @__PURE__ */ React.createElement("span", { key: x }, " ");
|
|
2057
2795
|
}
|
|
2058
|
-
return /* @__PURE__ */
|
|
2796
|
+
return /* @__PURE__ */ React.createElement(
|
|
2059
2797
|
"span",
|
|
2060
2798
|
{
|
|
2799
|
+
key: x,
|
|
2061
2800
|
style: {
|
|
2062
2801
|
fg: colorForCell(mutedColors, brightness[y][x])
|
|
2063
|
-
}
|
|
2064
|
-
children: cell
|
|
2802
|
+
}
|
|
2065
2803
|
},
|
|
2066
|
-
|
|
2804
|
+
cell
|
|
2067
2805
|
);
|
|
2068
|
-
})
|
|
2806
|
+
}))));
|
|
2069
2807
|
}
|
|
2070
2808
|
|
|
2071
|
-
//
|
|
2072
|
-
|
|
2073
|
-
var DEMO_RESPONSES = [
|
|
2074
|
-
"Gridland is a framework for building terminal apps with React. It works in both the browser and terminal!",
|
|
2075
|
-
"You can get started with `bun create gridland` to scaffold a new project.",
|
|
2076
|
-
"OpenTUI provides the layout primitives \u2014 flexbox, borders, text styling \u2014 while React handles the component model.",
|
|
2077
|
-
"Yes! Gridland apps are universal \u2014 the same code renders in a terminal emulator and in the browser.",
|
|
2078
|
-
"Check out the docs for examples of interactive components like inputs, selects, and tables."
|
|
2079
|
-
];
|
|
2080
|
-
function LandingApp({ useKeyboard: useKeyboard3 }) {
|
|
2809
|
+
// src/landing/landing-app.tsx
|
|
2810
|
+
function LandingApp({ useKeyboard: useKeyboard20 }) {
|
|
2081
2811
|
const theme = useTheme();
|
|
2082
2812
|
const { width, height, isNarrow, isTiny, isMobile } = useBreakpoints();
|
|
2083
|
-
const [showAbout, setShowAbout] = useState10(false);
|
|
2084
|
-
const [messages, setMessages] = useState10([]);
|
|
2085
|
-
const [chatStatus, setChatStatus] = useState10("ready");
|
|
2086
|
-
const responseIdx = useRef7(0);
|
|
2087
|
-
const handleChatSubmit = useCallback3(({ text }) => {
|
|
2088
|
-
const userMsg = { id: `u-${Date.now()}`, role: "user", content: text };
|
|
2089
|
-
setMessages((prev) => [...prev, userMsg]);
|
|
2090
|
-
setChatStatus("streaming");
|
|
2091
|
-
setTimeout(() => {
|
|
2092
|
-
const response = DEMO_RESPONSES[responseIdx.current % DEMO_RESPONSES.length];
|
|
2093
|
-
responseIdx.current += 1;
|
|
2094
|
-
const assistantMsg = { id: `a-${Date.now()}`, role: "assistant", content: response };
|
|
2095
|
-
setMessages((prev) => [...prev, assistantMsg]);
|
|
2096
|
-
setChatStatus("ready");
|
|
2097
|
-
}, 1200);
|
|
2098
|
-
}, []);
|
|
2099
|
-
useKeyboard3((event) => {
|
|
2100
|
-
if (event.name === "a" && !showAbout) {
|
|
2101
|
-
setShowAbout(true);
|
|
2102
|
-
}
|
|
2103
|
-
if (event.name === "q" && showAbout) {
|
|
2104
|
-
setShowAbout(false);
|
|
2105
|
-
}
|
|
2106
|
-
});
|
|
2107
|
-
if (showAbout) {
|
|
2108
|
-
return /* @__PURE__ */ jsxs19("box", { flexDirection: "column", width: "100%", height: "100%", children: [
|
|
2109
|
-
/* @__PURE__ */ jsx26("box", { flexGrow: 1, children: /* @__PURE__ */ jsx26(AboutModal, { onClose: () => setShowAbout(false), useKeyboard: useKeyboard3 }) }),
|
|
2110
|
-
/* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "q", label: "close" }] })
|
|
2111
|
-
] });
|
|
2112
|
-
}
|
|
2113
2813
|
const isBrowser = typeof document !== "undefined";
|
|
2114
|
-
const
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
/* @__PURE__ */ jsxs19("box", { position: "absolute", top: 0, left: 0, width, height, zIndex: 1, flexDirection: "column", shouldFill: false, children: [
|
|
2126
|
-
/* @__PURE__ */ jsxs19("box", { flexGrow: 1, flexDirection: "column", paddingTop: 3, paddingLeft: 1, paddingRight: 1, paddingBottom: 1, gap: isMobile ? 0 : 1, shouldFill: false, children: [
|
|
2127
|
-
/* @__PURE__ */ jsx26("box", { flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx26(Logo, { compact: isTiny, narrow: isNarrow, mobile: isMobile }) }),
|
|
2128
|
-
/* @__PURE__ */ jsxs19("box", { flexDirection: "row", flexWrap: "wrap", justifyContent: "center", gap: isMobile ? 0 : 1, flexShrink: 0, shouldFill: false, children: [
|
|
2129
|
-
/* @__PURE__ */ jsx26("box", { border: true, borderStyle: "rounded", borderColor: theme.border, paddingX: 1, flexDirection: "column", flexShrink: 0, children: /* @__PURE__ */ jsxs19("text", { children: [
|
|
2130
|
-
/* @__PURE__ */ jsx26("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
2131
|
-
/* @__PURE__ */ jsx26("span", { style: textStyle({ bold: true }), children: "bunx " }),
|
|
2132
|
-
/* @__PURE__ */ jsx26("span", { style: textStyle({ fg: theme.accent }), children: "@gridland/demo landing" })
|
|
2133
|
-
] }) }),
|
|
2134
|
-
/* @__PURE__ */ jsx26(InstallBox, {}),
|
|
2135
|
-
/* @__PURE__ */ jsx26(LinksBox, {})
|
|
2136
|
-
] }),
|
|
2137
|
-
/* @__PURE__ */ jsxs19("box", { flexGrow: 1, border: true, borderStyle: "rounded", borderColor: theme.border, flexDirection: "column", overflow: "hidden", children: [
|
|
2138
|
-
/* @__PURE__ */ jsx26("box", { flexGrow: 1, flexDirection: "column", paddingX: 1, overflow: "hidden", children: messages.map((msg) => /* @__PURE__ */ jsx26(Message, { role: msg.role, children: /* @__PURE__ */ jsx26(Message.Content, { children: /* @__PURE__ */ jsx26(Message.Text, { children: msg.content }) }) }, msg.id)) }),
|
|
2139
|
-
/* @__PURE__ */ jsx26("box", { flexShrink: 0, paddingX: 1, paddingBottom: 0, children: /* @__PURE__ */ jsx26(PromptInput, { splaceholder: "Ask about Gridland...", status: chatStatus, onSubmit: handleChatSubmit, useKeyboard: useKeyboard3 }) })
|
|
2140
|
-
] })
|
|
2141
|
-
] }),
|
|
2142
|
-
/* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "a", label: "about" }] })
|
|
2143
|
-
] })
|
|
2144
|
-
] });
|
|
2145
|
-
}
|
|
2146
|
-
|
|
2147
|
-
// ../docs/components/landing/matrix-rain.tsx
|
|
2148
|
-
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
2149
|
-
|
|
2150
|
-
// ../ui/scripts/demo-apps.tsx
|
|
2151
|
-
import figlet2 from "figlet";
|
|
2152
|
-
import ansiShadow2 from "figlet/importable-fonts/ANSI Shadow.js";
|
|
2153
|
-
import big from "figlet/importable-fonts/Big.js";
|
|
2154
|
-
import doom from "figlet/importable-fonts/Doom.js";
|
|
2155
|
-
import slant from "figlet/importable-fonts/Slant.js";
|
|
2156
|
-
import speed from "figlet/importable-fonts/Speed.js";
|
|
2157
|
-
import standard from "figlet/importable-fonts/Standard.js";
|
|
2158
|
-
import block from "figlet/importable-fonts/Block.js";
|
|
2159
|
-
import colossal from "figlet/importable-fonts/Colossal.js";
|
|
2160
|
-
import { jsx as jsx28, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2161
|
-
var fonts = [
|
|
2162
|
-
{ name: "ANSI Shadow", data: ansiShadow2 },
|
|
2163
|
-
{ name: "Standard", data: standard },
|
|
2164
|
-
{ name: "Big", data: big },
|
|
2165
|
-
{ name: "Doom", data: doom },
|
|
2166
|
-
{ name: "Slant", data: slant },
|
|
2167
|
-
{ name: "Speed", data: speed },
|
|
2168
|
-
{ name: "Block", data: block },
|
|
2169
|
-
{ name: "Colossal", data: colossal }
|
|
2170
|
-
];
|
|
2171
|
-
for (const f of fonts) {
|
|
2172
|
-
figlet2.parseFont(f.name, f.data);
|
|
2173
|
-
}
|
|
2174
|
-
function getFigletLines(fontName, text = "gridland") {
|
|
2175
|
-
const art = figlet2.textSync(text, { font: fontName });
|
|
2176
|
-
return art.split("\n").filter((l) => l.trimEnd().length > 0);
|
|
2177
|
-
}
|
|
2178
|
-
var gradientNames = Object.keys(GRADIENTS);
|
|
2179
|
-
function GradientApp() {
|
|
2180
|
-
const [index, setIndex] = useState11(0);
|
|
2181
|
-
const name = gradientNames[index];
|
|
2182
|
-
const lines = getFigletLines("ANSI Shadow");
|
|
2183
|
-
useKeyboard((event) => {
|
|
2184
|
-
if (event.name === "left") setIndex((i) => i > 0 ? i - 1 : gradientNames.length - 1);
|
|
2185
|
-
if (event.name === "right") setIndex((i) => i < gradientNames.length - 1 ? i + 1 : 0);
|
|
2186
|
-
});
|
|
2187
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2188
|
-
/* @__PURE__ */ jsx28("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: /* @__PURE__ */ jsx28(Gradient, { name, children: lines.join("\n") }) }),
|
|
2189
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(
|
|
2190
|
-
StatusBar,
|
|
2191
|
-
{
|
|
2192
|
-
items: [{ key: "\u2190\u2192", label: "gradient" }, { key: "q", label: "quit" }],
|
|
2193
|
-
extra: /* @__PURE__ */ jsx28("span", { style: textStyle({ fg: "cyan", bold: true }), children: name.padEnd(11) })
|
|
2194
|
-
}
|
|
2195
|
-
) })
|
|
2196
|
-
] });
|
|
2197
|
-
}
|
|
2198
|
-
function AsciiApp() {
|
|
2199
|
-
const [fontIndex, setFontIndex] = useState11(0);
|
|
2200
|
-
const font = fonts[fontIndex];
|
|
2201
|
-
const lines = getFigletLines(font.name);
|
|
2202
|
-
useKeyboard((event) => {
|
|
2203
|
-
if (event.name === "left") setFontIndex((i) => i > 0 ? i - 1 : fonts.length - 1);
|
|
2204
|
-
if (event.name === "right") setFontIndex((i) => i < fonts.length - 1 ? i + 1 : 0);
|
|
2205
|
-
});
|
|
2206
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2207
|
-
/* @__PURE__ */ jsx28("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: lines.map((line, i) => /* @__PURE__ */ jsx28("text", { fg: "#88c0d0", bold: true, children: line }, i)) }),
|
|
2208
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(
|
|
2209
|
-
StatusBar,
|
|
2210
|
-
{
|
|
2211
|
-
items: [{ key: "\u2190\u2192", label: "change font" }, { key: "q", label: "quit" }],
|
|
2212
|
-
extra: /* @__PURE__ */ jsx28("span", { style: textStyle({ fg: "cyan", bold: true }), children: font.name.padEnd(11) })
|
|
2213
|
-
}
|
|
2214
|
-
) })
|
|
2215
|
-
] });
|
|
2216
|
-
}
|
|
2217
|
-
function TableApp() {
|
|
2218
|
-
const data = [
|
|
2219
|
-
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
2220
|
-
{ name: "Bob", role: "Designer", status: "Active" },
|
|
2221
|
-
{ name: "Charlie", role: "PM", status: "Away" }
|
|
2222
|
-
];
|
|
2223
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2224
|
-
/* @__PURE__ */ jsx28("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx28(Table, { data, headerColor: "cyan", borderColor: "#5e81ac" }) }),
|
|
2225
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
2226
|
-
] });
|
|
2227
|
-
}
|
|
2228
|
-
function SpinnerApp() {
|
|
2229
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2230
|
-
/* @__PURE__ */ jsx28("box", { flexGrow: 1, children: /* @__PURE__ */ jsx28(SpinnerPicker, { useKeyboard }) }),
|
|
2231
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "\u2190\u2192", label: "change variant" }, { key: "q", label: "quit" }] }) })
|
|
2232
|
-
] });
|
|
2233
|
-
}
|
|
2234
|
-
function SelectInputApp() {
|
|
2235
|
-
const [submitted, setSubmitted] = useState11(false);
|
|
2236
|
-
const items = [
|
|
2237
|
-
{ label: "TypeScript", value: "ts" },
|
|
2238
|
-
{ label: "JavaScript", value: "js" },
|
|
2239
|
-
{ label: "Python", value: "py" },
|
|
2240
|
-
{ label: "Rust", value: "rs" }
|
|
2241
|
-
];
|
|
2242
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2243
|
-
/* @__PURE__ */ jsx28("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx28(SelectInput, { items, title: "Choose a language", useKeyboard, onSubmit: () => setSubmitted(true) }) }),
|
|
2244
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: submitted ? [{ key: "q", label: "quit" }] : [
|
|
2245
|
-
{ key: "\u2191\u2193", label: "select" },
|
|
2246
|
-
{ key: "enter", label: "submit" },
|
|
2247
|
-
{ key: "q", label: "quit" }
|
|
2248
|
-
] }) })
|
|
2249
|
-
] });
|
|
2250
|
-
}
|
|
2251
|
-
function MultiSelectApp() {
|
|
2252
|
-
const [submitted, setSubmitted] = useState11(false);
|
|
2253
|
-
const items = [
|
|
2254
|
-
{ label: "TypeScript", value: "ts" },
|
|
2255
|
-
{ label: "JavaScript", value: "js" },
|
|
2256
|
-
{ label: "Python", value: "py" },
|
|
2257
|
-
{ label: "Rust", value: "rs" }
|
|
2258
|
-
];
|
|
2259
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2260
|
-
/* @__PURE__ */ jsx28("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx28(MultiSelect, { items, title: "Select languages", useKeyboard, onSubmit: () => setSubmitted(true) }) }),
|
|
2261
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: submitted ? [{ key: "q", label: "quit" }] : [
|
|
2262
|
-
{ key: "\u2191\u2193", label: "move" },
|
|
2263
|
-
{ key: "enter", label: "select" },
|
|
2264
|
-
{ key: "a", label: "all" },
|
|
2265
|
-
{ key: "x", label: "clear" },
|
|
2266
|
-
{ key: "q", label: "quit" }
|
|
2267
|
-
] }) })
|
|
2268
|
-
] });
|
|
2269
|
-
}
|
|
2270
|
-
function PromptInputApp() {
|
|
2271
|
-
const [lastMessage, setLastMessage] = useState11("");
|
|
2272
|
-
const [model, setModel] = useState11("opus");
|
|
2273
|
-
const [showModelPicker, setShowModelPicker] = useState11(false);
|
|
2274
|
-
const [resetKey, setResetKey] = useState11(0);
|
|
2275
|
-
const commands = [
|
|
2276
|
-
{ cmd: "/help", desc: "Show commands" },
|
|
2277
|
-
{ cmd: "/model", desc: "Switch model" },
|
|
2278
|
-
{ cmd: "/clear", desc: "Clear conversation" }
|
|
2279
|
-
];
|
|
2280
|
-
const files = ["src/index.ts", "src/routes.ts", "src/auth.ts", "package.json"];
|
|
2281
|
-
const models = [
|
|
2282
|
-
{ label: "Claude Opus", value: "opus" },
|
|
2283
|
-
{ label: "Claude Sonnet", value: "sonnet" },
|
|
2284
|
-
{ label: "Claude Haiku", value: "haiku" }
|
|
2285
|
-
];
|
|
2286
|
-
const handleSubmit = (msg) => {
|
|
2287
|
-
if (msg.text === "/model") {
|
|
2288
|
-
setShowModelPicker(true);
|
|
2289
|
-
setResetKey((k) => k + 1);
|
|
2290
|
-
return;
|
|
2291
|
-
}
|
|
2292
|
-
if (msg.text === "/clear") {
|
|
2293
|
-
setLastMessage("");
|
|
2294
|
-
setResetKey((k) => k + 1);
|
|
2295
|
-
return;
|
|
2296
|
-
}
|
|
2297
|
-
setLastMessage(msg.text);
|
|
2298
|
-
};
|
|
2299
|
-
if (showModelPicker) {
|
|
2300
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2301
|
-
/* @__PURE__ */ jsx28(
|
|
2302
|
-
Modal,
|
|
2303
|
-
{
|
|
2304
|
-
title: "Select Model",
|
|
2305
|
-
useKeyboard,
|
|
2306
|
-
onClose: () => setShowModelPicker(false),
|
|
2307
|
-
children: /* @__PURE__ */ jsx28("box", { paddingX: 1, children: /* @__PURE__ */ jsx28(
|
|
2308
|
-
SelectInput,
|
|
2309
|
-
{
|
|
2310
|
-
items: models,
|
|
2311
|
-
defaultValue: model,
|
|
2312
|
-
useKeyboard,
|
|
2313
|
-
onSubmit: (value) => {
|
|
2314
|
-
setModel(value);
|
|
2315
|
-
setShowModelPicker(false);
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
|
-
) })
|
|
2319
|
-
}
|
|
2320
|
-
),
|
|
2321
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [
|
|
2322
|
-
{ key: "\u23CE", label: "select" },
|
|
2323
|
-
{ key: "esc", label: "cancel" },
|
|
2324
|
-
{ key: "q", label: "quit" }
|
|
2325
|
-
] }) })
|
|
2326
|
-
] });
|
|
2327
|
-
}
|
|
2328
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2329
|
-
/* @__PURE__ */ jsx28("box", { padding: 1, flexDirection: "column", flexGrow: 1, children: lastMessage ? /* @__PURE__ */ jsxs20("text", { children: [
|
|
2330
|
-
/* @__PURE__ */ jsx28("span", { children: "Sent: " }),
|
|
2331
|
-
/* @__PURE__ */ jsx28("span", { children: lastMessage })
|
|
2332
|
-
] }) : /* @__PURE__ */ jsx28("text", { style: textStyle({ dim: true }), children: "Type a message and press enter" }) }),
|
|
2333
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, children: /* @__PURE__ */ jsx28(
|
|
2334
|
-
PromptInput,
|
|
2335
|
-
{
|
|
2336
|
-
commands,
|
|
2337
|
-
files,
|
|
2338
|
-
placeholder: "Message Claude...",
|
|
2339
|
-
showDividers: true,
|
|
2340
|
-
useKeyboard,
|
|
2341
|
-
onSubmit: handleSubmit
|
|
2342
|
-
},
|
|
2343
|
-
resetKey
|
|
2344
|
-
) }),
|
|
2345
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, children: /* @__PURE__ */ jsxs20("text", { children: [
|
|
2346
|
-
/* @__PURE__ */ jsx28("span", { style: textStyle({ fg: "#C4A8FF" }), children: "[\u22A1_\u22A1]" }),
|
|
2347
|
-
/* @__PURE__ */ jsx28("span", { style: textStyle({ dim: true }), children: " " + model })
|
|
2348
|
-
] }) }),
|
|
2349
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [
|
|
2350
|
-
{ key: "\u23CE", label: "send" },
|
|
2351
|
-
{ key: "/", label: "commands" },
|
|
2352
|
-
{ key: "@", label: "files" },
|
|
2353
|
-
{ key: "\u2191", label: "history" },
|
|
2354
|
-
{ key: "q", label: "quit" }
|
|
2355
|
-
] }) })
|
|
2356
|
-
] });
|
|
2357
|
-
}
|
|
2358
|
-
var TEXT_INPUT_FIELDS = [
|
|
2359
|
-
{ label: "Username", placeholder: "enter your name", maxLength: 30, required: true },
|
|
2360
|
-
{ label: "Email", placeholder: "user@example.com", maxLength: 50, required: true, description: "We'll never share your email" },
|
|
2361
|
-
{ label: "Password", placeholder: "enter password", maxLength: 40 },
|
|
2362
|
-
{ label: "API Key", placeholder: "sk-...", maxLength: 60, disabled: true }
|
|
2363
|
-
];
|
|
2364
|
-
function TextInputApp() {
|
|
2365
|
-
const [activeField, setActiveField] = useState11(0);
|
|
2366
|
-
const [values, setValues] = useState11(TEXT_INPUT_FIELDS.map(() => ""));
|
|
2367
|
-
useKeyboard((event) => {
|
|
2368
|
-
if (event.name === "up") setActiveField((i) => Math.max(0, i - 1));
|
|
2369
|
-
if (event.name === "down" || event.name === "tab") setActiveField((i) => Math.min(TEXT_INPUT_FIELDS.length - 1, i + 1));
|
|
2370
|
-
});
|
|
2371
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2372
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingTop: 1, children: /* @__PURE__ */ jsxs20("text", { children: [
|
|
2373
|
-
/* @__PURE__ */ jsx28("span", { style: textStyle({ fg: "#FF71CE", bold: true }), children: "TextInput" }),
|
|
2374
|
-
/* @__PURE__ */ jsx28("span", { style: textStyle({ dim: true }), children: " Form with multiple input types" })
|
|
2375
|
-
] }) }),
|
|
2376
|
-
/* @__PURE__ */ jsx28("box", { flexDirection: "column", paddingX: 1, paddingTop: 1, flexGrow: 1, children: TEXT_INPUT_FIELDS.map((field, i) => /* @__PURE__ */ jsx28("box", { marginBottom: 1, children: /* @__PURE__ */ jsx28(
|
|
2377
|
-
TextInput,
|
|
2378
|
-
{
|
|
2379
|
-
label: field.label,
|
|
2380
|
-
placeholder: field.placeholder,
|
|
2381
|
-
prompt: "> ",
|
|
2382
|
-
focus: i === activeField,
|
|
2383
|
-
maxLength: field.maxLength,
|
|
2384
|
-
value: values[i],
|
|
2385
|
-
onChange: (v) => setValues((prev) => prev.map((old, j) => j === i ? v : old)),
|
|
2386
|
-
required: field.required,
|
|
2387
|
-
disabled: field.disabled,
|
|
2388
|
-
description: field.description
|
|
2389
|
-
}
|
|
2390
|
-
) }, field.label)) }),
|
|
2391
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [
|
|
2392
|
-
{ key: "\u2191\u2193", label: "field" },
|
|
2393
|
-
{ key: "\u2190\u2192", label: "cursor" },
|
|
2394
|
-
{ key: "tab", label: "complete" },
|
|
2395
|
-
{ key: "^k/^u", label: "kill" }
|
|
2396
|
-
] }) })
|
|
2397
|
-
] });
|
|
2398
|
-
}
|
|
2399
|
-
function LinkApp() {
|
|
2400
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2401
|
-
/* @__PURE__ */ jsx28("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx28(LinkDemo, { useKeyboard }) }),
|
|
2402
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
2403
|
-
] });
|
|
2404
|
-
}
|
|
2405
|
-
function TabBarApp() {
|
|
2406
|
-
const tabs = ["Files", "Search", "Git", "Debug"];
|
|
2407
|
-
const [selectedIndex, setSelectedIndex] = useState11(0);
|
|
2408
|
-
useKeyboard((event) => {
|
|
2409
|
-
if (event.name === "left") setSelectedIndex((i) => i > 0 ? i - 1 : tabs.length - 1);
|
|
2410
|
-
if (event.name === "right") setSelectedIndex((i) => i < tabs.length - 1 ? i + 1 : 0);
|
|
2411
|
-
});
|
|
2412
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2413
|
-
/* @__PURE__ */ jsxs20("box", { flexDirection: "column", gap: 1, padding: 1, flexGrow: 1, children: [
|
|
2414
|
-
/* @__PURE__ */ jsx28(TabBar, { label: "View", options: tabs, selectedIndex }),
|
|
2415
|
-
/* @__PURE__ */ jsx28("text", { style: textStyle({ dim: true }), children: "Use \u2190/\u2192 arrow keys to switch tabs" })
|
|
2416
|
-
] }),
|
|
2417
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "\u2190\u2192", label: "switch tab" }, { key: "q", label: "quit" }] }) })
|
|
2418
|
-
] });
|
|
2419
|
-
}
|
|
2420
|
-
function StatusBarApp() {
|
|
2421
|
-
const shortcuts = [
|
|
2422
|
-
{ key: "Tab", label: "switch focus" },
|
|
2423
|
-
{ key: "\u2190\u2192", label: "cycle" },
|
|
2424
|
-
{ key: "b", label: "back" },
|
|
2425
|
-
{ key: "z", label: "reset" }
|
|
2426
|
-
];
|
|
2427
|
-
const [lastKey, setLastKey] = useState11(null);
|
|
2428
|
-
useKeyboard((event) => {
|
|
2429
|
-
if (event.name === "tab") setLastKey("switch focus (Tab)");
|
|
2430
|
-
else if (event.name === "left") setLastKey("cycle (\u2190)");
|
|
2431
|
-
else if (event.name === "right") setLastKey("cycle (\u2192)");
|
|
2432
|
-
else if (event.name === "b") setLastKey("back (b)");
|
|
2433
|
-
else if (event.name === "z") setLastKey("reset (z)");
|
|
2434
|
-
});
|
|
2435
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", gap: 1, padding: 1, children: [
|
|
2436
|
-
lastKey ? /* @__PURE__ */ jsxs20("text", { children: [
|
|
2437
|
-
/* @__PURE__ */ jsx28("span", { children: "Pressed: " }),
|
|
2438
|
-
/* @__PURE__ */ jsx28("span", { style: textStyle({ bold: true, fg: "cyan" }), children: lastKey })
|
|
2439
|
-
] }) : /* @__PURE__ */ jsx28("text", { style: textStyle({ dim: true }), children: "Press a key to trigger an action" }),
|
|
2440
|
-
/* @__PURE__ */ jsx28(
|
|
2441
|
-
StatusBar,
|
|
2442
|
-
{
|
|
2443
|
-
items: [...shortcuts, { key: "q", label: "quit" }],
|
|
2444
|
-
extra: /* @__PURE__ */ jsx28("span", { style: textStyle({ fg: "green" }), children: "\u25CF Ready" })
|
|
2445
|
-
}
|
|
2446
|
-
)
|
|
2447
|
-
] });
|
|
2448
|
-
}
|
|
2449
|
-
function ModalApp() {
|
|
2450
|
-
const [isOpen, setIsOpen] = useState11(false);
|
|
2451
|
-
useKeyboard((event) => {
|
|
2452
|
-
if (!isOpen && event.name === "m") setIsOpen(true);
|
|
2453
|
-
if (isOpen && (event.name === "q" || event.name === "escape")) setIsOpen(false);
|
|
2454
|
-
});
|
|
2455
|
-
if (isOpen) {
|
|
2456
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2457
|
-
/* @__PURE__ */ jsx28(Modal, { title: "Example Modal", borderColor: "blue", useKeyboard, onClose: () => setIsOpen(false), children: /* @__PURE__ */ jsxs20("box", { paddingX: 1, flexDirection: "column", children: [
|
|
2458
|
-
/* @__PURE__ */ jsx28("text", { children: "This is a modal overlay component." }),
|
|
2459
|
-
/* @__PURE__ */ jsx28("text", { children: " " }),
|
|
2460
|
-
/* @__PURE__ */ jsx28("text", { style: textStyle({ dim: true }), children: "It stretches to fill the full terminal height." })
|
|
2461
|
-
] }) }),
|
|
2462
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "q", label: "close" }, { key: "Esc", label: "quit" }] }) })
|
|
2463
|
-
] });
|
|
2464
|
-
}
|
|
2465
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2466
|
-
/* @__PURE__ */ jsx28("box", { flexDirection: "column", flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsxs20("text", { children: [
|
|
2467
|
-
/* @__PURE__ */ jsx28("span", { style: textStyle({ dim: true }), children: "Press " }),
|
|
2468
|
-
/* @__PURE__ */ jsx28("span", { style: textStyle({ inverse: true, bold: true }), children: " m " }),
|
|
2469
|
-
/* @__PURE__ */ jsx28("span", { style: textStyle({ dim: true }), children: " to open modal" })
|
|
2470
|
-
] }) }),
|
|
2471
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "m", label: "open modal" }, { key: "q", label: "quit" }] }) })
|
|
2472
|
-
] });
|
|
2473
|
-
}
|
|
2474
|
-
function PrimitivesApp() {
|
|
2475
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2476
|
-
/* @__PURE__ */ jsxs20("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: [
|
|
2477
|
-
/* @__PURE__ */ jsx28("box", { border: true, borderStyle: "rounded", borderColor: "#5e81ac", title: "Layout", titleAlignment: "center", padding: 1, children: /* @__PURE__ */ jsxs20("box", { flexDirection: "row", gap: 2, children: [
|
|
2478
|
-
/* @__PURE__ */ jsx28("box", { border: true, borderStyle: "single", borderColor: "#a3be8c", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx28("text", { fg: "#a3be8c", bold: true, children: "Box 1" }) }),
|
|
2479
|
-
/* @__PURE__ */ jsx28("box", { border: true, borderStyle: "single", borderColor: "#ebcb8b", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx28("text", { fg: "#ebcb8b", bold: true, children: "Box 2" }) }),
|
|
2480
|
-
/* @__PURE__ */ jsx28("box", { border: true, borderStyle: "single", borderColor: "#b48ead", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx28("text", { fg: "#b48ead", bold: true, children: "Box 3" }) })
|
|
2481
|
-
] }) }),
|
|
2482
|
-
/* @__PURE__ */ jsx28("text", { fg: "#d8dee9", dim: true, children: " Nested boxes with borders, colors & flexbox layout" })
|
|
2483
|
-
] }),
|
|
2484
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
2485
|
-
] });
|
|
2486
|
-
}
|
|
2487
|
-
function TerminalWindowApp() {
|
|
2488
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2489
|
-
/* @__PURE__ */ jsxs20("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: [
|
|
2490
|
-
/* @__PURE__ */ jsx28("text", { style: textStyle({ fg: "green" }), children: '$ echo "Hello from OpenTUI"' }),
|
|
2491
|
-
/* @__PURE__ */ jsx28("text", { children: "Hello from OpenTUI" }),
|
|
2492
|
-
/* @__PURE__ */ jsx28("text", { style: textStyle({ fg: "green" }), children: "$ _" })
|
|
2493
|
-
] }),
|
|
2494
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
2495
|
-
] });
|
|
2496
|
-
}
|
|
2497
|
-
var COT_STEPS = [
|
|
2498
|
-
{ tool: "Read", label: "Reading codebase", description: "src/", status: "done", delay: 1800 },
|
|
2499
|
-
{ tool: "Think", label: "Planning changes", description: "auth module", status: "done", delay: 2500 },
|
|
2500
|
-
{ tool: "Edit", label: "Editing files", description: "4 files", status: "done", delay: 3200 },
|
|
2501
|
-
{ tool: "Bash", label: "Running tests", description: "vitest", status: "done", delay: 2e3 },
|
|
2502
|
-
{ tool: "Edit", label: "Fixing test", description: "routes.test.ts", status: "done", delay: 1500 }
|
|
2503
|
-
];
|
|
2504
|
-
function ChainOfThoughtApp() {
|
|
2505
|
-
const [expanded, setExpanded] = useState11(true);
|
|
2506
|
-
const [phase, setPhase] = useState11("running");
|
|
2507
|
-
const [stepIndex, setStepIndex] = useState11(0);
|
|
2508
|
-
const timerRef = useRef8(null);
|
|
2509
|
-
useKeyboard((event) => {
|
|
2510
|
-
if (event.name === "E" && event.ctrl && event.shift) setExpanded((v) => !v);
|
|
2511
|
-
if (event.name === "r") cotRestart();
|
|
2512
|
-
});
|
|
2513
|
-
function cotRestart() {
|
|
2514
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2515
|
-
setPhase("running");
|
|
2516
|
-
setStepIndex(0);
|
|
2517
|
-
}
|
|
2518
|
-
useEffect5(() => {
|
|
2519
|
-
if (phase !== "running") return;
|
|
2520
|
-
if (stepIndex < COT_STEPS.length) {
|
|
2521
|
-
const delay = COT_STEPS[stepIndex].delay;
|
|
2522
|
-
timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
|
|
2523
|
-
} else {
|
|
2524
|
-
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
2525
|
-
}
|
|
2526
|
-
return () => {
|
|
2527
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2528
|
-
};
|
|
2529
|
-
}, [phase, stepIndex]);
|
|
2530
|
-
useEffect5(() => {
|
|
2531
|
-
if (phase === "done") {
|
|
2532
|
-
timerRef.current = setTimeout(() => cotRestart(), 3e3);
|
|
2533
|
-
}
|
|
2534
|
-
return () => {
|
|
2535
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2814
|
+
const { clearRect, installLinksClearRect } = useMemo7(() => {
|
|
2815
|
+
const logoHeight = isTiny ? 2 : isNarrow ? 13 : 7;
|
|
2816
|
+
const logoExtra = isBrowser ? 1 : 0;
|
|
2817
|
+
const gap = isMobile ? 0 : 1;
|
|
2818
|
+
const installLinksTop = 3 + logoHeight + logoExtra + gap;
|
|
2819
|
+
const installLinksHeight = 3;
|
|
2820
|
+
const boxTop = installLinksTop + installLinksHeight + gap + 1;
|
|
2821
|
+
const bh = height - boxTop - 1;
|
|
2822
|
+
return {
|
|
2823
|
+
clearRect: { top: boxTop, left: 1, width: width - 2, height: bh },
|
|
2824
|
+
installLinksClearRect: { top: installLinksTop, left: 1, width: width - 2, height: installLinksHeight }
|
|
2536
2825
|
};
|
|
2537
|
-
}, [
|
|
2538
|
-
|
|
2539
|
-
if (i < stepIndex) return { ...s, status: "done" };
|
|
2540
|
-
if (i === stepIndex && phase === "running") return { ...s, status: "running" };
|
|
2541
|
-
return { ...s, status: phase === "done" ? "done" : "pending" };
|
|
2542
|
-
});
|
|
2543
|
-
const elapsedMs = COT_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
|
|
2544
|
-
const totalMs = COT_STEPS.reduce((sum, s) => sum + s.delay, 0);
|
|
2545
|
-
const durationStr = phase === "done" ? `${(totalMs / 1e3).toFixed(1)}s` : `${(elapsedMs / 1e3).toFixed(1)}s`;
|
|
2546
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2547
|
-
/* @__PURE__ */ jsx28("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsxs20(ChainOfThought, { open: expanded, onOpenChange: setExpanded, children: [
|
|
2548
|
-
/* @__PURE__ */ jsx28(ChainOfThoughtHeader, { duration: durationStr }),
|
|
2549
|
-
/* @__PURE__ */ jsx28(ChainOfThoughtContent, { children: steps.map((step, i) => /* @__PURE__ */ jsx28(
|
|
2550
|
-
ChainOfThoughtStep,
|
|
2551
|
-
{
|
|
2552
|
-
label: step.label,
|
|
2553
|
-
description: step.description,
|
|
2554
|
-
status: step.status,
|
|
2555
|
-
isLast: i === steps.length - 1,
|
|
2556
|
-
children: step.output
|
|
2557
|
-
},
|
|
2558
|
-
i
|
|
2559
|
-
)) })
|
|
2560
|
-
] }) }),
|
|
2561
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [
|
|
2562
|
-
{ key: "ctrl+shift+e", label: "toggle" },
|
|
2563
|
-
{ key: "r", label: "restart" },
|
|
2564
|
-
{ key: "q", label: "quit" }
|
|
2565
|
-
] }) })
|
|
2566
|
-
] });
|
|
2567
|
-
}
|
|
2568
|
-
var BUBBLE_STEPS = [
|
|
2569
|
-
{ tool: "Read", label: "Reading codebase", description: "src/", status: "done", delay: 1800 },
|
|
2570
|
-
{ tool: "Think", label: "Planning changes", description: "auth module", status: "done", delay: 2500 },
|
|
2571
|
-
{ tool: "Edit", label: "Editing files", description: "4 files", status: "done", delay: 3200 },
|
|
2572
|
-
{ tool: "Bash", label: "Running tests", description: "vitest", status: "done", delay: 2e3 },
|
|
2573
|
-
{ tool: "Edit", label: "Fixing test", description: "routes.test.ts", status: "done", delay: 1500 }
|
|
2574
|
-
];
|
|
2575
|
-
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.";
|
|
2576
|
-
var BUBBLE_TOTAL_MS = BUBBLE_STEPS.reduce((sum, s) => sum + s.delay, 0);
|
|
2577
|
-
function MessageApp() {
|
|
2578
|
-
const [expanded, setExpanded] = useState11(true);
|
|
2579
|
-
const [phase, setPhase] = useState11("idle");
|
|
2580
|
-
const [stepIndex, setStepIndex] = useState11(0);
|
|
2581
|
-
const [streamedText, setStreamedText] = useState11("");
|
|
2582
|
-
const timerRef = useRef8(null);
|
|
2583
|
-
useKeyboard((event) => {
|
|
2584
|
-
if (event.name === "E" && event.ctrl && event.shift) setExpanded((v) => !v);
|
|
2585
|
-
if (event.name === "r") bubbleRestart();
|
|
2586
|
-
});
|
|
2587
|
-
function bubbleRestart() {
|
|
2588
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2589
|
-
setPhase("idle");
|
|
2590
|
-
setStepIndex(0);
|
|
2591
|
-
setStreamedText("");
|
|
2592
|
-
}
|
|
2593
|
-
useEffect5(() => {
|
|
2594
|
-
if (phase === "idle") {
|
|
2595
|
-
timerRef.current = setTimeout(() => setPhase("thinking"), 800);
|
|
2596
|
-
}
|
|
2597
|
-
return () => {
|
|
2598
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2599
|
-
};
|
|
2600
|
-
}, [phase]);
|
|
2601
|
-
useEffect5(() => {
|
|
2602
|
-
if (phase !== "thinking") return;
|
|
2603
|
-
if (stepIndex < BUBBLE_STEPS.length) {
|
|
2604
|
-
const delay = BUBBLE_STEPS[stepIndex].delay;
|
|
2605
|
-
timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
|
|
2606
|
-
} else {
|
|
2607
|
-
timerRef.current = setTimeout(() => setPhase("streaming"), 500);
|
|
2608
|
-
}
|
|
2609
|
-
return () => {
|
|
2610
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2611
|
-
};
|
|
2612
|
-
}, [phase, stepIndex]);
|
|
2613
|
-
useEffect5(() => {
|
|
2614
|
-
if (phase !== "streaming") return;
|
|
2615
|
-
if (streamedText.length < BUBBLE_RESPONSE.length) {
|
|
2616
|
-
timerRef.current = setTimeout(() => {
|
|
2617
|
-
setStreamedText(BUBBLE_RESPONSE.slice(0, streamedText.length + 2));
|
|
2618
|
-
}, 25);
|
|
2619
|
-
} else {
|
|
2620
|
-
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
2621
|
-
}
|
|
2622
|
-
return () => {
|
|
2623
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2624
|
-
};
|
|
2625
|
-
}, [phase, streamedText]);
|
|
2626
|
-
useEffect5(() => {
|
|
2627
|
-
if (phase === "done") {
|
|
2628
|
-
timerRef.current = setTimeout(() => bubbleRestart(), 3e3);
|
|
2629
|
-
}
|
|
2630
|
-
return () => {
|
|
2631
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2632
|
-
};
|
|
2633
|
-
}, [phase]);
|
|
2634
|
-
const steps = BUBBLE_STEPS.map((s, i) => {
|
|
2635
|
-
if (i < stepIndex) return { ...s, status: "done" };
|
|
2636
|
-
if (i === stepIndex) return { ...s, status: "running" };
|
|
2637
|
-
return { ...s, status: "pending" };
|
|
2638
|
-
});
|
|
2639
|
-
const isThinking = phase === "thinking";
|
|
2640
|
-
const isStreaming = phase === "streaming";
|
|
2641
|
-
const isDone = phase === "done";
|
|
2642
|
-
const showAssistant = phase !== "idle";
|
|
2643
|
-
const elapsedMs = BUBBLE_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
|
|
2644
|
-
const reasoningDuration = isThinking ? `${(elapsedMs / 1e3).toFixed(1)}s` : `${(BUBBLE_TOTAL_MS / 1e3).toFixed(1)}s`;
|
|
2645
|
-
const reasoningSteps = isThinking ? steps : BUBBLE_STEPS.map((s) => ({ ...s, status: "done" }));
|
|
2646
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2647
|
-
/* @__PURE__ */ jsxs20("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1, children: [
|
|
2648
|
-
/* @__PURE__ */ jsx28(Message, { role: "user", children: /* @__PURE__ */ jsx28(Message.Content, { children: /* @__PURE__ */ jsx28(Message.Text, { children: "Can you refactor the auth module?" }) }) }),
|
|
2649
|
-
showAssistant && /* @__PURE__ */ jsxs20(Message, { role: "assistant", isStreaming, children: [
|
|
2650
|
-
/* @__PURE__ */ jsx28(Message.Reasoning, { part: {
|
|
2651
|
-
type: "reasoning",
|
|
2652
|
-
duration: reasoningDuration,
|
|
2653
|
-
collapsed: !expanded,
|
|
2654
|
-
steps: reasoningSteps
|
|
2655
|
-
} }),
|
|
2656
|
-
(isStreaming || isDone) && /* @__PURE__ */ jsx28(Message.Content, { children: /* @__PURE__ */ jsx28(Message.Text, { isLast: true, children: isDone ? BUBBLE_RESPONSE : streamedText }) })
|
|
2657
|
-
] })
|
|
2658
|
-
] }),
|
|
2659
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "ctrl+shift+e", label: "toggle chain of thought" }, { key: "r", label: "restart" }, { key: "q", label: "quit" }] }) })
|
|
2660
|
-
] });
|
|
2661
|
-
}
|
|
2662
|
-
var initialChatMessages = [
|
|
2663
|
-
{ id: "1", role: "user", content: "Show me my portfolio" },
|
|
2664
|
-
{ id: "2", role: "assistant", content: "Here's your current portfolio allocation:" },
|
|
2665
|
-
{ id: "3", role: "user", content: "Calculate rebalancing trades" },
|
|
2666
|
-
{ id: "4", role: "assistant", content: "I've calculated the optimal trades to rebalance your portfolio." }
|
|
2667
|
-
];
|
|
2668
|
-
var chatNextId = 5;
|
|
2669
|
-
function ChatApp() {
|
|
2670
|
-
const [messages, setMessages] = useState11(initialChatMessages);
|
|
2671
|
-
const [isLoading, setIsLoading] = useState11(false);
|
|
2672
|
-
const [streamingText, setStreamingText] = useState11("");
|
|
2673
|
-
const [activeToolCalls, setActiveToolCalls] = useState11([]);
|
|
2674
|
-
const intervalRef = useRef8(null);
|
|
2675
|
-
const handleSend = useCallback4((text) => {
|
|
2676
|
-
const userMsg = { id: String(chatNextId++), role: "user", content: text };
|
|
2677
|
-
setMessages((prev) => [...prev, userMsg]);
|
|
2678
|
-
setIsLoading(true);
|
|
2679
|
-
const toolCallId = `tc-${chatNextId}`;
|
|
2680
|
-
setTimeout(() => {
|
|
2681
|
-
setIsLoading(false);
|
|
2682
|
-
setActiveToolCalls([{ id: toolCallId, title: "process_request", status: "in_progress" }]);
|
|
2683
|
-
}, 500);
|
|
2684
|
-
setTimeout(() => {
|
|
2685
|
-
setActiveToolCalls([{ id: toolCallId, title: "process_request", status: "completed" }]);
|
|
2686
|
-
}, 1200);
|
|
2687
|
-
const response = `You said: "${text}". This is a demo response.`;
|
|
2688
|
-
let charIndex = 0;
|
|
2689
|
-
setTimeout(() => {
|
|
2690
|
-
intervalRef.current = setInterval(() => {
|
|
2691
|
-
charIndex = Math.min(charIndex + 3, response.length);
|
|
2692
|
-
if (charIndex < response.length) {
|
|
2693
|
-
setStreamingText(response.slice(0, charIndex));
|
|
2694
|
-
} else {
|
|
2695
|
-
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
2696
|
-
setStreamingText("");
|
|
2697
|
-
setActiveToolCalls([]);
|
|
2698
|
-
setMessages((prev) => [
|
|
2699
|
-
...prev,
|
|
2700
|
-
{ id: String(chatNextId++), role: "assistant", content: response }
|
|
2701
|
-
]);
|
|
2702
|
-
}
|
|
2703
|
-
}, 50);
|
|
2704
|
-
}, 1400);
|
|
2705
|
-
}, []);
|
|
2706
|
-
const handleCancel = useCallback4(() => {
|
|
2707
|
-
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
2708
|
-
setIsLoading(false);
|
|
2709
|
-
setStreamingText("");
|
|
2710
|
-
setActiveToolCalls([]);
|
|
2711
|
-
}, []);
|
|
2712
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2713
|
-
/* @__PURE__ */ jsx28(
|
|
2714
|
-
ChatPanel,
|
|
2715
|
-
{
|
|
2716
|
-
messages,
|
|
2717
|
-
streamingText,
|
|
2718
|
-
isLoading,
|
|
2719
|
-
activeToolCalls,
|
|
2720
|
-
onSendMessage: handleSend,
|
|
2721
|
-
onCancel: handleCancel,
|
|
2722
|
-
placeholder: "Ask about your portfolio...",
|
|
2723
|
-
useKeyboard
|
|
2724
|
-
}
|
|
2725
|
-
),
|
|
2726
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
2727
|
-
] });
|
|
2826
|
+
}, [width, height, isTiny, isNarrow, isMobile, isBrowser]);
|
|
2827
|
+
return /* @__PURE__ */ React.createElement("box", { width: "100%", height: "100%", position: "relative" }, /* @__PURE__ */ React.createElement(MatrixBackground, { width, height, clearRect, clearRects: isBrowser ? void 0 : [installLinksClearRect] }), /* @__PURE__ */ React.createElement("box", { position: "absolute", top: 0, left: 0, width, height, zIndex: 1, flexDirection: "column", shouldFill: false }, /* @__PURE__ */ React.createElement("box", { flexGrow: 1, flexDirection: "column", paddingTop: 3, paddingLeft: 1, paddingRight: 1, paddingBottom: 1, gap: isMobile ? 0 : 1, shouldFill: false }, /* @__PURE__ */ React.createElement("box", { flexShrink: 0, shouldFill: false }, /* @__PURE__ */ React.createElement(Logo, { compact: isTiny, narrow: isNarrow, mobile: isMobile })), /* @__PURE__ */ React.createElement("box", { flexDirection: "row", flexWrap: "wrap", justifyContent: "center", gap: isMobile ? 0 : 1, flexShrink: 0, shouldFill: false }, /* @__PURE__ */ React.createElement("box", { border: true, borderStyle: "rounded", borderColor: theme.border, paddingX: 1, flexDirection: "column", flexShrink: 0 }, /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true }) }, "$ "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true }) }, "bunx "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.accent }) }, "@gridland/demo landing"))), /* @__PURE__ */ React.createElement(InstallBox, null), /* @__PURE__ */ React.createElement(LinksBox, null)), /* @__PURE__ */ React.createElement("box", { flexGrow: 1, border: true, borderStyle: "rounded", borderColor: theme.border, flexDirection: "column", overflow: "hidden" }))));
|
|
2728
2828
|
}
|
|
2829
|
+
|
|
2830
|
+
// demos/index.tsx
|
|
2729
2831
|
var demos = [
|
|
2730
|
-
{ name: "gradient", app: () => /* @__PURE__ */
|
|
2731
|
-
{ name: "ascii", app: () => /* @__PURE__ */
|
|
2732
|
-
{ name: "table", app: () => /* @__PURE__ */
|
|
2733
|
-
{ name: "spinner", app: () => /* @__PURE__ */
|
|
2734
|
-
{ name: "select-input", app: () => /* @__PURE__ */
|
|
2735
|
-
{ name: "multi-select", app: () => /* @__PURE__ */
|
|
2736
|
-
{ name: "prompt-input", app: () => /* @__PURE__ */
|
|
2737
|
-
{ name: "text-input", app: () => /* @__PURE__ */
|
|
2738
|
-
{ name: "link", app: () => /* @__PURE__ */
|
|
2739
|
-
{ name: "tabs", app: () => /* @__PURE__ */
|
|
2740
|
-
{ name: "status-bar", app: () => /* @__PURE__ */
|
|
2741
|
-
{ name: "modal", app: () => /* @__PURE__ */
|
|
2742
|
-
{ name: "primitives", app: () => /* @__PURE__ */
|
|
2743
|
-
{ name: "chat", app: () => /* @__PURE__ */
|
|
2744
|
-
{ name: "chain-of-thought", app: () => /* @__PURE__ */
|
|
2745
|
-
{ name: "message", app: () => /* @__PURE__ */
|
|
2746
|
-
{ name: "terminal-window", app: () => /* @__PURE__ */
|
|
2747
|
-
{ name: "
|
|
2832
|
+
{ name: "gradient", app: () => /* @__PURE__ */ React.createElement(GradientApp, null) },
|
|
2833
|
+
{ name: "ascii", app: () => /* @__PURE__ */ React.createElement(AsciiApp, null) },
|
|
2834
|
+
{ name: "table", app: () => /* @__PURE__ */ React.createElement(TableApp, null) },
|
|
2835
|
+
{ name: "spinner", app: () => /* @__PURE__ */ React.createElement(SpinnerApp, null) },
|
|
2836
|
+
{ name: "select-input", app: () => /* @__PURE__ */ React.createElement(SelectInputApp, null) },
|
|
2837
|
+
{ name: "multi-select", app: () => /* @__PURE__ */ React.createElement(MultiSelectApp, null) },
|
|
2838
|
+
{ name: "prompt-input", app: () => /* @__PURE__ */ React.createElement(PromptInputApp, null) },
|
|
2839
|
+
{ name: "text-input", app: () => /* @__PURE__ */ React.createElement(TextInputApp, null) },
|
|
2840
|
+
{ name: "link", app: () => /* @__PURE__ */ React.createElement(LinkApp, null) },
|
|
2841
|
+
{ name: "tabs", app: () => /* @__PURE__ */ React.createElement(TabBarApp, null) },
|
|
2842
|
+
{ name: "status-bar", app: () => /* @__PURE__ */ React.createElement(StatusBarApp, null) },
|
|
2843
|
+
{ name: "modal", app: () => /* @__PURE__ */ React.createElement(ModalApp, null) },
|
|
2844
|
+
{ name: "primitives", app: () => /* @__PURE__ */ React.createElement(PrimitivesApp, null) },
|
|
2845
|
+
{ name: "chat", app: () => /* @__PURE__ */ React.createElement(ChatApp, null) },
|
|
2846
|
+
{ name: "chain-of-thought", app: () => /* @__PURE__ */ React.createElement(ChainOfThoughtApp, null) },
|
|
2847
|
+
{ name: "message", app: () => /* @__PURE__ */ React.createElement(MessageApp, null) },
|
|
2848
|
+
{ name: "terminal-window", app: () => /* @__PURE__ */ React.createElement(TerminalWindowApp, null) },
|
|
2849
|
+
{ name: "focus", app: () => /* @__PURE__ */ React.createElement(FocusApp, null) },
|
|
2850
|
+
{ name: "pointer", app: () => /* @__PURE__ */ React.createElement(PointerApp, null) },
|
|
2851
|
+
{ name: "cursor-highlight", app: () => /* @__PURE__ */ React.createElement(CursorHighlightApp, null) },
|
|
2852
|
+
{ name: "text-style", app: () => /* @__PURE__ */ React.createElement(TextStyleApp, null) },
|
|
2853
|
+
{ name: "headless", app: () => /* @__PURE__ */ React.createElement(HeadlessApp, null) },
|
|
2854
|
+
{ name: "theming", app: () => /* @__PURE__ */ React.createElement(ThemingApp, null) },
|
|
2855
|
+
{ name: "landing", app: () => /* @__PURE__ */ React.createElement(LandingApp, { useKeyboard: useKeyboard18 }) }
|
|
2748
2856
|
];
|
|
2749
2857
|
|
|
2750
2858
|
// src/run.tsx
|
|
2751
|
-
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
2752
2859
|
var _renderer;
|
|
2753
2860
|
function DemoShell({ children }) {
|
|
2754
|
-
|
|
2861
|
+
useKeyboard19((event) => {
|
|
2755
2862
|
if (event.name === "q" || event.name === "escape") {
|
|
2756
2863
|
_renderer.destroy();
|
|
2757
2864
|
}
|
|
2758
2865
|
});
|
|
2759
|
-
return /* @__PURE__ */
|
|
2866
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, children);
|
|
2760
2867
|
}
|
|
2761
|
-
async function runDemo(
|
|
2762
|
-
const demo = demos.find((d) => d.name ===
|
|
2868
|
+
async function runDemo(name2) {
|
|
2869
|
+
const demo = demos.find((d) => d.name === name2);
|
|
2763
2870
|
if (!demo) {
|
|
2764
|
-
console.error(`Unknown demo: "${
|
|
2871
|
+
console.error(`Unknown demo: "${name2}"`);
|
|
2765
2872
|
console.error(`Available: ${demos.map((d) => d.name).join(", ")}`);
|
|
2766
2873
|
process.exit(1);
|
|
2767
2874
|
}
|
|
2768
2875
|
_renderer = await createCliRenderer({ exitOnCtrlC: true });
|
|
2769
|
-
createRoot(_renderer).render(/* @__PURE__ */
|
|
2876
|
+
createRoot(_renderer).render(/* @__PURE__ */ React.createElement(DemoShell, null, demo.app()));
|
|
2877
|
+
}
|
|
2878
|
+
var name = process.argv[2];
|
|
2879
|
+
if (name) {
|
|
2880
|
+
runDemo(name);
|
|
2770
2881
|
}
|
|
2771
2882
|
export {
|
|
2772
2883
|
demos,
|