@gridland/demo 0.2.49 → 0.2.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-4VNS5WPM.js +42 -0
- package/dist/chunk-DTDQ3HF4.js +494 -0
- package/dist/demo-names.json +1 -1
- package/dist/landing.js +245 -344
- package/dist/run.js +1376 -1235
- 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
|
}
|
|
@@ -1443,13 +1489,19 @@ function ChatPanel({
|
|
|
1443
1489
|
] });
|
|
1444
1490
|
}
|
|
1445
1491
|
|
|
1446
|
-
// ../ui/components/
|
|
1447
|
-
import {
|
|
1448
|
-
import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1492
|
+
// ../ui/components/chain-of-thought/chain-of-thought.tsx
|
|
1493
|
+
import { createContext as createContext6, memo, useContext as useContext6, useEffect as useEffect3, useMemo as useMemo4, useState as useState7 } from "react";
|
|
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
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1496
|
+
var SPINNER_INTERVAL = 150;
|
|
1497
|
+
var ChainOfThoughtContext = createContext6(null);
|
|
1498
|
+
var useChainOfThought = () => {
|
|
1499
|
+
const context = useContext6(ChainOfThoughtContext);
|
|
1500
|
+
if (!context) {
|
|
1501
|
+
throw new Error("ChainOfThought components must be used within <ChainOfThought>");
|
|
1502
|
+
}
|
|
1503
|
+
return context;
|
|
1504
|
+
};
|
|
1453
1505
|
function getStepColor(status, theme) {
|
|
1454
1506
|
switch (status) {
|
|
1455
1507
|
case "done":
|
|
@@ -1464,78 +1516,89 @@ function getStepColor(status, theme) {
|
|
|
1464
1516
|
return theme.muted;
|
|
1465
1517
|
}
|
|
1466
1518
|
}
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1519
|
+
var ChainOfThought = memo(({
|
|
1520
|
+
open,
|
|
1521
|
+
defaultOpen = false,
|
|
1522
|
+
onOpenChange,
|
|
1523
|
+
children
|
|
1524
|
+
}) => {
|
|
1525
|
+
const [internalOpen, setInternalOpen] = useState7(defaultOpen);
|
|
1526
|
+
const isOpen = open ?? internalOpen;
|
|
1527
|
+
const setIsOpen = onOpenChange ?? setInternalOpen;
|
|
1528
|
+
const context = useMemo4(
|
|
1529
|
+
() => ({ isOpen, setIsOpen }),
|
|
1530
|
+
[isOpen, setIsOpen]
|
|
1531
|
+
);
|
|
1532
|
+
return /* @__PURE__ */ jsx18(ChainOfThoughtContext.Provider, { value: context, children: /* @__PURE__ */ jsx18("box", { flexDirection: "column", children }) });
|
|
1533
|
+
});
|
|
1534
|
+
var ChainOfThoughtHeader = memo(({
|
|
1535
|
+
duration,
|
|
1536
|
+
children = "Thought for"
|
|
1537
|
+
}) => {
|
|
1538
|
+
const theme = useTheme();
|
|
1539
|
+
const { isOpen } = useChainOfThought();
|
|
1540
|
+
const arrow = isOpen ? "\u25BC" : "\u25B6";
|
|
1541
|
+
return /* @__PURE__ */ jsxs12("text", { children: [
|
|
1542
|
+
/* @__PURE__ */ jsx18("span", { style: textStyle({ fg: theme.muted }), children: arrow }),
|
|
1543
|
+
/* @__PURE__ */ jsxs12("span", { style: textStyle({ dim: true, fg: theme.muted }), children: [
|
|
1544
|
+
" ",
|
|
1545
|
+
children,
|
|
1546
|
+
duration ? " " + duration : ""
|
|
1547
|
+
] })
|
|
1548
|
+
] });
|
|
1549
|
+
});
|
|
1550
|
+
var ChainOfThoughtContent = memo(({ children }) => {
|
|
1551
|
+
const { isOpen } = useChainOfThought();
|
|
1552
|
+
if (!isOpen) return null;
|
|
1553
|
+
return /* @__PURE__ */ jsx18(Fragment6, { children });
|
|
1554
|
+
});
|
|
1555
|
+
var ChainOfThoughtStep = memo(({
|
|
1556
|
+
label,
|
|
1557
|
+
description,
|
|
1558
|
+
status = "done",
|
|
1559
|
+
isLast = false,
|
|
1560
|
+
children
|
|
1561
|
+
}) => {
|
|
1562
|
+
const theme = useTheme();
|
|
1563
|
+
const isActive = status === "running";
|
|
1564
|
+
const isPending = status === "pending";
|
|
1565
|
+
const color = getStepColor(status, theme);
|
|
1471
1566
|
const pipe = "\u2502";
|
|
1472
|
-
const
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1567
|
+
const [frame, setFrame] = useState7(0);
|
|
1568
|
+
useEffect3(() => {
|
|
1569
|
+
if (!isActive) {
|
|
1570
|
+
setFrame(0);
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
const id = setInterval(() => setFrame((f) => f + 1), SPINNER_INTERVAL);
|
|
1574
|
+
return () => clearInterval(id);
|
|
1575
|
+
}, [isActive]);
|
|
1576
|
+
const dot = isActive ? DOTS[frame % DOTS.length] : isPending ? "\u25CB" : "\u25CF";
|
|
1476
1577
|
return /* @__PURE__ */ jsxs12("box", { flexDirection: "column", marginLeft: 1, children: [
|
|
1477
1578
|
/* @__PURE__ */ jsxs12("text", { children: [
|
|
1478
1579
|
/* @__PURE__ */ jsx18("span", { style: textStyle({ fg: color }), children: dot }),
|
|
1479
1580
|
/* @__PURE__ */ jsx18("span", { style: textStyle({ fg: theme.foreground }), children: " " }),
|
|
1480
|
-
/* @__PURE__ */ jsx18("span", { style: textStyle({ fg: isPending ? theme.muted : color, dim: isPending, bold: isActive }), children:
|
|
1481
|
-
|
|
1581
|
+
/* @__PURE__ */ jsx18("span", { style: textStyle({ fg: isPending ? theme.muted : color, dim: isPending, bold: isActive }), children: label }),
|
|
1582
|
+
description && /* @__PURE__ */ jsx18("span", { style: textStyle({ dim: true, fg: theme.muted }), children: " \u2014 " + description })
|
|
1482
1583
|
] }),
|
|
1483
|
-
|
|
1584
|
+
children && /* @__PURE__ */ jsxs12("text", { children: [
|
|
1484
1585
|
/* @__PURE__ */ jsx18("span", { style: textStyle({ fg: color, dim: true }), children: pipe + " " }),
|
|
1485
|
-
/* @__PURE__ */ jsx18("span", { style: textStyle({ fg:
|
|
1586
|
+
/* @__PURE__ */ jsx18("span", { style: textStyle({ fg: status === "error" ? theme.error : theme.accent }), children })
|
|
1486
1587
|
] }),
|
|
1487
1588
|
!isLast && /* @__PURE__ */ jsx18("text", { children: /* @__PURE__ */ jsx18("span", { style: textStyle({ fg: color, dim: true }), children: pipe }) })
|
|
1488
1589
|
] });
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
headerLabel = "Thought for"
|
|
1495
|
-
}) {
|
|
1496
|
-
const theme = useTheme();
|
|
1497
|
-
const arrow = collapsed ? "\u25B6" : "\u25BC";
|
|
1498
|
-
const durationStr = duration ?? "0ms";
|
|
1499
|
-
const hasRunning = steps?.some((s) => s.status === "running") ?? false;
|
|
1500
|
-
const [frame, setFrame] = useState7(0);
|
|
1501
|
-
const alive = useRef5(true);
|
|
1502
|
-
useEffect2(() => {
|
|
1503
|
-
alive.current = true;
|
|
1504
|
-
return () => {
|
|
1505
|
-
alive.current = false;
|
|
1506
|
-
};
|
|
1507
|
-
}, []);
|
|
1508
|
-
useEffect2(() => {
|
|
1509
|
-
if (!hasRunning) return;
|
|
1510
|
-
const id = setInterval(() => {
|
|
1511
|
-
if (alive.current) setFrame((f) => f + 1);
|
|
1512
|
-
}, 150);
|
|
1513
|
-
return () => clearInterval(id);
|
|
1514
|
-
}, [hasRunning]);
|
|
1515
|
-
return /* @__PURE__ */ jsxs12("box", { flexDirection: "column", children: [
|
|
1516
|
-
/* @__PURE__ */ jsxs12("text", { children: [
|
|
1517
|
-
/* @__PURE__ */ jsx18("span", { style: textStyle({ fg: theme.muted }), children: arrow }),
|
|
1518
|
-
/* @__PURE__ */ jsx18("span", { style: textStyle({ dim: true, fg: theme.muted }), children: " " + headerLabel + " " + durationStr })
|
|
1519
|
-
] }),
|
|
1520
|
-
!collapsed && steps && steps.map((step, i) => /* @__PURE__ */ jsx18(
|
|
1521
|
-
StepRow,
|
|
1522
|
-
{
|
|
1523
|
-
step,
|
|
1524
|
-
isLast: i === steps.length - 1,
|
|
1525
|
-
theme,
|
|
1526
|
-
frame
|
|
1527
|
-
},
|
|
1528
|
-
`step-${i}`
|
|
1529
|
-
))
|
|
1530
|
-
] });
|
|
1531
|
-
}
|
|
1590
|
+
});
|
|
1591
|
+
ChainOfThought.displayName = "ChainOfThought";
|
|
1592
|
+
ChainOfThoughtHeader.displayName = "ChainOfThoughtHeader";
|
|
1593
|
+
ChainOfThoughtContent.displayName = "ChainOfThoughtContent";
|
|
1594
|
+
ChainOfThoughtStep.displayName = "ChainOfThoughtStep";
|
|
1532
1595
|
|
|
1533
1596
|
// ../ui/components/message/message.tsx
|
|
1534
|
-
import { createContext as
|
|
1597
|
+
import { createContext as createContext7, useContext as useContext7 } from "react";
|
|
1535
1598
|
import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1536
|
-
var MessageContext =
|
|
1599
|
+
var MessageContext = createContext7(null);
|
|
1537
1600
|
function useMessage() {
|
|
1538
|
-
const ctx =
|
|
1601
|
+
const ctx = useContext7(MessageContext);
|
|
1539
1602
|
if (!ctx) throw new Error("useMessage must be used within <Message>");
|
|
1540
1603
|
return ctx;
|
|
1541
1604
|
}
|
|
@@ -1544,23 +1607,25 @@ function getBubbleColors(theme) {
|
|
|
1544
1607
|
return isDark ? { assistantBg: "#2a2a4a", userBg: "#2a3a3a" } : { assistantBg: "#F1F5F9", userBg: "#E2E8F0" };
|
|
1545
1608
|
}
|
|
1546
1609
|
var TOOL_STATE_ICONS = {
|
|
1547
|
-
|
|
1610
|
+
pending: "\u2022",
|
|
1548
1611
|
// •
|
|
1549
|
-
|
|
1612
|
+
running: "\u280B",
|
|
1550
1613
|
// ⠋
|
|
1551
|
-
|
|
1614
|
+
completed: "\u2713",
|
|
1552
1615
|
// ✓
|
|
1616
|
+
error: "\u2715"
|
|
1617
|
+
// ✕
|
|
1553
1618
|
};
|
|
1554
1619
|
function getToolStateColor(state, theme) {
|
|
1555
1620
|
switch (state) {
|
|
1556
|
-
case "
|
|
1621
|
+
case "pending":
|
|
1557
1622
|
return theme.muted;
|
|
1558
|
-
case "
|
|
1623
|
+
case "running":
|
|
1559
1624
|
return theme.warning;
|
|
1560
|
-
case "
|
|
1625
|
+
case "completed":
|
|
1561
1626
|
return theme.success;
|
|
1562
|
-
|
|
1563
|
-
return theme.
|
|
1627
|
+
case "error":
|
|
1628
|
+
return theme.error;
|
|
1564
1629
|
}
|
|
1565
1630
|
}
|
|
1566
1631
|
function MessageContent({ children }) {
|
|
@@ -1585,45 +1650,57 @@ function MessageText({ children, isLast = false }) {
|
|
|
1585
1650
|
isLast && isStreaming && /* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: streamingCursor })
|
|
1586
1651
|
] });
|
|
1587
1652
|
}
|
|
1588
|
-
function MessageReasoning({
|
|
1589
|
-
return /* @__PURE__ */
|
|
1590
|
-
|
|
1591
|
-
{
|
|
1592
|
-
steps
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
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
|
+
] })
|
|
1670
|
+
] });
|
|
1597
1671
|
}
|
|
1598
|
-
function
|
|
1672
|
+
function MessageToolCall({ name: name2, state = "pending", result, color }) {
|
|
1599
1673
|
const theme = useTheme();
|
|
1600
1674
|
const { backgroundColor, textColor } = useMessage();
|
|
1601
|
-
const
|
|
1602
|
-
const
|
|
1603
|
-
const
|
|
1604
|
-
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";
|
|
1605
1678
|
return /* @__PURE__ */ jsxs13("box", { flexDirection: "column", children: [
|
|
1606
1679
|
/* @__PURE__ */ jsxs13("text", { children: [
|
|
1607
1680
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: stateColor, bg: backgroundColor }), children: icon }),
|
|
1608
1681
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, bg: backgroundColor }), children: " " }),
|
|
1609
|
-
/* @__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 }),
|
|
1610
1683
|
isActive && /* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: " ..." })
|
|
1611
1684
|
] }),
|
|
1612
|
-
state === "
|
|
1685
|
+
state === "completed" && result !== void 0 && /* @__PURE__ */ jsxs13("text", { children: [
|
|
1613
1686
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: " \u2514\u2500 " }),
|
|
1614
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) })
|
|
1615
1692
|
] })
|
|
1616
1693
|
] });
|
|
1617
1694
|
}
|
|
1618
|
-
function MessageSource({
|
|
1695
|
+
function MessageSource({ title, url, index }) {
|
|
1619
1696
|
const theme = useTheme();
|
|
1620
1697
|
const { backgroundColor, textColor } = useMessage();
|
|
1621
|
-
const
|
|
1698
|
+
const displayTitle = title || url || "source";
|
|
1622
1699
|
return /* @__PURE__ */ jsxs13("text", { children: [
|
|
1623
1700
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: "[" }),
|
|
1624
1701
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: theme.accent, bg: backgroundColor }), children: String(index + 1) }),
|
|
1625
1702
|
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: textColor, dim: true, bg: backgroundColor }), children: "] " }),
|
|
1626
|
-
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: theme.accent, bg: backgroundColor }), children:
|
|
1703
|
+
/* @__PURE__ */ jsx19("span", { style: textStyle({ fg: theme.accent, bg: backgroundColor }), children: displayTitle })
|
|
1627
1704
|
] });
|
|
1628
1705
|
}
|
|
1629
1706
|
function MessageFooter({ model, timestamp }) {
|
|
@@ -1659,7 +1736,7 @@ function Message({
|
|
|
1659
1736
|
Message.Content = MessageContent;
|
|
1660
1737
|
Message.Text = MessageText;
|
|
1661
1738
|
Message.Reasoning = MessageReasoning;
|
|
1662
|
-
Message.
|
|
1739
|
+
Message.ToolCall = MessageToolCall;
|
|
1663
1740
|
Message.Source = MessageSource;
|
|
1664
1741
|
Message.Footer = MessageFooter;
|
|
1665
1742
|
|
|
@@ -1685,1058 +1762,1122 @@ function useBreakpoints() {
|
|
|
1685
1762
|
};
|
|
1686
1763
|
}
|
|
1687
1764
|
|
|
1688
|
-
//
|
|
1689
|
-
import
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1765
|
+
// demos/gradient.tsx
|
|
1766
|
+
import figlet from "figlet";
|
|
1767
|
+
import ansiShadow from "figlet/importable-fonts/ANSI Shadow.js";
|
|
1768
|
+
figlet.parseFont("ANSI Shadow", ansiShadow);
|
|
1769
|
+
var art = figlet.textSync("gridland", { font: "ANSI Shadow" });
|
|
1770
|
+
var lines = art.split("\n").filter((l) => l.trimEnd().length > 0);
|
|
1771
|
+
var gradientNames = Object.keys(GRADIENTS);
|
|
1772
|
+
function GradientApp() {
|
|
1694
1773
|
const theme = useTheme();
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
"
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
/* @__PURE__ */ jsxs15("span", { style: textStyle({ dim: true }), children: [
|
|
1709
|
-
"\u2022",
|
|
1710
|
-
" "
|
|
1711
|
-
] }),
|
|
1712
|
-
"React reconciler with JSX"
|
|
1713
|
-
] }),
|
|
1714
|
-
/* @__PURE__ */ jsxs15("text", { children: [
|
|
1715
|
-
/* @__PURE__ */ jsxs15("span", { style: textStyle({ dim: true }), children: [
|
|
1716
|
-
"\u2022",
|
|
1717
|
-
" "
|
|
1718
|
-
] }),
|
|
1719
|
-
"Yoga flexbox layout engine"
|
|
1720
|
-
] }),
|
|
1721
|
-
/* @__PURE__ */ jsxs15("text", { children: [
|
|
1722
|
-
/* @__PURE__ */ jsxs15("span", { style: textStyle({ dim: true }), children: [
|
|
1723
|
-
"\u2022",
|
|
1724
|
-
" "
|
|
1725
|
-
] }),
|
|
1726
|
-
"Keyboard, mouse, and clipboard support"
|
|
1727
|
-
] }),
|
|
1728
|
-
/* @__PURE__ */ jsxs15("text", { children: [
|
|
1729
|
-
/* @__PURE__ */ jsxs15("span", { style: textStyle({ dim: true }), children: [
|
|
1730
|
-
"\u2022",
|
|
1731
|
-
" "
|
|
1732
|
-
] }),
|
|
1733
|
-
"Next.js and Vite plugins"
|
|
1734
|
-
] }),
|
|
1735
|
-
/* @__PURE__ */ jsx21("text", { style: textStyle({ bold: true, fg: theme.accent }), children: "Tech Stack" }),
|
|
1736
|
-
/* @__PURE__ */ jsx21("text", { children: "React + opentui engine + yoga-layout + HTML5 Canvas" }),
|
|
1737
|
-
/* @__PURE__ */ jsx21("text", { style: textStyle({ dim: true }), children: "Press q to close" })
|
|
1738
|
-
] }) });
|
|
1774
|
+
const [index, setIndex] = useState8(gradientNames.indexOf("instagram"));
|
|
1775
|
+
const name2 = gradientNames[index];
|
|
1776
|
+
useKeyboard((event) => {
|
|
1777
|
+
if (event.name === "left") setIndex((i) => i > 0 ? i - 1 : gradientNames.length - 1);
|
|
1778
|
+
if (event.name === "right") setIndex((i) => i < gradientNames.length - 1 ? i + 1 : 0);
|
|
1779
|
+
});
|
|
1780
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1 }, /* @__PURE__ */ React.createElement(Gradient, { name: name2 }, lines.join("\n"))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
1781
|
+
StatusBar,
|
|
1782
|
+
{
|
|
1783
|
+
items: [{ key: "\u2190\u2192", label: "gradient" }],
|
|
1784
|
+
extra: /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.accent, bold: true }) }, name2.padEnd(11))
|
|
1785
|
+
}
|
|
1786
|
+
)));
|
|
1739
1787
|
}
|
|
1740
1788
|
|
|
1741
|
-
//
|
|
1742
|
-
import {
|
|
1743
|
-
|
|
1789
|
+
// demos/ascii.tsx
|
|
1790
|
+
import { useState as useState9 } from "react";
|
|
1791
|
+
import { useKeyboard as useKeyboard2 } from "@gridland/utils";
|
|
1792
|
+
import figlet2 from "figlet";
|
|
1793
|
+
import ansiShadow2 from "figlet/importable-fonts/ANSI Shadow.js";
|
|
1794
|
+
import big from "figlet/importable-fonts/Big.js";
|
|
1795
|
+
import doom from "figlet/importable-fonts/Doom.js";
|
|
1796
|
+
import slant from "figlet/importable-fonts/Slant.js";
|
|
1797
|
+
import speed from "figlet/importable-fonts/Speed.js";
|
|
1798
|
+
import standard from "figlet/importable-fonts/Standard.js";
|
|
1799
|
+
import block from "figlet/importable-fonts/Block.js";
|
|
1800
|
+
import colossal from "figlet/importable-fonts/Colossal.js";
|
|
1801
|
+
var fonts = [
|
|
1802
|
+
{ name: "ANSI Shadow", data: ansiShadow2 },
|
|
1803
|
+
{ name: "Standard", data: standard },
|
|
1804
|
+
{ name: "Big", data: big },
|
|
1805
|
+
{ name: "Doom", data: doom },
|
|
1806
|
+
{ name: "Slant", data: slant },
|
|
1807
|
+
{ name: "Speed", data: speed },
|
|
1808
|
+
{ name: "Block", data: block },
|
|
1809
|
+
{ name: "Colossal", data: colossal }
|
|
1810
|
+
];
|
|
1811
|
+
for (const f of fonts) {
|
|
1812
|
+
figlet2.parseFont(f.name, f.data);
|
|
1813
|
+
}
|
|
1814
|
+
function getLines(fontName) {
|
|
1815
|
+
const art2 = figlet2.textSync("gridland", { font: fontName });
|
|
1816
|
+
return art2.split("\n").filter((l) => l.trimEnd().length > 0);
|
|
1817
|
+
}
|
|
1818
|
+
function AsciiApp() {
|
|
1744
1819
|
const theme = useTheme();
|
|
1745
|
-
|
|
1746
|
-
|
|
1820
|
+
const [fontIndex, setFontIndex] = useState9(fonts.findIndex((f) => f.name === "Colossal"));
|
|
1821
|
+
const font = fonts[fontIndex];
|
|
1822
|
+
const lines2 = getLines(font.name);
|
|
1823
|
+
useKeyboard2((event) => {
|
|
1824
|
+
if (event.name === "left") setFontIndex((i) => i > 0 ? i - 1 : fonts.length - 1);
|
|
1825
|
+
if (event.name === "right") setFontIndex((i) => i < fonts.length - 1 ? i + 1 : 0);
|
|
1826
|
+
});
|
|
1827
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1 }, lines2.map((line, i) => /* @__PURE__ */ React.createElement("text", { key: i, fg: theme.accent, bold: true }, line))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
1828
|
+
StatusBar,
|
|
1747
1829
|
{
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
borderColor: theme.border,
|
|
1751
|
-
paddingX: 1,
|
|
1752
|
-
flexDirection: "column",
|
|
1753
|
-
flexShrink: 0,
|
|
1754
|
-
children: /* @__PURE__ */ jsxs16("text", { children: [
|
|
1755
|
-
/* @__PURE__ */ jsx22("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
1756
|
-
/* @__PURE__ */ jsx22("span", { style: textStyle({ bold: true }), children: "bun create " }),
|
|
1757
|
-
/* @__PURE__ */ jsx22("span", { style: textStyle({ fg: theme.accent }), children: "gridland" })
|
|
1758
|
-
] })
|
|
1830
|
+
items: [{ key: "\u2190\u2192", label: "change font" }],
|
|
1831
|
+
extra: /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.accent, bold: true }) }, font.name.padEnd(11))
|
|
1759
1832
|
}
|
|
1760
|
-
);
|
|
1833
|
+
)));
|
|
1761
1834
|
}
|
|
1762
1835
|
|
|
1763
|
-
//
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1836
|
+
// demos/table.tsx
|
|
1837
|
+
function TableApp() {
|
|
1838
|
+
const data2 = [
|
|
1839
|
+
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
1840
|
+
{ name: "Bob", role: "Designer", status: "Active" },
|
|
1841
|
+
{ name: "Charlie", role: "PM", status: "Away" }
|
|
1842
|
+
];
|
|
1843
|
+
return /* @__PURE__ */ React.createElement("box", { padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement(Table, { data: data2, headerColor: "cyan", borderColor: "#5e81ac" }));
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
// demos/spinner.tsx
|
|
1847
|
+
import { useKeyboard as useKeyboard3 } from "@gridland/utils";
|
|
1848
|
+
function SpinnerApp() {
|
|
1849
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { flexGrow: 1 }, /* @__PURE__ */ React.createElement(SpinnerPicker, { useKeyboard: useKeyboard3 })), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [{ key: "\u2190\u2192", label: "change variant" }] })));
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
// demos/select-input.tsx
|
|
1853
|
+
import { useState as useState10 } from "react";
|
|
1854
|
+
import { useKeyboard as useKeyboard4 } from "@gridland/utils";
|
|
1855
|
+
var items = [
|
|
1856
|
+
{ label: "TypeScript", value: "ts" },
|
|
1857
|
+
{ label: "JavaScript", value: "js" },
|
|
1858
|
+
{ label: "Python", value: "py" },
|
|
1859
|
+
{ label: "Rust", value: "rs" }
|
|
1860
|
+
];
|
|
1861
|
+
function SelectInputApp() {
|
|
1862
|
+
const [submitted, setSubmitted] = useState10(false);
|
|
1863
|
+
const [resetKey, setResetKey] = useState10(0);
|
|
1864
|
+
useKeyboard4((event) => {
|
|
1865
|
+
if (submitted && event.name === "r") {
|
|
1866
|
+
setSubmitted(false);
|
|
1867
|
+
setResetKey((k) => k + 1);
|
|
1868
|
+
}
|
|
1869
|
+
});
|
|
1870
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement(
|
|
1871
|
+
SelectInput,
|
|
1770
1872
|
{
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
flexShrink: 0,
|
|
1777
|
-
children: /* @__PURE__ */ jsxs17("text", { children: [
|
|
1778
|
-
/* @__PURE__ */ jsx23("span", { children: "\u{1F431}" }),
|
|
1779
|
-
/* @__PURE__ */ jsx23("a", { href: "https://github.com/thoughtfulllc/gridland", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " GitHub" }),
|
|
1780
|
-
/* @__PURE__ */ jsx23("span", { children: " " }),
|
|
1781
|
-
/* @__PURE__ */ jsx23("span", { children: "\u{1F4D6}" }),
|
|
1782
|
-
/* @__PURE__ */ jsx23("a", { href: "https://gridland.io/docs", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " Docs" })
|
|
1783
|
-
] })
|
|
1873
|
+
key: resetKey,
|
|
1874
|
+
items,
|
|
1875
|
+
title: "Choose a language",
|
|
1876
|
+
useKeyboard: useKeyboard4,
|
|
1877
|
+
onSubmit: () => setSubmitted(true)
|
|
1784
1878
|
}
|
|
1785
|
-
)
|
|
1879
|
+
)), /* @__PURE__ */ React.createElement(StatusBar, { items: submitted ? [{ key: "r", label: "reset demo" }] : [
|
|
1880
|
+
{ key: "\u2191\u2193", label: "select" },
|
|
1881
|
+
{ key: "enter", label: "submit" }
|
|
1882
|
+
] }));
|
|
1786
1883
|
}
|
|
1787
1884
|
|
|
1788
|
-
//
|
|
1789
|
-
import { useState as
|
|
1790
|
-
import
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1885
|
+
// demos/multi-select.tsx
|
|
1886
|
+
import { useState as useState11 } from "react";
|
|
1887
|
+
import { useKeyboard as useKeyboard5 } from "@gridland/utils";
|
|
1888
|
+
var items2 = [
|
|
1889
|
+
{ label: "TypeScript", value: "ts" },
|
|
1890
|
+
{ label: "JavaScript", value: "js" },
|
|
1891
|
+
{ label: "Python", value: "py" },
|
|
1892
|
+
{ label: "Rust", value: "rs" }
|
|
1893
|
+
];
|
|
1894
|
+
function MultiSelectApp() {
|
|
1895
|
+
const [submitted, setSubmitted] = useState11(false);
|
|
1896
|
+
const [resetKey, setResetKey] = useState11(0);
|
|
1897
|
+
useKeyboard5((event) => {
|
|
1898
|
+
if (submitted && event.name === "r") {
|
|
1899
|
+
setSubmitted(false);
|
|
1900
|
+
setResetKey((k) => k + 1);
|
|
1901
|
+
}
|
|
1902
|
+
});
|
|
1903
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement(
|
|
1904
|
+
MultiSelect,
|
|
1905
|
+
{
|
|
1906
|
+
key: resetKey,
|
|
1907
|
+
items: items2,
|
|
1908
|
+
title: "Select languages",
|
|
1909
|
+
useKeyboard: useKeyboard5,
|
|
1910
|
+
onSubmit: () => setSubmitted(true)
|
|
1911
|
+
}
|
|
1912
|
+
)), /* @__PURE__ */ React.createElement(StatusBar, { items: submitted ? [{ key: "r", label: "reset demo" }] : [
|
|
1913
|
+
{ key: "\u2191\u2193", label: "move" },
|
|
1914
|
+
{ key: "enter", label: "select" },
|
|
1915
|
+
{ key: "a", label: "all" },
|
|
1916
|
+
{ key: "x", label: "clear" }
|
|
1917
|
+
] }));
|
|
1796
1918
|
}
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
return progress;
|
|
1820
|
-
}
|
|
1821
|
-
function RevealGradient({ children, revealCol }) {
|
|
1822
|
-
const gradientColors = GRADIENTS.instagram;
|
|
1823
|
-
const lines = children.split("\n");
|
|
1824
|
-
const maxLength = Math.max(...lines.map((l) => l.length));
|
|
1825
|
-
if (maxLength === 0) return /* @__PURE__ */ jsx24("text", { children });
|
|
1826
|
-
const hexColors = useMemo4(() => generateGradient(gradientColors, maxLength), [maxLength]);
|
|
1827
|
-
return /* @__PURE__ */ jsx24("box", { position: "relative", width: maxLength, height: lines.length, shouldFill: false, children: lines.map((line, lineIndex) => {
|
|
1828
|
-
const runs = [];
|
|
1829
|
-
let current = null;
|
|
1830
|
-
for (let i = 0; i < line.length; i++) {
|
|
1831
|
-
const revealed = i <= revealCol;
|
|
1832
|
-
const char = line[i];
|
|
1833
|
-
const isVisible = revealed && char !== " ";
|
|
1834
|
-
if (isVisible) {
|
|
1835
|
-
if (!current) {
|
|
1836
|
-
current = { start: i, chars: [] };
|
|
1837
|
-
}
|
|
1838
|
-
current.chars.push(char);
|
|
1839
|
-
} else {
|
|
1840
|
-
if (current) {
|
|
1841
|
-
runs.push(current);
|
|
1842
|
-
current = null;
|
|
1843
|
-
}
|
|
1844
|
-
}
|
|
1919
|
+
|
|
1920
|
+
// demos/prompt-input.tsx
|
|
1921
|
+
import { useState as useState12 } from "react";
|
|
1922
|
+
import { useKeyboard as useKeyboard6 } from "@gridland/utils";
|
|
1923
|
+
var commands = [{ cmd: "/model", desc: "Switch model" }];
|
|
1924
|
+
var files = ["src/index.ts", "src/routes.ts", "src/auth.ts", "package.json"];
|
|
1925
|
+
var models = [
|
|
1926
|
+
{ label: "Claude Opus", value: "opus" },
|
|
1927
|
+
{ label: "Claude Sonnet", value: "sonnet" },
|
|
1928
|
+
{ label: "Claude Haiku", value: "haiku" }
|
|
1929
|
+
];
|
|
1930
|
+
function PromptInputApp() {
|
|
1931
|
+
const theme = useTheme();
|
|
1932
|
+
const [lastMessage, setLastMessage] = useState12("");
|
|
1933
|
+
const [model, setModel] = useState12("opus");
|
|
1934
|
+
const [showModelPicker, setShowModelPicker] = useState12(false);
|
|
1935
|
+
const [resetKey, setResetKey] = useState12(0);
|
|
1936
|
+
const handleSubmit = (msg) => {
|
|
1937
|
+
if (msg.text === "/model") {
|
|
1938
|
+
setShowModelPicker(true);
|
|
1939
|
+
setResetKey((k) => k + 1);
|
|
1940
|
+
return;
|
|
1845
1941
|
}
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1942
|
+
setLastMessage(msg.text);
|
|
1943
|
+
};
|
|
1944
|
+
if (showModelPicker) {
|
|
1945
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement(Modal, { title: "Select Model", useKeyboard: useKeyboard6, onClose: () => setShowModelPicker(false) }, /* @__PURE__ */ React.createElement("box", { paddingX: 1 }, /* @__PURE__ */ React.createElement(
|
|
1946
|
+
SelectInput,
|
|
1849
1947
|
{
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
},
|
|
1860
|
-
ci
|
|
1861
|
-
)) })
|
|
1862
|
-
},
|
|
1863
|
-
`${lineIndex}-${runIndex}`
|
|
1864
|
-
));
|
|
1865
|
-
}) });
|
|
1866
|
-
}
|
|
1867
|
-
function Logo({ compact, narrow, mobile }) {
|
|
1868
|
-
const isBrowser = typeof document !== "undefined";
|
|
1869
|
-
const progress = useAnimation(900);
|
|
1870
|
-
const artHeight = compact ? 1 : narrow ? ART_HEIGHT * 2 : ART_HEIGHT;
|
|
1871
|
-
const dropOffset = Math.round((1 - progress) * -artHeight);
|
|
1872
|
-
const revealProgress = Math.max(0, Math.min(1, (progress - 0.1) / 0.7));
|
|
1873
|
-
const maxWidth = compact ? 8 : narrow ? 40 : 62;
|
|
1874
|
-
const revealCol = Math.round(revealProgress * (maxWidth + 4)) - 2;
|
|
1875
|
-
const taglineOpacity = Math.max(0, Math.min(1, (progress - 0.7) / 0.3));
|
|
1876
|
-
const subtitle = /* @__PURE__ */ jsxs18(Fragment6, { children: [
|
|
1877
|
-
/* @__PURE__ */ jsx24("text", { children: " " }),
|
|
1878
|
-
/* @__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: [
|
|
1879
|
-
"A framework for building terminal apps, built on ",
|
|
1880
|
-
/* @__PURE__ */ jsx24("a", { href: "https://opentui.com", style: { attributes: 72, fg: "#d4b0e8" }, children: "OpenTUI" }),
|
|
1881
|
-
" + React." + (mobile ? " " : "\n") + "(Gridland apps, like this website, work in the browser and terminal.)"
|
|
1882
|
-
] }) })
|
|
1883
|
-
] });
|
|
1884
|
-
if (!isBrowser) {
|
|
1885
|
-
const art = compact ? "gridland" : narrow ? gridArt + "\n" + landArt : fullArt;
|
|
1886
|
-
return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexShrink: 0, width: "100%", alignItems: "center", children: [
|
|
1887
|
-
/* @__PURE__ */ jsx24(Gradient, { name: "instagram", children: art }),
|
|
1888
|
-
/* @__PURE__ */ jsx24("text", { children: " " }),
|
|
1889
|
-
/* @__PURE__ */ jsx24("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs18("text", { style: textStyle({ fg: "#d4b0e8" }), shouldFill: false, children: [
|
|
1890
|
-
"A framework for building terminal apps, built on OpenTUI + React.",
|
|
1891
|
-
"\n",
|
|
1892
|
-
"(Gridland apps, like this website, work in the browser and terminal.)"
|
|
1893
|
-
] }) })
|
|
1894
|
-
] });
|
|
1895
|
-
}
|
|
1896
|
-
if (compact) {
|
|
1897
|
-
return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
1898
|
-
/* @__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" }) }) }),
|
|
1899
|
-
subtitle
|
|
1900
|
-
] });
|
|
1901
|
-
}
|
|
1902
|
-
if (narrow) {
|
|
1903
|
-
return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
1904
|
-
/* @__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: [
|
|
1905
|
-
/* @__PURE__ */ jsx24(RevealGradient, { revealCol, children: gridArt }),
|
|
1906
|
-
/* @__PURE__ */ jsx24(RevealGradient, { revealCol, children: landArt })
|
|
1907
|
-
] }) }),
|
|
1908
|
-
subtitle
|
|
1909
|
-
] });
|
|
1948
|
+
items: models,
|
|
1949
|
+
defaultValue: model,
|
|
1950
|
+
useKeyboard: useKeyboard6,
|
|
1951
|
+
onSubmit: (value) => {
|
|
1952
|
+
setModel(value);
|
|
1953
|
+
setShowModelPicker(false);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
))));
|
|
1910
1957
|
}
|
|
1911
|
-
return /* @__PURE__ */
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1958
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, lastMessage ? /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.muted }) }, "Sent: "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground }) }, lastMessage)) : /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", null, " "))), /* @__PURE__ */ React.createElement(
|
|
1959
|
+
PromptInput,
|
|
1960
|
+
{
|
|
1961
|
+
key: resetKey,
|
|
1962
|
+
commands,
|
|
1963
|
+
files,
|
|
1964
|
+
placeholder: "Message Claude...",
|
|
1965
|
+
showDividers: true,
|
|
1966
|
+
useKeyboard: useKeyboard6,
|
|
1967
|
+
onSubmit: handleSubmit
|
|
1968
|
+
}
|
|
1969
|
+
), /* @__PURE__ */ React.createElement("box", null, /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true }) }, "model: " + model))), /* @__PURE__ */ React.createElement("box", { paddingTop: 1, paddingLeft: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [
|
|
1970
|
+
{ key: "\u23CE enter", label: "send" },
|
|
1971
|
+
{ key: "/model", label: "change model" },
|
|
1972
|
+
{ key: "\u2191", label: "history" }
|
|
1973
|
+
] })));
|
|
1915
1974
|
}
|
|
1916
1975
|
|
|
1917
|
-
//
|
|
1918
|
-
import {
|
|
1976
|
+
// demos/text-input.tsx
|
|
1977
|
+
import { useState as useState13 } from "react";
|
|
1978
|
+
import { useKeyboard as useKeyboard7 } from "@gridland/utils";
|
|
1979
|
+
var FIELDS = [
|
|
1980
|
+
{ label: "Username", placeholder: "enter your name", maxLength: 30, required: true },
|
|
1981
|
+
{ label: "Email", placeholder: "user@example.com", maxLength: 50, required: true, description: "We'll never share your email" },
|
|
1982
|
+
{ label: "Password", placeholder: "enter password", maxLength: 40 },
|
|
1983
|
+
{ label: "API Key", placeholder: "sk-...", maxLength: 60, disabled: true }
|
|
1984
|
+
];
|
|
1985
|
+
function TextInputApp() {
|
|
1986
|
+
const [activeField, setActiveField] = useState13(0);
|
|
1987
|
+
const [values, setValues] = useState13(FIELDS.map(() => ""));
|
|
1988
|
+
useKeyboard7((event) => {
|
|
1989
|
+
if (event.name === "up") setActiveField((i) => Math.max(0, i - 1));
|
|
1990
|
+
if (event.name === "down") setActiveField((i) => Math.min(FIELDS.length - 1, i + 1));
|
|
1991
|
+
});
|
|
1992
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", paddingX: 1, paddingTop: 1, flexGrow: 1 }, FIELDS.map((field, i) => /* @__PURE__ */ React.createElement("box", { key: field.label, marginBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
1993
|
+
TextInput,
|
|
1994
|
+
{
|
|
1995
|
+
label: field.label,
|
|
1996
|
+
placeholder: field.placeholder,
|
|
1997
|
+
prompt: "> ",
|
|
1998
|
+
focus: i === activeField,
|
|
1999
|
+
maxLength: field.maxLength,
|
|
2000
|
+
value: values[i],
|
|
2001
|
+
onChange: (v) => setValues((prev) => prev.map((old, j) => j === i ? v : old)),
|
|
2002
|
+
required: field.required,
|
|
2003
|
+
disabled: field.disabled,
|
|
2004
|
+
description: field.description
|
|
2005
|
+
}
|
|
2006
|
+
)))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [{ key: "\u2191\u2193", label: "field" }] })));
|
|
2007
|
+
}
|
|
1919
2008
|
|
|
1920
|
-
//
|
|
1921
|
-
import { useState as
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2009
|
+
// demos/link.tsx
|
|
2010
|
+
import { useState as useState14 } from "react";
|
|
2011
|
+
import { useKeyboard as useKeyboard8 } from "@gridland/utils";
|
|
2012
|
+
var MODES = ["solid", "dashed", "dotted", "none"];
|
|
2013
|
+
function LinkApp() {
|
|
2014
|
+
const theme = useTheme();
|
|
2015
|
+
const [modeIndex, setModeIndex] = useState14(0);
|
|
2016
|
+
const mode = MODES[modeIndex];
|
|
2017
|
+
useKeyboard8((event) => {
|
|
2018
|
+
if (event.name === "right") setModeIndex((i) => (i + 1) % MODES.length);
|
|
2019
|
+
if (event.name === "left") setModeIndex((i) => (i - 1 + MODES.length) % MODES.length);
|
|
2020
|
+
});
|
|
2021
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: theme.foreground }) }, "Made by ", /* @__PURE__ */ React.createElement("a", { href: "https://cjroth.com", style: { attributes: mode === "solid" ? 8 : mode === "dashed" ? 24 : mode === "dotted" ? 72 : 0, fg: theme.accent } }, "Chris Roth"), " and ", /* @__PURE__ */ React.createElement("a", { href: "https://jessicacheng.studio", style: { attributes: mode === "solid" ? 8 : mode === "dashed" ? 24 : mode === "dotted" ? 72 : 0, fg: theme.accent } }, "Jessica Cheng"), ".")), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
2022
|
+
StatusBar,
|
|
2023
|
+
{
|
|
2024
|
+
extra: /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true, fg: theme.foreground }) }, mode.padEnd(6)),
|
|
2025
|
+
items: [{ key: "\u2190\u2192", label: "underline style" }]
|
|
2026
|
+
}
|
|
2027
|
+
)));
|
|
1925
2028
|
}
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
2029
|
+
|
|
2030
|
+
// demos/tabs.tsx
|
|
2031
|
+
import { useState as useState15 } from "react";
|
|
2032
|
+
import { useKeyboard as useKeyboard9 } from "@gridland/utils";
|
|
2033
|
+
var tabs = ["Files", "Search", "Git", "Debug"];
|
|
2034
|
+
function TabBarApp() {
|
|
2035
|
+
const [selectedIndex, setSelectedIndex] = useState15(0);
|
|
2036
|
+
useKeyboard9((event) => {
|
|
2037
|
+
if (event.name === "left") setSelectedIndex((i) => i > 0 ? i - 1 : tabs.length - 1);
|
|
2038
|
+
if (event.name === "right") setSelectedIndex((i) => i < tabs.length - 1 ? i + 1 : 0);
|
|
2039
|
+
});
|
|
2040
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { padding: 1 }, /* @__PURE__ */ React.createElement(TabBar, { options: tabs, selectedIndex })), /* @__PURE__ */ React.createElement("box", { flexGrow: 1 }), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [{ key: "\u2190\u2192", label: "switch tab" }] })));
|
|
1934
2041
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
2042
|
+
|
|
2043
|
+
// demos/status-bar.tsx
|
|
2044
|
+
import { useState as useState16 } from "react";
|
|
2045
|
+
import { useKeyboard as useKeyboard10 } from "@gridland/utils";
|
|
2046
|
+
var shortcuts = [
|
|
2047
|
+
{ key: "Tab", label: "switch focus" },
|
|
2048
|
+
{ key: "\u2190\u2192", label: "cycle" },
|
|
2049
|
+
{ key: "b", label: "back" },
|
|
2050
|
+
{ key: "z", label: "reset" }
|
|
2051
|
+
];
|
|
2052
|
+
function StatusBarApp() {
|
|
2053
|
+
const theme = useTheme();
|
|
2054
|
+
const [lastKey, setLastKey] = useState16(null);
|
|
2055
|
+
useKeyboard10((event) => {
|
|
2056
|
+
if (event.name === "tab") setLastKey("switch focus (Tab)");
|
|
2057
|
+
else if (event.name === "left") setLastKey("cycle (\u2190)");
|
|
2058
|
+
else if (event.name === "right") setLastKey("cycle (\u2192)");
|
|
2059
|
+
else if (event.name === "b") setLastKey("back (b)");
|
|
2060
|
+
else if (event.name === "z") setLastKey("reset (z)");
|
|
2061
|
+
});
|
|
2062
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", gap: 1, padding: 1 }, lastKey ? /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", null, "Pressed: "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true, fg: theme.accent }) }, lastKey)) : /* @__PURE__ */ React.createElement("text", { style: textStyle({ dim: true }) }, "Press a key to trigger an action"), /* @__PURE__ */ React.createElement(
|
|
2063
|
+
StatusBar,
|
|
2064
|
+
{
|
|
2065
|
+
items: shortcuts,
|
|
2066
|
+
extra: /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.success }) }, "\u25CF Ready")
|
|
1950
2067
|
}
|
|
2068
|
+
));
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
// demos/modal.tsx
|
|
2072
|
+
import { useState as useState17 } from "react";
|
|
2073
|
+
import { useKeyboard as useKeyboard11 } from "@gridland/utils";
|
|
2074
|
+
function ModalApp() {
|
|
2075
|
+
const theme = useTheme();
|
|
2076
|
+
const [isOpen, setIsOpen] = useState17(false);
|
|
2077
|
+
useKeyboard11((event) => {
|
|
2078
|
+
if (!isOpen && event.name === "m") setIsOpen(true);
|
|
2079
|
+
if (isOpen && (event.name === "q" || event.name === "escape")) setIsOpen(false);
|
|
2080
|
+
});
|
|
2081
|
+
if (isOpen) {
|
|
2082
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement(Modal, { title: "Example Modal", useKeyboard: useKeyboard11, onClose: () => setIsOpen(false) }, /* @__PURE__ */ React.createElement("box", { paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: theme.foreground }) }, "This is a modal overlay component."), /* @__PURE__ */ React.createElement("text", null, " "), /* @__PURE__ */ React.createElement("text", { style: textStyle({ dim: true, fg: theme.muted }) }, "It stretches to fill the full terminal height."))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [{ key: "q", label: "close" }] })));
|
|
1951
2083
|
}
|
|
1952
|
-
return {
|
|
2084
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true, fg: theme.muted }) }, "Press "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true, fg: theme.background, bg: theme.muted }) }, " m "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true, fg: theme.muted }) }, " to open modal")));
|
|
1953
2085
|
}
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
2086
|
+
|
|
2087
|
+
// demos/primitives.tsx
|
|
2088
|
+
function PrimitivesApp() {
|
|
2089
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(
|
|
2090
|
+
"box",
|
|
2091
|
+
{
|
|
2092
|
+
border: true,
|
|
2093
|
+
borderStyle: "rounded",
|
|
2094
|
+
borderColor: "#75715e",
|
|
2095
|
+
title: "Layout",
|
|
2096
|
+
titleAlignment: "center",
|
|
2097
|
+
padding: 1
|
|
2098
|
+
},
|
|
2099
|
+
/* @__PURE__ */ React.createElement("box", { flexDirection: "row", gap: 2 }, /* @__PURE__ */ React.createElement("box", { border: true, borderStyle: "single", borderColor: "#a6e22e", padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement("text", { fg: "#a6e22e", bold: true }, "Box 1")), /* @__PURE__ */ React.createElement("box", { border: true, borderStyle: "single", borderColor: "#f92672", padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement("text", { fg: "#f92672", bold: true }, "Box 2")), /* @__PURE__ */ React.createElement("box", { border: true, borderStyle: "single", borderColor: "#66d9ef", padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement("text", { fg: "#66d9ef", bold: true }, "Box 3")))
|
|
2100
|
+
), /* @__PURE__ */ React.createElement("text", { dim: true, fg: "#75715e" }, " Nested boxes with borders, colors & flexbox layout"));
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
// demos/chat.tsx
|
|
2104
|
+
import { useState as useState18, useCallback as useCallback3, useRef as useRef5 } from "react";
|
|
2105
|
+
import { useKeyboard as useKeyboard12 } from "@gridland/utils";
|
|
2106
|
+
var initialMessages = [
|
|
2107
|
+
{ id: "1", role: "user", content: "Show me my portfolio" },
|
|
2108
|
+
{ id: "2", role: "assistant", content: "Here's your current portfolio allocation:" },
|
|
2109
|
+
{ id: "3", role: "user", content: "Calculate rebalancing trades" },
|
|
2110
|
+
{ id: "4", role: "assistant", content: "I've calculated the optimal trades to rebalance your portfolio." }
|
|
2111
|
+
];
|
|
2112
|
+
var nextId = 5;
|
|
2113
|
+
function ChatApp() {
|
|
2114
|
+
const [messages, setMessages] = useState18(initialMessages);
|
|
2115
|
+
const [isLoading, setIsLoading] = useState18(false);
|
|
2116
|
+
const [streamingText, setStreamingText] = useState18("");
|
|
2117
|
+
const [activeToolCalls, setActiveToolCalls] = useState18([]);
|
|
2118
|
+
const intervalRef = useRef5(null);
|
|
2119
|
+
const handleSend = useCallback3((text) => {
|
|
2120
|
+
const userMsg = { id: String(nextId++), role: "user", content: text };
|
|
2121
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
2122
|
+
setIsLoading(true);
|
|
2123
|
+
const toolCallId = `tc-${nextId}`;
|
|
2124
|
+
setTimeout(() => {
|
|
2125
|
+
setIsLoading(false);
|
|
2126
|
+
setActiveToolCalls([{ id: toolCallId, title: "process_request", status: "in_progress" }]);
|
|
2127
|
+
}, 500);
|
|
2128
|
+
setTimeout(() => {
|
|
2129
|
+
setActiveToolCalls([{ id: toolCallId, title: "process_request", status: "completed" }]);
|
|
2130
|
+
}, 1200);
|
|
2131
|
+
const response = `You said: "${text}". This is a demo response.`;
|
|
2132
|
+
let charIndex = 0;
|
|
2133
|
+
setTimeout(() => {
|
|
2134
|
+
intervalRef.current = setInterval(() => {
|
|
2135
|
+
charIndex = Math.min(charIndex + 3, response.length);
|
|
2136
|
+
if (charIndex < response.length) {
|
|
2137
|
+
setStreamingText(response.slice(0, charIndex));
|
|
2138
|
+
} else {
|
|
2139
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
2140
|
+
setStreamingText("");
|
|
2141
|
+
setActiveToolCalls([]);
|
|
2142
|
+
setMessages((prev) => [
|
|
2143
|
+
...prev,
|
|
2144
|
+
{ id: String(nextId++), role: "assistant", content: response }
|
|
2145
|
+
]);
|
|
2146
|
+
}
|
|
2147
|
+
}, 50);
|
|
2148
|
+
}, 1400);
|
|
2149
|
+
}, []);
|
|
2150
|
+
const handleCancel = useCallback3(() => {
|
|
2151
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
2152
|
+
setIsLoading(false);
|
|
2153
|
+
setStreamingText("");
|
|
2154
|
+
setActiveToolCalls([]);
|
|
2155
|
+
}, []);
|
|
2156
|
+
return /* @__PURE__ */ React.createElement(
|
|
2157
|
+
ChatPanel,
|
|
2158
|
+
{
|
|
2159
|
+
messages,
|
|
2160
|
+
streamingText,
|
|
2161
|
+
isLoading,
|
|
2162
|
+
activeToolCalls,
|
|
2163
|
+
onSendMessage: handleSend,
|
|
2164
|
+
onCancel: handleCancel,
|
|
2165
|
+
placeholder: "Ask about your portfolio...",
|
|
2166
|
+
useKeyboard: useKeyboard12
|
|
2167
|
+
}
|
|
2168
|
+
);
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
// demos/chain-of-thought.tsx
|
|
2172
|
+
import { useState as useState19, useEffect as useEffect4, useRef as useRef6 } from "react";
|
|
2173
|
+
import { useKeyboard as useKeyboard13 } from "@gridland/utils";
|
|
2174
|
+
var ALL_STEPS = [
|
|
2175
|
+
{ tool: "Read", label: "Reading codebase", description: "src/", status: "done", delay: 1800 },
|
|
2176
|
+
{ tool: "Think", label: "Planning changes", description: "auth module", status: "done", delay: 2500 },
|
|
2177
|
+
{ tool: "Edit", label: "Editing files", description: "4 files", status: "done", delay: 3200 },
|
|
2178
|
+
{ tool: "Bash", label: "Running tests", description: "vitest", status: "done", delay: 2e3 },
|
|
2179
|
+
{ tool: "Edit", label: "Fixing test", description: "routes.test.ts", status: "done", delay: 1500 }
|
|
2180
|
+
];
|
|
2181
|
+
function ChainOfThoughtApp() {
|
|
2182
|
+
const [expanded, setExpanded] = useState19(true);
|
|
2183
|
+
const [phase, setPhase] = useState19("running");
|
|
2184
|
+
const [stepIndex, setStepIndex] = useState19(0);
|
|
2185
|
+
const timerRef = useRef6(null);
|
|
2186
|
+
useKeyboard13((event) => {
|
|
2187
|
+
if (event.name === "E" && event.ctrl && event.shift) setExpanded((v) => !v);
|
|
2188
|
+
if (event.name === "r") restart();
|
|
1963
2189
|
});
|
|
2190
|
+
function restart() {
|
|
2191
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2192
|
+
setPhase("running");
|
|
2193
|
+
setStepIndex(0);
|
|
2194
|
+
}
|
|
1964
2195
|
useEffect4(() => {
|
|
1965
|
-
if (
|
|
1966
|
-
|
|
1967
|
-
const
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
drop.y += drop.speed;
|
|
1977
|
-
if (Math.random() < 0.1) {
|
|
1978
|
-
const idx = Math.floor(Math.random() * drop.chars.length);
|
|
1979
|
-
drop.chars[idx] = randomChar();
|
|
1980
|
-
}
|
|
1981
|
-
if (drop.y - drop.length > height) {
|
|
1982
|
-
columns[x] = null;
|
|
1983
|
-
}
|
|
1984
|
-
}
|
|
1985
|
-
setState(buildGrid(columns, width, height));
|
|
1986
|
-
}, 80);
|
|
1987
|
-
return () => clearInterval(id);
|
|
1988
|
-
}, [width, height]);
|
|
2196
|
+
if (phase !== "running") return;
|
|
2197
|
+
if (stepIndex < ALL_STEPS.length) {
|
|
2198
|
+
const delay = ALL_STEPS[stepIndex].delay;
|
|
2199
|
+
timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
|
|
2200
|
+
} else {
|
|
2201
|
+
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
2202
|
+
}
|
|
2203
|
+
return () => {
|
|
2204
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2205
|
+
};
|
|
2206
|
+
}, [phase, stepIndex]);
|
|
1989
2207
|
useEffect4(() => {
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
)
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
2208
|
+
if (phase === "done") {
|
|
2209
|
+
timerRef.current = setTimeout(() => restart(), 3e3);
|
|
2210
|
+
}
|
|
2211
|
+
return () => {
|
|
2212
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2213
|
+
};
|
|
2214
|
+
}, [phase]);
|
|
2215
|
+
const steps = ALL_STEPS.map((s, i) => {
|
|
2216
|
+
if (i < stepIndex) return { ...s, status: "done" };
|
|
2217
|
+
if (i === stepIndex && phase === "running") return { ...s, status: "running" };
|
|
2218
|
+
return { ...s, status: phase === "done" ? "done" : "pending" };
|
|
2219
|
+
});
|
|
2220
|
+
const elapsedMs = ALL_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
|
|
2221
|
+
const totalMs = ALL_STEPS.reduce((sum, s) => sum + s.delay, 0);
|
|
2222
|
+
const durationStr = phase === "done" ? `${(totalMs / 1e3).toFixed(1)}s` : `${(elapsedMs / 1e3).toFixed(1)}s`;
|
|
2223
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement(ChainOfThought, { open: expanded, onOpenChange: setExpanded }, /* @__PURE__ */ React.createElement(ChainOfThoughtHeader, { duration: durationStr }), /* @__PURE__ */ React.createElement(ChainOfThoughtContent, null, steps.map((step, i) => /* @__PURE__ */ React.createElement(
|
|
2224
|
+
ChainOfThoughtStep,
|
|
2225
|
+
{
|
|
2226
|
+
key: i,
|
|
2227
|
+
label: step.label,
|
|
2228
|
+
description: step.description,
|
|
2229
|
+
status: step.status,
|
|
2230
|
+
isLast: i === steps.length - 1
|
|
2231
|
+
},
|
|
2232
|
+
step.output
|
|
2233
|
+
))))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [
|
|
2234
|
+
{ key: "ctrl+shift+e", label: "toggle" },
|
|
2235
|
+
{ key: "r", label: "restart" }
|
|
2236
|
+
] })));
|
|
1997
2237
|
}
|
|
1998
2238
|
|
|
1999
|
-
//
|
|
2000
|
-
import {
|
|
2001
|
-
|
|
2002
|
-
var
|
|
2003
|
-
function
|
|
2004
|
-
const
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
})
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
const theme = useTheme();
|
|
2019
|
-
const columnColors = useMemo5(
|
|
2020
|
-
() => width > 0 ? generateGradient([theme.accent, theme.secondary, theme.primary], width) : [],
|
|
2021
|
-
[width, theme.accent, theme.secondary, theme.primary]
|
|
2022
|
-
);
|
|
2023
|
-
const columnMutedColors = useMemo5(
|
|
2024
|
-
() => columnColors.map(buildMutedColors),
|
|
2025
|
-
[columnColors]
|
|
2026
|
-
);
|
|
2027
|
-
return /* @__PURE__ */ jsx25("box", { flexDirection: "column", children: grid.map((row, y) => /* @__PURE__ */ jsx25("text", { children: row.map((cell, x) => {
|
|
2028
|
-
const inClearRect = clearRect && y >= clearRect.top && y < clearRect.top + clearRect.height && x >= clearRect.left && x < clearRect.left + clearRect.width || clearRects && clearRects.some(
|
|
2029
|
-
(r) => y >= r.top && y < r.top + r.height && x >= r.left && x < r.left + r.width
|
|
2030
|
-
);
|
|
2031
|
-
const mutedColors = columnMutedColors[x];
|
|
2032
|
-
if (cell === " " || inClearRect || !mutedColors) {
|
|
2033
|
-
return /* @__PURE__ */ jsx25("span", { children: " " }, x);
|
|
2239
|
+
// demos/message.tsx
|
|
2240
|
+
import { useState as useState20, useEffect as useEffect5, useRef as useRef7 } from "react";
|
|
2241
|
+
import { useKeyboard as useKeyboard14 } from "@gridland/utils";
|
|
2242
|
+
var RESPONSE = "I've refactored the auth module. The changes include extracting the token validation into a shared helper, consolidating the middleware chain, and updating the test suite to match.";
|
|
2243
|
+
function MessageApp() {
|
|
2244
|
+
const [phase, setPhase] = useState20("idle");
|
|
2245
|
+
const [streamedText, setStreamedText] = useState20("");
|
|
2246
|
+
const timerRef = useRef7(null);
|
|
2247
|
+
useKeyboard14((event) => {
|
|
2248
|
+
if (event.name === "r") restart();
|
|
2249
|
+
});
|
|
2250
|
+
function restart() {
|
|
2251
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2252
|
+
setPhase("idle");
|
|
2253
|
+
setStreamedText("");
|
|
2254
|
+
}
|
|
2255
|
+
useEffect5(() => {
|
|
2256
|
+
if (phase === "idle") {
|
|
2257
|
+
timerRef.current = setTimeout(() => setPhase("streaming"), 800);
|
|
2034
2258
|
}
|
|
2035
|
-
return
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2259
|
+
return () => {
|
|
2260
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2261
|
+
};
|
|
2262
|
+
}, [phase]);
|
|
2263
|
+
useEffect5(() => {
|
|
2264
|
+
if (phase !== "streaming") return;
|
|
2265
|
+
if (streamedText.length < RESPONSE.length) {
|
|
2266
|
+
timerRef.current = setTimeout(() => {
|
|
2267
|
+
setStreamedText(RESPONSE.slice(0, streamedText.length + 2));
|
|
2268
|
+
}, 25);
|
|
2269
|
+
} else {
|
|
2270
|
+
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
2271
|
+
}
|
|
2272
|
+
return () => {
|
|
2273
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2274
|
+
};
|
|
2275
|
+
}, [phase, streamedText]);
|
|
2276
|
+
useEffect5(() => {
|
|
2277
|
+
if (phase === "done") {
|
|
2278
|
+
timerRef.current = setTimeout(() => restart(), 3e3);
|
|
2279
|
+
}
|
|
2280
|
+
return () => {
|
|
2281
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2282
|
+
};
|
|
2283
|
+
}, [phase]);
|
|
2284
|
+
const isStreaming = phase === "streaming";
|
|
2285
|
+
const isDone = phase === "done";
|
|
2286
|
+
const showAssistant = phase !== "idle";
|
|
2287
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement(Message, { role: "user" }, /* @__PURE__ */ React.createElement(Message.Content, null, /* @__PURE__ */ React.createElement(Message.Text, null, "Can you refactor the auth module?"))), showAssistant && /* @__PURE__ */ React.createElement(Message, { role: "assistant", isStreaming }, /* @__PURE__ */ React.createElement(Message.Content, null, /* @__PURE__ */ React.createElement(Message.Text, { isLast: true }, isDone ? RESPONSE : streamedText)))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [{ key: "r", label: "restart" }] })));
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
// demos/terminal-window.tsx
|
|
2291
|
+
function TerminalWindowApp() {
|
|
2292
|
+
const theme = useTheme();
|
|
2293
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: theme.secondary }) }, '$ echo "Hello from TerminalWindow"'), /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: theme.foreground }) }, "Hello from TerminalWindow"), /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: theme.secondary }) }, "$ _"));
|
|
2046
2294
|
}
|
|
2047
2295
|
|
|
2048
|
-
//
|
|
2049
|
-
import {
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2296
|
+
// demos/focus.tsx
|
|
2297
|
+
import { useState as useState21, useRef as useRef8 } from "react";
|
|
2298
|
+
import { useKeyboard as useKeyboard15 } from "@gridland/utils";
|
|
2299
|
+
var focusPanels = [
|
|
2300
|
+
{
|
|
2301
|
+
label: "Language",
|
|
2302
|
+
items: [
|
|
2303
|
+
{ label: "TypeScript", value: "ts" },
|
|
2304
|
+
{ label: "JavaScript", value: "js" },
|
|
2305
|
+
{ label: "Python", value: "py" }
|
|
2306
|
+
]
|
|
2307
|
+
},
|
|
2308
|
+
{
|
|
2309
|
+
label: "Framework",
|
|
2310
|
+
items: [
|
|
2311
|
+
{ label: "React", value: "react" },
|
|
2312
|
+
{ label: "Vue", value: "vue" },
|
|
2313
|
+
{ label: "Svelte", value: "svelte" }
|
|
2314
|
+
]
|
|
2315
|
+
},
|
|
2316
|
+
{
|
|
2317
|
+
label: "Runtime",
|
|
2318
|
+
items: [
|
|
2319
|
+
{ label: "Bun", value: "bun" },
|
|
2320
|
+
{ label: "Node", value: "node" },
|
|
2321
|
+
{ label: "Deno", value: "deno" }
|
|
2322
|
+
]
|
|
2323
|
+
}
|
|
2056
2324
|
];
|
|
2057
|
-
function
|
|
2058
|
-
const
|
|
2059
|
-
const
|
|
2060
|
-
const [
|
|
2061
|
-
const [
|
|
2062
|
-
const
|
|
2063
|
-
const
|
|
2064
|
-
const
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
const
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2325
|
+
function FocusApp() {
|
|
2326
|
+
const [panelIndex, setPanelIndex] = useState21(0);
|
|
2327
|
+
const [entered, setEntered] = useState21(false);
|
|
2328
|
+
const [cursors, setCursors] = useState21([0, 0, 0]);
|
|
2329
|
+
const [selections, setSelections] = useState21([null, null, null]);
|
|
2330
|
+
const panelRef = useRef8(0);
|
|
2331
|
+
const enteredRef = useRef8(false);
|
|
2332
|
+
const cursorsRef = useRef8([0, 0, 0]);
|
|
2333
|
+
panelRef.current = panelIndex;
|
|
2334
|
+
enteredRef.current = entered;
|
|
2335
|
+
cursorsRef.current = cursors;
|
|
2336
|
+
useKeyboard15((event) => {
|
|
2337
|
+
const pi = panelRef.current;
|
|
2338
|
+
if (enteredRef.current) {
|
|
2339
|
+
const items3 = focusPanels[pi].items;
|
|
2340
|
+
const cur = cursorsRef.current[pi];
|
|
2341
|
+
if (event.name === "down" || event.name === "j") {
|
|
2342
|
+
const next = (cur + 1) % items3.length;
|
|
2343
|
+
cursorsRef.current = [...cursorsRef.current];
|
|
2344
|
+
cursorsRef.current[pi] = next;
|
|
2345
|
+
setCursors([...cursorsRef.current]);
|
|
2346
|
+
} else if (event.name === "up" || event.name === "k") {
|
|
2347
|
+
const next = (cur - 1 + items3.length) % items3.length;
|
|
2348
|
+
cursorsRef.current = [...cursorsRef.current];
|
|
2349
|
+
cursorsRef.current[pi] = next;
|
|
2350
|
+
setCursors([...cursorsRef.current]);
|
|
2351
|
+
} else if (event.name === "return") {
|
|
2352
|
+
const selected = items3[cursorsRef.current[pi]].label;
|
|
2353
|
+
setSelections((s) => {
|
|
2354
|
+
const n = [...s];
|
|
2355
|
+
n[pi] = selected;
|
|
2356
|
+
return n;
|
|
2357
|
+
});
|
|
2358
|
+
enteredRef.current = false;
|
|
2359
|
+
setEntered(false);
|
|
2360
|
+
} else if (event.name === "escape") {
|
|
2361
|
+
enteredRef.current = false;
|
|
2362
|
+
setEntered(false);
|
|
2363
|
+
}
|
|
2364
|
+
} else {
|
|
2365
|
+
if (event.name === "right" || event.name === "tab") {
|
|
2366
|
+
const next = (pi + 1) % focusPanels.length;
|
|
2367
|
+
panelRef.current = next;
|
|
2368
|
+
setPanelIndex(next);
|
|
2369
|
+
} else if (event.name === "left") {
|
|
2370
|
+
const next = (pi - 1 + focusPanels.length) % focusPanels.length;
|
|
2371
|
+
panelRef.current = next;
|
|
2372
|
+
setPanelIndex(next);
|
|
2373
|
+
} else if (event.name === "return") {
|
|
2374
|
+
enteredRef.current = true;
|
|
2375
|
+
setEntered(true);
|
|
2376
|
+
}
|
|
2082
2377
|
}
|
|
2378
|
+
event.preventDefault();
|
|
2083
2379
|
});
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
/* @__PURE__ */ jsxs19("box", { flexGrow: 1, border: true, borderStyle: "rounded", borderColor: theme.border, flexDirection: "column", overflow: "hidden", children: [
|
|
2115
|
-
/* @__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)) }),
|
|
2116
|
-
/* @__PURE__ */ jsx26("box", { flexShrink: 0, paddingX: 1, paddingBottom: 0, children: /* @__PURE__ */ jsx26(PromptInput, { splaceholder: "Ask about Gridland...", status: chatStatus, onSubmit: handleChatSubmit, useKeyboard: useKeyboard3 }) })
|
|
2117
|
-
] })
|
|
2118
|
-
] }),
|
|
2119
|
-
/* @__PURE__ */ jsx26(StatusBar, { items: [{ key: "a", label: "about" }] })
|
|
2120
|
-
] })
|
|
2121
|
-
] });
|
|
2380
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "row", gap: 1, padding: 1, flexGrow: 1 }, focusPanels.map((panel, i) => {
|
|
2381
|
+
const focused = i === panelIndex;
|
|
2382
|
+
const active = focused && entered;
|
|
2383
|
+
const selected = selections[i];
|
|
2384
|
+
return /* @__PURE__ */ React.createElement(
|
|
2385
|
+
"box",
|
|
2386
|
+
{
|
|
2387
|
+
key: panel.label,
|
|
2388
|
+
border: true,
|
|
2389
|
+
borderStyle: "rounded",
|
|
2390
|
+
borderColor: active ? "#22c55e" : focused ? "#3b82f6" : "#555",
|
|
2391
|
+
flexGrow: 1
|
|
2392
|
+
},
|
|
2393
|
+
/* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement("text", { style: {
|
|
2394
|
+
fg: active ? "#22c55e" : focused ? "#3b82f6" : "#888",
|
|
2395
|
+
bold: focused
|
|
2396
|
+
} }, focused ? "\u25B8 " : " ", panel.label, selected ? `: ${selected}` : ""), (active || !entered && focused) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("box", { height: 1 }), /* @__PURE__ */ React.createElement("box", { flexDirection: "column" }, panel.items.map((item, j) => {
|
|
2397
|
+
const highlighted = active && j === cursors[i];
|
|
2398
|
+
return /* @__PURE__ */ React.createElement("text", { key: item.value, style: {
|
|
2399
|
+
fg: highlighted ? "#22c55e" : active ? "#ccc" : "#666",
|
|
2400
|
+
bold: highlighted
|
|
2401
|
+
} }, highlighted ? " \u25B8 " : " ", item.label);
|
|
2402
|
+
}))))
|
|
2403
|
+
);
|
|
2404
|
+
})), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
2405
|
+
StatusBar,
|
|
2406
|
+
{
|
|
2407
|
+
items: entered ? [{ key: "\u2191\u2193", label: "select" }, { key: "enter", label: "confirm" }, { key: "esc", label: "back" }] : [{ key: "\u2190\u2192", label: "navigate" }, { key: "enter", label: "select" }, { key: "tab", label: "next" }]
|
|
2408
|
+
}
|
|
2409
|
+
)));
|
|
2122
2410
|
}
|
|
2123
2411
|
|
|
2124
|
-
//
|
|
2125
|
-
import {
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
{ name: "Speed", data: speed },
|
|
2145
|
-
{ name: "Block", data: block },
|
|
2146
|
-
{ name: "Colossal", data: colossal }
|
|
2147
|
-
];
|
|
2148
|
-
for (const f of fonts) {
|
|
2149
|
-
figlet2.parseFont(f.name, f.data);
|
|
2150
|
-
}
|
|
2151
|
-
function getFigletLines(fontName, text = "gridland") {
|
|
2152
|
-
const art = figlet2.textSync(text, { font: fontName });
|
|
2153
|
-
return art.split("\n").filter((l) => l.trimEnd().length > 0);
|
|
2412
|
+
// demos/pointer.tsx
|
|
2413
|
+
import { useState as useState22, useRef as useRef9 } from "react";
|
|
2414
|
+
import { useKeyboard as useKeyboard16 } from "@gridland/utils";
|
|
2415
|
+
var pointerColors = ["#ef4444", "#f97316", "#eab308", "#22c55e", "#3b82f6", "#8b5cf6"];
|
|
2416
|
+
var pointerColorNames = ["Red", "Orange", "Yellow", "Green", "Blue", "Purple"];
|
|
2417
|
+
function HoverBox() {
|
|
2418
|
+
const [hovering, setHovering] = useState22(false);
|
|
2419
|
+
return /* @__PURE__ */ React.createElement(
|
|
2420
|
+
"box",
|
|
2421
|
+
{
|
|
2422
|
+
border: true,
|
|
2423
|
+
borderStyle: "rounded",
|
|
2424
|
+
borderColor: hovering ? "#22c55e" : "#555",
|
|
2425
|
+
width: 20,
|
|
2426
|
+
height: 5,
|
|
2427
|
+
onMouseOver: () => setHovering(true),
|
|
2428
|
+
onMouseOut: () => setHovering(false)
|
|
2429
|
+
},
|
|
2430
|
+
/* @__PURE__ */ React.createElement("box", { padding: 1 }, /* @__PURE__ */ React.createElement("text", { style: { fg: hovering ? "#22c55e" : "#888", bold: hovering } }, hovering ? "Mouse inside!" : "Hover me"))
|
|
2431
|
+
);
|
|
2154
2432
|
}
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
const [
|
|
2158
|
-
const
|
|
2159
|
-
const
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2433
|
+
function PointerApp() {
|
|
2434
|
+
const [selected, setSelected] = useState22(null);
|
|
2435
|
+
const [clickCount, setClickCount] = useState22(0);
|
|
2436
|
+
const [mousePos, setMousePos] = useState22(null);
|
|
2437
|
+
const selectedRef = useRef9(null);
|
|
2438
|
+
const clickCountRef = useRef9(0);
|
|
2439
|
+
selectedRef.current = selected;
|
|
2440
|
+
clickCountRef.current = clickCount;
|
|
2441
|
+
useKeyboard16((event) => {
|
|
2442
|
+
const cur = selectedRef.current ?? -1;
|
|
2443
|
+
if (event.name === "right" || event.name === "tab") {
|
|
2444
|
+
const next = (cur + 1) % pointerColors.length;
|
|
2445
|
+
selectedRef.current = next;
|
|
2446
|
+
setSelected(next);
|
|
2447
|
+
} else if (event.name === "left") {
|
|
2448
|
+
const next = (cur - 1 + pointerColors.length) % pointerColors.length;
|
|
2449
|
+
selectedRef.current = next;
|
|
2450
|
+
setSelected(next);
|
|
2451
|
+
}
|
|
2452
|
+
event.preventDefault();
|
|
2163
2453
|
});
|
|
2164
|
-
return /* @__PURE__ */
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2454
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement("box", { flexDirection: "row", gap: 1 }, pointerColors.map((color, i) => /* @__PURE__ */ React.createElement(
|
|
2455
|
+
"box",
|
|
2456
|
+
{
|
|
2457
|
+
key: color,
|
|
2458
|
+
flexGrow: 1,
|
|
2459
|
+
height: 3,
|
|
2460
|
+
border: true,
|
|
2461
|
+
borderStyle: "rounded",
|
|
2462
|
+
borderColor: i === selected ? color : "#555",
|
|
2463
|
+
onMouseDown: (e) => {
|
|
2464
|
+
clickCountRef.current++;
|
|
2465
|
+
setClickCount(clickCountRef.current);
|
|
2466
|
+
selectedRef.current = i;
|
|
2467
|
+
setSelected(i);
|
|
2468
|
+
setMousePos({ x: e.x, y: e.y });
|
|
2171
2469
|
}
|
|
2172
|
-
|
|
2173
|
-
|
|
2470
|
+
},
|
|
2471
|
+
/* @__PURE__ */ React.createElement("text", { style: { fg: color, bold: i === selected } }, i === selected ? `\u25B8 ${pointerColorNames[i]}` : ` ${pointerColorNames[i]}`)
|
|
2472
|
+
))), /* @__PURE__ */ React.createElement("box", { height: 1 }), /* @__PURE__ */ React.createElement("box", { flexDirection: "row", gap: 2 }, /* @__PURE__ */ React.createElement(HoverBox, null), /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, paddingTop: 1 }, /* @__PURE__ */ React.createElement("text", { style: { fg: selected !== null ? pointerColors[selected] : "#888" } }, selected !== null ? `Clicked ${pointerColorNames[selected]}` : "Click a color", clickCount > 0 ? ` (${clickCount} clicks)` : ""), /* @__PURE__ */ React.createElement("text", { style: { dim: true, fg: "#888" } }, mousePos ? `mouse: ${mousePos.x}, ${mousePos.y}` : ""))), /* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(StatusBar, { items: [
|
|
2473
|
+
{ key: "click", label: "select" },
|
|
2474
|
+
{ key: "\u2190\u2192", label: "keyboard nav" }
|
|
2475
|
+
] })));
|
|
2174
2476
|
}
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2477
|
+
|
|
2478
|
+
// demos/cursor-highlight.tsx
|
|
2479
|
+
import { useState as useState23 } from "react";
|
|
2480
|
+
function CursorHighlightApp() {
|
|
2481
|
+
const [pos, setPos] = useState23(null);
|
|
2482
|
+
return /* @__PURE__ */ React.createElement(
|
|
2483
|
+
"box",
|
|
2484
|
+
{
|
|
2485
|
+
flexDirection: "column",
|
|
2486
|
+
flexGrow: 1,
|
|
2487
|
+
onMouseMove: (e) => {
|
|
2488
|
+
setPos({ x: e.x, y: e.y });
|
|
2489
|
+
}
|
|
2490
|
+
},
|
|
2491
|
+
/* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1, padding: 1 }, /* @__PURE__ */ React.createElement("text", { style: { bold: true, fg: "#fff" } }, "Cursor Highlight"), /* @__PURE__ */ React.createElement("text", { style: { dim: true, fg: "#888" } }, "Move your mouse over the grid"), /* @__PURE__ */ React.createElement("box", { height: 1 }), /* @__PURE__ */ React.createElement("box", { flexDirection: "column" }, Array.from({ length: 6 }, (_, row) => /* @__PURE__ */ React.createElement("text", { key: row }, Array.from({ length: 40 }, (_2, col) => {
|
|
2492
|
+
const isEven = (row + col) % 2 === 0;
|
|
2493
|
+
return /* @__PURE__ */ React.createElement("span", { key: col, style: {
|
|
2494
|
+
fg: isEven ? "#3b82f6" : "#8b5cf6",
|
|
2495
|
+
dim: !isEven
|
|
2496
|
+
} }, isEven ? "\u2591\u2591" : "\u2593\u2593");
|
|
2497
|
+
}))))),
|
|
2498
|
+
/* @__PURE__ */ React.createElement("box", { paddingX: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(
|
|
2186
2499
|
StatusBar,
|
|
2187
2500
|
{
|
|
2188
|
-
items: [
|
|
2189
|
-
extra: /* @__PURE__ */
|
|
2501
|
+
items: [],
|
|
2502
|
+
extra: /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true, fg: "#1e1e2e", bg: "#888" }) }, " x "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true, fg: "#888" }) }, ` ${pos ? String(pos.x).padStart(3) : " -"} `), /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true, fg: "#1e1e2e", bg: "#888" }) }, " y "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true, fg: "#888" }) }, ` ${pos ? String(pos.y).padStart(3) : " -"}`))
|
|
2190
2503
|
}
|
|
2191
|
-
)
|
|
2192
|
-
|
|
2504
|
+
))
|
|
2505
|
+
);
|
|
2193
2506
|
}
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2201
|
-
/* @__PURE__ */ jsx28("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx28(Table, { data, headerColor: "cyan", borderColor: "#5e81ac" }) }),
|
|
2202
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
2203
|
-
] });
|
|
2507
|
+
|
|
2508
|
+
// demos/text-style.tsx
|
|
2509
|
+
function TextStyleApp() {
|
|
2510
|
+
const theme = useTheme();
|
|
2511
|
+
const desc = textStyle({ fg: theme.muted });
|
|
2512
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1, gap: 0 }, /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground, bold: true }) }, "bold "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " bold: true ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground, dim: true }) }, "dim "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " dim: true ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground, italic: true }) }, "italic "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " italic: true ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground, underline: true }) }, "underline "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " underline: true ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ inverse: true }) }, "inverse "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " inverse: true ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, " "), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.primary }) }, "fg color "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " fg: theme.primary ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.foreground, bg: theme.secondary }) }, "bg color "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " fg: theme.foreground, bg: theme.secondary ", "}", ")")), /* @__PURE__ */ React.createElement("text", null, " "), /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.accent, bold: true, underline: true }) }, "combined "), /* @__PURE__ */ React.createElement("span", { style: desc }, "textStyle(", "{", " fg: theme.accent, bold: true, underline: true ", "}", ")")));
|
|
2204
2513
|
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2514
|
+
|
|
2515
|
+
// demos/headless.tsx
|
|
2516
|
+
var data = [
|
|
2517
|
+
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
2518
|
+
{ name: "Bob", role: "Designer", status: "Active" },
|
|
2519
|
+
{ name: "Charlie", role: "PM", status: "Away" }
|
|
2520
|
+
];
|
|
2521
|
+
function HeadlessApp() {
|
|
2522
|
+
return /* @__PURE__ */ React.createElement("box", { padding: 1 }, /* @__PURE__ */ React.createElement(Table, { data }));
|
|
2210
2523
|
}
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
] }) })
|
|
2226
|
-
] });
|
|
2524
|
+
|
|
2525
|
+
// demos/theming.tsx
|
|
2526
|
+
import { useKeyboard as useKeyboard17 } from "@gridland/utils";
|
|
2527
|
+
var tableData = [
|
|
2528
|
+
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
2529
|
+
{ name: "Bob", role: "Designer", status: "Away" }
|
|
2530
|
+
];
|
|
2531
|
+
var selectItems = [
|
|
2532
|
+
{ label: "TypeScript", value: "ts" },
|
|
2533
|
+
{ label: "JavaScript", value: "js" },
|
|
2534
|
+
{ label: "Python", value: "py" }
|
|
2535
|
+
];
|
|
2536
|
+
function ThemingApp() {
|
|
2537
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1 }, /* @__PURE__ */ React.createElement(Spinner, { text: "Loading data..." }), /* @__PURE__ */ React.createElement(Table, { data: tableData }), /* @__PURE__ */ React.createElement(MultiSelect, { items: selectItems, useKeyboard: useKeyboard17 }));
|
|
2227
2538
|
}
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2539
|
+
|
|
2540
|
+
// src/landing/landing-app.tsx
|
|
2541
|
+
import { useMemo as useMemo7 } from "react";
|
|
2542
|
+
|
|
2543
|
+
// src/landing/install-box.tsx
|
|
2544
|
+
function InstallBox() {
|
|
2545
|
+
const theme = useTheme();
|
|
2546
|
+
return /* @__PURE__ */ React.createElement(
|
|
2547
|
+
"box",
|
|
2548
|
+
{
|
|
2549
|
+
border: true,
|
|
2550
|
+
borderStyle: "rounded",
|
|
2551
|
+
borderColor: theme.border,
|
|
2552
|
+
paddingX: 1,
|
|
2553
|
+
flexDirection: "column",
|
|
2554
|
+
flexShrink: 0
|
|
2555
|
+
},
|
|
2556
|
+
/* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true }) }, "$ "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true }) }, "bun create "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.accent }) }, "gridland"))
|
|
2557
|
+
);
|
|
2246
2558
|
}
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
const
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
{
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
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
|
-
|
|
2559
|
+
|
|
2560
|
+
// src/landing/links-box.tsx
|
|
2561
|
+
var UNDERLINE3 = 1 << 3;
|
|
2562
|
+
function LinksBox() {
|
|
2563
|
+
const theme = useTheme();
|
|
2564
|
+
return /* @__PURE__ */ React.createElement(
|
|
2565
|
+
"box",
|
|
2566
|
+
{
|
|
2567
|
+
border: true,
|
|
2568
|
+
borderStyle: "rounded",
|
|
2569
|
+
borderColor: theme.border,
|
|
2570
|
+
paddingX: 1,
|
|
2571
|
+
flexDirection: "column",
|
|
2572
|
+
flexShrink: 0
|
|
2573
|
+
},
|
|
2574
|
+
/* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", null, "\u{1F431}"), /* @__PURE__ */ React.createElement("a", { href: "https://github.com/thoughtfulllc/gridland", style: { attributes: UNDERLINE3, fg: theme.accent } }, " GitHub"), /* @__PURE__ */ React.createElement("span", null, " "), /* @__PURE__ */ React.createElement("span", null, "\u{1F4D6}"), /* @__PURE__ */ React.createElement("a", { href: "https://gridland.io/docs", style: { attributes: UNDERLINE3, fg: theme.accent } }, " Docs"))
|
|
2575
|
+
);
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
// src/landing/logo.tsx
|
|
2579
|
+
import { useState as useState24, useEffect as useEffect6, useRef as useRef10, useMemo as useMemo5 } from "react";
|
|
2580
|
+
import figlet3 from "figlet";
|
|
2581
|
+
import ansiShadow3 from "figlet/importable-fonts/ANSI Shadow.js";
|
|
2582
|
+
figlet3.parseFont("ANSI Shadow", ansiShadow3);
|
|
2583
|
+
function makeArt(text) {
|
|
2584
|
+
return figlet3.textSync(text, { font: "ANSI Shadow" }).split("\n").filter((l) => l.trimEnd().length > 0).join("\n");
|
|
2585
|
+
}
|
|
2586
|
+
var fullArt = makeArt("gridland");
|
|
2587
|
+
var gridArt = makeArt("grid");
|
|
2588
|
+
var landArt = makeArt("land");
|
|
2589
|
+
var ART_HEIGHT = 6;
|
|
2590
|
+
function useAnimation(duration = 1e3) {
|
|
2591
|
+
const isBrowser = typeof document !== "undefined";
|
|
2592
|
+
const [progress, setProgress] = useState24(isBrowser ? 0 : 1);
|
|
2593
|
+
const startTime = useRef10(null);
|
|
2594
|
+
useEffect6(() => {
|
|
2595
|
+
if (!isBrowser) return;
|
|
2596
|
+
let raf;
|
|
2597
|
+
const tick = (time) => {
|
|
2598
|
+
if (startTime.current === null) startTime.current = time;
|
|
2599
|
+
const elapsed = time - startTime.current;
|
|
2600
|
+
const t = Math.min(1, elapsed / duration);
|
|
2601
|
+
const eased = 1 - Math.pow(1 - t, 3);
|
|
2602
|
+
setProgress(eased);
|
|
2603
|
+
if (t < 1) raf = requestAnimationFrame(tick);
|
|
2604
|
+
};
|
|
2605
|
+
raf = requestAnimationFrame(tick);
|
|
2606
|
+
return () => cancelAnimationFrame(raf);
|
|
2607
|
+
}, []);
|
|
2608
|
+
return progress;
|
|
2609
|
+
}
|
|
2610
|
+
function RevealGradient({ children, revealCol }) {
|
|
2611
|
+
const gradientColors = GRADIENTS.instagram;
|
|
2612
|
+
const lines2 = children.split("\n");
|
|
2613
|
+
const maxLength = Math.max(...lines2.map((l) => l.length));
|
|
2614
|
+
if (maxLength === 0) return /* @__PURE__ */ React.createElement("text", null, children);
|
|
2615
|
+
const hexColors = useMemo5(() => generateGradient(gradientColors, maxLength), [maxLength]);
|
|
2616
|
+
return /* @__PURE__ */ React.createElement("box", { position: "relative", width: maxLength, height: lines2.length, shouldFill: false }, lines2.map((line, lineIndex) => {
|
|
2617
|
+
const runs = [];
|
|
2618
|
+
let current = null;
|
|
2619
|
+
for (let i = 0; i < line.length; i++) {
|
|
2620
|
+
const revealed = i <= revealCol;
|
|
2621
|
+
const char = line[i];
|
|
2622
|
+
const isVisible = revealed && char !== " ";
|
|
2623
|
+
if (isVisible) {
|
|
2624
|
+
if (!current) {
|
|
2625
|
+
current = { start: i, chars: [] };
|
|
2296
2626
|
}
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
/* @__PURE__ */ jsx28("span", { children: lastMessage })
|
|
2309
|
-
] }) : /* @__PURE__ */ jsx28("text", { style: textStyle({ dim: true }), children: "Type a message and press enter" }) }),
|
|
2310
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, children: /* @__PURE__ */ jsx28(
|
|
2311
|
-
PromptInput,
|
|
2627
|
+
current.chars.push(char);
|
|
2628
|
+
} else {
|
|
2629
|
+
if (current) {
|
|
2630
|
+
runs.push(current);
|
|
2631
|
+
current = null;
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
if (current) runs.push(current);
|
|
2636
|
+
return runs.map((run, runIndex) => /* @__PURE__ */ React.createElement(
|
|
2637
|
+
"box",
|
|
2312
2638
|
{
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
onSubmit: handleSubmit
|
|
2639
|
+
key: `${lineIndex}-${runIndex}`,
|
|
2640
|
+
position: "absolute",
|
|
2641
|
+
top: lineIndex,
|
|
2642
|
+
left: run.start,
|
|
2643
|
+
shouldFill: false
|
|
2319
2644
|
},
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
{ key: "\u2191", label: "history" },
|
|
2331
|
-
{ key: "q", label: "quit" }
|
|
2332
|
-
] }) })
|
|
2333
|
-
] });
|
|
2334
|
-
}
|
|
2335
|
-
var TEXT_INPUT_FIELDS = [
|
|
2336
|
-
{ label: "Username", placeholder: "enter your name", maxLength: 30, required: true },
|
|
2337
|
-
{ label: "Email", placeholder: "user@example.com", maxLength: 50, required: true, description: "We'll never share your email" },
|
|
2338
|
-
{ label: "Password", placeholder: "enter password", maxLength: 40 },
|
|
2339
|
-
{ label: "API Key", placeholder: "sk-...", maxLength: 60, disabled: true }
|
|
2340
|
-
];
|
|
2341
|
-
function TextInputApp() {
|
|
2342
|
-
const [activeField, setActiveField] = useState11(0);
|
|
2343
|
-
const [values, setValues] = useState11(TEXT_INPUT_FIELDS.map(() => ""));
|
|
2344
|
-
useKeyboard((event) => {
|
|
2345
|
-
if (event.name === "up") setActiveField((i) => Math.max(0, i - 1));
|
|
2346
|
-
if (event.name === "down" || event.name === "tab") setActiveField((i) => Math.min(TEXT_INPUT_FIELDS.length - 1, i + 1));
|
|
2347
|
-
});
|
|
2348
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2349
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingTop: 1, children: /* @__PURE__ */ jsxs20("text", { children: [
|
|
2350
|
-
/* @__PURE__ */ jsx28("span", { style: textStyle({ fg: "#FF71CE", bold: true }), children: "TextInput" }),
|
|
2351
|
-
/* @__PURE__ */ jsx28("span", { style: textStyle({ dim: true }), children: " Form with multiple input types" })
|
|
2352
|
-
] }) }),
|
|
2353
|
-
/* @__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(
|
|
2354
|
-
TextInput,
|
|
2355
|
-
{
|
|
2356
|
-
label: field.label,
|
|
2357
|
-
placeholder: field.placeholder,
|
|
2358
|
-
prompt: "> ",
|
|
2359
|
-
focus: i === activeField,
|
|
2360
|
-
maxLength: field.maxLength,
|
|
2361
|
-
value: values[i],
|
|
2362
|
-
onChange: (v) => setValues((prev) => prev.map((old, j) => j === i ? v : old)),
|
|
2363
|
-
required: field.required,
|
|
2364
|
-
disabled: field.disabled,
|
|
2365
|
-
description: field.description
|
|
2366
|
-
}
|
|
2367
|
-
) }, field.label)) }),
|
|
2368
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [
|
|
2369
|
-
{ key: "\u2191\u2193", label: "field" },
|
|
2370
|
-
{ key: "\u2190\u2192", label: "cursor" },
|
|
2371
|
-
{ key: "tab", label: "complete" },
|
|
2372
|
-
{ key: "^k/^u", label: "kill" }
|
|
2373
|
-
] }) })
|
|
2374
|
-
] });
|
|
2645
|
+
/* @__PURE__ */ React.createElement("text", { shouldFill: false }, run.chars.map((char, ci) => /* @__PURE__ */ React.createElement(
|
|
2646
|
+
"span",
|
|
2647
|
+
{
|
|
2648
|
+
key: ci,
|
|
2649
|
+
style: { fg: hexColors[run.start + ci] }
|
|
2650
|
+
},
|
|
2651
|
+
char
|
|
2652
|
+
)))
|
|
2653
|
+
));
|
|
2654
|
+
}));
|
|
2375
2655
|
}
|
|
2376
|
-
function
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2656
|
+
function Logo({ compact, narrow, mobile }) {
|
|
2657
|
+
const isBrowser = typeof document !== "undefined";
|
|
2658
|
+
const progress = useAnimation(900);
|
|
2659
|
+
const artHeight = compact ? 1 : narrow ? ART_HEIGHT * 2 : ART_HEIGHT;
|
|
2660
|
+
const dropOffset = Math.round((1 - progress) * -artHeight);
|
|
2661
|
+
const revealProgress = Math.max(0, Math.min(1, (progress - 0.1) / 0.7));
|
|
2662
|
+
const maxWidth = compact ? 8 : narrow ? 40 : 62;
|
|
2663
|
+
const revealCol = Math.round(revealProgress * (maxWidth + 4)) - 2;
|
|
2664
|
+
const taglineOpacity = Math.max(0, Math.min(1, (progress - 0.7) / 0.3));
|
|
2665
|
+
const subtitle = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("text", null, " "), /* @__PURE__ */ React.createElement("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false }, /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: "#d4b0e8" }), opacity: taglineOpacity, wrapMode: "word", textAlign: "center", width: "100%", shouldFill: false }, "A framework for building terminal apps, built on ", /* @__PURE__ */ React.createElement("a", { href: "https://opentui.com", style: { attributes: 72, fg: "#d4b0e8" } }, "OpenTUI"), " + React." + (mobile ? " " : "\n") + "(Gridland apps, like this website, work in the browser and terminal.)")));
|
|
2666
|
+
if (!isBrowser) {
|
|
2667
|
+
const art2 = compact ? "gridland" : narrow ? gridArt + "\n" + landArt : fullArt;
|
|
2668
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexShrink: 0, width: "100%", alignItems: "center", shouldFill: false }, /* @__PURE__ */ React.createElement(Gradient, { name: "instagram" }, art2), /* @__PURE__ */ React.createElement("text", null, " "), /* @__PURE__ */ React.createElement("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false }, /* @__PURE__ */ React.createElement("text", { style: textStyle({ fg: "#d4b0e8" }), shouldFill: false }, "A framework for building terminal apps, built on OpenTUI + React.", "\n", "(Gridland apps, like this website, work in the browser and terminal.)")));
|
|
2669
|
+
}
|
|
2670
|
+
if (compact) {
|
|
2671
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false }, /* @__PURE__ */ React.createElement("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false }, /* @__PURE__ */ React.createElement("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false }, /* @__PURE__ */ React.createElement(RevealGradient, { revealCol }, "gridland"))), subtitle);
|
|
2672
|
+
}
|
|
2673
|
+
if (narrow) {
|
|
2674
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false }, /* @__PURE__ */ React.createElement("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false }, /* @__PURE__ */ React.createElement("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false }, /* @__PURE__ */ React.createElement(RevealGradient, { revealCol }, gridArt), /* @__PURE__ */ React.createElement(RevealGradient, { revealCol }, landArt))), subtitle);
|
|
2675
|
+
}
|
|
2676
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false }, /* @__PURE__ */ React.createElement("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false }, /* @__PURE__ */ React.createElement("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false }, /* @__PURE__ */ React.createElement(RevealGradient, { revealCol }, fullArt))), subtitle);
|
|
2381
2677
|
}
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
/* @__PURE__ */ jsx28(TabBar, { label: "View", options: tabs, selectedIndex }),
|
|
2392
|
-
/* @__PURE__ */ jsx28("text", { style: textStyle({ dim: true }), children: "Use \u2190/\u2192 arrow keys to switch tabs" })
|
|
2393
|
-
] }),
|
|
2394
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "\u2190\u2192", label: "switch tab" }, { key: "q", label: "quit" }] }) })
|
|
2395
|
-
] });
|
|
2678
|
+
|
|
2679
|
+
// src/landing/matrix-background.tsx
|
|
2680
|
+
import { useMemo as useMemo6 } from "react";
|
|
2681
|
+
|
|
2682
|
+
// src/landing/use-matrix.ts
|
|
2683
|
+
import { useState as useState25, useEffect as useEffect7, useRef as useRef11 } from "react";
|
|
2684
|
+
var CHARS = "abcdefghijklmnopqrstuvwxyz0123456789@#$%^&*(){}[]|;:<>,.?/~`";
|
|
2685
|
+
function randomChar() {
|
|
2686
|
+
return CHARS[Math.floor(Math.random() * CHARS.length)];
|
|
2396
2687
|
}
|
|
2397
|
-
function
|
|
2398
|
-
const
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
items: [...shortcuts, { key: "q", label: "quit" }],
|
|
2421
|
-
extra: /* @__PURE__ */ jsx28("span", { style: textStyle({ fg: "green" }), children: "\u25CF Ready" })
|
|
2688
|
+
function createDrop(height, seeded = false) {
|
|
2689
|
+
const length = Math.floor(Math.random() * Math.floor(height * 0.6)) + 4;
|
|
2690
|
+
return {
|
|
2691
|
+
y: seeded ? Math.floor(Math.random() * (height + length)) : -Math.floor(Math.random() * height),
|
|
2692
|
+
speed: 1,
|
|
2693
|
+
length,
|
|
2694
|
+
chars: Array.from({ length }, randomChar)
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
function buildGrid(columns, width, height) {
|
|
2698
|
+
const grid = Array.from({ length: height }, () => Array(width).fill(" "));
|
|
2699
|
+
const brightness = Array.from({ length: height }, () => Array(width).fill(0));
|
|
2700
|
+
for (let x = 0; x < width; x++) {
|
|
2701
|
+
const drop = columns[x];
|
|
2702
|
+
if (!drop) continue;
|
|
2703
|
+
for (let i = 0; i < drop.length; i++) {
|
|
2704
|
+
const row = Math.floor(drop.y) - i;
|
|
2705
|
+
if (row < 0 || row >= height) continue;
|
|
2706
|
+
grid[row][x] = drop.chars[i];
|
|
2707
|
+
if (i === 0) {
|
|
2708
|
+
brightness[row][x] = 1;
|
|
2709
|
+
} else {
|
|
2710
|
+
brightness[row][x] = Math.max(0.15, 1 - i / drop.length);
|
|
2422
2711
|
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2714
|
+
return { grid, brightness };
|
|
2425
2715
|
}
|
|
2426
|
-
function
|
|
2427
|
-
const
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2716
|
+
function useMatrix(width, height) {
|
|
2717
|
+
const columnsRef = useRef11([]);
|
|
2718
|
+
const [state, setState] = useState25(() => {
|
|
2719
|
+
const columns = Array.from(
|
|
2720
|
+
{ length: width },
|
|
2721
|
+
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
2722
|
+
);
|
|
2723
|
+
columnsRef.current = columns;
|
|
2724
|
+
return buildGrid(columns, width, height);
|
|
2431
2725
|
});
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2726
|
+
useEffect7(() => {
|
|
2727
|
+
if (width < 2 || height < 2) return;
|
|
2728
|
+
const id = setInterval(() => {
|
|
2729
|
+
const columns = columnsRef.current;
|
|
2730
|
+
for (let x = 0; x < width; x++) {
|
|
2731
|
+
if (columns[x] === null || columns[x] === void 0) {
|
|
2732
|
+
if (Math.random() < 0.03) {
|
|
2733
|
+
columns[x] = createDrop(height);
|
|
2734
|
+
}
|
|
2735
|
+
continue;
|
|
2736
|
+
}
|
|
2737
|
+
const drop = columns[x];
|
|
2738
|
+
drop.y += drop.speed;
|
|
2739
|
+
if (Math.random() < 0.1) {
|
|
2740
|
+
const idx = Math.floor(Math.random() * drop.chars.length);
|
|
2741
|
+
drop.chars[idx] = randomChar();
|
|
2742
|
+
}
|
|
2743
|
+
if (drop.y - drop.length > height) {
|
|
2744
|
+
columns[x] = null;
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
setState(buildGrid(columns, width, height));
|
|
2748
|
+
}, 80);
|
|
2749
|
+
return () => clearInterval(id);
|
|
2750
|
+
}, [width, height]);
|
|
2751
|
+
useEffect7(() => {
|
|
2752
|
+
columnsRef.current = Array.from(
|
|
2753
|
+
{ length: width },
|
|
2754
|
+
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
2755
|
+
);
|
|
2756
|
+
setState(buildGrid(columnsRef.current, width, height));
|
|
2757
|
+
}, [width, height]);
|
|
2758
|
+
return state;
|
|
2450
2759
|
}
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
] });
|
|
2760
|
+
|
|
2761
|
+
// src/landing/matrix-background.tsx
|
|
2762
|
+
var MUTE_LEVELS = [0.12, 0.18, 0.24, 0.3, 0.38];
|
|
2763
|
+
var BG = hexToRgb("#1a1a2e");
|
|
2764
|
+
function buildMutedColors(baseHex) {
|
|
2765
|
+
const fg = hexToRgb(baseHex);
|
|
2766
|
+
return MUTE_LEVELS.map((factor) => rgbToHex({
|
|
2767
|
+
r: Math.round(BG.r + (fg.r - BG.r) * factor),
|
|
2768
|
+
g: Math.round(BG.g + (fg.g - BG.g) * factor),
|
|
2769
|
+
b: Math.round(BG.b + (fg.b - BG.b) * factor)
|
|
2770
|
+
}));
|
|
2463
2771
|
}
|
|
2464
|
-
function
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
/* @__PURE__ */ jsx28("text", { children: "Hello from OpenTUI" }),
|
|
2469
|
-
/* @__PURE__ */ jsx28("text", { style: textStyle({ fg: "green" }), children: "$ _" })
|
|
2470
|
-
] }),
|
|
2471
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
2472
|
-
] });
|
|
2772
|
+
function colorForCell(mutedColors, b) {
|
|
2773
|
+
if (b >= 1) return mutedColors[4];
|
|
2774
|
+
const idx = Math.min(Math.floor(b * (MUTE_LEVELS.length - 1)), MUTE_LEVELS.length - 2);
|
|
2775
|
+
return mutedColors[idx];
|
|
2473
2776
|
}
|
|
2474
|
-
|
|
2475
|
-
{
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
setPhase("running");
|
|
2493
|
-
setStepIndex(0);
|
|
2494
|
-
}
|
|
2495
|
-
useEffect5(() => {
|
|
2496
|
-
if (phase !== "running") return;
|
|
2497
|
-
if (stepIndex < TIMELINE_STEPS.length) {
|
|
2498
|
-
const delay = TIMELINE_STEPS[stepIndex].delay;
|
|
2499
|
-
timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
|
|
2500
|
-
} else {
|
|
2501
|
-
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
2502
|
-
}
|
|
2503
|
-
return () => {
|
|
2504
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2505
|
-
};
|
|
2506
|
-
}, [phase, stepIndex]);
|
|
2507
|
-
useEffect5(() => {
|
|
2508
|
-
if (phase === "done") {
|
|
2509
|
-
timerRef.current = setTimeout(() => timelineRestart(), 3e3);
|
|
2777
|
+
function MatrixBackground({ width, height, clearRect, clearRects }) {
|
|
2778
|
+
const { grid, brightness } = useMatrix(width, height);
|
|
2779
|
+
const theme = useTheme();
|
|
2780
|
+
const columnColors = useMemo6(
|
|
2781
|
+
() => width > 0 ? generateGradient([theme.accent, theme.secondary, theme.primary], width) : [],
|
|
2782
|
+
[width, theme.accent, theme.secondary, theme.primary]
|
|
2783
|
+
);
|
|
2784
|
+
const columnMutedColors = useMemo6(
|
|
2785
|
+
() => columnColors.map(buildMutedColors),
|
|
2786
|
+
[columnColors]
|
|
2787
|
+
);
|
|
2788
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column" }, grid.map((row, y) => /* @__PURE__ */ React.createElement("text", { key: y }, row.map((cell, x) => {
|
|
2789
|
+
const inClearRect = clearRect && y >= clearRect.top && y < clearRect.top + clearRect.height && x >= clearRect.left && x < clearRect.left + clearRect.width || clearRects && clearRects.some(
|
|
2790
|
+
(r) => y >= r.top && y < r.top + r.height && x >= r.left && x < r.left + r.width
|
|
2791
|
+
);
|
|
2792
|
+
const mutedColors = columnMutedColors[x];
|
|
2793
|
+
if (cell === " " || inClearRect || !mutedColors) {
|
|
2794
|
+
return /* @__PURE__ */ React.createElement("span", { key: x }, " ");
|
|
2510
2795
|
}
|
|
2511
|
-
return
|
|
2512
|
-
|
|
2513
|
-
};
|
|
2514
|
-
}, [phase]);
|
|
2515
|
-
const steps = TIMELINE_STEPS.map((s, i) => {
|
|
2516
|
-
if (i < stepIndex) return { ...s, status: "done" };
|
|
2517
|
-
if (i === stepIndex && phase === "running") return { ...s, status: "running" };
|
|
2518
|
-
return { ...s, status: phase === "done" ? "done" : "pending" };
|
|
2519
|
-
});
|
|
2520
|
-
const elapsedMs = TIMELINE_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
|
|
2521
|
-
const totalMs = TIMELINE_STEPS.reduce((sum, s) => sum + s.delay, 0);
|
|
2522
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2523
|
-
/* @__PURE__ */ jsx28("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx28(
|
|
2524
|
-
Timeline,
|
|
2796
|
+
return /* @__PURE__ */ React.createElement(
|
|
2797
|
+
"span",
|
|
2525
2798
|
{
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
{ key: "q", label: "quit" }
|
|
2535
|
-
] }) })
|
|
2536
|
-
] });
|
|
2799
|
+
key: x,
|
|
2800
|
+
style: {
|
|
2801
|
+
fg: colorForCell(mutedColors, brightness[y][x])
|
|
2802
|
+
}
|
|
2803
|
+
},
|
|
2804
|
+
cell
|
|
2805
|
+
);
|
|
2806
|
+
}))));
|
|
2537
2807
|
}
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
{
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
if (event.name === "r") bubbleRestart();
|
|
2556
|
-
});
|
|
2557
|
-
function bubbleRestart() {
|
|
2558
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2559
|
-
setPhase("idle");
|
|
2560
|
-
setStepIndex(0);
|
|
2561
|
-
setStreamedText("");
|
|
2562
|
-
}
|
|
2563
|
-
useEffect5(() => {
|
|
2564
|
-
if (phase === "idle") {
|
|
2565
|
-
timerRef.current = setTimeout(() => setPhase("thinking"), 800);
|
|
2566
|
-
}
|
|
2567
|
-
return () => {
|
|
2568
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2569
|
-
};
|
|
2570
|
-
}, [phase]);
|
|
2571
|
-
useEffect5(() => {
|
|
2572
|
-
if (phase !== "thinking") return;
|
|
2573
|
-
if (stepIndex < BUBBLE_STEPS.length) {
|
|
2574
|
-
const delay = BUBBLE_STEPS[stepIndex].delay;
|
|
2575
|
-
timerRef.current = setTimeout(() => setStepIndex((i) => i + 1), delay);
|
|
2576
|
-
} else {
|
|
2577
|
-
timerRef.current = setTimeout(() => setPhase("streaming"), 500);
|
|
2578
|
-
}
|
|
2579
|
-
return () => {
|
|
2580
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2581
|
-
};
|
|
2582
|
-
}, [phase, stepIndex]);
|
|
2583
|
-
useEffect5(() => {
|
|
2584
|
-
if (phase !== "streaming") return;
|
|
2585
|
-
if (streamedText.length < BUBBLE_RESPONSE.length) {
|
|
2586
|
-
timerRef.current = setTimeout(() => {
|
|
2587
|
-
setStreamedText(BUBBLE_RESPONSE.slice(0, streamedText.length + 2));
|
|
2588
|
-
}, 25);
|
|
2589
|
-
} else {
|
|
2590
|
-
timerRef.current = setTimeout(() => setPhase("done"), 500);
|
|
2591
|
-
}
|
|
2592
|
-
return () => {
|
|
2593
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2594
|
-
};
|
|
2595
|
-
}, [phase, streamedText]);
|
|
2596
|
-
useEffect5(() => {
|
|
2597
|
-
if (phase === "done") {
|
|
2598
|
-
timerRef.current = setTimeout(() => bubbleRestart(), 3e3);
|
|
2599
|
-
}
|
|
2600
|
-
return () => {
|
|
2601
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2808
|
+
|
|
2809
|
+
// src/landing/landing-app.tsx
|
|
2810
|
+
function LandingApp({ useKeyboard: useKeyboard20 }) {
|
|
2811
|
+
const theme = useTheme();
|
|
2812
|
+
const { width, height, isNarrow, isTiny, isMobile } = useBreakpoints();
|
|
2813
|
+
const isBrowser = typeof document !== "undefined";
|
|
2814
|
+
const { clearRect, installLinksClearRect } = useMemo7(() => {
|
|
2815
|
+
const logoHeight = isTiny ? 2 : isNarrow ? 13 : 7;
|
|
2816
|
+
const logoExtra = isBrowser ? 1 : 0;
|
|
2817
|
+
const gap = isMobile ? 0 : 1;
|
|
2818
|
+
const installLinksTop = 3 + logoHeight + logoExtra + gap;
|
|
2819
|
+
const installLinksHeight = 3;
|
|
2820
|
+
const boxTop = installLinksTop + installLinksHeight + gap + 1;
|
|
2821
|
+
const bh = height - boxTop - 1;
|
|
2822
|
+
return {
|
|
2823
|
+
clearRect: { top: boxTop, left: 1, width: width - 2, height: bh },
|
|
2824
|
+
installLinksClearRect: { top: installLinksTop, left: 1, width: width - 2, height: installLinksHeight }
|
|
2602
2825
|
};
|
|
2603
|
-
}, [
|
|
2604
|
-
|
|
2605
|
-
if (i < stepIndex) return { ...s, status: "done" };
|
|
2606
|
-
if (i === stepIndex) return { ...s, status: "running" };
|
|
2607
|
-
return { ...s, status: "pending" };
|
|
2608
|
-
});
|
|
2609
|
-
const isThinking = phase === "thinking";
|
|
2610
|
-
const isStreaming = phase === "streaming";
|
|
2611
|
-
const isDone = phase === "done";
|
|
2612
|
-
const showAssistant = phase !== "idle";
|
|
2613
|
-
const elapsedMs = BUBBLE_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
|
|
2614
|
-
const reasoningDuration = isThinking ? `${(elapsedMs / 1e3).toFixed(1)}s` : `${(BUBBLE_TOTAL_MS / 1e3).toFixed(1)}s`;
|
|
2615
|
-
const reasoningSteps = isThinking ? steps : BUBBLE_STEPS.map((s) => ({ ...s, status: "done" }));
|
|
2616
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2617
|
-
/* @__PURE__ */ jsxs20("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1, children: [
|
|
2618
|
-
/* @__PURE__ */ jsx28(Message, { role: "user", children: /* @__PURE__ */ jsx28(Message.Content, { children: /* @__PURE__ */ jsx28(Message.Text, { children: "Can you refactor the auth module?" }) }) }),
|
|
2619
|
-
showAssistant && /* @__PURE__ */ jsxs20(Message, { role: "assistant", isStreaming, children: [
|
|
2620
|
-
/* @__PURE__ */ jsx28(Message.Reasoning, { part: {
|
|
2621
|
-
type: "reasoning",
|
|
2622
|
-
duration: reasoningDuration,
|
|
2623
|
-
collapsed: !expanded,
|
|
2624
|
-
steps: reasoningSteps
|
|
2625
|
-
} }),
|
|
2626
|
-
(isStreaming || isDone) && /* @__PURE__ */ jsx28(Message.Content, { children: /* @__PURE__ */ jsx28(Message.Text, { isLast: true, children: isDone ? BUBBLE_RESPONSE : streamedText }) })
|
|
2627
|
-
] })
|
|
2628
|
-
] }),
|
|
2629
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "ctrl+shift+e", label: "toggle timeline" }, { key: "r", label: "restart" }, { key: "q", label: "quit" }] }) })
|
|
2630
|
-
] });
|
|
2631
|
-
}
|
|
2632
|
-
var initialChatMessages = [
|
|
2633
|
-
{ id: "1", role: "user", content: "Show me my portfolio" },
|
|
2634
|
-
{ id: "2", role: "assistant", content: "Here's your current portfolio allocation:" },
|
|
2635
|
-
{ id: "3", role: "user", content: "Calculate rebalancing trades" },
|
|
2636
|
-
{ id: "4", role: "assistant", content: "I've calculated the optimal trades to rebalance your portfolio." }
|
|
2637
|
-
];
|
|
2638
|
-
var chatNextId = 5;
|
|
2639
|
-
function ChatApp() {
|
|
2640
|
-
const [messages, setMessages] = useState11(initialChatMessages);
|
|
2641
|
-
const [isLoading, setIsLoading] = useState11(false);
|
|
2642
|
-
const [streamingText, setStreamingText] = useState11("");
|
|
2643
|
-
const [activeToolCalls, setActiveToolCalls] = useState11([]);
|
|
2644
|
-
const intervalRef = useRef9(null);
|
|
2645
|
-
const handleSend = useCallback4((text) => {
|
|
2646
|
-
const userMsg = { id: String(chatNextId++), role: "user", content: text };
|
|
2647
|
-
setMessages((prev) => [...prev, userMsg]);
|
|
2648
|
-
setIsLoading(true);
|
|
2649
|
-
const toolCallId = `tc-${chatNextId}`;
|
|
2650
|
-
setTimeout(() => {
|
|
2651
|
-
setIsLoading(false);
|
|
2652
|
-
setActiveToolCalls([{ id: toolCallId, title: "process_request", status: "in_progress" }]);
|
|
2653
|
-
}, 500);
|
|
2654
|
-
setTimeout(() => {
|
|
2655
|
-
setActiveToolCalls([{ id: toolCallId, title: "process_request", status: "completed" }]);
|
|
2656
|
-
}, 1200);
|
|
2657
|
-
const response = `You said: "${text}". This is a demo response.`;
|
|
2658
|
-
let charIndex = 0;
|
|
2659
|
-
setTimeout(() => {
|
|
2660
|
-
intervalRef.current = setInterval(() => {
|
|
2661
|
-
charIndex = Math.min(charIndex + 3, response.length);
|
|
2662
|
-
if (charIndex < response.length) {
|
|
2663
|
-
setStreamingText(response.slice(0, charIndex));
|
|
2664
|
-
} else {
|
|
2665
|
-
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
2666
|
-
setStreamingText("");
|
|
2667
|
-
setActiveToolCalls([]);
|
|
2668
|
-
setMessages((prev) => [
|
|
2669
|
-
...prev,
|
|
2670
|
-
{ id: String(chatNextId++), role: "assistant", content: response }
|
|
2671
|
-
]);
|
|
2672
|
-
}
|
|
2673
|
-
}, 50);
|
|
2674
|
-
}, 1400);
|
|
2675
|
-
}, []);
|
|
2676
|
-
const handleCancel = useCallback4(() => {
|
|
2677
|
-
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
2678
|
-
setIsLoading(false);
|
|
2679
|
-
setStreamingText("");
|
|
2680
|
-
setActiveToolCalls([]);
|
|
2681
|
-
}, []);
|
|
2682
|
-
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2683
|
-
/* @__PURE__ */ jsx28(
|
|
2684
|
-
ChatPanel,
|
|
2685
|
-
{
|
|
2686
|
-
messages,
|
|
2687
|
-
streamingText,
|
|
2688
|
-
isLoading,
|
|
2689
|
-
activeToolCalls,
|
|
2690
|
-
onSendMessage: handleSend,
|
|
2691
|
-
onCancel: handleCancel,
|
|
2692
|
-
placeholder: "Ask about your portfolio...",
|
|
2693
|
-
useKeyboard
|
|
2694
|
-
}
|
|
2695
|
-
),
|
|
2696
|
-
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "q", label: "quit" }] }) })
|
|
2697
|
-
] });
|
|
2826
|
+
}, [width, height, isTiny, isNarrow, isMobile, isBrowser]);
|
|
2827
|
+
return /* @__PURE__ */ React.createElement("box", { width: "100%", height: "100%", position: "relative" }, /* @__PURE__ */ React.createElement(MatrixBackground, { width, height, clearRect, clearRects: isBrowser ? void 0 : [installLinksClearRect] }), /* @__PURE__ */ React.createElement("box", { position: "absolute", top: 0, left: 0, width, height, zIndex: 1, flexDirection: "column", shouldFill: false }, /* @__PURE__ */ React.createElement("box", { flexGrow: 1, flexDirection: "column", paddingTop: 3, paddingLeft: 1, paddingRight: 1, paddingBottom: 1, gap: isMobile ? 0 : 1, shouldFill: false }, /* @__PURE__ */ React.createElement("box", { flexShrink: 0, shouldFill: false }, /* @__PURE__ */ React.createElement(Logo, { compact: isTiny, narrow: isNarrow, mobile: isMobile })), /* @__PURE__ */ React.createElement("box", { flexDirection: "row", flexWrap: "wrap", justifyContent: "center", gap: isMobile ? 0 : 1, flexShrink: 0, shouldFill: false }, /* @__PURE__ */ React.createElement("box", { border: true, borderStyle: "rounded", borderColor: theme.border, paddingX: 1, flexDirection: "column", flexShrink: 0 }, /* @__PURE__ */ React.createElement("text", null, /* @__PURE__ */ React.createElement("span", { style: textStyle({ dim: true }) }, "$ "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ bold: true }) }, "bunx "), /* @__PURE__ */ React.createElement("span", { style: textStyle({ fg: theme.accent }) }, "@gridland/demo landing"))), /* @__PURE__ */ React.createElement(InstallBox, null), /* @__PURE__ */ React.createElement(LinksBox, null)), /* @__PURE__ */ React.createElement("box", { flexGrow: 1, border: true, borderStyle: "rounded", borderColor: theme.border, flexDirection: "column", overflow: "hidden" }))));
|
|
2698
2828
|
}
|
|
2829
|
+
|
|
2830
|
+
// demos/index.tsx
|
|
2699
2831
|
var demos = [
|
|
2700
|
-
{ name: "gradient", app: () => /* @__PURE__ */
|
|
2701
|
-
{ name: "ascii", app: () => /* @__PURE__ */
|
|
2702
|
-
{ name: "table", app: () => /* @__PURE__ */
|
|
2703
|
-
{ name: "spinner", app: () => /* @__PURE__ */
|
|
2704
|
-
{ name: "select-input", app: () => /* @__PURE__ */
|
|
2705
|
-
{ name: "multi-select", app: () => /* @__PURE__ */
|
|
2706
|
-
{ name: "prompt-input", app: () => /* @__PURE__ */
|
|
2707
|
-
{ name: "text-input", app: () => /* @__PURE__ */
|
|
2708
|
-
{ name: "link", app: () => /* @__PURE__ */
|
|
2709
|
-
{ name: "tabs", app: () => /* @__PURE__ */
|
|
2710
|
-
{ name: "status-bar", app: () => /* @__PURE__ */
|
|
2711
|
-
{ name: "modal", app: () => /* @__PURE__ */
|
|
2712
|
-
{ name: "primitives", app: () => /* @__PURE__ */
|
|
2713
|
-
{ name: "chat", app: () => /* @__PURE__ */
|
|
2714
|
-
{ name: "
|
|
2715
|
-
{ name: "message", app: () => /* @__PURE__ */
|
|
2716
|
-
{ name: "terminal-window", app: () => /* @__PURE__ */
|
|
2717
|
-
{ name: "
|
|
2832
|
+
{ name: "gradient", app: () => /* @__PURE__ */ React.createElement(GradientApp, null) },
|
|
2833
|
+
{ name: "ascii", app: () => /* @__PURE__ */ React.createElement(AsciiApp, null) },
|
|
2834
|
+
{ name: "table", app: () => /* @__PURE__ */ React.createElement(TableApp, null) },
|
|
2835
|
+
{ name: "spinner", app: () => /* @__PURE__ */ React.createElement(SpinnerApp, null) },
|
|
2836
|
+
{ name: "select-input", app: () => /* @__PURE__ */ React.createElement(SelectInputApp, null) },
|
|
2837
|
+
{ name: "multi-select", app: () => /* @__PURE__ */ React.createElement(MultiSelectApp, null) },
|
|
2838
|
+
{ name: "prompt-input", app: () => /* @__PURE__ */ React.createElement(PromptInputApp, null) },
|
|
2839
|
+
{ name: "text-input", app: () => /* @__PURE__ */ React.createElement(TextInputApp, null) },
|
|
2840
|
+
{ name: "link", app: () => /* @__PURE__ */ React.createElement(LinkApp, null) },
|
|
2841
|
+
{ name: "tabs", app: () => /* @__PURE__ */ React.createElement(TabBarApp, null) },
|
|
2842
|
+
{ name: "status-bar", app: () => /* @__PURE__ */ React.createElement(StatusBarApp, null) },
|
|
2843
|
+
{ name: "modal", app: () => /* @__PURE__ */ React.createElement(ModalApp, null) },
|
|
2844
|
+
{ name: "primitives", app: () => /* @__PURE__ */ React.createElement(PrimitivesApp, null) },
|
|
2845
|
+
{ name: "chat", app: () => /* @__PURE__ */ React.createElement(ChatApp, null) },
|
|
2846
|
+
{ name: "chain-of-thought", app: () => /* @__PURE__ */ React.createElement(ChainOfThoughtApp, null) },
|
|
2847
|
+
{ name: "message", app: () => /* @__PURE__ */ React.createElement(MessageApp, null) },
|
|
2848
|
+
{ name: "terminal-window", app: () => /* @__PURE__ */ React.createElement(TerminalWindowApp, null) },
|
|
2849
|
+
{ name: "focus", app: () => /* @__PURE__ */ React.createElement(FocusApp, null) },
|
|
2850
|
+
{ name: "pointer", app: () => /* @__PURE__ */ React.createElement(PointerApp, null) },
|
|
2851
|
+
{ name: "cursor-highlight", app: () => /* @__PURE__ */ React.createElement(CursorHighlightApp, null) },
|
|
2852
|
+
{ name: "text-style", app: () => /* @__PURE__ */ React.createElement(TextStyleApp, null) },
|
|
2853
|
+
{ name: "headless", app: () => /* @__PURE__ */ React.createElement(HeadlessApp, null) },
|
|
2854
|
+
{ name: "theming", app: () => /* @__PURE__ */ React.createElement(ThemingApp, null) },
|
|
2855
|
+
{ name: "landing", app: () => /* @__PURE__ */ React.createElement(LandingApp, { useKeyboard: useKeyboard18 }) }
|
|
2718
2856
|
];
|
|
2719
2857
|
|
|
2720
2858
|
// src/run.tsx
|
|
2721
|
-
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
2722
2859
|
var _renderer;
|
|
2723
2860
|
function DemoShell({ children }) {
|
|
2724
|
-
|
|
2861
|
+
useKeyboard19((event) => {
|
|
2725
2862
|
if (event.name === "q" || event.name === "escape") {
|
|
2726
2863
|
_renderer.destroy();
|
|
2727
2864
|
}
|
|
2728
2865
|
});
|
|
2729
|
-
return /* @__PURE__ */
|
|
2866
|
+
return /* @__PURE__ */ React.createElement("box", { flexDirection: "column", flexGrow: 1 }, children);
|
|
2730
2867
|
}
|
|
2731
|
-
async function runDemo(
|
|
2732
|
-
const demo = demos.find((d) => d.name ===
|
|
2868
|
+
async function runDemo(name2) {
|
|
2869
|
+
const demo = demos.find((d) => d.name === name2);
|
|
2733
2870
|
if (!demo) {
|
|
2734
|
-
console.error(`Unknown demo: "${
|
|
2871
|
+
console.error(`Unknown demo: "${name2}"`);
|
|
2735
2872
|
console.error(`Available: ${demos.map((d) => d.name).join(", ")}`);
|
|
2736
2873
|
process.exit(1);
|
|
2737
2874
|
}
|
|
2738
2875
|
_renderer = await createCliRenderer({ exitOnCtrlC: true });
|
|
2739
|
-
createRoot(_renderer).render(/* @__PURE__ */
|
|
2876
|
+
createRoot(_renderer).render(/* @__PURE__ */ React.createElement(DemoShell, null, demo.app()));
|
|
2877
|
+
}
|
|
2878
|
+
var name = process.argv[2];
|
|
2879
|
+
if (name) {
|
|
2880
|
+
runDemo(name);
|
|
2740
2881
|
}
|
|
2741
2882
|
export {
|
|
2742
2883
|
demos,
|