@gridland/demo 0.2.50 → 0.2.52
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 +1583 -1176
- 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,1065 +1762,1418 @@ function useBreakpoints() {
|
|
|
1708
1762
|
};
|
|
1709
1763
|
}
|
|
1710
1764
|
|
|
1711
|
-
//
|
|
1712
|
-
import
|
|
1713
|
-
|
|
1714
|
-
// ../docs/components/landing/about-modal.tsx
|
|
1765
|
+
// demos/gradient.tsx
|
|
1766
|
+
import figlet from "figlet";
|
|
1767
|
+
import ansiShadow from "figlet/importable-fonts/ANSI Shadow.js";
|
|
1715
1768
|
import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1716
|
-
|
|
1769
|
+
figlet.parseFont("ANSI Shadow", ansiShadow);
|
|
1770
|
+
var art = figlet.textSync("gridland", { font: "ANSI Shadow" });
|
|
1771
|
+
var lines = art.split("\n").filter((l) => l.trimEnd().length > 0);
|
|
1772
|
+
var gradientNames = Object.keys(GRADIENTS);
|
|
1773
|
+
function GradientApp() {
|
|
1717
1774
|
const theme = useTheme();
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
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
|
-
] }) });
|
|
1775
|
+
const [index, setIndex] = useState8(gradientNames.indexOf("instagram"));
|
|
1776
|
+
const name2 = gradientNames[index];
|
|
1777
|
+
useKeyboard((event) => {
|
|
1778
|
+
if (event.name === "left") setIndex((i) => i > 0 ? i - 1 : gradientNames.length - 1);
|
|
1779
|
+
if (event.name === "right") setIndex((i) => i < gradientNames.length - 1 ? i + 1 : 0);
|
|
1780
|
+
});
|
|
1781
|
+
return /* @__PURE__ */ jsxs15("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
1782
|
+
/* @__PURE__ */ jsx21("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: /* @__PURE__ */ jsx21(Gradient, { name: name2, children: lines.join("\n") }) }),
|
|
1783
|
+
/* @__PURE__ */ jsx21("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx21(
|
|
1784
|
+
StatusBar,
|
|
1785
|
+
{
|
|
1786
|
+
items: [{ key: "\u2190\u2192", label: "gradient" }],
|
|
1787
|
+
extra: /* @__PURE__ */ jsx21("span", { style: textStyle({ fg: theme.accent, bold: true }), children: name2.padEnd(11) })
|
|
1788
|
+
}
|
|
1789
|
+
) })
|
|
1790
|
+
] });
|
|
1762
1791
|
}
|
|
1763
1792
|
|
|
1764
|
-
//
|
|
1793
|
+
// demos/ascii.tsx
|
|
1794
|
+
import { useState as useState9 } from "react";
|
|
1795
|
+
import { useKeyboard as useKeyboard2 } from "@gridland/utils";
|
|
1796
|
+
import figlet2 from "figlet";
|
|
1797
|
+
import ansiShadow2 from "figlet/importable-fonts/ANSI Shadow.js";
|
|
1798
|
+
import big from "figlet/importable-fonts/Big.js";
|
|
1799
|
+
import doom from "figlet/importable-fonts/Doom.js";
|
|
1800
|
+
import slant from "figlet/importable-fonts/Slant.js";
|
|
1801
|
+
import speed from "figlet/importable-fonts/Speed.js";
|
|
1802
|
+
import standard from "figlet/importable-fonts/Standard.js";
|
|
1803
|
+
import block from "figlet/importable-fonts/Block.js";
|
|
1804
|
+
import colossal from "figlet/importable-fonts/Colossal.js";
|
|
1765
1805
|
import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
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
|
-
] })
|
|
1782
|
-
}
|
|
1783
|
-
);
|
|
1806
|
+
var fonts = [
|
|
1807
|
+
{ name: "ANSI Shadow", data: ansiShadow2 },
|
|
1808
|
+
{ name: "Standard", data: standard },
|
|
1809
|
+
{ name: "Big", data: big },
|
|
1810
|
+
{ name: "Doom", data: doom },
|
|
1811
|
+
{ name: "Slant", data: slant },
|
|
1812
|
+
{ name: "Speed", data: speed },
|
|
1813
|
+
{ name: "Block", data: block },
|
|
1814
|
+
{ name: "Colossal", data: colossal }
|
|
1815
|
+
];
|
|
1816
|
+
for (const f of fonts) {
|
|
1817
|
+
figlet2.parseFont(f.name, f.data);
|
|
1784
1818
|
}
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
function
|
|
1819
|
+
function getLines(fontName) {
|
|
1820
|
+
const art2 = figlet2.textSync("gridland", { font: fontName });
|
|
1821
|
+
return art2.split("\n").filter((l) => l.trimEnd().length > 0);
|
|
1822
|
+
}
|
|
1823
|
+
function AsciiApp() {
|
|
1790
1824
|
const theme = useTheme();
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
/* @__PURE__ */
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
);
|
|
1825
|
+
const [fontIndex, setFontIndex] = useState9(fonts.findIndex((f) => f.name === "Colossal"));
|
|
1826
|
+
const font = fonts[fontIndex];
|
|
1827
|
+
const lines2 = getLines(font.name);
|
|
1828
|
+
useKeyboard2((event) => {
|
|
1829
|
+
if (event.name === "left") setFontIndex((i) => i > 0 ? i - 1 : fonts.length - 1);
|
|
1830
|
+
if (event.name === "right") setFontIndex((i) => i < fonts.length - 1 ? i + 1 : 0);
|
|
1831
|
+
});
|
|
1832
|
+
return /* @__PURE__ */ jsxs16("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
1833
|
+
/* @__PURE__ */ jsx22("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: lines2.map((line, i) => /* @__PURE__ */ jsx22("text", { fg: theme.accent, bold: true, children: line }, i)) }),
|
|
1834
|
+
/* @__PURE__ */ jsx22("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx22(
|
|
1835
|
+
StatusBar,
|
|
1836
|
+
{
|
|
1837
|
+
items: [{ key: "\u2190\u2192", label: "change font" }],
|
|
1838
|
+
extra: /* @__PURE__ */ jsx22("span", { style: textStyle({ fg: theme.accent, bold: true }), children: font.name.padEnd(11) })
|
|
1839
|
+
}
|
|
1840
|
+
) })
|
|
1841
|
+
] });
|
|
1809
1842
|
}
|
|
1810
1843
|
|
|
1811
|
-
//
|
|
1812
|
-
import {
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1844
|
+
// demos/table.tsx
|
|
1845
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
1846
|
+
function TableApp() {
|
|
1847
|
+
const data2 = [
|
|
1848
|
+
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
1849
|
+
{ name: "Bob", role: "Designer", status: "Active" },
|
|
1850
|
+
{ name: "Charlie", role: "PM", status: "Away" }
|
|
1851
|
+
];
|
|
1852
|
+
return /* @__PURE__ */ jsx23("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx23(Table, { data: data2, headerColor: "cyan", borderColor: "#5e81ac" }) });
|
|
1819
1853
|
}
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
function
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
if (!isBrowser) return;
|
|
1830
|
-
let raf;
|
|
1831
|
-
const tick = (time) => {
|
|
1832
|
-
if (startTime.current === null) startTime.current = time;
|
|
1833
|
-
const elapsed = time - startTime.current;
|
|
1834
|
-
const t = Math.min(1, elapsed / duration);
|
|
1835
|
-
const eased = 1 - Math.pow(1 - t, 3);
|
|
1836
|
-
setProgress(eased);
|
|
1837
|
-
if (t < 1) raf = requestAnimationFrame(tick);
|
|
1838
|
-
};
|
|
1839
|
-
raf = requestAnimationFrame(tick);
|
|
1840
|
-
return () => cancelAnimationFrame(raf);
|
|
1841
|
-
}, []);
|
|
1842
|
-
return progress;
|
|
1854
|
+
|
|
1855
|
+
// demos/spinner.tsx
|
|
1856
|
+
import { useKeyboard as useKeyboard3 } from "@gridland/utils";
|
|
1857
|
+
import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1858
|
+
function SpinnerApp() {
|
|
1859
|
+
return /* @__PURE__ */ jsxs17("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
1860
|
+
/* @__PURE__ */ jsx24("box", { flexGrow: 1, children: /* @__PURE__ */ jsx24(SpinnerPicker, { useKeyboard: useKeyboard3 }) }),
|
|
1861
|
+
/* @__PURE__ */ jsx24("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx24(StatusBar, { items: [{ key: "\u2190\u2192", label: "change variant" }] }) })
|
|
1862
|
+
] });
|
|
1843
1863
|
}
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
} else {
|
|
1863
|
-
if (current) {
|
|
1864
|
-
runs.push(current);
|
|
1865
|
-
current = null;
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1864
|
+
|
|
1865
|
+
// demos/select-input.tsx
|
|
1866
|
+
import { useState as useState10 } from "react";
|
|
1867
|
+
import { useKeyboard as useKeyboard4 } from "@gridland/utils";
|
|
1868
|
+
import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1869
|
+
var items = [
|
|
1870
|
+
{ label: "TypeScript", value: "ts" },
|
|
1871
|
+
{ label: "JavaScript", value: "js" },
|
|
1872
|
+
{ label: "Python", value: "py" },
|
|
1873
|
+
{ label: "Rust", value: "rs" }
|
|
1874
|
+
];
|
|
1875
|
+
function SelectInputApp() {
|
|
1876
|
+
const [submitted, setSubmitted] = useState10(false);
|
|
1877
|
+
const [resetKey, setResetKey] = useState10(0);
|
|
1878
|
+
useKeyboard4((event) => {
|
|
1879
|
+
if (submitted && event.name === "r") {
|
|
1880
|
+
setSubmitted(false);
|
|
1881
|
+
setResetKey((k) => k + 1);
|
|
1868
1882
|
}
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1883
|
+
});
|
|
1884
|
+
return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
1885
|
+
/* @__PURE__ */ jsx25("box", { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx25(
|
|
1886
|
+
SelectInput,
|
|
1872
1887
|
{
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
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
|
-
)) })
|
|
1888
|
+
items,
|
|
1889
|
+
title: "Choose a language",
|
|
1890
|
+
useKeyboard: useKeyboard4,
|
|
1891
|
+
onSubmit: () => setSubmitted(true)
|
|
1885
1892
|
},
|
|
1886
|
-
|
|
1887
|
-
))
|
|
1888
|
-
|
|
1889
|
-
}
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
const progress = useAnimation(900);
|
|
1893
|
-
const artHeight = compact ? 1 : narrow ? ART_HEIGHT * 2 : ART_HEIGHT;
|
|
1894
|
-
const dropOffset = Math.round((1 - progress) * -artHeight);
|
|
1895
|
-
const revealProgress = Math.max(0, Math.min(1, (progress - 0.1) / 0.7));
|
|
1896
|
-
const maxWidth = compact ? 8 : narrow ? 40 : 62;
|
|
1897
|
-
const revealCol = Math.round(revealProgress * (maxWidth + 4)) - 2;
|
|
1898
|
-
const taglineOpacity = Math.max(0, Math.min(1, (progress - 0.7) / 0.3));
|
|
1899
|
-
const subtitle = /* @__PURE__ */ jsxs18(Fragment7, { children: [
|
|
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
|
-
] });
|
|
1907
|
-
if (!isBrowser) {
|
|
1908
|
-
const art = compact ? "gridland" : narrow ? gridArt + "\n" + landArt : fullArt;
|
|
1909
|
-
return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexShrink: 0, width: "100%", alignItems: "center", children: [
|
|
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
|
-
] });
|
|
1918
|
-
}
|
|
1919
|
-
if (compact) {
|
|
1920
|
-
return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
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
|
-
] });
|
|
1924
|
-
}
|
|
1925
|
-
if (narrow) {
|
|
1926
|
-
return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
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
|
-
] });
|
|
1933
|
-
}
|
|
1934
|
-
return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
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
|
|
1893
|
+
resetKey
|
|
1894
|
+
) }),
|
|
1895
|
+
/* @__PURE__ */ jsx25(StatusBar, { items: submitted ? [{ key: "r", label: "reset demo" }] : [
|
|
1896
|
+
{ key: "\u2191\u2193", label: "select" },
|
|
1897
|
+
{ key: "enter", label: "submit" }
|
|
1898
|
+
] })
|
|
1937
1899
|
] });
|
|
1938
1900
|
}
|
|
1939
1901
|
|
|
1940
|
-
//
|
|
1941
|
-
import {
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
}
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
}
|
|
1958
|
-
function buildGrid(columns, width, height) {
|
|
1959
|
-
const grid = Array.from({ length: height }, () => Array(width).fill(" "));
|
|
1960
|
-
const brightness = Array.from({ length: height }, () => Array(width).fill(0));
|
|
1961
|
-
for (let x = 0; x < width; x++) {
|
|
1962
|
-
const drop = columns[x];
|
|
1963
|
-
if (!drop) continue;
|
|
1964
|
-
for (let i = 0; i < drop.length; i++) {
|
|
1965
|
-
const row = Math.floor(drop.y) - i;
|
|
1966
|
-
if (row < 0 || row >= height) continue;
|
|
1967
|
-
grid[row][x] = drop.chars[i];
|
|
1968
|
-
if (i === 0) {
|
|
1969
|
-
brightness[row][x] = 1;
|
|
1970
|
-
} else {
|
|
1971
|
-
brightness[row][x] = Math.max(0.15, 1 - i / drop.length);
|
|
1972
|
-
}
|
|
1902
|
+
// demos/multi-select.tsx
|
|
1903
|
+
import { useState as useState11 } from "react";
|
|
1904
|
+
import { useKeyboard as useKeyboard5 } from "@gridland/utils";
|
|
1905
|
+
import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1906
|
+
var items2 = [
|
|
1907
|
+
{ label: "TypeScript", value: "ts" },
|
|
1908
|
+
{ label: "JavaScript", value: "js" },
|
|
1909
|
+
{ label: "Python", value: "py" },
|
|
1910
|
+
{ label: "Rust", value: "rs" }
|
|
1911
|
+
];
|
|
1912
|
+
function MultiSelectApp() {
|
|
1913
|
+
const [submitted, setSubmitted] = useState11(false);
|
|
1914
|
+
const [resetKey, setResetKey] = useState11(0);
|
|
1915
|
+
useKeyboard5((event) => {
|
|
1916
|
+
if (submitted && event.name === "r") {
|
|
1917
|
+
setSubmitted(false);
|
|
1918
|
+
setResetKey((k) => k + 1);
|
|
1973
1919
|
}
|
|
1974
|
-
}
|
|
1975
|
-
return { grid, brightness };
|
|
1976
|
-
}
|
|
1977
|
-
function useMatrix(width, height) {
|
|
1978
|
-
const columnsRef = useRef6([]);
|
|
1979
|
-
const [state, setState] = useState9(() => {
|
|
1980
|
-
const columns = Array.from(
|
|
1981
|
-
{ length: width },
|
|
1982
|
-
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
1983
|
-
);
|
|
1984
|
-
columnsRef.current = columns;
|
|
1985
|
-
return buildGrid(columns, width, height);
|
|
1986
1920
|
});
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
columns[x] = null;
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
setState(buildGrid(columns, width, height));
|
|
2009
|
-
}, 80);
|
|
2010
|
-
return () => clearInterval(id);
|
|
2011
|
-
}, [width, height]);
|
|
2012
|
-
useEffect4(() => {
|
|
2013
|
-
columnsRef.current = Array.from(
|
|
2014
|
-
{ length: width },
|
|
2015
|
-
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
2016
|
-
);
|
|
2017
|
-
setState(buildGrid(columnsRef.current, width, height));
|
|
2018
|
-
}, [width, height]);
|
|
2019
|
-
return state;
|
|
1921
|
+
return /* @__PURE__ */ jsxs19("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
1922
|
+
/* @__PURE__ */ jsx26("box", { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx26(
|
|
1923
|
+
MultiSelect,
|
|
1924
|
+
{
|
|
1925
|
+
items: items2,
|
|
1926
|
+
title: "Select languages",
|
|
1927
|
+
useKeyboard: useKeyboard5,
|
|
1928
|
+
onSubmit: () => setSubmitted(true)
|
|
1929
|
+
},
|
|
1930
|
+
resetKey
|
|
1931
|
+
) }),
|
|
1932
|
+
/* @__PURE__ */ jsx26(StatusBar, { items: submitted ? [{ key: "r", label: "reset demo" }] : [
|
|
1933
|
+
{ key: "\u2191\u2193", label: "move" },
|
|
1934
|
+
{ key: "enter", label: "select" },
|
|
1935
|
+
{ key: "a", label: "all" },
|
|
1936
|
+
{ key: "x", label: "clear" }
|
|
1937
|
+
] })
|
|
1938
|
+
] });
|
|
2020
1939
|
}
|
|
2021
1940
|
|
|
2022
|
-
//
|
|
2023
|
-
import {
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
function colorForCell(mutedColors, b) {
|
|
2035
|
-
if (b >= 1) return mutedColors[4];
|
|
2036
|
-
const idx = Math.min(Math.floor(b * (MUTE_LEVELS.length - 1)), MUTE_LEVELS.length - 2);
|
|
2037
|
-
return mutedColors[idx];
|
|
2038
|
-
}
|
|
2039
|
-
function MatrixBackground({ width, height, clearRect, clearRects }) {
|
|
2040
|
-
const { grid, brightness } = useMatrix(width, height);
|
|
1941
|
+
// demos/prompt-input.tsx
|
|
1942
|
+
import { useState as useState12 } from "react";
|
|
1943
|
+
import { useKeyboard as useKeyboard6 } from "@gridland/utils";
|
|
1944
|
+
import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1945
|
+
var commands = [{ cmd: "/model", desc: "Switch model" }];
|
|
1946
|
+
var files = ["src/index.ts", "src/routes.ts", "src/auth.ts", "package.json"];
|
|
1947
|
+
var models = [
|
|
1948
|
+
{ label: "Claude Opus", value: "opus" },
|
|
1949
|
+
{ label: "Claude Sonnet", value: "sonnet" },
|
|
1950
|
+
{ label: "Claude Haiku", value: "haiku" }
|
|
1951
|
+
];
|
|
1952
|
+
function PromptInputApp() {
|
|
2041
1953
|
const theme = useTheme();
|
|
2042
|
-
const
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
);
|
|
2046
|
-
const
|
|
2047
|
-
(
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
const inClearRect = clearRect && y >= clearRect.top && y < clearRect.top + clearRect.height && x >= clearRect.left && x < clearRect.left + clearRect.width || clearRects && clearRects.some(
|
|
2052
|
-
(r) => y >= r.top && y < r.top + r.height && x >= r.left && x < r.left + r.width
|
|
2053
|
-
);
|
|
2054
|
-
const mutedColors = columnMutedColors[x];
|
|
2055
|
-
if (cell === " " || inClearRect || !mutedColors) {
|
|
2056
|
-
return /* @__PURE__ */ jsx25("span", { children: " " }, x);
|
|
1954
|
+
const [lastMessage, setLastMessage] = useState12("");
|
|
1955
|
+
const [model, setModel] = useState12("opus");
|
|
1956
|
+
const [showModelPicker, setShowModelPicker] = useState12(false);
|
|
1957
|
+
const [resetKey, setResetKey] = useState12(0);
|
|
1958
|
+
const handleSubmit = (msg) => {
|
|
1959
|
+
if (msg.text === "/model") {
|
|
1960
|
+
setShowModelPicker(true);
|
|
1961
|
+
setResetKey((k) => k + 1);
|
|
1962
|
+
return;
|
|
2057
1963
|
}
|
|
2058
|
-
|
|
2059
|
-
|
|
1964
|
+
setLastMessage(msg.text);
|
|
1965
|
+
};
|
|
1966
|
+
if (showModelPicker) {
|
|
1967
|
+
return /* @__PURE__ */ jsx27("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: /* @__PURE__ */ jsx27(Modal, { title: "Select Model", useKeyboard: useKeyboard6, onClose: () => setShowModelPicker(false), children: /* @__PURE__ */ jsx27("box", { paddingX: 1, children: /* @__PURE__ */ jsx27(
|
|
1968
|
+
SelectInput,
|
|
2060
1969
|
{
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
1970
|
+
items: models,
|
|
1971
|
+
defaultValue: model,
|
|
1972
|
+
useKeyboard: useKeyboard6,
|
|
1973
|
+
onSubmit: (value) => {
|
|
1974
|
+
setModel(value);
|
|
1975
|
+
setShowModelPicker(false);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
) }) }) });
|
|
1979
|
+
}
|
|
1980
|
+
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
1981
|
+
/* @__PURE__ */ jsx27("box", { flexDirection: "column", flexGrow: 1, children: lastMessage ? /* @__PURE__ */ jsxs20("text", { children: [
|
|
1982
|
+
/* @__PURE__ */ jsx27("span", { style: textStyle({ fg: theme.muted }), children: "Sent: " }),
|
|
1983
|
+
/* @__PURE__ */ jsx27("span", { style: textStyle({ fg: theme.foreground }), children: lastMessage })
|
|
1984
|
+
] }) : /* @__PURE__ */ jsx27("text", { children: /* @__PURE__ */ jsx27("span", { children: " " }) }) }),
|
|
1985
|
+
/* @__PURE__ */ jsx27(
|
|
1986
|
+
PromptInput,
|
|
1987
|
+
{
|
|
1988
|
+
commands,
|
|
1989
|
+
files,
|
|
1990
|
+
placeholder: "Message Claude...",
|
|
1991
|
+
showDividers: true,
|
|
1992
|
+
useKeyboard: useKeyboard6,
|
|
1993
|
+
onSubmit: handleSubmit
|
|
2065
1994
|
},
|
|
2066
|
-
|
|
2067
|
-
)
|
|
2068
|
-
|
|
1995
|
+
resetKey
|
|
1996
|
+
),
|
|
1997
|
+
/* @__PURE__ */ jsx27("box", { children: /* @__PURE__ */ jsx27("text", { children: /* @__PURE__ */ jsx27("span", { style: textStyle({ dim: true }), children: "model: " + model }) }) }),
|
|
1998
|
+
/* @__PURE__ */ jsx27("box", { paddingTop: 1, paddingLeft: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx27(StatusBar, { items: [
|
|
1999
|
+
{ key: "\u23CE enter", label: "send" },
|
|
2000
|
+
{ key: "/model", label: "change model" },
|
|
2001
|
+
{ key: "\u2191", label: "history" }
|
|
2002
|
+
] }) })
|
|
2003
|
+
] });
|
|
2069
2004
|
}
|
|
2070
2005
|
|
|
2071
|
-
//
|
|
2072
|
-
import {
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2006
|
+
// demos/text-input.tsx
|
|
2007
|
+
import { useState as useState13 } from "react";
|
|
2008
|
+
import { useKeyboard as useKeyboard7 } from "@gridland/utils";
|
|
2009
|
+
import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2010
|
+
var FIELDS = [
|
|
2011
|
+
{ label: "Username", placeholder: "enter your name", maxLength: 30, required: true },
|
|
2012
|
+
{ label: "Email", placeholder: "user@example.com", maxLength: 50, required: true, description: "We'll never share your email" },
|
|
2013
|
+
{ label: "Password", placeholder: "enter password", maxLength: 40 },
|
|
2014
|
+
{ label: "API Key", placeholder: "sk-...", maxLength: 60, disabled: true }
|
|
2079
2015
|
];
|
|
2080
|
-
function
|
|
2016
|
+
function TextInputApp() {
|
|
2017
|
+
const [activeField, setActiveField] = useState13(0);
|
|
2018
|
+
const [values, setValues] = useState13(FIELDS.map(() => ""));
|
|
2019
|
+
useKeyboard7((event) => {
|
|
2020
|
+
if (event.name === "up") setActiveField((i) => Math.max(0, i - 1));
|
|
2021
|
+
if (event.name === "down") setActiveField((i) => Math.min(FIELDS.length - 1, i + 1));
|
|
2022
|
+
});
|
|
2023
|
+
return /* @__PURE__ */ jsxs21("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2024
|
+
/* @__PURE__ */ jsx28("box", { flexDirection: "column", paddingX: 1, paddingTop: 1, flexGrow: 1, children: FIELDS.map((field, i) => /* @__PURE__ */ jsx28("box", { marginBottom: 1, children: /* @__PURE__ */ jsx28(
|
|
2025
|
+
TextInput,
|
|
2026
|
+
{
|
|
2027
|
+
label: field.label,
|
|
2028
|
+
placeholder: field.placeholder,
|
|
2029
|
+
prompt: "> ",
|
|
2030
|
+
focus: i === activeField,
|
|
2031
|
+
maxLength: field.maxLength,
|
|
2032
|
+
value: values[i],
|
|
2033
|
+
onChange: (v) => setValues((prev) => prev.map((old, j) => j === i ? v : old)),
|
|
2034
|
+
required: field.required,
|
|
2035
|
+
disabled: field.disabled,
|
|
2036
|
+
description: field.description
|
|
2037
|
+
}
|
|
2038
|
+
) }, field.label)) }),
|
|
2039
|
+
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "\u2191\u2193", label: "field" }] }) })
|
|
2040
|
+
] });
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
// demos/link.tsx
|
|
2044
|
+
import { useState as useState14 } from "react";
|
|
2045
|
+
import { useKeyboard as useKeyboard8 } from "@gridland/utils";
|
|
2046
|
+
import { jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2047
|
+
var MODES = ["solid", "dashed", "dotted", "none"];
|
|
2048
|
+
function LinkApp() {
|
|
2081
2049
|
const theme = useTheme();
|
|
2082
|
-
const
|
|
2083
|
-
const
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
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
|
-
}
|
|
2050
|
+
const [modeIndex, setModeIndex] = useState14(0);
|
|
2051
|
+
const mode = MODES[modeIndex];
|
|
2052
|
+
useKeyboard8((event) => {
|
|
2053
|
+
if (event.name === "right") setModeIndex((i) => (i + 1) % MODES.length);
|
|
2054
|
+
if (event.name === "left") setModeIndex((i) => (i - 1 + MODES.length) % MODES.length);
|
|
2106
2055
|
});
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
/* @__PURE__ */
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
const installLinksClearRect = { top: installLinksTop, left: 1, width: width - 2, height: installLinksHeight };
|
|
2123
|
-
return /* @__PURE__ */ jsxs19("box", { width: "100%", height: "100%", position: "relative", children: [
|
|
2124
|
-
/* @__PURE__ */ jsx26(MatrixBackground, { width, height, clearRect, clearRects: [installLinksClearRect] }),
|
|
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
|
-
] })
|
|
2056
|
+
return /* @__PURE__ */ jsxs22("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2057
|
+
/* @__PURE__ */ jsx29("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsxs22("text", { style: textStyle({ fg: theme.foreground }), children: [
|
|
2058
|
+
"Made by ",
|
|
2059
|
+
/* @__PURE__ */ jsx29("a", { href: "https://cjroth.com", style: { attributes: mode === "solid" ? 8 : mode === "dashed" ? 24 : mode === "dotted" ? 72 : 0, fg: theme.accent }, children: "Chris Roth" }),
|
|
2060
|
+
" and ",
|
|
2061
|
+
/* @__PURE__ */ jsx29("a", { href: "https://jessicacheng.studio", style: { attributes: mode === "solid" ? 8 : mode === "dashed" ? 24 : mode === "dotted" ? 72 : 0, fg: theme.accent }, children: "Jessica Cheng" }),
|
|
2062
|
+
"."
|
|
2063
|
+
] }) }),
|
|
2064
|
+
/* @__PURE__ */ jsx29("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx29(
|
|
2065
|
+
StatusBar,
|
|
2066
|
+
{
|
|
2067
|
+
extra: /* @__PURE__ */ jsx29("span", { style: textStyle({ bold: true, fg: theme.foreground }), children: mode.padEnd(6) }),
|
|
2068
|
+
items: [{ key: "\u2190\u2192", label: "underline style" }]
|
|
2069
|
+
}
|
|
2070
|
+
) })
|
|
2144
2071
|
] });
|
|
2145
2072
|
}
|
|
2146
2073
|
|
|
2147
|
-
//
|
|
2148
|
-
import {
|
|
2074
|
+
// demos/tabs.tsx
|
|
2075
|
+
import { useState as useState15 } from "react";
|
|
2076
|
+
import { useKeyboard as useKeyboard9 } from "@gridland/utils";
|
|
2077
|
+
import { jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2078
|
+
var tabs = ["Files", "Search", "Git", "Debug"];
|
|
2079
|
+
function TabBarApp() {
|
|
2080
|
+
const [selectedIndex, setSelectedIndex] = useState15(0);
|
|
2081
|
+
useKeyboard9((event) => {
|
|
2082
|
+
if (event.name === "left") setSelectedIndex((i) => i > 0 ? i - 1 : tabs.length - 1);
|
|
2083
|
+
if (event.name === "right") setSelectedIndex((i) => i < tabs.length - 1 ? i + 1 : 0);
|
|
2084
|
+
});
|
|
2085
|
+
return /* @__PURE__ */ jsxs23("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2086
|
+
/* @__PURE__ */ jsx30("box", { padding: 1, children: /* @__PURE__ */ jsx30(TabBar, { options: tabs, selectedIndex }) }),
|
|
2087
|
+
/* @__PURE__ */ jsx30("box", { flexGrow: 1 }),
|
|
2088
|
+
/* @__PURE__ */ jsx30("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx30(StatusBar, { items: [{ key: "\u2190\u2192", label: "switch tab" }] }) })
|
|
2089
|
+
] });
|
|
2090
|
+
}
|
|
2149
2091
|
|
|
2150
|
-
//
|
|
2151
|
-
import
|
|
2152
|
-
import
|
|
2153
|
-
import
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
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 }
|
|
2092
|
+
// demos/status-bar.tsx
|
|
2093
|
+
import { useState as useState16 } from "react";
|
|
2094
|
+
import { useKeyboard as useKeyboard10 } from "@gridland/utils";
|
|
2095
|
+
import { jsx as jsx31, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2096
|
+
var shortcuts = [
|
|
2097
|
+
{ key: "Tab", label: "switch focus" },
|
|
2098
|
+
{ key: "\u2190\u2192", label: "cycle" },
|
|
2099
|
+
{ key: "b", label: "back" },
|
|
2100
|
+
{ key: "z", label: "reset" }
|
|
2170
2101
|
];
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
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);
|
|
2102
|
+
function StatusBarApp() {
|
|
2103
|
+
const theme = useTheme();
|
|
2104
|
+
const [lastKey, setLastKey] = useState16(null);
|
|
2105
|
+
useKeyboard10((event) => {
|
|
2106
|
+
if (event.name === "tab") setLastKey("switch focus (Tab)");
|
|
2107
|
+
else if (event.name === "left") setLastKey("cycle (\u2190)");
|
|
2108
|
+
else if (event.name === "right") setLastKey("cycle (\u2192)");
|
|
2109
|
+
else if (event.name === "b") setLastKey("back (b)");
|
|
2110
|
+
else if (event.name === "z") setLastKey("reset (z)");
|
|
2186
2111
|
});
|
|
2187
|
-
return /* @__PURE__ */
|
|
2188
|
-
/* @__PURE__ */
|
|
2189
|
-
|
|
2112
|
+
return /* @__PURE__ */ jsxs24("box", { flexDirection: "column", gap: 1, padding: 1, children: [
|
|
2113
|
+
lastKey ? /* @__PURE__ */ jsxs24("text", { children: [
|
|
2114
|
+
/* @__PURE__ */ jsx31("span", { children: "Pressed: " }),
|
|
2115
|
+
/* @__PURE__ */ jsx31("span", { style: textStyle({ bold: true, fg: theme.accent }), children: lastKey })
|
|
2116
|
+
] }) : /* @__PURE__ */ jsx31("text", { style: textStyle({ dim: true }), children: "Press a key to trigger an action" }),
|
|
2117
|
+
/* @__PURE__ */ jsx31(
|
|
2190
2118
|
StatusBar,
|
|
2191
2119
|
{
|
|
2192
|
-
items:
|
|
2193
|
-
extra: /* @__PURE__ */
|
|
2120
|
+
items: shortcuts,
|
|
2121
|
+
extra: /* @__PURE__ */ jsx31("span", { style: textStyle({ fg: theme.success }), children: "\u25CF Ready" })
|
|
2194
2122
|
}
|
|
2195
|
-
)
|
|
2123
|
+
)
|
|
2196
2124
|
] });
|
|
2197
2125
|
}
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2126
|
+
|
|
2127
|
+
// demos/modal.tsx
|
|
2128
|
+
import { useState as useState17 } from "react";
|
|
2129
|
+
import { useKeyboard as useKeyboard11 } from "@gridland/utils";
|
|
2130
|
+
import { jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2131
|
+
function ModalApp() {
|
|
2132
|
+
const theme = useTheme();
|
|
2133
|
+
const [isOpen, setIsOpen] = useState17(false);
|
|
2134
|
+
useKeyboard11((event) => {
|
|
2135
|
+
if (!isOpen && event.name === "m") setIsOpen(true);
|
|
2136
|
+
if (isOpen && (event.name === "q" || event.name === "escape")) setIsOpen(false);
|
|
2205
2137
|
});
|
|
2206
|
-
|
|
2207
|
-
/* @__PURE__ */
|
|
2208
|
-
|
|
2209
|
-
|
|
2138
|
+
if (isOpen) {
|
|
2139
|
+
return /* @__PURE__ */ jsxs25("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2140
|
+
/* @__PURE__ */ jsx32(Modal, { title: "Example Modal", useKeyboard: useKeyboard11, onClose: () => setIsOpen(false), children: /* @__PURE__ */ jsxs25("box", { paddingX: 1, flexDirection: "column", children: [
|
|
2141
|
+
/* @__PURE__ */ jsx32("text", { style: textStyle({ fg: theme.foreground }), children: "This is a modal overlay component." }),
|
|
2142
|
+
/* @__PURE__ */ jsx32("text", { children: " " }),
|
|
2143
|
+
/* @__PURE__ */ jsx32("text", { style: textStyle({ dim: true, fg: theme.muted }), children: "It stretches to fill the full terminal height." })
|
|
2144
|
+
] }) }),
|
|
2145
|
+
/* @__PURE__ */ jsx32("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx32(StatusBar, { items: [{ key: "q", label: "close" }] }) })
|
|
2146
|
+
] });
|
|
2147
|
+
}
|
|
2148
|
+
return /* @__PURE__ */ jsx32("box", { flexDirection: "column", flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsxs25("text", { children: [
|
|
2149
|
+
/* @__PURE__ */ jsx32("span", { style: textStyle({ dim: true, fg: theme.muted }), children: "Press " }),
|
|
2150
|
+
/* @__PURE__ */ jsx32("span", { style: textStyle({ bold: true, fg: theme.background, bg: theme.muted }), children: " m " }),
|
|
2151
|
+
/* @__PURE__ */ jsx32("span", { style: textStyle({ dim: true, fg: theme.muted }), children: " to open modal" })
|
|
2152
|
+
] }) });
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
// demos/primitives.tsx
|
|
2156
|
+
import { jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2157
|
+
function PrimitivesApp() {
|
|
2158
|
+
return /* @__PURE__ */ jsxs26("box", { flexDirection: "column", padding: 1, children: [
|
|
2159
|
+
/* @__PURE__ */ jsx33(
|
|
2160
|
+
"box",
|
|
2210
2161
|
{
|
|
2211
|
-
|
|
2212
|
-
|
|
2162
|
+
border: true,
|
|
2163
|
+
borderStyle: "rounded",
|
|
2164
|
+
borderColor: "#75715e",
|
|
2165
|
+
title: "Layout",
|
|
2166
|
+
titleAlignment: "center",
|
|
2167
|
+
padding: 1,
|
|
2168
|
+
children: /* @__PURE__ */ jsxs26("box", { flexDirection: "row", gap: 2, children: [
|
|
2169
|
+
/* @__PURE__ */ jsx33("box", { border: true, borderStyle: "single", borderColor: "#a6e22e", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx33("text", { fg: "#a6e22e", bold: true, children: "Box 1" }) }),
|
|
2170
|
+
/* @__PURE__ */ jsx33("box", { border: true, borderStyle: "single", borderColor: "#f92672", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx33("text", { fg: "#f92672", bold: true, children: "Box 2" }) }),
|
|
2171
|
+
/* @__PURE__ */ jsx33("box", { border: true, borderStyle: "single", borderColor: "#66d9ef", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx33("text", { fg: "#66d9ef", bold: true, children: "Box 3" }) })
|
|
2172
|
+
] })
|
|
2213
2173
|
}
|
|
2214
|
-
)
|
|
2174
|
+
),
|
|
2175
|
+
/* @__PURE__ */ jsx33("text", { dim: true, fg: "#75715e", children: " Nested boxes with borders, colors & flexbox layout" })
|
|
2215
2176
|
] });
|
|
2216
2177
|
}
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2178
|
+
|
|
2179
|
+
// demos/chat.tsx
|
|
2180
|
+
import { useState as useState18, useCallback as useCallback3, useRef as useRef5 } from "react";
|
|
2181
|
+
import { useKeyboard as useKeyboard12 } from "@gridland/utils";
|
|
2182
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
2183
|
+
var initialMessages = [
|
|
2184
|
+
{ id: "1", role: "user", content: "Show me my portfolio" },
|
|
2185
|
+
{ id: "2", role: "assistant", content: "Here's your current portfolio allocation:" },
|
|
2186
|
+
{ id: "3", role: "user", content: "Calculate rebalancing trades" },
|
|
2187
|
+
{ id: "4", role: "assistant", content: "I've calculated the optimal trades to rebalance your portfolio." }
|
|
2188
|
+
];
|
|
2189
|
+
var nextId = 5;
|
|
2190
|
+
function ChatApp() {
|
|
2191
|
+
const [messages, setMessages] = useState18(initialMessages);
|
|
2192
|
+
const [isLoading, setIsLoading] = useState18(false);
|
|
2193
|
+
const [streamingText, setStreamingText] = useState18("");
|
|
2194
|
+
const [activeToolCalls, setActiveToolCalls] = useState18([]);
|
|
2195
|
+
const intervalRef = useRef5(null);
|
|
2196
|
+
const handleSend = useCallback3((text) => {
|
|
2197
|
+
const userMsg = { id: String(nextId++), role: "user", content: text };
|
|
2198
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
2199
|
+
setIsLoading(true);
|
|
2200
|
+
const toolCallId = `tc-${nextId}`;
|
|
2201
|
+
setTimeout(() => {
|
|
2202
|
+
setIsLoading(false);
|
|
2203
|
+
setActiveToolCalls([{ id: toolCallId, title: "process_request", status: "in_progress" }]);
|
|
2204
|
+
}, 500);
|
|
2205
|
+
setTimeout(() => {
|
|
2206
|
+
setActiveToolCalls([{ id: toolCallId, title: "process_request", status: "completed" }]);
|
|
2207
|
+
}, 1200);
|
|
2208
|
+
const response = `You said: "${text}". This is a demo response.`;
|
|
2209
|
+
let charIndex = 0;
|
|
2210
|
+
setTimeout(() => {
|
|
2211
|
+
intervalRef.current = setInterval(() => {
|
|
2212
|
+
charIndex = Math.min(charIndex + 3, response.length);
|
|
2213
|
+
if (charIndex < response.length) {
|
|
2214
|
+
setStreamingText(response.slice(0, charIndex));
|
|
2215
|
+
} else {
|
|
2216
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
2217
|
+
setStreamingText("");
|
|
2218
|
+
setActiveToolCalls([]);
|
|
2219
|
+
setMessages((prev) => [
|
|
2220
|
+
...prev,
|
|
2221
|
+
{ id: String(nextId++), role: "assistant", content: response }
|
|
2222
|
+
]);
|
|
2223
|
+
}
|
|
2224
|
+
}, 50);
|
|
2225
|
+
}, 1400);
|
|
2226
|
+
}, []);
|
|
2227
|
+
const handleCancel = useCallback3(() => {
|
|
2228
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
2229
|
+
setIsLoading(false);
|
|
2230
|
+
setStreamingText("");
|
|
2231
|
+
setActiveToolCalls([]);
|
|
2232
|
+
}, []);
|
|
2233
|
+
return /* @__PURE__ */ jsx34(
|
|
2234
|
+
ChatPanel,
|
|
2235
|
+
{
|
|
2236
|
+
messages,
|
|
2237
|
+
streamingText,
|
|
2238
|
+
isLoading,
|
|
2239
|
+
activeToolCalls,
|
|
2240
|
+
onSendMessage: handleSend,
|
|
2241
|
+
onCancel: handleCancel,
|
|
2242
|
+
placeholder: "Ask about your portfolio...",
|
|
2243
|
+
useKeyboard: useKeyboard12
|
|
2244
|
+
}
|
|
2245
|
+
);
|
|
2227
2246
|
}
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2247
|
+
|
|
2248
|
+
// demos/chain-of-thought.tsx
|
|
2249
|
+
import { useState as useState19, useEffect as useEffect4, useRef as useRef6 } from "react";
|
|
2250
|
+
import { useKeyboard as useKeyboard13 } from "@gridland/utils";
|
|
2251
|
+
import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2252
|
+
var ALL_STEPS = [
|
|
2253
|
+
{ tool: "Read", label: "Reading codebase", description: "src/", status: "done", delay: 1800 },
|
|
2254
|
+
{ tool: "Think", label: "Planning changes", description: "auth module", status: "done", delay: 2500 },
|
|
2255
|
+
{ tool: "Edit", label: "Editing files", description: "4 files", status: "done", delay: 3200 },
|
|
2256
|
+
{ tool: "Bash", label: "Running tests", description: "vitest", status: "done", delay: 2e3 },
|
|
2257
|
+
{ tool: "Edit", label: "Fixing test", description: "routes.test.ts", status: "done", delay: 1500 }
|
|
2258
|
+
];
|
|
2259
|
+
function ChainOfThoughtApp() {
|
|
2260
|
+
const [expanded, setExpanded] = useState19(true);
|
|
2261
|
+
const [phase, setPhase] = useState19("running");
|
|
2262
|
+
const [stepIndex, setStepIndex] = useState19(0);
|
|
2263
|
+
const timerRef = useRef6(null);
|
|
2264
|
+
useKeyboard13((event) => {
|
|
2265
|
+
if (event.name === "E" && event.ctrl && event.shift) setExpanded((v) => !v);
|
|
2266
|
+
if (event.name === "r") restart();
|
|
2267
|
+
});
|
|
2268
|
+
function restart() {
|
|
2269
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2270
|
+
setPhase("running");
|
|
2271
|
+
setStepIndex(0);
|
|
2272
|
+
}
|
|
2273
|
+
useEffect4(() => {
|
|
2274
|
+
if (phase !== "running") return;
|
|
2275
|
+
if (stepIndex < ALL_STEPS.length) {
|
|
2276
|
+
const delay = ALL_STEPS[stepIndex].delay;
|
|
2277
|
+
timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
|
|
2278
|
+
} else {
|
|
2279
|
+
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
2280
|
+
}
|
|
2281
|
+
return () => {
|
|
2282
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2283
|
+
};
|
|
2284
|
+
}, [phase, stepIndex]);
|
|
2285
|
+
useEffect4(() => {
|
|
2286
|
+
if (phase === "done") {
|
|
2287
|
+
timerRef.current = setTimeout(() => restart(), 3e3);
|
|
2288
|
+
}
|
|
2289
|
+
return () => {
|
|
2290
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2291
|
+
};
|
|
2292
|
+
}, [phase]);
|
|
2293
|
+
const steps = ALL_STEPS.map((s, i) => {
|
|
2294
|
+
if (i < stepIndex) return { ...s, status: "done" };
|
|
2295
|
+
if (i === stepIndex && phase === "running") return { ...s, status: "running" };
|
|
2296
|
+
return { ...s, status: phase === "done" ? "done" : "pending" };
|
|
2297
|
+
});
|
|
2298
|
+
const elapsedMs = ALL_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
|
|
2299
|
+
const totalMs = ALL_STEPS.reduce((sum, s) => sum + s.delay, 0);
|
|
2300
|
+
const durationStr = phase === "done" ? `${(totalMs / 1e3).toFixed(1)}s` : `${(elapsedMs / 1e3).toFixed(1)}s`;
|
|
2301
|
+
return /* @__PURE__ */ jsxs27("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2302
|
+
/* @__PURE__ */ jsx35("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsxs27(ChainOfThought, { open: expanded, onOpenChange: setExpanded, children: [
|
|
2303
|
+
/* @__PURE__ */ jsx35(ChainOfThoughtHeader, { duration: durationStr }),
|
|
2304
|
+
/* @__PURE__ */ jsx35(ChainOfThoughtContent, { children: steps.map((step, i) => /* @__PURE__ */ jsx35(
|
|
2305
|
+
ChainOfThoughtStep,
|
|
2306
|
+
{
|
|
2307
|
+
label: step.label,
|
|
2308
|
+
description: step.description,
|
|
2309
|
+
status: step.status,
|
|
2310
|
+
isLast: i === steps.length - 1,
|
|
2311
|
+
children: step.output
|
|
2312
|
+
},
|
|
2313
|
+
i
|
|
2314
|
+
)) })
|
|
2315
|
+
] }) }),
|
|
2316
|
+
/* @__PURE__ */ jsx35("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx35(StatusBar, { items: [
|
|
2317
|
+
{ key: "ctrl+shift+e", label: "toggle" },
|
|
2318
|
+
{ key: "r", label: "restart" }
|
|
2319
|
+
] }) })
|
|
2232
2320
|
] });
|
|
2233
2321
|
}
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
];
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2322
|
+
|
|
2323
|
+
// demos/message.tsx
|
|
2324
|
+
import { useState as useState20, useEffect as useEffect5, useRef as useRef7 } from "react";
|
|
2325
|
+
import { useKeyboard as useKeyboard14 } from "@gridland/utils";
|
|
2326
|
+
import { jsx as jsx36, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2327
|
+
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.";
|
|
2328
|
+
function MessageApp() {
|
|
2329
|
+
const [phase, setPhase] = useState20("idle");
|
|
2330
|
+
const [streamedText, setStreamedText] = useState20("");
|
|
2331
|
+
const timerRef = useRef7(null);
|
|
2332
|
+
useKeyboard14((event) => {
|
|
2333
|
+
if (event.name === "r") restart();
|
|
2334
|
+
});
|
|
2335
|
+
function restart() {
|
|
2336
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2337
|
+
setPhase("idle");
|
|
2338
|
+
setStreamedText("");
|
|
2339
|
+
}
|
|
2340
|
+
useEffect5(() => {
|
|
2341
|
+
if (phase === "idle") {
|
|
2342
|
+
timerRef.current = setTimeout(() => setPhase("streaming"), 800);
|
|
2343
|
+
}
|
|
2344
|
+
return () => {
|
|
2345
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2346
|
+
};
|
|
2347
|
+
}, [phase]);
|
|
2348
|
+
useEffect5(() => {
|
|
2349
|
+
if (phase !== "streaming") return;
|
|
2350
|
+
if (streamedText.length < RESPONSE.length) {
|
|
2351
|
+
timerRef.current = setTimeout(() => {
|
|
2352
|
+
setStreamedText(RESPONSE.slice(0, streamedText.length + 2));
|
|
2353
|
+
}, 25);
|
|
2354
|
+
} else {
|
|
2355
|
+
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
2356
|
+
}
|
|
2357
|
+
return () => {
|
|
2358
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2359
|
+
};
|
|
2360
|
+
}, [phase, streamedText]);
|
|
2361
|
+
useEffect5(() => {
|
|
2362
|
+
if (phase === "done") {
|
|
2363
|
+
timerRef.current = setTimeout(() => restart(), 3e3);
|
|
2364
|
+
}
|
|
2365
|
+
return () => {
|
|
2366
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2367
|
+
};
|
|
2368
|
+
}, [phase]);
|
|
2369
|
+
const isStreaming = phase === "streaming";
|
|
2370
|
+
const isDone = phase === "done";
|
|
2371
|
+
const showAssistant = phase !== "idle";
|
|
2372
|
+
return /* @__PURE__ */ jsxs28("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2373
|
+
/* @__PURE__ */ jsxs28("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1, children: [
|
|
2374
|
+
/* @__PURE__ */ jsx36(Message, { role: "user", children: /* @__PURE__ */ jsx36(Message.Content, { children: /* @__PURE__ */ jsx36(Message.Text, { children: "Can you refactor the auth module?" }) }) }),
|
|
2375
|
+
showAssistant && /* @__PURE__ */ jsx36(Message, { role: "assistant", isStreaming, children: /* @__PURE__ */ jsx36(Message.Content, { children: /* @__PURE__ */ jsx36(Message.Text, { isLast: true, children: isDone ? RESPONSE : streamedText }) }) })
|
|
2376
|
+
] }),
|
|
2377
|
+
/* @__PURE__ */ jsx36("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx36(StatusBar, { items: [{ key: "r", label: "restart" }] }) })
|
|
2249
2378
|
] });
|
|
2250
2379
|
}
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
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
|
-
] }) })
|
|
2380
|
+
|
|
2381
|
+
// demos/terminal-window.tsx
|
|
2382
|
+
import { jsx as jsx37, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2383
|
+
function TerminalWindowApp() {
|
|
2384
|
+
const theme = useTheme();
|
|
2385
|
+
return /* @__PURE__ */ jsxs29("box", { flexDirection: "column", padding: 1, children: [
|
|
2386
|
+
/* @__PURE__ */ jsx37("text", { style: textStyle({ fg: theme.secondary }), children: '$ echo "Hello from TerminalWindow"' }),
|
|
2387
|
+
/* @__PURE__ */ jsx37("text", { style: textStyle({ fg: theme.foreground }), children: "Hello from TerminalWindow" }),
|
|
2388
|
+
/* @__PURE__ */ jsx37("text", { style: textStyle({ fg: theme.secondary }), children: "$ _" })
|
|
2268
2389
|
] });
|
|
2269
2390
|
}
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2391
|
+
|
|
2392
|
+
// demos/focus.tsx
|
|
2393
|
+
import { useState as useState21, useRef as useRef8 } from "react";
|
|
2394
|
+
import { useKeyboard as useKeyboard15 } from "@gridland/utils";
|
|
2395
|
+
import { Fragment as Fragment7, jsx as jsx38, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2396
|
+
var focusPanels = [
|
|
2397
|
+
{
|
|
2398
|
+
label: "Language",
|
|
2399
|
+
items: [
|
|
2400
|
+
{ label: "TypeScript", value: "ts" },
|
|
2401
|
+
{ label: "JavaScript", value: "js" },
|
|
2402
|
+
{ label: "Python", value: "py" }
|
|
2403
|
+
]
|
|
2404
|
+
},
|
|
2405
|
+
{
|
|
2406
|
+
label: "Framework",
|
|
2407
|
+
items: [
|
|
2408
|
+
{ label: "React", value: "react" },
|
|
2409
|
+
{ label: "Vue", value: "vue" },
|
|
2410
|
+
{ label: "Svelte", value: "svelte" }
|
|
2411
|
+
]
|
|
2412
|
+
},
|
|
2413
|
+
{
|
|
2414
|
+
label: "Runtime",
|
|
2415
|
+
items: [
|
|
2416
|
+
{ label: "Bun", value: "bun" },
|
|
2417
|
+
{ label: "Node", value: "node" },
|
|
2418
|
+
{ label: "Deno", value: "deno" }
|
|
2419
|
+
]
|
|
2420
|
+
}
|
|
2421
|
+
];
|
|
2422
|
+
function FocusApp() {
|
|
2423
|
+
const [panelIndex, setPanelIndex] = useState21(0);
|
|
2424
|
+
const [entered, setEntered] = useState21(false);
|
|
2425
|
+
const [cursors, setCursors] = useState21([0, 0, 0]);
|
|
2426
|
+
const [selections, setSelections] = useState21([null, null, null]);
|
|
2427
|
+
const panelRef = useRef8(0);
|
|
2428
|
+
const enteredRef = useRef8(false);
|
|
2429
|
+
const cursorsRef = useRef8([0, 0, 0]);
|
|
2430
|
+
panelRef.current = panelIndex;
|
|
2431
|
+
enteredRef.current = entered;
|
|
2432
|
+
cursorsRef.current = cursors;
|
|
2433
|
+
useKeyboard15((event) => {
|
|
2434
|
+
const pi = panelRef.current;
|
|
2435
|
+
if (enteredRef.current) {
|
|
2436
|
+
const items3 = focusPanels[pi].items;
|
|
2437
|
+
const cur = cursorsRef.current[pi];
|
|
2438
|
+
if (event.name === "down" || event.name === "j") {
|
|
2439
|
+
const next = (cur + 1) % items3.length;
|
|
2440
|
+
cursorsRef.current = [...cursorsRef.current];
|
|
2441
|
+
cursorsRef.current[pi] = next;
|
|
2442
|
+
setCursors([...cursorsRef.current]);
|
|
2443
|
+
} else if (event.name === "up" || event.name === "k") {
|
|
2444
|
+
const next = (cur - 1 + items3.length) % items3.length;
|
|
2445
|
+
cursorsRef.current = [...cursorsRef.current];
|
|
2446
|
+
cursorsRef.current[pi] = next;
|
|
2447
|
+
setCursors([...cursorsRef.current]);
|
|
2448
|
+
} else if (event.name === "return") {
|
|
2449
|
+
const selected = items3[cursorsRef.current[pi]].label;
|
|
2450
|
+
setSelections((s) => {
|
|
2451
|
+
const n = [...s];
|
|
2452
|
+
n[pi] = selected;
|
|
2453
|
+
return n;
|
|
2454
|
+
});
|
|
2455
|
+
enteredRef.current = false;
|
|
2456
|
+
setEntered(false);
|
|
2457
|
+
} else if (event.name === "escape") {
|
|
2458
|
+
enteredRef.current = false;
|
|
2459
|
+
setEntered(false);
|
|
2460
|
+
}
|
|
2461
|
+
} else {
|
|
2462
|
+
if (event.name === "right" || event.name === "tab") {
|
|
2463
|
+
const next = (pi + 1) % focusPanels.length;
|
|
2464
|
+
panelRef.current = next;
|
|
2465
|
+
setPanelIndex(next);
|
|
2466
|
+
} else if (event.name === "left") {
|
|
2467
|
+
const next = (pi - 1 + focusPanels.length) % focusPanels.length;
|
|
2468
|
+
panelRef.current = next;
|
|
2469
|
+
setPanelIndex(next);
|
|
2470
|
+
} else if (event.name === "return") {
|
|
2471
|
+
enteredRef.current = true;
|
|
2472
|
+
setEntered(true);
|
|
2473
|
+
}
|
|
2296
2474
|
}
|
|
2297
|
-
|
|
2298
|
-
};
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2475
|
+
event.preventDefault();
|
|
2476
|
+
});
|
|
2477
|
+
return /* @__PURE__ */ jsxs30("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2478
|
+
/* @__PURE__ */ jsx38("box", { flexDirection: "row", gap: 1, padding: 1, flexGrow: 1, children: focusPanels.map((panel, i) => {
|
|
2479
|
+
const focused = i === panelIndex;
|
|
2480
|
+
const active = focused && entered;
|
|
2481
|
+
const selected = selections[i];
|
|
2482
|
+
return /* @__PURE__ */ jsx38(
|
|
2483
|
+
"box",
|
|
2303
2484
|
{
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
{
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2485
|
+
border: true,
|
|
2486
|
+
borderStyle: "rounded",
|
|
2487
|
+
borderColor: active ? "#22c55e" : focused ? "#3b82f6" : "#555",
|
|
2488
|
+
flexGrow: 1,
|
|
2489
|
+
children: /* @__PURE__ */ jsxs30("box", { flexDirection: "column", padding: 1, children: [
|
|
2490
|
+
/* @__PURE__ */ jsxs30("text", { style: {
|
|
2491
|
+
fg: active ? "#22c55e" : focused ? "#3b82f6" : "#888",
|
|
2492
|
+
bold: focused
|
|
2493
|
+
}, children: [
|
|
2494
|
+
focused ? "\u25B8 " : " ",
|
|
2495
|
+
panel.label,
|
|
2496
|
+
selected ? `: ${selected}` : ""
|
|
2497
|
+
] }),
|
|
2498
|
+
(active || !entered && focused) && /* @__PURE__ */ jsxs30(Fragment7, { children: [
|
|
2499
|
+
/* @__PURE__ */ jsx38("box", { height: 1 }),
|
|
2500
|
+
/* @__PURE__ */ jsx38("box", { flexDirection: "column", children: panel.items.map((item, j) => {
|
|
2501
|
+
const highlighted = active && j === cursors[i];
|
|
2502
|
+
return /* @__PURE__ */ jsxs30("text", { style: {
|
|
2503
|
+
fg: highlighted ? "#22c55e" : active ? "#ccc" : "#666",
|
|
2504
|
+
bold: highlighted
|
|
2505
|
+
}, children: [
|
|
2506
|
+
highlighted ? " \u25B8 " : " ",
|
|
2507
|
+
item.label
|
|
2508
|
+
] }, item.value);
|
|
2509
|
+
}) })
|
|
2510
|
+
] })
|
|
2511
|
+
] })
|
|
2512
|
+
},
|
|
2513
|
+
panel.label
|
|
2514
|
+
);
|
|
2515
|
+
}) }),
|
|
2516
|
+
/* @__PURE__ */ jsx38("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx38(
|
|
2517
|
+
StatusBar,
|
|
2335
2518
|
{
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
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
|
-
] }) })
|
|
2519
|
+
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" }]
|
|
2520
|
+
}
|
|
2521
|
+
) })
|
|
2356
2522
|
] });
|
|
2357
2523
|
}
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
];
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
const [
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2524
|
+
|
|
2525
|
+
// demos/pointer.tsx
|
|
2526
|
+
import { useState as useState22, useRef as useRef9 } from "react";
|
|
2527
|
+
import { useKeyboard as useKeyboard16 } from "@gridland/utils";
|
|
2528
|
+
import { jsx as jsx39, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2529
|
+
var pointerColors = ["#ef4444", "#f97316", "#eab308", "#22c55e", "#3b82f6", "#8b5cf6"];
|
|
2530
|
+
var pointerColorNames = ["Red", "Orange", "Yellow", "Green", "Blue", "Purple"];
|
|
2531
|
+
function HoverBox() {
|
|
2532
|
+
const [hovering, setHovering] = useState22(false);
|
|
2533
|
+
return /* @__PURE__ */ jsx39(
|
|
2534
|
+
"box",
|
|
2535
|
+
{
|
|
2536
|
+
border: true,
|
|
2537
|
+
borderStyle: "rounded",
|
|
2538
|
+
borderColor: hovering ? "#22c55e" : "#555",
|
|
2539
|
+
width: 20,
|
|
2540
|
+
height: 5,
|
|
2541
|
+
onMouseOver: () => setHovering(true),
|
|
2542
|
+
onMouseOut: () => setHovering(false),
|
|
2543
|
+
children: /* @__PURE__ */ jsx39("box", { padding: 1, children: /* @__PURE__ */ jsx39("text", { style: { fg: hovering ? "#22c55e" : "#888", bold: hovering }, children: hovering ? "Mouse inside!" : "Hover me" }) })
|
|
2544
|
+
}
|
|
2545
|
+
);
|
|
2546
|
+
}
|
|
2547
|
+
function PointerApp() {
|
|
2548
|
+
const [selected, setSelected] = useState22(null);
|
|
2549
|
+
const [clickCount, setClickCount] = useState22(0);
|
|
2550
|
+
const [mousePos, setMousePos] = useState22(null);
|
|
2551
|
+
const selectedRef = useRef9(null);
|
|
2552
|
+
const clickCountRef = useRef9(0);
|
|
2553
|
+
selectedRef.current = selected;
|
|
2554
|
+
clickCountRef.current = clickCount;
|
|
2555
|
+
useKeyboard16((event) => {
|
|
2556
|
+
const cur = selectedRef.current ?? -1;
|
|
2557
|
+
if (event.name === "right" || event.name === "tab") {
|
|
2558
|
+
const next = (cur + 1) % pointerColors.length;
|
|
2559
|
+
selectedRef.current = next;
|
|
2560
|
+
setSelected(next);
|
|
2561
|
+
} else if (event.name === "left") {
|
|
2562
|
+
const next = (cur - 1 + pointerColors.length) % pointerColors.length;
|
|
2563
|
+
selectedRef.current = next;
|
|
2564
|
+
setSelected(next);
|
|
2565
|
+
}
|
|
2566
|
+
event.preventDefault();
|
|
2370
2567
|
});
|
|
2371
|
-
return /* @__PURE__ */
|
|
2372
|
-
/* @__PURE__ */
|
|
2373
|
-
|
|
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,
|
|
2568
|
+
return /* @__PURE__ */ jsxs31("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
2569
|
+
/* @__PURE__ */ jsx39("box", { flexDirection: "row", gap: 1, children: pointerColors.map((color, i) => /* @__PURE__ */ jsx39(
|
|
2570
|
+
"box",
|
|
2378
2571
|
{
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2572
|
+
flexGrow: 1,
|
|
2573
|
+
height: 3,
|
|
2574
|
+
border: true,
|
|
2575
|
+
borderStyle: "rounded",
|
|
2576
|
+
borderColor: i === selected ? color : "#555",
|
|
2577
|
+
onMouseDown: (e) => {
|
|
2578
|
+
clickCountRef.current++;
|
|
2579
|
+
setClickCount(clickCountRef.current);
|
|
2580
|
+
selectedRef.current = i;
|
|
2581
|
+
setSelected(i);
|
|
2582
|
+
setMousePos({ x: e.x, y: e.y });
|
|
2583
|
+
},
|
|
2584
|
+
children: /* @__PURE__ */ jsx39("text", { style: { fg: color, bold: i === selected }, children: i === selected ? `\u25B8 ${pointerColorNames[i]}` : ` ${pointerColorNames[i]}` })
|
|
2585
|
+
},
|
|
2586
|
+
color
|
|
2587
|
+
)) }),
|
|
2588
|
+
/* @__PURE__ */ jsx39("box", { height: 1 }),
|
|
2589
|
+
/* @__PURE__ */ jsxs31("box", { flexDirection: "row", gap: 2, children: [
|
|
2590
|
+
/* @__PURE__ */ jsx39(HoverBox, {}),
|
|
2591
|
+
/* @__PURE__ */ jsxs31("box", { flexDirection: "column", flexGrow: 1, paddingTop: 1, children: [
|
|
2592
|
+
/* @__PURE__ */ jsxs31("text", { style: { fg: selected !== null ? pointerColors[selected] : "#888" }, children: [
|
|
2593
|
+
selected !== null ? `Clicked ${pointerColorNames[selected]}` : "Click a color",
|
|
2594
|
+
clickCount > 0 ? ` (${clickCount} clicks)` : ""
|
|
2595
|
+
] }),
|
|
2596
|
+
/* @__PURE__ */ jsx39("text", { style: { dim: true, fg: "#888" }, children: mousePos ? `mouse: ${mousePos.x}, ${mousePos.y}` : "" })
|
|
2597
|
+
] })
|
|
2598
|
+
] }),
|
|
2599
|
+
/* @__PURE__ */ jsx39("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx39(StatusBar, { items: [
|
|
2600
|
+
{ key: "click", label: "select" },
|
|
2601
|
+
{ key: "\u2190\u2192", label: "keyboard nav" }
|
|
2396
2602
|
] }) })
|
|
2397
2603
|
] });
|
|
2398
2604
|
}
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2605
|
+
|
|
2606
|
+
// demos/cursor-highlight.tsx
|
|
2607
|
+
import { useState as useState23 } from "react";
|
|
2608
|
+
import { jsx as jsx40, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2609
|
+
function CursorHighlightApp() {
|
|
2610
|
+
const [pos, setPos] = useState23(null);
|
|
2611
|
+
return /* @__PURE__ */ jsxs32(
|
|
2612
|
+
"box",
|
|
2613
|
+
{
|
|
2614
|
+
flexDirection: "column",
|
|
2615
|
+
flexGrow: 1,
|
|
2616
|
+
onMouseMove: (e) => {
|
|
2617
|
+
setPos({ x: e.x, y: e.y });
|
|
2618
|
+
},
|
|
2619
|
+
children: [
|
|
2620
|
+
/* @__PURE__ */ jsxs32("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
2621
|
+
/* @__PURE__ */ jsx40("text", { style: { bold: true, fg: "#fff" }, children: "Cursor Highlight" }),
|
|
2622
|
+
/* @__PURE__ */ jsx40("text", { style: { dim: true, fg: "#888" }, children: "Move your mouse over the grid" }),
|
|
2623
|
+
/* @__PURE__ */ jsx40("box", { height: 1 }),
|
|
2624
|
+
/* @__PURE__ */ jsx40("box", { flexDirection: "column", children: Array.from({ length: 6 }, (_, row) => /* @__PURE__ */ jsx40("text", { children: Array.from({ length: 40 }, (_2, col) => {
|
|
2625
|
+
const isEven = (row + col) % 2 === 0;
|
|
2626
|
+
return /* @__PURE__ */ jsx40("span", { style: {
|
|
2627
|
+
fg: isEven ? "#3b82f6" : "#8b5cf6",
|
|
2628
|
+
dim: !isEven
|
|
2629
|
+
}, children: isEven ? "\u2591\u2591" : "\u2593\u2593" }, col);
|
|
2630
|
+
}) }, row)) })
|
|
2631
|
+
] }),
|
|
2632
|
+
/* @__PURE__ */ jsx40("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx40(
|
|
2633
|
+
StatusBar,
|
|
2634
|
+
{
|
|
2635
|
+
items: [],
|
|
2636
|
+
extra: /* @__PURE__ */ jsxs32("span", { children: [
|
|
2637
|
+
/* @__PURE__ */ jsx40("span", { style: textStyle({ bold: true, fg: "#1e1e2e", bg: "#888" }), children: " x " }),
|
|
2638
|
+
/* @__PURE__ */ jsx40("span", { style: textStyle({ dim: true, fg: "#888" }), children: ` ${pos ? String(pos.x).padStart(3) : " -"} ` }),
|
|
2639
|
+
/* @__PURE__ */ jsx40("span", { style: textStyle({ bold: true, fg: "#1e1e2e", bg: "#888" }), children: " y " }),
|
|
2640
|
+
/* @__PURE__ */ jsx40("span", { style: textStyle({ dim: true, fg: "#888" }), children: ` ${pos ? String(pos.y).padStart(3) : " -"}` })
|
|
2641
|
+
] })
|
|
2642
|
+
}
|
|
2643
|
+
) })
|
|
2644
|
+
]
|
|
2645
|
+
}
|
|
2646
|
+
);
|
|
2404
2647
|
}
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
/* @__PURE__ */
|
|
2415
|
-
|
|
2648
|
+
|
|
2649
|
+
// demos/text-style.tsx
|
|
2650
|
+
import { jsx as jsx41, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2651
|
+
function TextStyleApp() {
|
|
2652
|
+
const theme = useTheme();
|
|
2653
|
+
const desc = textStyle({ fg: theme.muted });
|
|
2654
|
+
return /* @__PURE__ */ jsxs33("box", { flexDirection: "column", padding: 1, gap: 0, children: [
|
|
2655
|
+
/* @__PURE__ */ jsxs33("text", { children: [
|
|
2656
|
+
/* @__PURE__ */ jsx41("span", { style: textStyle({ fg: theme.foreground, bold: true }), children: "bold " }),
|
|
2657
|
+
/* @__PURE__ */ jsxs33("span", { style: desc, children: [
|
|
2658
|
+
"textStyle(",
|
|
2659
|
+
"{",
|
|
2660
|
+
" bold: true ",
|
|
2661
|
+
"}",
|
|
2662
|
+
")"
|
|
2663
|
+
] })
|
|
2664
|
+
] }),
|
|
2665
|
+
/* @__PURE__ */ jsxs33("text", { children: [
|
|
2666
|
+
/* @__PURE__ */ jsx41("span", { style: textStyle({ fg: theme.foreground, dim: true }), children: "dim " }),
|
|
2667
|
+
/* @__PURE__ */ jsxs33("span", { style: desc, children: [
|
|
2668
|
+
"textStyle(",
|
|
2669
|
+
"{",
|
|
2670
|
+
" dim: true ",
|
|
2671
|
+
"}",
|
|
2672
|
+
")"
|
|
2673
|
+
] })
|
|
2674
|
+
] }),
|
|
2675
|
+
/* @__PURE__ */ jsxs33("text", { children: [
|
|
2676
|
+
/* @__PURE__ */ jsx41("span", { style: textStyle({ fg: theme.foreground, italic: true }), children: "italic " }),
|
|
2677
|
+
/* @__PURE__ */ jsxs33("span", { style: desc, children: [
|
|
2678
|
+
"textStyle(",
|
|
2679
|
+
"{",
|
|
2680
|
+
" italic: true ",
|
|
2681
|
+
"}",
|
|
2682
|
+
")"
|
|
2683
|
+
] })
|
|
2684
|
+
] }),
|
|
2685
|
+
/* @__PURE__ */ jsxs33("text", { children: [
|
|
2686
|
+
/* @__PURE__ */ jsx41("span", { style: textStyle({ fg: theme.foreground, underline: true }), children: "underline " }),
|
|
2687
|
+
/* @__PURE__ */ jsxs33("span", { style: desc, children: [
|
|
2688
|
+
"textStyle(",
|
|
2689
|
+
"{",
|
|
2690
|
+
" underline: true ",
|
|
2691
|
+
"}",
|
|
2692
|
+
")"
|
|
2693
|
+
] })
|
|
2694
|
+
] }),
|
|
2695
|
+
/* @__PURE__ */ jsxs33("text", { children: [
|
|
2696
|
+
/* @__PURE__ */ jsx41("span", { style: textStyle({ inverse: true }), children: "inverse " }),
|
|
2697
|
+
/* @__PURE__ */ jsxs33("span", { style: desc, children: [
|
|
2698
|
+
"textStyle(",
|
|
2699
|
+
"{",
|
|
2700
|
+
" inverse: true ",
|
|
2701
|
+
"}",
|
|
2702
|
+
")"
|
|
2703
|
+
] })
|
|
2704
|
+
] }),
|
|
2705
|
+
/* @__PURE__ */ jsx41("text", { children: " " }),
|
|
2706
|
+
/* @__PURE__ */ jsxs33("text", { children: [
|
|
2707
|
+
/* @__PURE__ */ jsx41("span", { style: textStyle({ fg: theme.primary }), children: "fg color " }),
|
|
2708
|
+
/* @__PURE__ */ jsxs33("span", { style: desc, children: [
|
|
2709
|
+
"textStyle(",
|
|
2710
|
+
"{",
|
|
2711
|
+
" fg: theme.primary ",
|
|
2712
|
+
"}",
|
|
2713
|
+
")"
|
|
2714
|
+
] })
|
|
2715
|
+
] }),
|
|
2716
|
+
/* @__PURE__ */ jsxs33("text", { children: [
|
|
2717
|
+
/* @__PURE__ */ jsx41("span", { style: textStyle({ fg: theme.foreground, bg: theme.secondary }), children: "bg color " }),
|
|
2718
|
+
/* @__PURE__ */ jsxs33("span", { style: desc, children: [
|
|
2719
|
+
"textStyle(",
|
|
2720
|
+
"{",
|
|
2721
|
+
" fg: theme.foreground, bg: theme.secondary ",
|
|
2722
|
+
"}",
|
|
2723
|
+
")"
|
|
2724
|
+
] })
|
|
2416
2725
|
] }),
|
|
2417
|
-
/* @__PURE__ */
|
|
2726
|
+
/* @__PURE__ */ jsx41("text", { children: " " }),
|
|
2727
|
+
/* @__PURE__ */ jsxs33("text", { children: [
|
|
2728
|
+
/* @__PURE__ */ jsx41("span", { style: textStyle({ fg: theme.accent, bold: true, underline: true }), children: "combined " }),
|
|
2729
|
+
/* @__PURE__ */ jsxs33("span", { style: desc, children: [
|
|
2730
|
+
"textStyle(",
|
|
2731
|
+
"{",
|
|
2732
|
+
" fg: theme.accent, bold: true, underline: true ",
|
|
2733
|
+
"}",
|
|
2734
|
+
")"
|
|
2735
|
+
] })
|
|
2736
|
+
] })
|
|
2418
2737
|
] });
|
|
2419
2738
|
}
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2739
|
+
|
|
2740
|
+
// demos/headless.tsx
|
|
2741
|
+
import { jsx as jsx42 } from "react/jsx-runtime";
|
|
2742
|
+
var data = [
|
|
2743
|
+
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
2744
|
+
{ name: "Bob", role: "Designer", status: "Active" },
|
|
2745
|
+
{ name: "Charlie", role: "PM", status: "Away" }
|
|
2746
|
+
];
|
|
2747
|
+
function HeadlessApp() {
|
|
2748
|
+
return /* @__PURE__ */ jsx42("box", { padding: 1, children: /* @__PURE__ */ jsx42(Table, { data }) });
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
// demos/theming.tsx
|
|
2752
|
+
import { useKeyboard as useKeyboard17 } from "@gridland/utils";
|
|
2753
|
+
import { jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2754
|
+
var tableData = [
|
|
2755
|
+
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
2756
|
+
{ name: "Bob", role: "Designer", status: "Away" }
|
|
2757
|
+
];
|
|
2758
|
+
var selectItems = [
|
|
2759
|
+
{ label: "TypeScript", value: "ts" },
|
|
2760
|
+
{ label: "JavaScript", value: "js" },
|
|
2761
|
+
{ label: "Python", value: "py" }
|
|
2762
|
+
];
|
|
2763
|
+
function ThemingApp() {
|
|
2764
|
+
return /* @__PURE__ */ jsxs34("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1, children: [
|
|
2765
|
+
/* @__PURE__ */ jsx43(Spinner, { text: "Loading data..." }),
|
|
2766
|
+
/* @__PURE__ */ jsx43(Table, { data: tableData }),
|
|
2767
|
+
/* @__PURE__ */ jsx43(MultiSelect, { items: selectItems, useKeyboard: useKeyboard17 })
|
|
2768
|
+
] });
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
// src/landing/landing-app.tsx
|
|
2772
|
+
import { useMemo as useMemo7 } from "react";
|
|
2773
|
+
|
|
2774
|
+
// src/landing/install-box.tsx
|
|
2775
|
+
import { jsx as jsx44, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2776
|
+
function InstallBox() {
|
|
2777
|
+
const theme = useTheme();
|
|
2778
|
+
return /* @__PURE__ */ jsx44(
|
|
2779
|
+
"box",
|
|
2780
|
+
{
|
|
2781
|
+
border: true,
|
|
2782
|
+
borderStyle: "rounded",
|
|
2783
|
+
borderColor: theme.border,
|
|
2784
|
+
paddingX: 1,
|
|
2785
|
+
flexDirection: "column",
|
|
2786
|
+
flexShrink: 0,
|
|
2787
|
+
children: /* @__PURE__ */ jsxs35("text", { children: [
|
|
2788
|
+
/* @__PURE__ */ jsx44("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
2789
|
+
/* @__PURE__ */ jsx44("span", { style: textStyle({ bold: true }), children: "bun create " }),
|
|
2790
|
+
/* @__PURE__ */ jsx44("span", { style: textStyle({ fg: theme.accent }), children: "gridland" })
|
|
2791
|
+
] })
|
|
2792
|
+
}
|
|
2793
|
+
);
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2796
|
+
// src/landing/links-box.tsx
|
|
2797
|
+
import { jsx as jsx45, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2798
|
+
var UNDERLINE3 = 1 << 3;
|
|
2799
|
+
function LinksBox() {
|
|
2800
|
+
const theme = useTheme();
|
|
2801
|
+
return /* @__PURE__ */ jsx45(
|
|
2802
|
+
"box",
|
|
2803
|
+
{
|
|
2804
|
+
border: true,
|
|
2805
|
+
borderStyle: "rounded",
|
|
2806
|
+
borderColor: theme.border,
|
|
2807
|
+
paddingX: 1,
|
|
2808
|
+
flexDirection: "column",
|
|
2809
|
+
flexShrink: 0,
|
|
2810
|
+
children: /* @__PURE__ */ jsxs36("text", { children: [
|
|
2811
|
+
/* @__PURE__ */ jsx45("span", { children: "\u{1F431}" }),
|
|
2812
|
+
/* @__PURE__ */ jsx45("a", { href: "https://github.com/thoughtfulllc/gridland", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " GitHub" }),
|
|
2813
|
+
/* @__PURE__ */ jsx45("span", { children: " " }),
|
|
2814
|
+
/* @__PURE__ */ jsx45("span", { children: "\u{1F4D6}" }),
|
|
2815
|
+
/* @__PURE__ */ jsx45("a", { href: "https://gridland.io/docs", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " Docs" })
|
|
2816
|
+
] })
|
|
2817
|
+
}
|
|
2818
|
+
);
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
// src/landing/logo.tsx
|
|
2822
|
+
import { useState as useState24, useEffect as useEffect6, useRef as useRef10, useMemo as useMemo5 } from "react";
|
|
2823
|
+
import figlet3 from "figlet";
|
|
2824
|
+
import ansiShadow3 from "figlet/importable-fonts/ANSI Shadow.js";
|
|
2825
|
+
import { Fragment as Fragment8, jsx as jsx46, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
2826
|
+
figlet3.parseFont("ANSI Shadow", ansiShadow3);
|
|
2827
|
+
function makeArt(text) {
|
|
2828
|
+
return figlet3.textSync(text, { font: "ANSI Shadow" }).split("\n").filter((l) => l.trimEnd().length > 0).join("\n");
|
|
2829
|
+
}
|
|
2830
|
+
var fullArt = makeArt("gridland");
|
|
2831
|
+
var gridArt = makeArt("grid");
|
|
2832
|
+
var landArt = makeArt("land");
|
|
2833
|
+
var ART_HEIGHT = 6;
|
|
2834
|
+
function useAnimation(duration = 1e3) {
|
|
2835
|
+
const isBrowser = typeof document !== "undefined";
|
|
2836
|
+
const [progress, setProgress] = useState24(isBrowser ? 0 : 1);
|
|
2837
|
+
const startTime = useRef10(null);
|
|
2838
|
+
useEffect6(() => {
|
|
2839
|
+
if (!isBrowser) return;
|
|
2840
|
+
let raf;
|
|
2841
|
+
const tick = (time) => {
|
|
2842
|
+
if (startTime.current === null) startTime.current = time;
|
|
2843
|
+
const elapsed = time - startTime.current;
|
|
2844
|
+
const t = Math.min(1, elapsed / duration);
|
|
2845
|
+
const eased = 1 - Math.pow(1 - t, 3);
|
|
2846
|
+
setProgress(eased);
|
|
2847
|
+
if (t < 1) raf = requestAnimationFrame(tick);
|
|
2848
|
+
};
|
|
2849
|
+
raf = requestAnimationFrame(tick);
|
|
2850
|
+
return () => cancelAnimationFrame(raf);
|
|
2851
|
+
}, []);
|
|
2852
|
+
return progress;
|
|
2853
|
+
}
|
|
2854
|
+
function RevealGradient({ children, revealCol }) {
|
|
2855
|
+
const gradientColors = GRADIENTS.instagram;
|
|
2856
|
+
const lines2 = children.split("\n");
|
|
2857
|
+
const maxLength = Math.max(...lines2.map((l) => l.length));
|
|
2858
|
+
if (maxLength === 0) return /* @__PURE__ */ jsx46("text", { children });
|
|
2859
|
+
const hexColors = useMemo5(() => generateGradient(gradientColors, maxLength), [maxLength]);
|
|
2860
|
+
return /* @__PURE__ */ jsx46("box", { position: "relative", width: maxLength, height: lines2.length, shouldFill: false, children: lines2.map((line, lineIndex) => {
|
|
2861
|
+
const runs = [];
|
|
2862
|
+
let current = null;
|
|
2863
|
+
for (let i = 0; i < line.length; i++) {
|
|
2864
|
+
const revealed = i <= revealCol;
|
|
2865
|
+
const char = line[i];
|
|
2866
|
+
const isVisible = revealed && char !== " ";
|
|
2867
|
+
if (isVisible) {
|
|
2868
|
+
if (!current) {
|
|
2869
|
+
current = { start: i, chars: [] };
|
|
2870
|
+
}
|
|
2871
|
+
current.chars.push(char);
|
|
2872
|
+
} else {
|
|
2873
|
+
if (current) {
|
|
2874
|
+
runs.push(current);
|
|
2875
|
+
current = null;
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
if (current) runs.push(current);
|
|
2880
|
+
return runs.map((run, runIndex) => /* @__PURE__ */ jsx46(
|
|
2881
|
+
"box",
|
|
2442
2882
|
{
|
|
2443
|
-
|
|
2444
|
-
|
|
2883
|
+
position: "absolute",
|
|
2884
|
+
top: lineIndex,
|
|
2885
|
+
left: run.start,
|
|
2886
|
+
shouldFill: false,
|
|
2887
|
+
children: /* @__PURE__ */ jsx46("text", { shouldFill: false, children: run.chars.map((char, ci) => /* @__PURE__ */ jsx46(
|
|
2888
|
+
"span",
|
|
2889
|
+
{
|
|
2890
|
+
style: { fg: hexColors[run.start + ci] },
|
|
2891
|
+
children: char
|
|
2892
|
+
},
|
|
2893
|
+
ci
|
|
2894
|
+
)) })
|
|
2895
|
+
},
|
|
2896
|
+
`${lineIndex}-${runIndex}`
|
|
2897
|
+
));
|
|
2898
|
+
}) });
|
|
2899
|
+
}
|
|
2900
|
+
function Logo({ compact, narrow, mobile }) {
|
|
2901
|
+
const isBrowser = typeof document !== "undefined";
|
|
2902
|
+
const progress = useAnimation(900);
|
|
2903
|
+
const artHeight = compact ? 1 : narrow ? ART_HEIGHT * 2 : ART_HEIGHT;
|
|
2904
|
+
const dropOffset = Math.round((1 - progress) * -artHeight);
|
|
2905
|
+
const revealProgress = Math.max(0, Math.min(1, (progress - 0.1) / 0.7));
|
|
2906
|
+
const maxWidth = compact ? 8 : narrow ? 40 : 62;
|
|
2907
|
+
const revealCol = Math.round(revealProgress * (maxWidth + 4)) - 2;
|
|
2908
|
+
const taglineOpacity = Math.max(0, Math.min(1, (progress - 0.7) / 0.3));
|
|
2909
|
+
const subtitle = /* @__PURE__ */ jsxs37(Fragment8, { children: [
|
|
2910
|
+
/* @__PURE__ */ jsx46("text", { children: " " }),
|
|
2911
|
+
/* @__PURE__ */ jsx46("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs37("text", { style: textStyle({ fg: "#d4b0e8" }), opacity: taglineOpacity, wrapMode: "word", textAlign: "center", width: "100%", shouldFill: false, children: [
|
|
2912
|
+
"A framework for building terminal apps, built on ",
|
|
2913
|
+
/* @__PURE__ */ jsx46("a", { href: "https://opentui.com", style: { attributes: 72, fg: "#d4b0e8" }, children: "OpenTUI" }),
|
|
2914
|
+
" + React." + (mobile ? " " : "\n") + "(Gridland apps, like this website, work in the browser and terminal.)"
|
|
2915
|
+
] }) })
|
|
2916
|
+
] });
|
|
2917
|
+
if (!isBrowser) {
|
|
2918
|
+
const art2 = compact ? "gridland" : narrow ? gridArt + "\n" + landArt : fullArt;
|
|
2919
|
+
return /* @__PURE__ */ jsxs37("box", { flexDirection: "column", flexShrink: 0, width: "100%", alignItems: "center", shouldFill: false, children: [
|
|
2920
|
+
/* @__PURE__ */ jsx46(Gradient, { name: "instagram", children: art2 }),
|
|
2921
|
+
/* @__PURE__ */ jsx46("text", { children: " " }),
|
|
2922
|
+
/* @__PURE__ */ jsx46("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs37("text", { style: textStyle({ fg: "#d4b0e8" }), shouldFill: false, children: [
|
|
2923
|
+
"A framework for building terminal apps, built on OpenTUI + React.",
|
|
2924
|
+
"\n",
|
|
2925
|
+
"(Gridland apps, like this website, work in the browser and terminal.)"
|
|
2926
|
+
] }) })
|
|
2927
|
+
] });
|
|
2928
|
+
}
|
|
2929
|
+
if (compact) {
|
|
2930
|
+
return /* @__PURE__ */ jsxs37("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
2931
|
+
/* @__PURE__ */ jsx46("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx46("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: /* @__PURE__ */ jsx46(RevealGradient, { revealCol, children: "gridland" }) }) }),
|
|
2932
|
+
subtitle
|
|
2933
|
+
] });
|
|
2934
|
+
}
|
|
2935
|
+
if (narrow) {
|
|
2936
|
+
return /* @__PURE__ */ jsxs37("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
2937
|
+
/* @__PURE__ */ jsx46("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsxs37("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: [
|
|
2938
|
+
/* @__PURE__ */ jsx46(RevealGradient, { revealCol, children: gridArt }),
|
|
2939
|
+
/* @__PURE__ */ jsx46(RevealGradient, { revealCol, children: landArt })
|
|
2940
|
+
] }) }),
|
|
2941
|
+
subtitle
|
|
2942
|
+
] });
|
|
2943
|
+
}
|
|
2944
|
+
return /* @__PURE__ */ jsxs37("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
2945
|
+
/* @__PURE__ */ jsx46("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx46("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: /* @__PURE__ */ jsx46(RevealGradient, { revealCol, children: fullArt }) }) }),
|
|
2946
|
+
subtitle
|
|
2947
|
+
] });
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
// src/landing/matrix-background.tsx
|
|
2951
|
+
import { useMemo as useMemo6 } from "react";
|
|
2952
|
+
|
|
2953
|
+
// src/landing/use-matrix.ts
|
|
2954
|
+
import { useState as useState25, useEffect as useEffect7, useRef as useRef11 } from "react";
|
|
2955
|
+
var CHARS = "abcdefghijklmnopqrstuvwxyz0123456789@#$%^&*(){}[]|;:<>,.?/~`";
|
|
2956
|
+
function randomChar() {
|
|
2957
|
+
return CHARS[Math.floor(Math.random() * CHARS.length)];
|
|
2958
|
+
}
|
|
2959
|
+
function createDrop(height, seeded = false) {
|
|
2960
|
+
const length = Math.floor(Math.random() * Math.floor(height * 0.6)) + 4;
|
|
2961
|
+
return {
|
|
2962
|
+
y: seeded ? Math.floor(Math.random() * (height + length)) : -Math.floor(Math.random() * height),
|
|
2963
|
+
speed: 1,
|
|
2964
|
+
length,
|
|
2965
|
+
chars: Array.from({ length }, randomChar)
|
|
2966
|
+
};
|
|
2967
|
+
}
|
|
2968
|
+
function buildGrid(columns, width, height) {
|
|
2969
|
+
const grid = Array.from({ length: height }, () => Array(width).fill(" "));
|
|
2970
|
+
const brightness = Array.from({ length: height }, () => Array(width).fill(0));
|
|
2971
|
+
for (let x = 0; x < width; x++) {
|
|
2972
|
+
const drop = columns[x];
|
|
2973
|
+
if (!drop) continue;
|
|
2974
|
+
for (let i = 0; i < drop.length; i++) {
|
|
2975
|
+
const row = Math.floor(drop.y) - i;
|
|
2976
|
+
if (row < 0 || row >= height) continue;
|
|
2977
|
+
grid[row][x] = drop.chars[i];
|
|
2978
|
+
if (i === 0) {
|
|
2979
|
+
brightness[row][x] = 1;
|
|
2980
|
+
} else {
|
|
2981
|
+
brightness[row][x] = Math.max(0.15, 1 - i / drop.length);
|
|
2445
2982
|
}
|
|
2446
|
-
|
|
2447
|
-
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
return { grid, brightness };
|
|
2448
2986
|
}
|
|
2449
|
-
function
|
|
2450
|
-
const
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2987
|
+
function useMatrix(width, height) {
|
|
2988
|
+
const columnsRef = useRef11([]);
|
|
2989
|
+
const [state, setState] = useState25(() => {
|
|
2990
|
+
const columns = Array.from(
|
|
2991
|
+
{ length: width },
|
|
2992
|
+
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
2993
|
+
);
|
|
2994
|
+
columnsRef.current = columns;
|
|
2995
|
+
return buildGrid(columns, width, height);
|
|
2454
2996
|
});
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2997
|
+
useEffect7(() => {
|
|
2998
|
+
if (width < 2 || height < 2) return;
|
|
2999
|
+
const id = setInterval(() => {
|
|
3000
|
+
const columns = columnsRef.current;
|
|
3001
|
+
for (let x = 0; x < width; x++) {
|
|
3002
|
+
if (columns[x] === null || columns[x] === void 0) {
|
|
3003
|
+
if (Math.random() < 0.03) {
|
|
3004
|
+
columns[x] = createDrop(height);
|
|
3005
|
+
}
|
|
3006
|
+
continue;
|
|
3007
|
+
}
|
|
3008
|
+
const drop = columns[x];
|
|
3009
|
+
drop.y += drop.speed;
|
|
3010
|
+
if (Math.random() < 0.1) {
|
|
3011
|
+
const idx = Math.floor(Math.random() * drop.chars.length);
|
|
3012
|
+
drop.chars[idx] = randomChar();
|
|
3013
|
+
}
|
|
3014
|
+
if (drop.y - drop.length > height) {
|
|
3015
|
+
columns[x] = null;
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
setState(buildGrid(columns, width, height));
|
|
3019
|
+
}, 80);
|
|
3020
|
+
return () => clearInterval(id);
|
|
3021
|
+
}, [width, height]);
|
|
3022
|
+
useEffect7(() => {
|
|
3023
|
+
columnsRef.current = Array.from(
|
|
3024
|
+
{ length: width },
|
|
3025
|
+
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
3026
|
+
);
|
|
3027
|
+
setState(buildGrid(columnsRef.current, width, height));
|
|
3028
|
+
}, [width, height]);
|
|
3029
|
+
return state;
|
|
2473
3030
|
}
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
3031
|
+
|
|
3032
|
+
// src/landing/matrix-background.tsx
|
|
3033
|
+
import { jsx as jsx47 } from "react/jsx-runtime";
|
|
3034
|
+
var MUTE_LEVELS = [0.12, 0.18, 0.24, 0.3, 0.38];
|
|
3035
|
+
var BG = hexToRgb("#1a1a2e");
|
|
3036
|
+
function buildMutedColors(baseHex) {
|
|
3037
|
+
const fg = hexToRgb(baseHex);
|
|
3038
|
+
return MUTE_LEVELS.map((factor) => rgbToHex({
|
|
3039
|
+
r: Math.round(BG.r + (fg.r - BG.r) * factor),
|
|
3040
|
+
g: Math.round(BG.g + (fg.g - BG.g) * factor),
|
|
3041
|
+
b: Math.round(BG.b + (fg.b - BG.b) * factor)
|
|
3042
|
+
}));
|
|
2486
3043
|
}
|
|
2487
|
-
function
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
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
|
-
] });
|
|
3044
|
+
function colorForCell(mutedColors, b) {
|
|
3045
|
+
if (b >= 1) return mutedColors[4];
|
|
3046
|
+
const idx = Math.min(Math.floor(b * (MUTE_LEVELS.length - 1)), MUTE_LEVELS.length - 2);
|
|
3047
|
+
return mutedColors[idx];
|
|
2496
3048
|
}
|
|
2497
|
-
|
|
2498
|
-
{
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
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);
|
|
3049
|
+
function MatrixBackground({ width, height, clearRect, clearRects }) {
|
|
3050
|
+
const { grid, brightness } = useMatrix(width, height);
|
|
3051
|
+
const theme = useTheme();
|
|
3052
|
+
const columnColors = useMemo6(
|
|
3053
|
+
() => width > 0 ? generateGradient([theme.accent, theme.secondary, theme.primary], width) : [],
|
|
3054
|
+
[width, theme.accent, theme.secondary, theme.primary]
|
|
3055
|
+
);
|
|
3056
|
+
const columnMutedColors = useMemo6(
|
|
3057
|
+
() => columnColors.map(buildMutedColors),
|
|
3058
|
+
[columnColors]
|
|
3059
|
+
);
|
|
3060
|
+
return /* @__PURE__ */ jsx47("box", { flexDirection: "column", children: grid.map((row, y) => /* @__PURE__ */ jsx47("text", { children: row.map((cell, x) => {
|
|
3061
|
+
const inClearRect = clearRect && y >= clearRect.top && y < clearRect.top + clearRect.height && x >= clearRect.left && x < clearRect.left + clearRect.width || clearRects && clearRects.some(
|
|
3062
|
+
(r) => y >= r.top && y < r.top + r.height && x >= r.left && x < r.left + r.width
|
|
3063
|
+
);
|
|
3064
|
+
const mutedColors = columnMutedColors[x];
|
|
3065
|
+
if (cell === " " || inClearRect || !mutedColors) {
|
|
3066
|
+
return /* @__PURE__ */ jsx47("span", { children: " " }, x);
|
|
2533
3067
|
}
|
|
2534
|
-
return
|
|
2535
|
-
|
|
2536
|
-
|
|
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
|
|
3068
|
+
return /* @__PURE__ */ jsx47(
|
|
3069
|
+
"span",
|
|
3070
|
+
{
|
|
3071
|
+
style: {
|
|
3072
|
+
fg: colorForCell(mutedColors, brightness[y][x])
|
|
2557
3073
|
},
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
{ key: "r", label: "restart" },
|
|
2564
|
-
{ key: "q", label: "quit" }
|
|
2565
|
-
] }) })
|
|
2566
|
-
] });
|
|
3074
|
+
children: cell
|
|
3075
|
+
},
|
|
3076
|
+
x
|
|
3077
|
+
);
|
|
3078
|
+
}) }, y)) });
|
|
2567
3079
|
}
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
{
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
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);
|
|
3080
|
+
|
|
3081
|
+
// src/landing/landing-app.tsx
|
|
3082
|
+
import { jsx as jsx48, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
3083
|
+
function LandingApp({ useKeyboard: useKeyboard20 }) {
|
|
3084
|
+
const theme = useTheme();
|
|
3085
|
+
const { width, height, isNarrow, isTiny, isMobile } = useBreakpoints();
|
|
3086
|
+
const isBrowser = typeof document !== "undefined";
|
|
3087
|
+
const { clearRect, installLinksClearRect } = useMemo7(() => {
|
|
3088
|
+
const logoHeight = isTiny ? 2 : isNarrow ? 13 : 7;
|
|
3089
|
+
const logoExtra = isBrowser ? 1 : 0;
|
|
3090
|
+
const gap = isMobile ? 0 : 1;
|
|
3091
|
+
const installLinksTop = 3 + logoHeight + logoExtra + gap;
|
|
3092
|
+
const installLinksHeight = 3;
|
|
3093
|
+
const boxTop = installLinksTop + installLinksHeight + gap + 1;
|
|
3094
|
+
const bh = height - boxTop - 1;
|
|
3095
|
+
return {
|
|
3096
|
+
clearRect: { top: boxTop, left: 1, width: width - 2, height: bh },
|
|
3097
|
+
installLinksClearRect: { top: installLinksTop, left: 1, width: width - 2, height: installLinksHeight }
|
|
2632
3098
|
};
|
|
2633
|
-
}, [
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
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" }] }) })
|
|
3099
|
+
}, [width, height, isTiny, isNarrow, isMobile, isBrowser]);
|
|
3100
|
+
return /* @__PURE__ */ jsxs38("box", { width: "100%", height: "100%", position: "relative", children: [
|
|
3101
|
+
/* @__PURE__ */ jsx48(MatrixBackground, { width, height, clearRect, clearRects: isBrowser ? void 0 : [installLinksClearRect] }),
|
|
3102
|
+
/* @__PURE__ */ jsx48("box", { position: "absolute", top: 0, left: 0, width, height, zIndex: 1, flexDirection: "column", shouldFill: false, children: /* @__PURE__ */ jsxs38("box", { flexGrow: 1, flexDirection: "column", paddingTop: 3, paddingLeft: 1, paddingRight: 1, paddingBottom: 1, gap: isMobile ? 0 : 1, shouldFill: false, children: [
|
|
3103
|
+
/* @__PURE__ */ jsx48("box", { flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx48(Logo, { compact: isTiny, narrow: isNarrow, mobile: isMobile }) }),
|
|
3104
|
+
/* @__PURE__ */ jsxs38("box", { flexDirection: "row", flexWrap: "wrap", justifyContent: "center", gap: isMobile ? 0 : 1, flexShrink: 0, shouldFill: false, children: [
|
|
3105
|
+
/* @__PURE__ */ jsx48("box", { border: true, borderStyle: "rounded", borderColor: theme.border, paddingX: 1, flexDirection: "column", flexShrink: 0, children: /* @__PURE__ */ jsxs38("text", { children: [
|
|
3106
|
+
/* @__PURE__ */ jsx48("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
3107
|
+
/* @__PURE__ */ jsx48("span", { style: textStyle({ bold: true }), children: "bunx " }),
|
|
3108
|
+
/* @__PURE__ */ jsx48("span", { style: textStyle({ fg: theme.accent }), children: "@gridland/demo landing" })
|
|
3109
|
+
] }) }),
|
|
3110
|
+
/* @__PURE__ */ jsx48(InstallBox, {}),
|
|
3111
|
+
/* @__PURE__ */ jsx48(LinksBox, {})
|
|
3112
|
+
] }),
|
|
3113
|
+
/* @__PURE__ */ jsx48("box", { flexGrow: 1, border: true, borderStyle: "rounded", borderColor: theme.border, flexDirection: "column", overflow: "hidden" })
|
|
3114
|
+
] }) })
|
|
2727
3115
|
] });
|
|
2728
3116
|
}
|
|
3117
|
+
|
|
3118
|
+
// src/landing/matrix-rain.tsx
|
|
3119
|
+
import { jsx as jsx49 } from "react/jsx-runtime";
|
|
3120
|
+
|
|
3121
|
+
// src/landing/about-modal.tsx
|
|
3122
|
+
import { jsx as jsx50, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3123
|
+
|
|
3124
|
+
// demos/index.tsx
|
|
3125
|
+
import { jsx as jsx51 } from "react/jsx-runtime";
|
|
2729
3126
|
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: "
|
|
3127
|
+
{ name: "gradient", app: () => /* @__PURE__ */ jsx51(GradientApp, {}) },
|
|
3128
|
+
{ name: "ascii", app: () => /* @__PURE__ */ jsx51(AsciiApp, {}) },
|
|
3129
|
+
{ name: "table", app: () => /* @__PURE__ */ jsx51(TableApp, {}) },
|
|
3130
|
+
{ name: "spinner", app: () => /* @__PURE__ */ jsx51(SpinnerApp, {}) },
|
|
3131
|
+
{ name: "select-input", app: () => /* @__PURE__ */ jsx51(SelectInputApp, {}) },
|
|
3132
|
+
{ name: "multi-select", app: () => /* @__PURE__ */ jsx51(MultiSelectApp, {}) },
|
|
3133
|
+
{ name: "prompt-input", app: () => /* @__PURE__ */ jsx51(PromptInputApp, {}) },
|
|
3134
|
+
{ name: "text-input", app: () => /* @__PURE__ */ jsx51(TextInputApp, {}) },
|
|
3135
|
+
{ name: "link", app: () => /* @__PURE__ */ jsx51(LinkApp, {}) },
|
|
3136
|
+
{ name: "tabs", app: () => /* @__PURE__ */ jsx51(TabBarApp, {}) },
|
|
3137
|
+
{ name: "status-bar", app: () => /* @__PURE__ */ jsx51(StatusBarApp, {}) },
|
|
3138
|
+
{ name: "modal", app: () => /* @__PURE__ */ jsx51(ModalApp, {}) },
|
|
3139
|
+
{ name: "primitives", app: () => /* @__PURE__ */ jsx51(PrimitivesApp, {}) },
|
|
3140
|
+
{ name: "chat", app: () => /* @__PURE__ */ jsx51(ChatApp, {}) },
|
|
3141
|
+
{ name: "chain-of-thought", app: () => /* @__PURE__ */ jsx51(ChainOfThoughtApp, {}) },
|
|
3142
|
+
{ name: "message", app: () => /* @__PURE__ */ jsx51(MessageApp, {}) },
|
|
3143
|
+
{ name: "terminal-window", app: () => /* @__PURE__ */ jsx51(TerminalWindowApp, {}) },
|
|
3144
|
+
{ name: "focus", app: () => /* @__PURE__ */ jsx51(FocusApp, {}) },
|
|
3145
|
+
{ name: "pointer", app: () => /* @__PURE__ */ jsx51(PointerApp, {}) },
|
|
3146
|
+
{ name: "cursor-highlight", app: () => /* @__PURE__ */ jsx51(CursorHighlightApp, {}) },
|
|
3147
|
+
{ name: "text-style", app: () => /* @__PURE__ */ jsx51(TextStyleApp, {}) },
|
|
3148
|
+
{ name: "headless", app: () => /* @__PURE__ */ jsx51(HeadlessApp, {}) },
|
|
3149
|
+
{ name: "theming", app: () => /* @__PURE__ */ jsx51(ThemingApp, {}) },
|
|
3150
|
+
{ name: "landing", app: () => /* @__PURE__ */ jsx51(LandingApp, { useKeyboard: useKeyboard18 }) }
|
|
2748
3151
|
];
|
|
2749
3152
|
|
|
2750
3153
|
// src/run.tsx
|
|
2751
|
-
import { jsx as
|
|
3154
|
+
import { jsx as jsx52 } from "react/jsx-runtime";
|
|
2752
3155
|
var _renderer;
|
|
2753
3156
|
function DemoShell({ children }) {
|
|
2754
|
-
|
|
3157
|
+
useKeyboard19((event) => {
|
|
2755
3158
|
if (event.name === "q" || event.name === "escape") {
|
|
2756
3159
|
_renderer.destroy();
|
|
2757
3160
|
}
|
|
2758
3161
|
});
|
|
2759
|
-
return /* @__PURE__ */
|
|
3162
|
+
return /* @__PURE__ */ jsx52("box", { flexDirection: "column", flexGrow: 1, children });
|
|
2760
3163
|
}
|
|
2761
|
-
async function runDemo(
|
|
2762
|
-
const demo = demos.find((d) => d.name ===
|
|
3164
|
+
async function runDemo(name2) {
|
|
3165
|
+
const demo = demos.find((d) => d.name === name2);
|
|
2763
3166
|
if (!demo) {
|
|
2764
|
-
console.error(`Unknown demo: "${
|
|
3167
|
+
console.error(`Unknown demo: "${name2}"`);
|
|
2765
3168
|
console.error(`Available: ${demos.map((d) => d.name).join(", ")}`);
|
|
2766
3169
|
process.exit(1);
|
|
2767
3170
|
}
|
|
2768
3171
|
_renderer = await createCliRenderer({ exitOnCtrlC: true });
|
|
2769
|
-
createRoot(_renderer).render(/* @__PURE__ */
|
|
3172
|
+
createRoot(_renderer).render(/* @__PURE__ */ jsx52(DemoShell, { children: demo.app() }));
|
|
3173
|
+
}
|
|
3174
|
+
var name = process.argv[2];
|
|
3175
|
+
if (name) {
|
|
3176
|
+
runDemo(name);
|
|
2770
3177
|
}
|
|
2771
3178
|
export {
|
|
2772
3179
|
demos,
|