@gridland/demo 0.2.51 → 0.2.53
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/demo-names.json +1 -1
- package/dist/landing.js +703 -87
- package/dist/run.js +1356 -411
- package/package.json +3 -3
package/dist/run.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/run.tsx
|
|
2
|
-
import { createCliRenderer, createRoot, useKeyboard as
|
|
2
|
+
import { createCliRenderer, createRoot, useKeyboard as useKeyboard22 } from "@gridland/bun";
|
|
3
3
|
|
|
4
4
|
// demos/index.tsx
|
|
5
|
-
import { useKeyboard as
|
|
5
|
+
import { useKeyboard as useKeyboard21 } from "@gridland/utils";
|
|
6
6
|
|
|
7
7
|
// demos/gradient.tsx
|
|
8
8
|
import { useState as useState8 } from "react";
|
|
@@ -160,9 +160,9 @@ import { useState as useState3 } from "react";
|
|
|
160
160
|
import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
161
161
|
function SpinnerPicker({ useKeyboard: useKeyboardProp }) {
|
|
162
162
|
const theme = useTheme();
|
|
163
|
-
const
|
|
163
|
+
const useKeyboard23 = useKeyboardContext(useKeyboardProp);
|
|
164
164
|
const [selected, setSelected] = useState3(0);
|
|
165
|
-
|
|
165
|
+
useKeyboard23?.((event) => {
|
|
166
166
|
if (event.name === "left") {
|
|
167
167
|
setSelected((s) => s > 0 ? s - 1 : VARIANT_NAMES.length - 1);
|
|
168
168
|
} else if (event.name === "right") {
|
|
@@ -291,7 +291,7 @@ function SelectInput({
|
|
|
291
291
|
useKeyboard: useKeyboardProp
|
|
292
292
|
}) {
|
|
293
293
|
const theme = useTheme();
|
|
294
|
-
const
|
|
294
|
+
const useKeyboard23 = useKeyboardContext(useKeyboardProp);
|
|
295
295
|
const resolvedHighlight = highlightColor ?? theme.primary;
|
|
296
296
|
const isControlled = controlledValue !== void 0;
|
|
297
297
|
const controlledRef = useRef2(isControlled);
|
|
@@ -334,7 +334,7 @@ function SelectInput({
|
|
|
334
334
|
const scrollOffset = Math.max(0, Math.min(cursorRowIndex - Math.floor(visibleCount / 2), flatRows.length - visibleCount));
|
|
335
335
|
const visibleRows = flatRows.slice(scrollOffset, scrollOffset + visibleCount);
|
|
336
336
|
const diamondColor = invalid ? theme.error : disabled ? theme.muted : theme.accent;
|
|
337
|
-
|
|
337
|
+
useKeyboard23?.((event) => {
|
|
338
338
|
if (state.submitted || disabled) return;
|
|
339
339
|
if (event.name === "up" || event.name === "k") {
|
|
340
340
|
const direction = -1;
|
|
@@ -498,7 +498,7 @@ function MultiSelect({
|
|
|
498
498
|
useKeyboard: useKeyboardProp
|
|
499
499
|
}) {
|
|
500
500
|
const theme = useTheme();
|
|
501
|
-
const
|
|
501
|
+
const useKeyboard23 = useKeyboardContext(useKeyboardProp);
|
|
502
502
|
const resolvedHighlight = highlightColor ?? theme.primary;
|
|
503
503
|
const resolvedCheckbox = checkboxColor ?? theme.accent;
|
|
504
504
|
const isControlled = controlledSelected !== void 0;
|
|
@@ -554,7 +554,7 @@ function MultiSelect({
|
|
|
554
554
|
}
|
|
555
555
|
};
|
|
556
556
|
const diamondColor = invalid ? theme.error : disabled ? theme.muted : theme.accent;
|
|
557
|
-
|
|
557
|
+
useKeyboard23?.((event) => {
|
|
558
558
|
if (state.submitted || disabled) return;
|
|
559
559
|
const move = (direction) => {
|
|
560
560
|
let next = cursorRef.current + direction;
|
|
@@ -1004,9 +1004,9 @@ function Modal({
|
|
|
1004
1004
|
useKeyboard: useKeyboardProp
|
|
1005
1005
|
}) {
|
|
1006
1006
|
const theme = useTheme();
|
|
1007
|
-
const
|
|
1007
|
+
const useKeyboard23 = useKeyboardContext(useKeyboardProp);
|
|
1008
1008
|
const resolvedBorderColor = borderColor ?? theme.muted;
|
|
1009
|
-
|
|
1009
|
+
useKeyboard23?.((event) => {
|
|
1010
1010
|
if (event.name === "escape" && onClose) {
|
|
1011
1011
|
onClose();
|
|
1012
1012
|
}
|
|
@@ -1037,7 +1037,7 @@ import {
|
|
|
1037
1037
|
createContext as createContext5,
|
|
1038
1038
|
useContext as useContext5
|
|
1039
1039
|
} from "react";
|
|
1040
|
-
import {
|
|
1040
|
+
import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1041
1041
|
var PromptInputControllerCtx = createContext5(null);
|
|
1042
1042
|
var useOptionalController = () => useContext5(PromptInputControllerCtx);
|
|
1043
1043
|
var PromptInputContext = createContext5(null);
|
|
@@ -1064,10 +1064,11 @@ function resolveStatusHintText(status, submittedText, streamingText, errorText,
|
|
|
1064
1064
|
if (status === "error") return errorText;
|
|
1065
1065
|
return disabledText;
|
|
1066
1066
|
}
|
|
1067
|
-
var DIVIDER_LINE = "\u2500".repeat(500);
|
|
1068
1067
|
function PromptInputDivider() {
|
|
1069
|
-
const { theme } = usePromptInput();
|
|
1070
|
-
|
|
1068
|
+
const { dividerColor, dividerDashed, theme } = usePromptInput();
|
|
1069
|
+
const color = dividerColor ?? theme.muted;
|
|
1070
|
+
const char = dividerDashed ? "\u254C" : "\u2500";
|
|
1071
|
+
return /* @__PURE__ */ jsx16("text", { wrapMode: "none", marginLeft: -1, marginRight: -1, children: /* @__PURE__ */ jsx16("span", { style: textStyle({ dim: !dividerColor, fg: color }), children: char.repeat(500) }) });
|
|
1071
1072
|
}
|
|
1072
1073
|
function PromptInputSuggestions() {
|
|
1073
1074
|
const { suggestions, sugIdx, maxSuggestions, theme } = usePromptInput();
|
|
@@ -1082,18 +1083,25 @@ function PromptInputSuggestions() {
|
|
|
1082
1083
|
] }, sug.text);
|
|
1083
1084
|
}) });
|
|
1084
1085
|
}
|
|
1085
|
-
var CURSOR_CHAR = "\u258D";
|
|
1086
1086
|
function PromptInputTextarea() {
|
|
1087
|
-
const { value, disabled, statusHintText, placeholder, prompt, promptColor, theme } = usePromptInput();
|
|
1088
|
-
return /* @__PURE__ */ jsxs10("
|
|
1089
|
-
/* @__PURE__ */ jsx16("span", { style: textStyle({ fg: promptColor }), children: prompt }),
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1087
|
+
const { value, isFocused, disabled, statusHintText, placeholder, prompt, promptColor, theme, handleInput, handleInputSubmit, handleInputKeyDown } = usePromptInput();
|
|
1088
|
+
return /* @__PURE__ */ jsxs10("box", { flexDirection: "row", children: [
|
|
1089
|
+
/* @__PURE__ */ jsx16("text", { children: /* @__PURE__ */ jsx16("span", { style: textStyle({ fg: promptColor }), children: prompt }) }),
|
|
1090
|
+
isFocused ? /* @__PURE__ */ jsx16(
|
|
1091
|
+
"input",
|
|
1092
|
+
{
|
|
1093
|
+
value,
|
|
1094
|
+
placeholder,
|
|
1095
|
+
focused: true,
|
|
1096
|
+
onInput: handleInput,
|
|
1097
|
+
onSubmit: handleInputSubmit,
|
|
1098
|
+
onKeyDown: handleInputKeyDown,
|
|
1099
|
+
cursorColor: theme.muted,
|
|
1100
|
+
cursorStyle: { style: "line", blinking: !value },
|
|
1101
|
+
placeholderColor: theme.placeholder,
|
|
1102
|
+
textColor: theme.foreground
|
|
1103
|
+
}
|
|
1104
|
+
) : disabled && value.length === 0 ? /* @__PURE__ */ jsx16("text", { children: /* @__PURE__ */ jsx16("span", { style: textStyle({ dim: true, fg: theme.placeholder }), children: statusHintText }) }) : /* @__PURE__ */ jsx16("text", { children: /* @__PURE__ */ jsx16("span", { style: textStyle({ fg: value ? theme.foreground : theme.placeholder, dim: !value }), children: value || placeholder }) })
|
|
1097
1105
|
] });
|
|
1098
1106
|
}
|
|
1099
1107
|
function PromptInputSubmit(props) {
|
|
@@ -1140,13 +1148,16 @@ function PromptInput({
|
|
|
1140
1148
|
maxSuggestions = 5,
|
|
1141
1149
|
enableHistory = true,
|
|
1142
1150
|
model,
|
|
1151
|
+
focus = true,
|
|
1143
1152
|
showDividers = true,
|
|
1144
1153
|
autoFocus = false,
|
|
1154
|
+
dividerColor,
|
|
1155
|
+
dividerDashed,
|
|
1145
1156
|
useKeyboard: useKeyboardProp,
|
|
1146
1157
|
children
|
|
1147
1158
|
}) {
|
|
1148
1159
|
const theme = useTheme();
|
|
1149
|
-
const
|
|
1160
|
+
const useKeyboard23 = useKeyboardContext(useKeyboardProp);
|
|
1150
1161
|
useEffect2(() => {
|
|
1151
1162
|
if (!autoFocus) return;
|
|
1152
1163
|
if (typeof document === "undefined") return;
|
|
@@ -1157,6 +1168,7 @@ function PromptInput({
|
|
|
1157
1168
|
}, [autoFocus]);
|
|
1158
1169
|
const resolvedPromptColor = promptColor ?? theme.muted;
|
|
1159
1170
|
const disabled = status ? status === "submitted" || status === "streaming" : disabledProp;
|
|
1171
|
+
const isFocused = focus && !disabled;
|
|
1160
1172
|
const statusHintText = resolveStatusHintText(status, submittedText, streamingLabel, errorText, disabledText);
|
|
1161
1173
|
const controller = useOptionalController();
|
|
1162
1174
|
const usingProvider = !!controller;
|
|
@@ -1247,18 +1259,86 @@ function PromptInput({
|
|
|
1247
1259
|
clearInput();
|
|
1248
1260
|
}
|
|
1249
1261
|
}, [onSubmit, clearInput]);
|
|
1250
|
-
|
|
1262
|
+
const handleInputSubmit = (text) => {
|
|
1263
|
+
const trimmed = text.trim();
|
|
1264
|
+
if (!trimmed) return;
|
|
1265
|
+
if (enableHistory) {
|
|
1266
|
+
setHist([trimmed, ...historyRef.current]);
|
|
1267
|
+
}
|
|
1268
|
+
updateValue("");
|
|
1269
|
+
setHistI(-1);
|
|
1270
|
+
handleSubmit(trimmed);
|
|
1271
|
+
};
|
|
1272
|
+
const handleInputKeyDown = (key) => {
|
|
1273
|
+
if (key.name === "return" && suggestionsRef.current.length > 0) {
|
|
1274
|
+
const sel = suggestionsRef.current[sugIdxRef.current];
|
|
1275
|
+
if (sel) {
|
|
1276
|
+
if (valueRef.current.startsWith("/")) {
|
|
1277
|
+
updateValue("");
|
|
1278
|
+
if (enableHistory) {
|
|
1279
|
+
setHist([sel.text, ...historyRef.current]);
|
|
1280
|
+
}
|
|
1281
|
+
setHistI(-1);
|
|
1282
|
+
handleSubmit(sel.text);
|
|
1283
|
+
} else {
|
|
1284
|
+
const base = valueRef.current.slice(0, valueRef.current.lastIndexOf("@"));
|
|
1285
|
+
updateValue(base + sel.text + " ");
|
|
1286
|
+
setSug([]);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
key.preventDefault();
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
if (key.name === "tab" && suggestionsRef.current.length > 0) {
|
|
1293
|
+
setSugI((sugIdxRef.current + 1) % suggestionsRef.current.length);
|
|
1294
|
+
key.preventDefault();
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
if (key.name === "up") {
|
|
1298
|
+
if (suggestionsRef.current.length > 0) {
|
|
1299
|
+
setSugI(Math.max(0, sugIdxRef.current - 1));
|
|
1300
|
+
} else if (enableHistory && historyRef.current.length > 0) {
|
|
1301
|
+
const idx = Math.min(historyRef.current.length - 1, histIdxRef.current + 1);
|
|
1302
|
+
setHistI(idx);
|
|
1303
|
+
updateValue(historyRef.current[idx]);
|
|
1304
|
+
}
|
|
1305
|
+
key.preventDefault();
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
if (key.name === "down") {
|
|
1309
|
+
if (suggestionsRef.current.length > 0) {
|
|
1310
|
+
setSugI(Math.min(suggestionsRef.current.length - 1, sugIdxRef.current + 1));
|
|
1311
|
+
} else if (enableHistory && histIdxRef.current > 0) {
|
|
1312
|
+
const nextIdx = histIdxRef.current - 1;
|
|
1313
|
+
setHistI(nextIdx);
|
|
1314
|
+
updateValue(historyRef.current[nextIdx]);
|
|
1315
|
+
} else if (enableHistory && histIdxRef.current === 0) {
|
|
1316
|
+
setHistI(-1);
|
|
1317
|
+
updateValue("");
|
|
1318
|
+
}
|
|
1319
|
+
key.preventDefault();
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
if (key.name === "escape") {
|
|
1323
|
+
if (suggestionsRef.current.length > 0) {
|
|
1324
|
+
setSug([]);
|
|
1325
|
+
key.preventDefault();
|
|
1326
|
+
}
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
useKeyboard23?.((event) => {
|
|
1251
1331
|
if (event.name === "escape" && (status === "streaming" || status === "submitted") && onStop) {
|
|
1252
1332
|
onStop();
|
|
1253
1333
|
return;
|
|
1254
1334
|
}
|
|
1335
|
+
if (isFocused) return;
|
|
1255
1336
|
if (disabled) return;
|
|
1256
1337
|
if (event.name === "return") {
|
|
1257
1338
|
if (suggestionsRef.current.length > 0) {
|
|
1258
1339
|
const sel = suggestionsRef.current[sugIdxRef.current];
|
|
1259
1340
|
if (sel) {
|
|
1260
1341
|
if (valueRef.current.startsWith("/")) {
|
|
1261
|
-
setSug([]);
|
|
1262
1342
|
updateValue("");
|
|
1263
1343
|
if (enableHistory) {
|
|
1264
1344
|
setHist([sel.text, ...historyRef.current]);
|
|
@@ -1279,7 +1359,6 @@ function PromptInput({
|
|
|
1279
1359
|
}
|
|
1280
1360
|
updateValue("");
|
|
1281
1361
|
setHistI(-1);
|
|
1282
|
-
setSug([]);
|
|
1283
1362
|
handleSubmit(trimmed);
|
|
1284
1363
|
}
|
|
1285
1364
|
return;
|
|
@@ -1333,6 +1412,7 @@ function PromptInput({
|
|
|
1333
1412
|
const visibleSuggestions = suggestions.slice(0, maxSuggestions);
|
|
1334
1413
|
const ctxValue = {
|
|
1335
1414
|
value,
|
|
1415
|
+
isFocused,
|
|
1336
1416
|
disabled,
|
|
1337
1417
|
status,
|
|
1338
1418
|
onStop,
|
|
@@ -1345,7 +1425,12 @@ function PromptInput({
|
|
|
1345
1425
|
maxSuggestions,
|
|
1346
1426
|
errorText,
|
|
1347
1427
|
model,
|
|
1348
|
-
|
|
1428
|
+
dividerColor,
|
|
1429
|
+
dividerDashed,
|
|
1430
|
+
theme,
|
|
1431
|
+
handleInput: updateValue,
|
|
1432
|
+
handleInputSubmit,
|
|
1433
|
+
handleInputKeyDown
|
|
1349
1434
|
};
|
|
1350
1435
|
if (children) {
|
|
1351
1436
|
return /* @__PURE__ */ jsx16(PromptInputContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx16("box", { flexDirection: "column", flexShrink: 0, children }) });
|
|
@@ -1438,6 +1523,7 @@ function ChatPanel({
|
|
|
1438
1523
|
userColor,
|
|
1439
1524
|
assistantColor,
|
|
1440
1525
|
loadingText = "Thinking...",
|
|
1526
|
+
focus,
|
|
1441
1527
|
useKeyboard: useKeyboardProp
|
|
1442
1528
|
}) {
|
|
1443
1529
|
const theme = useTheme();
|
|
@@ -1483,6 +1569,7 @@ function ChatPanel({
|
|
|
1483
1569
|
promptColor: resolvedPromptColor,
|
|
1484
1570
|
foregroundColor: theme.foreground,
|
|
1485
1571
|
submittedText: loadingText,
|
|
1572
|
+
focus,
|
|
1486
1573
|
useKeyboard: useKeyboardProp
|
|
1487
1574
|
}
|
|
1488
1575
|
) })
|
|
@@ -1491,7 +1578,7 @@ function ChatPanel({
|
|
|
1491
1578
|
|
|
1492
1579
|
// ../ui/components/chain-of-thought/chain-of-thought.tsx
|
|
1493
1580
|
import { createContext as createContext6, memo, useContext as useContext6, useEffect as useEffect3, useMemo as useMemo4, useState as useState7 } from "react";
|
|
1494
|
-
import { Fragment as
|
|
1581
|
+
import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1495
1582
|
var DOTS = ["\u25CB", "\u25D4", "\u25D1", "\u25D5", "\u25CF"];
|
|
1496
1583
|
var SPINNER_INTERVAL = 150;
|
|
1497
1584
|
var ChainOfThoughtContext = createContext6(null);
|
|
@@ -1550,7 +1637,7 @@ var ChainOfThoughtHeader = memo(({
|
|
|
1550
1637
|
var ChainOfThoughtContent = memo(({ children }) => {
|
|
1551
1638
|
const { isOpen } = useChainOfThought();
|
|
1552
1639
|
if (!isOpen) return null;
|
|
1553
|
-
return /* @__PURE__ */ jsx18(
|
|
1640
|
+
return /* @__PURE__ */ jsx18(Fragment5, { children });
|
|
1554
1641
|
});
|
|
1555
1642
|
var ChainOfThoughtStep = memo(({
|
|
1556
1643
|
label,
|
|
@@ -1765,6 +1852,7 @@ function useBreakpoints() {
|
|
|
1765
1852
|
// demos/gradient.tsx
|
|
1766
1853
|
import figlet from "figlet";
|
|
1767
1854
|
import ansiShadow from "figlet/importable-fonts/ANSI Shadow.js";
|
|
1855
|
+
import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1768
1856
|
figlet.parseFont("ANSI Shadow", ansiShadow);
|
|
1769
1857
|
var art = figlet.textSync("gridland", { font: "ANSI Shadow" });
|
|
1770
1858
|
var lines = art.split("\n").filter((l) => l.trimEnd().length > 0);
|
|
@@ -1777,13 +1865,16 @@ function GradientApp() {
|
|
|
1777
1865
|
if (event.name === "left") setIndex((i) => i > 0 ? i - 1 : gradientNames.length - 1);
|
|
1778
1866
|
if (event.name === "right") setIndex((i) => i < gradientNames.length - 1 ? i + 1 : 0);
|
|
1779
1867
|
});
|
|
1780
|
-
return /* @__PURE__ */
|
|
1781
|
-
|
|
1782
|
-
{
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1868
|
+
return /* @__PURE__ */ jsxs15("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
1869
|
+
/* @__PURE__ */ jsx21("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: /* @__PURE__ */ jsx21(Gradient, { name: name2, children: lines.join("\n") }) }),
|
|
1870
|
+
/* @__PURE__ */ jsx21("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx21(
|
|
1871
|
+
StatusBar,
|
|
1872
|
+
{
|
|
1873
|
+
items: [{ key: "\u2190\u2192", label: "gradient" }],
|
|
1874
|
+
extra: /* @__PURE__ */ jsx21("span", { style: textStyle({ fg: theme.accent, bold: true }), children: name2.padEnd(11) })
|
|
1875
|
+
}
|
|
1876
|
+
) })
|
|
1877
|
+
] });
|
|
1787
1878
|
}
|
|
1788
1879
|
|
|
1789
1880
|
// demos/ascii.tsx
|
|
@@ -1798,6 +1889,7 @@ import speed from "figlet/importable-fonts/Speed.js";
|
|
|
1798
1889
|
import standard from "figlet/importable-fonts/Standard.js";
|
|
1799
1890
|
import block from "figlet/importable-fonts/Block.js";
|
|
1800
1891
|
import colossal from "figlet/importable-fonts/Colossal.js";
|
|
1892
|
+
import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1801
1893
|
var fonts = [
|
|
1802
1894
|
{ name: "ANSI Shadow", data: ansiShadow2 },
|
|
1803
1895
|
{ name: "Standard", data: standard },
|
|
@@ -1824,34 +1916,40 @@ function AsciiApp() {
|
|
|
1824
1916
|
if (event.name === "left") setFontIndex((i) => i > 0 ? i - 1 : fonts.length - 1);
|
|
1825
1917
|
if (event.name === "right") setFontIndex((i) => i < fonts.length - 1 ? i + 1 : 0);
|
|
1826
1918
|
});
|
|
1827
|
-
return /* @__PURE__ */
|
|
1828
|
-
|
|
1829
|
-
{
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1919
|
+
return /* @__PURE__ */ jsxs16("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
1920
|
+
/* @__PURE__ */ jsx22("box", { padding: 1, flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: lines2.map((line, i) => /* @__PURE__ */ jsx22("text", { fg: theme.accent, bold: true, children: line }, i)) }),
|
|
1921
|
+
/* @__PURE__ */ jsx22("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx22(
|
|
1922
|
+
StatusBar,
|
|
1923
|
+
{
|
|
1924
|
+
items: [{ key: "\u2190\u2192", label: "change font" }],
|
|
1925
|
+
extra: /* @__PURE__ */ jsx22("span", { style: textStyle({ fg: theme.accent, bold: true }), children: font.name.padEnd(11) })
|
|
1926
|
+
}
|
|
1927
|
+
) })
|
|
1928
|
+
] });
|
|
1834
1929
|
}
|
|
1835
1930
|
|
|
1836
1931
|
// demos/table.tsx
|
|
1932
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
1837
1933
|
function TableApp() {
|
|
1838
1934
|
const data2 = [
|
|
1839
1935
|
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
1840
1936
|
{ name: "Bob", role: "Designer", status: "Active" },
|
|
1841
1937
|
{ name: "Charlie", role: "PM", status: "Away" }
|
|
1842
1938
|
];
|
|
1843
|
-
return /* @__PURE__ */
|
|
1939
|
+
return /* @__PURE__ */ jsx23("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx23(Table, { data: data2, headerColor: "cyan", borderColor: "#5e81ac" }) });
|
|
1844
1940
|
}
|
|
1845
1941
|
|
|
1846
1942
|
// demos/spinner.tsx
|
|
1847
1943
|
import { useKeyboard as useKeyboard3 } from "@gridland/utils";
|
|
1944
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1848
1945
|
function SpinnerApp() {
|
|
1849
|
-
return /* @__PURE__ */
|
|
1946
|
+
return /* @__PURE__ */ jsx24("box", { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx24(SpinnerPicker, { useKeyboard: useKeyboard3 }) });
|
|
1850
1947
|
}
|
|
1851
1948
|
|
|
1852
1949
|
// demos/select-input.tsx
|
|
1853
1950
|
import { useState as useState10 } from "react";
|
|
1854
1951
|
import { useKeyboard as useKeyboard4 } from "@gridland/utils";
|
|
1952
|
+
import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1855
1953
|
var items = [
|
|
1856
1954
|
{ label: "TypeScript", value: "ts" },
|
|
1857
1955
|
{ label: "JavaScript", value: "js" },
|
|
@@ -1867,24 +1965,28 @@ function SelectInputApp() {
|
|
|
1867
1965
|
setResetKey((k) => k + 1);
|
|
1868
1966
|
}
|
|
1869
1967
|
});
|
|
1870
|
-
return /* @__PURE__ */
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
{ key: "
|
|
1882
|
-
|
|
1968
|
+
return /* @__PURE__ */ jsxs17("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
1969
|
+
/* @__PURE__ */ jsx25("box", { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx25(
|
|
1970
|
+
SelectInput,
|
|
1971
|
+
{
|
|
1972
|
+
items,
|
|
1973
|
+
title: "Choose a language",
|
|
1974
|
+
useKeyboard: useKeyboard4,
|
|
1975
|
+
onSubmit: () => setSubmitted(true)
|
|
1976
|
+
},
|
|
1977
|
+
resetKey
|
|
1978
|
+
) }),
|
|
1979
|
+
/* @__PURE__ */ jsx25(StatusBar, { items: submitted ? [{ key: "r", label: "reset demo" }] : [
|
|
1980
|
+
{ key: "\u2191\u2193", label: "select" },
|
|
1981
|
+
{ key: "enter", label: "submit" }
|
|
1982
|
+
] })
|
|
1983
|
+
] });
|
|
1883
1984
|
}
|
|
1884
1985
|
|
|
1885
1986
|
// demos/multi-select.tsx
|
|
1886
1987
|
import { useState as useState11 } from "react";
|
|
1887
1988
|
import { useKeyboard as useKeyboard5 } from "@gridland/utils";
|
|
1989
|
+
import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1888
1990
|
var items2 = [
|
|
1889
1991
|
{ label: "TypeScript", value: "ts" },
|
|
1890
1992
|
{ label: "JavaScript", value: "js" },
|
|
@@ -1900,26 +2002,30 @@ function MultiSelectApp() {
|
|
|
1900
2002
|
setResetKey((k) => k + 1);
|
|
1901
2003
|
}
|
|
1902
2004
|
});
|
|
1903
|
-
return /* @__PURE__ */
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
{ key: "
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
2005
|
+
return /* @__PURE__ */ jsxs18("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
2006
|
+
/* @__PURE__ */ jsx26("box", { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx26(
|
|
2007
|
+
MultiSelect,
|
|
2008
|
+
{
|
|
2009
|
+
items: items2,
|
|
2010
|
+
title: "Select languages",
|
|
2011
|
+
useKeyboard: useKeyboard5,
|
|
2012
|
+
onSubmit: () => setSubmitted(true)
|
|
2013
|
+
},
|
|
2014
|
+
resetKey
|
|
2015
|
+
) }),
|
|
2016
|
+
/* @__PURE__ */ jsx26(StatusBar, { items: submitted ? [{ key: "r", label: "reset demo" }] : [
|
|
2017
|
+
{ key: "\u2191\u2193", label: "move" },
|
|
2018
|
+
{ key: "enter", label: "select" },
|
|
2019
|
+
{ key: "a", label: "all" },
|
|
2020
|
+
{ key: "x", label: "clear" }
|
|
2021
|
+
] })
|
|
2022
|
+
] });
|
|
1918
2023
|
}
|
|
1919
2024
|
|
|
1920
2025
|
// demos/prompt-input.tsx
|
|
1921
2026
|
import { useState as useState12 } from "react";
|
|
1922
2027
|
import { useKeyboard as useKeyboard6 } from "@gridland/utils";
|
|
2028
|
+
import { jsx as jsx27, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1923
2029
|
var commands = [{ cmd: "/model", desc: "Switch model" }];
|
|
1924
2030
|
var files = ["src/index.ts", "src/routes.ts", "src/auth.ts", "package.json"];
|
|
1925
2031
|
var models = [
|
|
@@ -1942,7 +2048,7 @@ function PromptInputApp() {
|
|
|
1942
2048
|
setLastMessage(msg.text);
|
|
1943
2049
|
};
|
|
1944
2050
|
if (showModelPicker) {
|
|
1945
|
-
return /* @__PURE__ */
|
|
2051
|
+
return /* @__PURE__ */ jsx27("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: /* @__PURE__ */ jsx27(Modal, { title: "Select Model", useKeyboard: useKeyboard6, onClose: () => setShowModelPicker(false), children: /* @__PURE__ */ jsx27("box", { paddingX: 1, children: /* @__PURE__ */ jsx27(
|
|
1946
2052
|
SelectInput,
|
|
1947
2053
|
{
|
|
1948
2054
|
items: models,
|
|
@@ -1953,29 +2059,39 @@ function PromptInputApp() {
|
|
|
1953
2059
|
setShowModelPicker(false);
|
|
1954
2060
|
}
|
|
1955
2061
|
}
|
|
1956
|
-
))));
|
|
2062
|
+
) }) }) });
|
|
1957
2063
|
}
|
|
1958
|
-
return /* @__PURE__ */
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
2064
|
+
return /* @__PURE__ */ jsxs19("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
2065
|
+
/* @__PURE__ */ jsx27("box", { flexDirection: "column", flexGrow: 1, children: lastMessage ? /* @__PURE__ */ jsxs19("text", { children: [
|
|
2066
|
+
/* @__PURE__ */ jsx27("span", { style: textStyle({ fg: theme.muted }), children: "Sent: " }),
|
|
2067
|
+
/* @__PURE__ */ jsx27("span", { style: textStyle({ fg: theme.foreground }), children: lastMessage })
|
|
2068
|
+
] }) : /* @__PURE__ */ jsx27("text", { children: /* @__PURE__ */ jsx27("span", { children: " " }) }) }),
|
|
2069
|
+
/* @__PURE__ */ jsx27(
|
|
2070
|
+
PromptInput,
|
|
2071
|
+
{
|
|
2072
|
+
commands,
|
|
2073
|
+
files,
|
|
2074
|
+
placeholder: "Message Claude...",
|
|
2075
|
+
showDividers: true,
|
|
2076
|
+
autoFocus: true,
|
|
2077
|
+
useKeyboard: useKeyboard6,
|
|
2078
|
+
onSubmit: handleSubmit
|
|
2079
|
+
},
|
|
2080
|
+
resetKey
|
|
2081
|
+
),
|
|
2082
|
+
/* @__PURE__ */ jsx27("box", { children: /* @__PURE__ */ jsx27("text", { children: /* @__PURE__ */ jsx27("span", { style: textStyle({ dim: true }), children: "model: " + model }) }) }),
|
|
2083
|
+
/* @__PURE__ */ jsx27("box", { paddingTop: 1, paddingLeft: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx27(StatusBar, { items: [
|
|
2084
|
+
{ key: "\u23CE enter", label: "send" },
|
|
2085
|
+
{ key: "/model", label: "change model" },
|
|
2086
|
+
{ key: "\u2191", label: "history" }
|
|
2087
|
+
] }) })
|
|
2088
|
+
] });
|
|
1974
2089
|
}
|
|
1975
2090
|
|
|
1976
2091
|
// demos/text-input.tsx
|
|
1977
2092
|
import { useState as useState13 } from "react";
|
|
1978
2093
|
import { useKeyboard as useKeyboard7 } from "@gridland/utils";
|
|
2094
|
+
import { jsx as jsx28, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1979
2095
|
var FIELDS = [
|
|
1980
2096
|
{ label: "Username", placeholder: "enter your name", maxLength: 30, required: true },
|
|
1981
2097
|
{ label: "Email", placeholder: "user@example.com", maxLength: 50, required: true, description: "We'll never share your email" },
|
|
@@ -1989,26 +2105,30 @@ function TextInputApp() {
|
|
|
1989
2105
|
if (event.name === "up") setActiveField((i) => Math.max(0, i - 1));
|
|
1990
2106
|
if (event.name === "down") setActiveField((i) => Math.min(FIELDS.length - 1, i + 1));
|
|
1991
2107
|
});
|
|
1992
|
-
return /* @__PURE__ */
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2108
|
+
return /* @__PURE__ */ jsxs20("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2109
|
+
/* @__PURE__ */ jsx28("box", { flexDirection: "column", paddingX: 1, paddingTop: 1, flexGrow: 1, children: FIELDS.map((field, i) => /* @__PURE__ */ jsx28("box", { marginBottom: 1, children: /* @__PURE__ */ jsx28(
|
|
2110
|
+
TextInput,
|
|
2111
|
+
{
|
|
2112
|
+
label: field.label,
|
|
2113
|
+
placeholder: field.placeholder,
|
|
2114
|
+
prompt: "> ",
|
|
2115
|
+
focus: i === activeField,
|
|
2116
|
+
maxLength: field.maxLength,
|
|
2117
|
+
value: values[i],
|
|
2118
|
+
onChange: (v) => setValues((prev) => prev.map((old, j) => j === i ? v : old)),
|
|
2119
|
+
required: field.required,
|
|
2120
|
+
disabled: field.disabled,
|
|
2121
|
+
description: field.description
|
|
2122
|
+
}
|
|
2123
|
+
) }, field.label)) }),
|
|
2124
|
+
/* @__PURE__ */ jsx28("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx28(StatusBar, { items: [{ key: "\u2191\u2193", label: "field" }] }) })
|
|
2125
|
+
] });
|
|
2007
2126
|
}
|
|
2008
2127
|
|
|
2009
2128
|
// demos/link.tsx
|
|
2010
2129
|
import { useState as useState14 } from "react";
|
|
2011
2130
|
import { useKeyboard as useKeyboard8 } from "@gridland/utils";
|
|
2131
|
+
import { jsx as jsx29, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2012
2132
|
var MODES = ["solid", "dashed", "dotted", "none"];
|
|
2013
2133
|
function LinkApp() {
|
|
2014
2134
|
const theme = useTheme();
|
|
@@ -2018,18 +2138,28 @@ function LinkApp() {
|
|
|
2018
2138
|
if (event.name === "right") setModeIndex((i) => (i + 1) % MODES.length);
|
|
2019
2139
|
if (event.name === "left") setModeIndex((i) => (i - 1 + MODES.length) % MODES.length);
|
|
2020
2140
|
});
|
|
2021
|
-
return /* @__PURE__ */
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2141
|
+
return /* @__PURE__ */ jsxs21("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2142
|
+
/* @__PURE__ */ jsx29("box", { padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsxs21("text", { style: textStyle({ fg: theme.foreground }), children: [
|
|
2143
|
+
"Made by ",
|
|
2144
|
+
/* @__PURE__ */ jsx29("a", { href: "https://cjroth.com", style: { attributes: mode === "solid" ? 8 : mode === "dashed" ? 24 : mode === "dotted" ? 72 : 0, fg: theme.accent }, children: "Chris Roth" }),
|
|
2145
|
+
" and ",
|
|
2146
|
+
/* @__PURE__ */ jsx29("a", { href: "https://jessicacheng.studio", style: { attributes: mode === "solid" ? 8 : mode === "dashed" ? 24 : mode === "dotted" ? 72 : 0, fg: theme.accent }, children: "Jessica Cheng" }),
|
|
2147
|
+
"."
|
|
2148
|
+
] }) }),
|
|
2149
|
+
/* @__PURE__ */ jsx29("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx29(
|
|
2150
|
+
StatusBar,
|
|
2151
|
+
{
|
|
2152
|
+
extra: /* @__PURE__ */ jsx29("span", { style: textStyle({ bold: true, fg: theme.foreground }), children: mode.padEnd(6) }),
|
|
2153
|
+
items: [{ key: "\u2190\u2192", label: "underline style" }]
|
|
2154
|
+
}
|
|
2155
|
+
) })
|
|
2156
|
+
] });
|
|
2028
2157
|
}
|
|
2029
2158
|
|
|
2030
2159
|
// demos/tabs.tsx
|
|
2031
2160
|
import { useState as useState15 } from "react";
|
|
2032
2161
|
import { useKeyboard as useKeyboard9 } from "@gridland/utils";
|
|
2162
|
+
import { jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2033
2163
|
var tabs = ["Files", "Search", "Git", "Debug"];
|
|
2034
2164
|
function TabBarApp() {
|
|
2035
2165
|
const [selectedIndex, setSelectedIndex] = useState15(0);
|
|
@@ -2037,12 +2167,17 @@ function TabBarApp() {
|
|
|
2037
2167
|
if (event.name === "left") setSelectedIndex((i) => i > 0 ? i - 1 : tabs.length - 1);
|
|
2038
2168
|
if (event.name === "right") setSelectedIndex((i) => i < tabs.length - 1 ? i + 1 : 0);
|
|
2039
2169
|
});
|
|
2040
|
-
return /* @__PURE__ */
|
|
2170
|
+
return /* @__PURE__ */ jsxs22("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2171
|
+
/* @__PURE__ */ jsx30("box", { padding: 1, children: /* @__PURE__ */ jsx30(TabBar, { options: tabs, selectedIndex }) }),
|
|
2172
|
+
/* @__PURE__ */ jsx30("box", { flexGrow: 1 }),
|
|
2173
|
+
/* @__PURE__ */ jsx30("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx30(StatusBar, { items: [{ key: "\u2190\u2192", label: "switch tab" }] }) })
|
|
2174
|
+
] });
|
|
2041
2175
|
}
|
|
2042
2176
|
|
|
2043
2177
|
// demos/status-bar.tsx
|
|
2044
2178
|
import { useState as useState16 } from "react";
|
|
2045
2179
|
import { useKeyboard as useKeyboard10 } from "@gridland/utils";
|
|
2180
|
+
import { jsx as jsx31, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2046
2181
|
var shortcuts = [
|
|
2047
2182
|
{ key: "Tab", label: "switch focus" },
|
|
2048
2183
|
{ key: "\u2190\u2192", label: "cycle" },
|
|
@@ -2059,18 +2194,25 @@ function StatusBarApp() {
|
|
|
2059
2194
|
else if (event.name === "b") setLastKey("back (b)");
|
|
2060
2195
|
else if (event.name === "z") setLastKey("reset (z)");
|
|
2061
2196
|
});
|
|
2062
|
-
return /* @__PURE__ */
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2197
|
+
return /* @__PURE__ */ jsxs23("box", { flexDirection: "column", gap: 1, padding: 1, children: [
|
|
2198
|
+
lastKey ? /* @__PURE__ */ jsxs23("text", { children: [
|
|
2199
|
+
/* @__PURE__ */ jsx31("span", { children: "Pressed: " }),
|
|
2200
|
+
/* @__PURE__ */ jsx31("span", { style: textStyle({ bold: true, fg: theme.accent }), children: lastKey })
|
|
2201
|
+
] }) : /* @__PURE__ */ jsx31("text", { style: textStyle({ dim: true }), children: "Press a key to trigger an action" }),
|
|
2202
|
+
/* @__PURE__ */ jsx31(
|
|
2203
|
+
StatusBar,
|
|
2204
|
+
{
|
|
2205
|
+
items: shortcuts,
|
|
2206
|
+
extra: /* @__PURE__ */ jsx31("span", { style: textStyle({ fg: theme.success }), children: "\u25CF Ready" })
|
|
2207
|
+
}
|
|
2208
|
+
)
|
|
2209
|
+
] });
|
|
2069
2210
|
}
|
|
2070
2211
|
|
|
2071
2212
|
// demos/modal.tsx
|
|
2072
2213
|
import { useState as useState17 } from "react";
|
|
2073
2214
|
import { useKeyboard as useKeyboard11 } from "@gridland/utils";
|
|
2215
|
+
import { jsx as jsx32, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2074
2216
|
function ModalApp() {
|
|
2075
2217
|
const theme = useTheme();
|
|
2076
2218
|
const [isOpen, setIsOpen] = useState17(false);
|
|
@@ -2079,30 +2221,50 @@ function ModalApp() {
|
|
|
2079
2221
|
if (isOpen && (event.name === "q" || event.name === "escape")) setIsOpen(false);
|
|
2080
2222
|
});
|
|
2081
2223
|
if (isOpen) {
|
|
2082
|
-
return /* @__PURE__ */
|
|
2224
|
+
return /* @__PURE__ */ jsxs24("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2225
|
+
/* @__PURE__ */ jsx32(Modal, { title: "Example Modal", useKeyboard: useKeyboard11, onClose: () => setIsOpen(false), children: /* @__PURE__ */ jsxs24("box", { paddingX: 1, flexDirection: "column", children: [
|
|
2226
|
+
/* @__PURE__ */ jsx32("text", { style: textStyle({ fg: theme.foreground }), children: "This is a modal overlay component." }),
|
|
2227
|
+
/* @__PURE__ */ jsx32("text", { children: " " }),
|
|
2228
|
+
/* @__PURE__ */ jsx32("text", { style: textStyle({ dim: true, fg: theme.muted }), children: "It stretches to fill the full terminal height." })
|
|
2229
|
+
] }) }),
|
|
2230
|
+
/* @__PURE__ */ jsx32("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx32(StatusBar, { items: [{ key: "q", label: "close" }] }) })
|
|
2231
|
+
] });
|
|
2083
2232
|
}
|
|
2084
|
-
return /* @__PURE__ */
|
|
2233
|
+
return /* @__PURE__ */ jsx32("box", { flexDirection: "column", flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsxs24("text", { children: [
|
|
2234
|
+
/* @__PURE__ */ jsx32("span", { style: textStyle({ dim: true, fg: theme.muted }), children: "Press " }),
|
|
2235
|
+
/* @__PURE__ */ jsx32("span", { style: textStyle({ bold: true, fg: theme.background, bg: theme.muted }), children: " m " }),
|
|
2236
|
+
/* @__PURE__ */ jsx32("span", { style: textStyle({ dim: true, fg: theme.muted }), children: " to open modal" })
|
|
2237
|
+
] }) });
|
|
2085
2238
|
}
|
|
2086
2239
|
|
|
2087
2240
|
// demos/primitives.tsx
|
|
2241
|
+
import { jsx as jsx33, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2088
2242
|
function PrimitivesApp() {
|
|
2089
|
-
return /* @__PURE__ */
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2243
|
+
return /* @__PURE__ */ jsxs25("box", { flexDirection: "column", padding: 1, children: [
|
|
2244
|
+
/* @__PURE__ */ jsx33(
|
|
2245
|
+
"box",
|
|
2246
|
+
{
|
|
2247
|
+
border: true,
|
|
2248
|
+
borderStyle: "rounded",
|
|
2249
|
+
borderColor: "#75715e",
|
|
2250
|
+
title: "Layout",
|
|
2251
|
+
titleAlignment: "center",
|
|
2252
|
+
padding: 1,
|
|
2253
|
+
children: /* @__PURE__ */ jsxs25("box", { flexDirection: "row", gap: 2, children: [
|
|
2254
|
+
/* @__PURE__ */ jsx33("box", { border: true, borderStyle: "single", borderColor: "#a6e22e", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx33("text", { fg: "#a6e22e", bold: true, children: "Box 1" }) }),
|
|
2255
|
+
/* @__PURE__ */ jsx33("box", { border: true, borderStyle: "single", borderColor: "#f92672", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx33("text", { fg: "#f92672", bold: true, children: "Box 2" }) }),
|
|
2256
|
+
/* @__PURE__ */ jsx33("box", { border: true, borderStyle: "single", borderColor: "#66d9ef", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsx33("text", { fg: "#66d9ef", bold: true, children: "Box 3" }) })
|
|
2257
|
+
] })
|
|
2258
|
+
}
|
|
2259
|
+
),
|
|
2260
|
+
/* @__PURE__ */ jsx33("text", { dim: true, fg: "#75715e", children: " Nested boxes with borders, colors & flexbox layout" })
|
|
2261
|
+
] });
|
|
2101
2262
|
}
|
|
2102
2263
|
|
|
2103
2264
|
// demos/chat.tsx
|
|
2104
2265
|
import { useState as useState18, useCallback as useCallback3, useRef as useRef5 } from "react";
|
|
2105
2266
|
import { useKeyboard as useKeyboard12 } from "@gridland/utils";
|
|
2267
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
2106
2268
|
var initialMessages = [
|
|
2107
2269
|
{ id: "1", role: "user", content: "Show me my portfolio" },
|
|
2108
2270
|
{ id: "2", role: "assistant", content: "Here's your current portfolio allocation:" },
|
|
@@ -2153,7 +2315,7 @@ function ChatApp() {
|
|
|
2153
2315
|
setStreamingText("");
|
|
2154
2316
|
setActiveToolCalls([]);
|
|
2155
2317
|
}, []);
|
|
2156
|
-
return /* @__PURE__ */
|
|
2318
|
+
return /* @__PURE__ */ jsx34(
|
|
2157
2319
|
ChatPanel,
|
|
2158
2320
|
{
|
|
2159
2321
|
messages,
|
|
@@ -2171,6 +2333,7 @@ function ChatApp() {
|
|
|
2171
2333
|
// demos/chain-of-thought.tsx
|
|
2172
2334
|
import { useState as useState19, useEffect as useEffect4, useRef as useRef6 } from "react";
|
|
2173
2335
|
import { useKeyboard as useKeyboard13 } from "@gridland/utils";
|
|
2336
|
+
import { jsx as jsx35, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2174
2337
|
var ALL_STEPS = [
|
|
2175
2338
|
{ tool: "Read", label: "Reading codebase", description: "src/", status: "done", delay: 1800 },
|
|
2176
2339
|
{ tool: "Think", label: "Planning changes", description: "auth module", status: "done", delay: 2500 },
|
|
@@ -2220,25 +2383,32 @@ function ChainOfThoughtApp() {
|
|
|
2220
2383
|
const elapsedMs = ALL_STEPS.slice(0, stepIndex).reduce((sum, s) => sum + s.delay, 0);
|
|
2221
2384
|
const totalMs = ALL_STEPS.reduce((sum, s) => sum + s.delay, 0);
|
|
2222
2385
|
const durationStr = phase === "done" ? `${(totalMs / 1e3).toFixed(1)}s` : `${(elapsedMs / 1e3).toFixed(1)}s`;
|
|
2223
|
-
return /* @__PURE__ */
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2386
|
+
return /* @__PURE__ */ jsxs26("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2387
|
+
/* @__PURE__ */ jsx35("box", { flexDirection: "column", padding: 1, flexGrow: 1, children: /* @__PURE__ */ jsxs26(ChainOfThought, { open: expanded, onOpenChange: setExpanded, children: [
|
|
2388
|
+
/* @__PURE__ */ jsx35(ChainOfThoughtHeader, { duration: durationStr }),
|
|
2389
|
+
/* @__PURE__ */ jsx35(ChainOfThoughtContent, { children: steps.map((step, i) => /* @__PURE__ */ jsx35(
|
|
2390
|
+
ChainOfThoughtStep,
|
|
2391
|
+
{
|
|
2392
|
+
label: step.label,
|
|
2393
|
+
description: step.description,
|
|
2394
|
+
status: step.status,
|
|
2395
|
+
isLast: i === steps.length - 1,
|
|
2396
|
+
children: step.output
|
|
2397
|
+
},
|
|
2398
|
+
i
|
|
2399
|
+
)) })
|
|
2400
|
+
] }) }),
|
|
2401
|
+
/* @__PURE__ */ jsx35("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx35(StatusBar, { items: [
|
|
2402
|
+
{ key: "ctrl+shift+e", label: "toggle" },
|
|
2403
|
+
{ key: "r", label: "restart" }
|
|
2404
|
+
] }) })
|
|
2405
|
+
] });
|
|
2237
2406
|
}
|
|
2238
2407
|
|
|
2239
2408
|
// demos/message.tsx
|
|
2240
2409
|
import { useState as useState20, useEffect as useEffect5, useRef as useRef7 } from "react";
|
|
2241
2410
|
import { useKeyboard as useKeyboard14 } from "@gridland/utils";
|
|
2411
|
+
import { jsx as jsx36, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2242
2412
|
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
2413
|
function MessageApp() {
|
|
2244
2414
|
const [phase, setPhase] = useState20("idle");
|
|
@@ -2284,37 +2454,54 @@ function MessageApp() {
|
|
|
2284
2454
|
const isStreaming = phase === "streaming";
|
|
2285
2455
|
const isDone = phase === "done";
|
|
2286
2456
|
const showAssistant = phase !== "idle";
|
|
2287
|
-
return /* @__PURE__ */
|
|
2457
|
+
return /* @__PURE__ */ jsxs27("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2458
|
+
/* @__PURE__ */ jsxs27("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1, children: [
|
|
2459
|
+
/* @__PURE__ */ jsx36(Message, { role: "user", children: /* @__PURE__ */ jsx36(Message.Content, { children: /* @__PURE__ */ jsx36(Message.Text, { children: "Can you refactor the auth module?" }) }) }),
|
|
2460
|
+
showAssistant && /* @__PURE__ */ jsx36(Message, { role: "assistant", isStreaming, children: /* @__PURE__ */ jsx36(Message.Content, { children: /* @__PURE__ */ jsx36(Message.Text, { isLast: true, children: isDone ? RESPONSE : streamedText }) }) })
|
|
2461
|
+
] }),
|
|
2462
|
+
/* @__PURE__ */ jsx36("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx36(StatusBar, { items: [{ key: "r", label: "restart" }] }) })
|
|
2463
|
+
] });
|
|
2288
2464
|
}
|
|
2289
2465
|
|
|
2290
2466
|
// demos/terminal-window.tsx
|
|
2467
|
+
import { jsx as jsx37, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2291
2468
|
function TerminalWindowApp() {
|
|
2292
2469
|
const theme = useTheme();
|
|
2293
|
-
return /* @__PURE__ */
|
|
2470
|
+
return /* @__PURE__ */ jsxs28("box", { flexDirection: "column", padding: 1, children: [
|
|
2471
|
+
/* @__PURE__ */ jsx37("text", { style: textStyle({ fg: theme.secondary }), children: '$ echo "Hello from TerminalWindow"' }),
|
|
2472
|
+
/* @__PURE__ */ jsx37("text", { style: textStyle({ fg: theme.foreground }), children: "Hello from TerminalWindow" }),
|
|
2473
|
+
/* @__PURE__ */ jsx37("text", { style: textStyle({ fg: theme.secondary }), children: "$ _" })
|
|
2474
|
+
] });
|
|
2294
2475
|
}
|
|
2295
2476
|
|
|
2296
2477
|
// demos/focus.tsx
|
|
2297
|
-
import {
|
|
2298
|
-
import { useKeyboard as useKeyboard15 } from "@gridland/utils";
|
|
2299
|
-
|
|
2478
|
+
import { useRef as useRef8, useCallback as useCallback4 } from "react";
|
|
2479
|
+
import { useKeyboard as useKeyboard15, useFocus, FocusProvider, useShortcuts, useFocusedShortcuts } from "@gridland/utils";
|
|
2480
|
+
import { jsx as jsx38, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2481
|
+
var focusMultiSelects = [
|
|
2300
2482
|
{
|
|
2301
|
-
|
|
2483
|
+
id: "language",
|
|
2484
|
+
title: "Language",
|
|
2302
2485
|
items: [
|
|
2303
2486
|
{ label: "TypeScript", value: "ts" },
|
|
2304
2487
|
{ label: "JavaScript", value: "js" },
|
|
2305
|
-
{ label: "Python", value: "py" }
|
|
2488
|
+
{ label: "Python", value: "py" },
|
|
2489
|
+
{ label: "Rust", value: "rs" }
|
|
2306
2490
|
]
|
|
2307
2491
|
},
|
|
2308
2492
|
{
|
|
2309
|
-
|
|
2493
|
+
id: "framework",
|
|
2494
|
+
title: "Framework",
|
|
2310
2495
|
items: [
|
|
2311
2496
|
{ label: "React", value: "react" },
|
|
2312
2497
|
{ label: "Vue", value: "vue" },
|
|
2313
|
-
{ label: "Svelte", value: "svelte" }
|
|
2498
|
+
{ label: "Svelte", value: "svelte" },
|
|
2499
|
+
{ label: "Solid", value: "solid" }
|
|
2314
2500
|
]
|
|
2315
2501
|
},
|
|
2316
2502
|
{
|
|
2317
|
-
|
|
2503
|
+
id: "runtime",
|
|
2504
|
+
title: "Runtime",
|
|
2318
2505
|
items: [
|
|
2319
2506
|
{ label: "Bun", value: "bun" },
|
|
2320
2507
|
{ label: "Node", value: "node" },
|
|
@@ -2322,101 +2509,168 @@ var focusPanels = [
|
|
|
2322
2509
|
]
|
|
2323
2510
|
}
|
|
2324
2511
|
];
|
|
2325
|
-
function
|
|
2326
|
-
const
|
|
2327
|
-
const
|
|
2328
|
-
const
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
const enteredRef = useRef8(false);
|
|
2332
|
-
const cursorsRef = useRef8([0, 0, 0]);
|
|
2333
|
-
panelRef.current = panelIndex;
|
|
2334
|
-
enteredRef.current = entered;
|
|
2335
|
-
cursorsRef.current = cursors;
|
|
2512
|
+
function FocusMultiSelectPanel({ id, title, items: items3, autoFocus }) {
|
|
2513
|
+
const { isFocused, isSelected, isAnySelected, focusId, focusRef } = useFocus({ id, autoFocus });
|
|
2514
|
+
const multiSelectHandlerRef = useRef8(null);
|
|
2515
|
+
const captureKeyboard = useCallback4((handler) => {
|
|
2516
|
+
multiSelectHandlerRef.current = handler;
|
|
2517
|
+
}, []);
|
|
2336
2518
|
useKeyboard15((event) => {
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
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
|
-
}
|
|
2519
|
+
multiSelectHandlerRef.current?.(event);
|
|
2520
|
+
}, { focusId, selectedOnly: true });
|
|
2521
|
+
useShortcuts(
|
|
2522
|
+
isSelected ? [{ key: "\u2191\u2193", label: "move" }, { key: "enter", label: "toggle" }, { key: "esc", label: "back" }] : [{ key: "\u2190\u2192", label: "navigate" }, { key: "tab", label: "cycle" }, { key: "enter", label: "select" }],
|
|
2523
|
+
focusId
|
|
2524
|
+
);
|
|
2525
|
+
const borderStyle = isSelected ? "rounded" : isFocused ? "dashed" : "rounded";
|
|
2526
|
+
const borderColor = isSelected ? "#818cf8" : isAnySelected ? "transparent" : isFocused ? "#6366f1" : "#3b3466";
|
|
2527
|
+
return /* @__PURE__ */ jsx38("box", { ref: focusRef, border: true, borderStyle, borderColor, flexGrow: 1, children: /* @__PURE__ */ jsx38("box", { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsx38(
|
|
2528
|
+
MultiSelect,
|
|
2529
|
+
{
|
|
2530
|
+
items: items3,
|
|
2531
|
+
title,
|
|
2532
|
+
allowEmpty: true,
|
|
2533
|
+
enableSelectAll: false,
|
|
2534
|
+
enableClear: false,
|
|
2535
|
+
highlightColor: isSelected ? "#a5b4fc" : "#6366f1",
|
|
2536
|
+
checkboxColor: "#818cf8",
|
|
2537
|
+
useKeyboard: captureKeyboard
|
|
2377
2538
|
}
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2539
|
+
) }) });
|
|
2540
|
+
}
|
|
2541
|
+
function FocusNavStatusBar() {
|
|
2542
|
+
const shortcuts2 = useFocusedShortcuts();
|
|
2543
|
+
return /* @__PURE__ */ jsx38("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx38(StatusBar, { items: shortcuts2 }) });
|
|
2544
|
+
}
|
|
2545
|
+
function FocusApp() {
|
|
2546
|
+
return /* @__PURE__ */ jsx38(FocusProvider, { selectable: true, children: /* @__PURE__ */ jsxs29("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2547
|
+
/* @__PURE__ */ jsx38("box", { flexDirection: "row", gap: 1, padding: 1, flexGrow: 1, children: focusMultiSelects.map((panel, i) => /* @__PURE__ */ jsx38(
|
|
2548
|
+
FocusMultiSelectPanel,
|
|
2386
2549
|
{
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
flexGrow: 1
|
|
2550
|
+
id: panel.id,
|
|
2551
|
+
title: panel.title,
|
|
2552
|
+
items: panel.items,
|
|
2553
|
+
autoFocus: i === 0
|
|
2392
2554
|
},
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2555
|
+
panel.id
|
|
2556
|
+
)) }),
|
|
2557
|
+
/* @__PURE__ */ jsx38(FocusNavStatusBar, {})
|
|
2558
|
+
] }) });
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
// demos/focus-grid.tsx
|
|
2562
|
+
import { useFocus as useFocus2, FocusProvider as FocusProvider2, useShortcuts as useShortcuts2, useFocusedShortcuts as useFocusedShortcuts2 } from "@gridland/utils";
|
|
2563
|
+
import { jsx as jsx39, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2564
|
+
var gridItems = [
|
|
2565
|
+
{ id: "cell-1" },
|
|
2566
|
+
{ id: "cell-2" },
|
|
2567
|
+
{ id: "cell-3" },
|
|
2568
|
+
{ id: "cell-4" },
|
|
2569
|
+
{ id: "cell-5" },
|
|
2570
|
+
{ id: "cell-6" }
|
|
2571
|
+
];
|
|
2572
|
+
function GridCell({ id, autoFocus }) {
|
|
2573
|
+
const { isFocused, isSelected, isAnySelected, focusId, focusRef } = useFocus2({ id, autoFocus });
|
|
2574
|
+
useShortcuts2(
|
|
2575
|
+
isSelected ? [{ key: "esc", label: "back" }] : [{ key: "\u2191\u2193\u2190\u2192", label: "navigate" }, { key: "enter", label: "select" }, { key: "tab", label: "cycle" }],
|
|
2576
|
+
focusId
|
|
2577
|
+
);
|
|
2578
|
+
const borderStyle = isSelected ? "rounded" : isFocused ? "dashed" : "rounded";
|
|
2579
|
+
const borderColor = isSelected ? "#818cf8" : isAnySelected ? "transparent" : isFocused ? "#6366f1" : "#3b3466";
|
|
2580
|
+
const fg = isSelected ? "#a5b4fc" : isFocused ? "#a5b4fc" : "#888";
|
|
2581
|
+
return /* @__PURE__ */ jsx39("box", { ref: focusRef, border: true, borderStyle, borderColor, width: 16, height: 5, children: /* @__PURE__ */ jsx39("box", { flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: /* @__PURE__ */ jsx39("text", { style: { fg, bold: isFocused || isSelected }, children: isSelected ? "selected" : "not selected" }) }) });
|
|
2582
|
+
}
|
|
2583
|
+
function FocusGridStatusBar() {
|
|
2584
|
+
const shortcuts2 = useFocusedShortcuts2();
|
|
2585
|
+
return /* @__PURE__ */ jsx39("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx39(StatusBar, { items: shortcuts2 }) });
|
|
2586
|
+
}
|
|
2587
|
+
function FocusGridApp() {
|
|
2588
|
+
return /* @__PURE__ */ jsx39(FocusProvider2, { selectable: true, children: /* @__PURE__ */ jsxs30("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2589
|
+
/* @__PURE__ */ jsxs30("box", { flexDirection: "column", gap: 1, padding: 1, flexGrow: 1, alignItems: "center", children: [
|
|
2590
|
+
/* @__PURE__ */ jsx39("box", { flexDirection: "row", gap: 1, children: gridItems.slice(0, 3).map((item, i) => /* @__PURE__ */ jsx39(GridCell, { ...item, autoFocus: i === 0 }, item.id)) }),
|
|
2591
|
+
/* @__PURE__ */ jsx39("box", { flexDirection: "row", gap: 1, children: gridItems.slice(3, 6).map((item) => /* @__PURE__ */ jsx39(GridCell, { ...item }, item.id)) })
|
|
2592
|
+
] }),
|
|
2593
|
+
/* @__PURE__ */ jsx39(FocusGridStatusBar, {})
|
|
2594
|
+
] }) });
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
// demos/focus-chat.tsx
|
|
2598
|
+
import { useState as useState22, useRef as useRef9, useCallback as useCallback5 } from "react";
|
|
2599
|
+
import { useKeyboard as useKeyboard16, useFocus as useFocus3, FocusProvider as FocusProvider3, useShortcuts as useShortcuts3, useFocusedShortcuts as useFocusedShortcuts3 } from "@gridland/utils";
|
|
2600
|
+
import { jsx as jsx40, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2601
|
+
function CotSection() {
|
|
2602
|
+
const { isFocused, isSelected, isAnySelected, focusId, focusRef } = useFocus3({ id: "cot", autoFocus: true });
|
|
2603
|
+
const [cotOpen, setCotOpen] = useState22(false);
|
|
2604
|
+
useKeyboard16((event) => {
|
|
2605
|
+
if (event.name === "return") {
|
|
2606
|
+
setCotOpen((v) => !v);
|
|
2607
|
+
event.preventDefault();
|
|
2608
|
+
}
|
|
2609
|
+
}, { focusId, selectedOnly: true });
|
|
2610
|
+
useShortcuts3(
|
|
2611
|
+
isSelected ? [{ key: "enter", label: "expand/collapse" }, { key: "esc", label: "back" }] : [{ key: "\u2191\u2193", label: "navigate" }, { key: "tab", label: "cycle" }, { key: "enter", label: "select" }],
|
|
2612
|
+
focusId
|
|
2613
|
+
);
|
|
2614
|
+
const borderStyle = isSelected ? "rounded" : isFocused ? "dashed" : "rounded";
|
|
2615
|
+
const borderColor = isSelected ? "#818cf8" : isAnySelected ? "transparent" : isFocused ? "#6366f1" : "#3b3466";
|
|
2616
|
+
return /* @__PURE__ */ jsx40("box", { ref: focusRef, marginTop: 1, border: true, borderStyle, borderColor, children: /* @__PURE__ */ jsxs31(ChainOfThought, { open: cotOpen, onOpenChange: setCotOpen, children: [
|
|
2617
|
+
/* @__PURE__ */ jsx40(ChainOfThoughtHeader, { duration: "1.2s" }),
|
|
2618
|
+
/* @__PURE__ */ jsx40(ChainOfThoughtContent, { children: /* @__PURE__ */ jsx40(ChainOfThoughtStep, { label: "Searched docs", status: "done", isLast: true }) })
|
|
2619
|
+
] }) });
|
|
2620
|
+
}
|
|
2621
|
+
function PromptSection() {
|
|
2622
|
+
const { isFocused, isSelected, isAnySelected, focusId, focusRef } = useFocus3({ id: "prompt" });
|
|
2623
|
+
const promptHandlerRef = useRef9(null);
|
|
2624
|
+
const captureKeyboard = useCallback5((handler) => {
|
|
2625
|
+
promptHandlerRef.current = handler;
|
|
2626
|
+
}, []);
|
|
2627
|
+
useKeyboard16((event) => {
|
|
2628
|
+
promptHandlerRef.current?.(event);
|
|
2629
|
+
}, { focusId, selectedOnly: true });
|
|
2630
|
+
useShortcuts3(
|
|
2631
|
+
isSelected ? [{ key: "\u23CE", label: "send" }, { key: "esc", label: "back" }] : [{ key: "\u2191\u2193", label: "navigate" }, { key: "tab", label: "cycle" }, { key: "enter", label: "select" }],
|
|
2632
|
+
focusId
|
|
2633
|
+
);
|
|
2634
|
+
const dividerColor = isSelected ? "#818cf8" : isAnySelected ? void 0 : isFocused ? "#6366f1" : "#3b3466";
|
|
2635
|
+
const dividerDashed = isFocused && !isSelected && !isAnySelected;
|
|
2636
|
+
return /* @__PURE__ */ jsx40("box", { ref: focusRef, children: /* @__PURE__ */ jsx40(
|
|
2637
|
+
PromptInput,
|
|
2406
2638
|
{
|
|
2407
|
-
|
|
2639
|
+
placeholder: "Type a message...",
|
|
2640
|
+
status: "ready",
|
|
2641
|
+
dividerColor,
|
|
2642
|
+
dividerDashed,
|
|
2643
|
+
useKeyboard: captureKeyboard
|
|
2408
2644
|
}
|
|
2409
|
-
))
|
|
2645
|
+
) });
|
|
2646
|
+
}
|
|
2647
|
+
function FocusChatStatusBar() {
|
|
2648
|
+
const shortcuts2 = useFocusedShortcuts3();
|
|
2649
|
+
return /* @__PURE__ */ jsx40("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx40(StatusBar, { items: shortcuts2 }) });
|
|
2650
|
+
}
|
|
2651
|
+
function FocusChatApp() {
|
|
2652
|
+
return /* @__PURE__ */ jsx40(FocusProvider3, { selectable: true, children: /* @__PURE__ */ jsxs31("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2653
|
+
/* @__PURE__ */ jsxs31("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
2654
|
+
/* @__PURE__ */ jsxs31("box", { flexDirection: "column", paddingX: 1, paddingTop: 1, flexGrow: 1, children: [
|
|
2655
|
+
/* @__PURE__ */ jsx40(Message, { role: "user", children: /* @__PURE__ */ jsx40(Message.Content, { children: /* @__PURE__ */ jsx40(Message.Text, { children: "How do I set up keyboard navigation?" }) }) }),
|
|
2656
|
+
/* @__PURE__ */ jsx40(CotSection, {}),
|
|
2657
|
+
/* @__PURE__ */ jsx40(Message, { role: "assistant", children: /* @__PURE__ */ jsx40(Message.Content, { children: /* @__PURE__ */ jsx40(Message.Text, { children: "Use the useKeyboard hook to listen for key events. Wrap your app in a FocusProvider to enable tab navigation between focusable components." }) }) })
|
|
2658
|
+
] }),
|
|
2659
|
+
/* @__PURE__ */ jsx40(PromptSection, {})
|
|
2660
|
+
] }),
|
|
2661
|
+
/* @__PURE__ */ jsx40(FocusChatStatusBar, {})
|
|
2662
|
+
] }) });
|
|
2410
2663
|
}
|
|
2411
2664
|
|
|
2412
2665
|
// demos/pointer.tsx
|
|
2413
|
-
import { useState as
|
|
2414
|
-
import { useKeyboard as
|
|
2666
|
+
import { useState as useState23, useRef as useRef10 } from "react";
|
|
2667
|
+
import { useKeyboard as useKeyboard17 } from "@gridland/utils";
|
|
2668
|
+
import { jsx as jsx41, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2415
2669
|
var pointerColors = ["#ef4444", "#f97316", "#eab308", "#22c55e", "#3b82f6", "#8b5cf6"];
|
|
2416
2670
|
var pointerColorNames = ["Red", "Orange", "Yellow", "Green", "Blue", "Purple"];
|
|
2417
2671
|
function HoverBox() {
|
|
2418
|
-
const [hovering, setHovering] =
|
|
2419
|
-
return /* @__PURE__ */
|
|
2672
|
+
const [hovering, setHovering] = useState23(false);
|
|
2673
|
+
return /* @__PURE__ */ jsx41(
|
|
2420
2674
|
"box",
|
|
2421
2675
|
{
|
|
2422
2676
|
border: true,
|
|
@@ -2425,20 +2679,20 @@ function HoverBox() {
|
|
|
2425
2679
|
width: 20,
|
|
2426
2680
|
height: 5,
|
|
2427
2681
|
onMouseOver: () => setHovering(true),
|
|
2428
|
-
onMouseOut: () => setHovering(false)
|
|
2429
|
-
|
|
2430
|
-
|
|
2682
|
+
onMouseOut: () => setHovering(false),
|
|
2683
|
+
children: /* @__PURE__ */ jsx41("box", { padding: 1, children: /* @__PURE__ */ jsx41("text", { style: { fg: hovering ? "#22c55e" : "#888", bold: hovering }, children: hovering ? "Mouse inside!" : "Hover me" }) })
|
|
2684
|
+
}
|
|
2431
2685
|
);
|
|
2432
2686
|
}
|
|
2433
2687
|
function PointerApp() {
|
|
2434
|
-
const [selected, setSelected] =
|
|
2435
|
-
const [clickCount, setClickCount] =
|
|
2436
|
-
const [mousePos, setMousePos] =
|
|
2437
|
-
const selectedRef =
|
|
2438
|
-
const clickCountRef =
|
|
2688
|
+
const [selected, setSelected] = useState23(null);
|
|
2689
|
+
const [clickCount, setClickCount] = useState23(0);
|
|
2690
|
+
const [mousePos, setMousePos] = useState23(null);
|
|
2691
|
+
const selectedRef = useRef10(null);
|
|
2692
|
+
const clickCountRef = useRef10(0);
|
|
2439
2693
|
selectedRef.current = selected;
|
|
2440
2694
|
clickCountRef.current = clickCount;
|
|
2441
|
-
|
|
2695
|
+
useKeyboard17((event) => {
|
|
2442
2696
|
const cur = selectedRef.current ?? -1;
|
|
2443
2697
|
if (event.name === "right" || event.name === "tab") {
|
|
2444
2698
|
const next = (cur + 1) % pointerColors.length;
|
|
@@ -2451,79 +2705,192 @@ function PointerApp() {
|
|
|
2451
2705
|
}
|
|
2452
2706
|
event.preventDefault();
|
|
2453
2707
|
});
|
|
2454
|
-
return /* @__PURE__ */
|
|
2455
|
-
"box",
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2708
|
+
return /* @__PURE__ */ jsxs32("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
2709
|
+
/* @__PURE__ */ jsx41("box", { flexDirection: "row", gap: 1, children: pointerColors.map((color, i) => /* @__PURE__ */ jsx41(
|
|
2710
|
+
"box",
|
|
2711
|
+
{
|
|
2712
|
+
flexGrow: 1,
|
|
2713
|
+
height: 3,
|
|
2714
|
+
border: true,
|
|
2715
|
+
borderStyle: "rounded",
|
|
2716
|
+
borderColor: i === selected ? color : "#555",
|
|
2717
|
+
onMouseDown: (e) => {
|
|
2718
|
+
clickCountRef.current++;
|
|
2719
|
+
setClickCount(clickCountRef.current);
|
|
2720
|
+
selectedRef.current = i;
|
|
2721
|
+
setSelected(i);
|
|
2722
|
+
setMousePos({ x: e.x, y: e.y });
|
|
2723
|
+
},
|
|
2724
|
+
children: /* @__PURE__ */ jsx41("text", { style: { fg: color, bold: i === selected }, children: i === selected ? `\u25B8 ${pointerColorNames[i]}` : ` ${pointerColorNames[i]}` })
|
|
2725
|
+
},
|
|
2726
|
+
color
|
|
2727
|
+
)) }),
|
|
2728
|
+
/* @__PURE__ */ jsx41("box", { height: 1 }),
|
|
2729
|
+
/* @__PURE__ */ jsxs32("box", { flexDirection: "row", gap: 2, children: [
|
|
2730
|
+
/* @__PURE__ */ jsx41(HoverBox, {}),
|
|
2731
|
+
/* @__PURE__ */ jsxs32("box", { flexDirection: "column", flexGrow: 1, paddingTop: 1, children: [
|
|
2732
|
+
/* @__PURE__ */ jsxs32("text", { style: { fg: selected !== null ? pointerColors[selected] : "#888" }, children: [
|
|
2733
|
+
selected !== null ? `Clicked ${pointerColorNames[selected]}` : "Click a color",
|
|
2734
|
+
clickCount > 0 ? ` (${clickCount} clicks)` : ""
|
|
2735
|
+
] }),
|
|
2736
|
+
/* @__PURE__ */ jsx41("text", { style: { dim: true, fg: "#888" }, children: mousePos ? `mouse: ${mousePos.x}, ${mousePos.y}` : "" })
|
|
2737
|
+
] })
|
|
2738
|
+
] }),
|
|
2739
|
+
/* @__PURE__ */ jsx41("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx41(StatusBar, { items: [
|
|
2740
|
+
{ key: "click", label: "select" },
|
|
2741
|
+
{ key: "\u2190\u2192", label: "keyboard nav" }
|
|
2742
|
+
] }) })
|
|
2743
|
+
] });
|
|
2476
2744
|
}
|
|
2477
2745
|
|
|
2478
2746
|
// demos/cursor-highlight.tsx
|
|
2479
|
-
import { useState as
|
|
2747
|
+
import { useState as useState24 } from "react";
|
|
2748
|
+
import { jsx as jsx42, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2480
2749
|
function CursorHighlightApp() {
|
|
2481
|
-
const [pos, setPos] =
|
|
2482
|
-
return /* @__PURE__ */
|
|
2750
|
+
const [pos, setPos] = useState24(null);
|
|
2751
|
+
return /* @__PURE__ */ jsxs33(
|
|
2483
2752
|
"box",
|
|
2484
2753
|
{
|
|
2485
2754
|
flexDirection: "column",
|
|
2486
2755
|
flexGrow: 1,
|
|
2487
2756
|
onMouseMove: (e) => {
|
|
2488
2757
|
setPos({ x: e.x, y: e.y });
|
|
2489
|
-
}
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2758
|
+
},
|
|
2759
|
+
children: [
|
|
2760
|
+
/* @__PURE__ */ jsxs33("box", { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
2761
|
+
/* @__PURE__ */ jsx42("text", { style: { bold: true, fg: "#fff" }, children: "Cursor Highlight" }),
|
|
2762
|
+
/* @__PURE__ */ jsx42("text", { style: { dim: true, fg: "#888" }, children: "Move your mouse over the grid" }),
|
|
2763
|
+
/* @__PURE__ */ jsx42("box", { height: 1 }),
|
|
2764
|
+
/* @__PURE__ */ jsx42("box", { flexDirection: "column", children: Array.from({ length: 6 }, (_, row) => /* @__PURE__ */ jsx42("text", { children: Array.from({ length: 40 }, (_2, col) => {
|
|
2765
|
+
const isEven = (row + col) % 2 === 0;
|
|
2766
|
+
return /* @__PURE__ */ jsx42("span", { style: {
|
|
2767
|
+
fg: isEven ? "#3b82f6" : "#8b5cf6",
|
|
2768
|
+
dim: !isEven
|
|
2769
|
+
}, children: isEven ? "\u2591\u2591" : "\u2593\u2593" }, col);
|
|
2770
|
+
}) }, row)) })
|
|
2771
|
+
] }),
|
|
2772
|
+
/* @__PURE__ */ jsx42("box", { paddingX: 1, paddingBottom: 1, children: /* @__PURE__ */ jsx42(
|
|
2773
|
+
StatusBar,
|
|
2774
|
+
{
|
|
2775
|
+
items: [],
|
|
2776
|
+
extra: /* @__PURE__ */ jsxs33("span", { children: [
|
|
2777
|
+
/* @__PURE__ */ jsx42("span", { style: textStyle({ bold: true, fg: "#1e1e2e", bg: "#888" }), children: " x " }),
|
|
2778
|
+
/* @__PURE__ */ jsx42("span", { style: textStyle({ dim: true, fg: "#888" }), children: ` ${pos ? String(pos.x).padStart(3) : " -"} ` }),
|
|
2779
|
+
/* @__PURE__ */ jsx42("span", { style: textStyle({ bold: true, fg: "#1e1e2e", bg: "#888" }), children: " y " }),
|
|
2780
|
+
/* @__PURE__ */ jsx42("span", { style: textStyle({ dim: true, fg: "#888" }), children: ` ${pos ? String(pos.y).padStart(3) : " -"}` })
|
|
2781
|
+
] })
|
|
2782
|
+
}
|
|
2783
|
+
) })
|
|
2784
|
+
]
|
|
2785
|
+
}
|
|
2505
2786
|
);
|
|
2506
2787
|
}
|
|
2507
2788
|
|
|
2508
2789
|
// demos/text-style.tsx
|
|
2790
|
+
import { jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2509
2791
|
function TextStyleApp() {
|
|
2510
2792
|
const theme = useTheme();
|
|
2511
2793
|
const desc = textStyle({ fg: theme.muted });
|
|
2512
|
-
return /* @__PURE__ */
|
|
2794
|
+
return /* @__PURE__ */ jsxs34("box", { flexDirection: "column", padding: 1, gap: 0, children: [
|
|
2795
|
+
/* @__PURE__ */ jsxs34("text", { children: [
|
|
2796
|
+
/* @__PURE__ */ jsx43("span", { style: textStyle({ fg: theme.foreground, bold: true }), children: "bold " }),
|
|
2797
|
+
/* @__PURE__ */ jsxs34("span", { style: desc, children: [
|
|
2798
|
+
"textStyle(",
|
|
2799
|
+
"{",
|
|
2800
|
+
" bold: true ",
|
|
2801
|
+
"}",
|
|
2802
|
+
")"
|
|
2803
|
+
] })
|
|
2804
|
+
] }),
|
|
2805
|
+
/* @__PURE__ */ jsxs34("text", { children: [
|
|
2806
|
+
/* @__PURE__ */ jsx43("span", { style: textStyle({ fg: theme.foreground, dim: true }), children: "dim " }),
|
|
2807
|
+
/* @__PURE__ */ jsxs34("span", { style: desc, children: [
|
|
2808
|
+
"textStyle(",
|
|
2809
|
+
"{",
|
|
2810
|
+
" dim: true ",
|
|
2811
|
+
"}",
|
|
2812
|
+
")"
|
|
2813
|
+
] })
|
|
2814
|
+
] }),
|
|
2815
|
+
/* @__PURE__ */ jsxs34("text", { children: [
|
|
2816
|
+
/* @__PURE__ */ jsx43("span", { style: textStyle({ fg: theme.foreground, italic: true }), children: "italic " }),
|
|
2817
|
+
/* @__PURE__ */ jsxs34("span", { style: desc, children: [
|
|
2818
|
+
"textStyle(",
|
|
2819
|
+
"{",
|
|
2820
|
+
" italic: true ",
|
|
2821
|
+
"}",
|
|
2822
|
+
")"
|
|
2823
|
+
] })
|
|
2824
|
+
] }),
|
|
2825
|
+
/* @__PURE__ */ jsxs34("text", { children: [
|
|
2826
|
+
/* @__PURE__ */ jsx43("span", { style: textStyle({ fg: theme.foreground, underline: true }), children: "underline " }),
|
|
2827
|
+
/* @__PURE__ */ jsxs34("span", { style: desc, children: [
|
|
2828
|
+
"textStyle(",
|
|
2829
|
+
"{",
|
|
2830
|
+
" underline: true ",
|
|
2831
|
+
"}",
|
|
2832
|
+
")"
|
|
2833
|
+
] })
|
|
2834
|
+
] }),
|
|
2835
|
+
/* @__PURE__ */ jsxs34("text", { children: [
|
|
2836
|
+
/* @__PURE__ */ jsx43("span", { style: textStyle({ inverse: true }), children: "inverse " }),
|
|
2837
|
+
/* @__PURE__ */ jsxs34("span", { style: desc, children: [
|
|
2838
|
+
"textStyle(",
|
|
2839
|
+
"{",
|
|
2840
|
+
" inverse: true ",
|
|
2841
|
+
"}",
|
|
2842
|
+
")"
|
|
2843
|
+
] })
|
|
2844
|
+
] }),
|
|
2845
|
+
/* @__PURE__ */ jsx43("text", { children: " " }),
|
|
2846
|
+
/* @__PURE__ */ jsxs34("text", { children: [
|
|
2847
|
+
/* @__PURE__ */ jsx43("span", { style: textStyle({ fg: theme.primary }), children: "fg color " }),
|
|
2848
|
+
/* @__PURE__ */ jsxs34("span", { style: desc, children: [
|
|
2849
|
+
"textStyle(",
|
|
2850
|
+
"{",
|
|
2851
|
+
" fg: theme.primary ",
|
|
2852
|
+
"}",
|
|
2853
|
+
")"
|
|
2854
|
+
] })
|
|
2855
|
+
] }),
|
|
2856
|
+
/* @__PURE__ */ jsxs34("text", { children: [
|
|
2857
|
+
/* @__PURE__ */ jsx43("span", { style: textStyle({ fg: theme.foreground, bg: theme.secondary }), children: "bg color " }),
|
|
2858
|
+
/* @__PURE__ */ jsxs34("span", { style: desc, children: [
|
|
2859
|
+
"textStyle(",
|
|
2860
|
+
"{",
|
|
2861
|
+
" fg: theme.foreground, bg: theme.secondary ",
|
|
2862
|
+
"}",
|
|
2863
|
+
")"
|
|
2864
|
+
] })
|
|
2865
|
+
] }),
|
|
2866
|
+
/* @__PURE__ */ jsx43("text", { children: " " }),
|
|
2867
|
+
/* @__PURE__ */ jsxs34("text", { children: [
|
|
2868
|
+
/* @__PURE__ */ jsx43("span", { style: textStyle({ fg: theme.accent, bold: true, underline: true }), children: "combined " }),
|
|
2869
|
+
/* @__PURE__ */ jsxs34("span", { style: desc, children: [
|
|
2870
|
+
"textStyle(",
|
|
2871
|
+
"{",
|
|
2872
|
+
" fg: theme.accent, bold: true, underline: true ",
|
|
2873
|
+
"}",
|
|
2874
|
+
")"
|
|
2875
|
+
] })
|
|
2876
|
+
] })
|
|
2877
|
+
] });
|
|
2513
2878
|
}
|
|
2514
2879
|
|
|
2515
2880
|
// demos/headless.tsx
|
|
2881
|
+
import { jsx as jsx44 } from "react/jsx-runtime";
|
|
2516
2882
|
var data = [
|
|
2517
2883
|
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
2518
2884
|
{ name: "Bob", role: "Designer", status: "Active" },
|
|
2519
2885
|
{ name: "Charlie", role: "PM", status: "Away" }
|
|
2520
2886
|
];
|
|
2521
2887
|
function HeadlessApp() {
|
|
2522
|
-
return /* @__PURE__ */
|
|
2888
|
+
return /* @__PURE__ */ jsx44("box", { padding: 1, children: /* @__PURE__ */ jsx44(Table, { data }) });
|
|
2523
2889
|
}
|
|
2524
2890
|
|
|
2525
2891
|
// demos/theming.tsx
|
|
2526
|
-
import { useKeyboard as
|
|
2892
|
+
import { useKeyboard as useKeyboard18 } from "@gridland/utils";
|
|
2893
|
+
import { jsx as jsx45, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2527
2894
|
var tableData = [
|
|
2528
2895
|
{ name: "Alice", role: "Engineer", status: "Active" },
|
|
2529
2896
|
{ name: "Bob", role: "Designer", status: "Away" }
|
|
@@ -2534,16 +2901,21 @@ var selectItems = [
|
|
|
2534
2901
|
{ label: "Python", value: "py" }
|
|
2535
2902
|
];
|
|
2536
2903
|
function ThemingApp() {
|
|
2537
|
-
return /* @__PURE__ */
|
|
2904
|
+
return /* @__PURE__ */ jsxs35("box", { flexDirection: "column", padding: 1, gap: 1, flexGrow: 1, children: [
|
|
2905
|
+
/* @__PURE__ */ jsx45(Spinner, { text: "Loading data..." }),
|
|
2906
|
+
/* @__PURE__ */ jsx45(Table, { data: tableData }),
|
|
2907
|
+
/* @__PURE__ */ jsx45(MultiSelect, { items: selectItems, useKeyboard: useKeyboard18 })
|
|
2908
|
+
] });
|
|
2538
2909
|
}
|
|
2539
2910
|
|
|
2540
2911
|
// src/landing/landing-app.tsx
|
|
2541
|
-
import { useMemo as
|
|
2912
|
+
import { useMemo as useMemo8, useRef as useRef15, useState as useState29 } from "react";
|
|
2542
2913
|
|
|
2543
2914
|
// src/landing/install-box.tsx
|
|
2915
|
+
import { jsx as jsx46, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2544
2916
|
function InstallBox() {
|
|
2545
2917
|
const theme = useTheme();
|
|
2546
|
-
return /* @__PURE__ */
|
|
2918
|
+
return /* @__PURE__ */ jsx46(
|
|
2547
2919
|
"box",
|
|
2548
2920
|
{
|
|
2549
2921
|
border: true,
|
|
@@ -2551,17 +2923,24 @@ function InstallBox() {
|
|
|
2551
2923
|
borderColor: theme.border,
|
|
2552
2924
|
paddingX: 1,
|
|
2553
2925
|
flexDirection: "column",
|
|
2554
|
-
flexShrink: 0
|
|
2555
|
-
|
|
2556
|
-
|
|
2926
|
+
flexShrink: 0,
|
|
2927
|
+
children: /* @__PURE__ */ jsxs36("text", { children: [
|
|
2928
|
+
/* @__PURE__ */ jsx46("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
2929
|
+
/* @__PURE__ */ jsx46("span", { style: textStyle({ bold: true }), children: "bun create " }),
|
|
2930
|
+
/* @__PURE__ */ jsx46("span", { style: textStyle({ fg: theme.accent }), children: "gridland" })
|
|
2931
|
+
] })
|
|
2932
|
+
}
|
|
2557
2933
|
);
|
|
2558
2934
|
}
|
|
2559
2935
|
|
|
2560
2936
|
// src/landing/links-box.tsx
|
|
2937
|
+
import { isBrowser } from "@gridland/utils";
|
|
2938
|
+
import { jsx as jsx47, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
2561
2939
|
var UNDERLINE3 = 1 << 3;
|
|
2562
2940
|
function LinksBox() {
|
|
2563
2941
|
const theme = useTheme();
|
|
2564
|
-
|
|
2942
|
+
const docsHref = isBrowser() ? `${window.location.origin}/docs` : "https://gridland.io/docs";
|
|
2943
|
+
return /* @__PURE__ */ jsx47(
|
|
2565
2944
|
"box",
|
|
2566
2945
|
{
|
|
2567
2946
|
border: true,
|
|
@@ -2569,30 +2948,37 @@ function LinksBox() {
|
|
|
2569
2948
|
borderColor: theme.border,
|
|
2570
2949
|
paddingX: 1,
|
|
2571
2950
|
flexDirection: "column",
|
|
2572
|
-
flexShrink: 0
|
|
2573
|
-
|
|
2574
|
-
|
|
2951
|
+
flexShrink: 0,
|
|
2952
|
+
children: /* @__PURE__ */ jsxs37("text", { children: [
|
|
2953
|
+
/* @__PURE__ */ jsx47("span", { children: "\u{1F431}" }),
|
|
2954
|
+
/* @__PURE__ */ jsx47("a", { href: "https://github.com/thoughtfulllc/gridland", style: { attributes: UNDERLINE3, fg: theme.accent }, children: " GitHub" }),
|
|
2955
|
+
/* @__PURE__ */ jsx47("span", { children: " " }),
|
|
2956
|
+
/* @__PURE__ */ jsx47("span", { children: "\u{1F4D6}" }),
|
|
2957
|
+
/* @__PURE__ */ jsx47("a", { href: docsHref, style: { attributes: UNDERLINE3, fg: theme.accent }, children: " Docs" })
|
|
2958
|
+
] })
|
|
2959
|
+
}
|
|
2575
2960
|
);
|
|
2576
2961
|
}
|
|
2577
2962
|
|
|
2578
2963
|
// src/landing/logo.tsx
|
|
2579
|
-
import { useState as
|
|
2964
|
+
import { useState as useState25, useEffect as useEffect6, useRef as useRef11, useMemo as useMemo5 } from "react";
|
|
2580
2965
|
import figlet3 from "figlet";
|
|
2581
|
-
import
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
}
|
|
2586
|
-
|
|
2587
|
-
var
|
|
2588
|
-
var
|
|
2589
|
-
var
|
|
2966
|
+
import blockFont from "figlet/importable-fonts/Block.js";
|
|
2967
|
+
import { Fragment as Fragment6, jsx as jsx48, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
2968
|
+
figlet3.parseFont("Block", blockFont);
|
|
2969
|
+
function makeArt(text, font = "Block") {
|
|
2970
|
+
return figlet3.textSync(text, { font }).split("\n").filter((l) => l.trimEnd().length > 0).join("\n");
|
|
2971
|
+
}
|
|
2972
|
+
var fullArt = makeArt("gridland", "Block");
|
|
2973
|
+
var gridArt = makeArt("grid", "Block");
|
|
2974
|
+
var landArt = makeArt("land", "Block");
|
|
2975
|
+
var ART_HEIGHT = fullArt.split("\n").length;
|
|
2590
2976
|
function useAnimation(duration = 1e3) {
|
|
2591
|
-
const
|
|
2592
|
-
const [progress, setProgress] =
|
|
2593
|
-
const startTime =
|
|
2977
|
+
const isBrowser2 = typeof document !== "undefined";
|
|
2978
|
+
const [progress, setProgress] = useState25(isBrowser2 ? 0 : 1);
|
|
2979
|
+
const startTime = useRef11(null);
|
|
2594
2980
|
useEffect6(() => {
|
|
2595
|
-
if (!
|
|
2981
|
+
if (!isBrowser2) return;
|
|
2596
2982
|
let raf;
|
|
2597
2983
|
const tick = (time) => {
|
|
2598
2984
|
if (startTime.current === null) startTime.current = time;
|
|
@@ -2607,13 +2993,20 @@ function useAnimation(duration = 1e3) {
|
|
|
2607
2993
|
}, []);
|
|
2608
2994
|
return progress;
|
|
2609
2995
|
}
|
|
2996
|
+
function darkenHex(hex, factor = 0.4) {
|
|
2997
|
+
const r = Math.round(parseInt(hex.slice(1, 3), 16) * factor);
|
|
2998
|
+
const g = Math.round(parseInt(hex.slice(3, 5), 16) * factor);
|
|
2999
|
+
const b = Math.round(parseInt(hex.slice(5, 7), 16) * factor);
|
|
3000
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
3001
|
+
}
|
|
2610
3002
|
function RevealGradient({ children, revealCol }) {
|
|
2611
3003
|
const gradientColors = GRADIENTS.instagram;
|
|
2612
3004
|
const lines2 = children.split("\n");
|
|
2613
3005
|
const maxLength = Math.max(...lines2.map((l) => l.length));
|
|
2614
|
-
if (maxLength === 0) return /* @__PURE__ */
|
|
3006
|
+
if (maxLength === 0) return /* @__PURE__ */ jsx48("text", { children });
|
|
2615
3007
|
const hexColors = useMemo5(() => generateGradient(gradientColors, maxLength), [maxLength]);
|
|
2616
|
-
|
|
3008
|
+
const bgColors = useMemo5(() => hexColors.map((c) => darkenHex(c)), [hexColors]);
|
|
3009
|
+
return /* @__PURE__ */ jsx48("box", { position: "relative", width: maxLength, height: lines2.length, shouldFill: false, children: lines2.map((line, lineIndex) => {
|
|
2617
3010
|
const runs = [];
|
|
2618
3011
|
let current = null;
|
|
2619
3012
|
for (let i = 0; i < line.length; i++) {
|
|
@@ -2633,54 +3026,81 @@ function RevealGradient({ children, revealCol }) {
|
|
|
2633
3026
|
}
|
|
2634
3027
|
}
|
|
2635
3028
|
if (current) runs.push(current);
|
|
2636
|
-
return runs.map((run, runIndex) => /* @__PURE__ */
|
|
3029
|
+
return runs.map((run, runIndex) => /* @__PURE__ */ jsx48(
|
|
2637
3030
|
"box",
|
|
2638
3031
|
{
|
|
2639
|
-
key: `${lineIndex}-${runIndex}`,
|
|
2640
3032
|
position: "absolute",
|
|
2641
3033
|
top: lineIndex,
|
|
2642
3034
|
left: run.start,
|
|
2643
|
-
shouldFill: false
|
|
3035
|
+
shouldFill: false,
|
|
3036
|
+
children: /* @__PURE__ */ jsx48("text", { shouldFill: false, children: run.chars.map((char, ci) => /* @__PURE__ */ jsx48(
|
|
3037
|
+
"span",
|
|
3038
|
+
{
|
|
3039
|
+
style: { fg: hexColors[run.start + ci], bg: bgColors[run.start + ci] },
|
|
3040
|
+
children: char
|
|
3041
|
+
},
|
|
3042
|
+
ci
|
|
3043
|
+
)) })
|
|
2644
3044
|
},
|
|
2645
|
-
|
|
2646
|
-
"span",
|
|
2647
|
-
{
|
|
2648
|
-
key: ci,
|
|
2649
|
-
style: { fg: hexColors[run.start + ci] }
|
|
2650
|
-
},
|
|
2651
|
-
char
|
|
2652
|
-
)))
|
|
3045
|
+
`${lineIndex}-${runIndex}`
|
|
2653
3046
|
));
|
|
2654
|
-
}));
|
|
3047
|
+
}) });
|
|
2655
3048
|
}
|
|
2656
3049
|
function Logo({ compact, narrow, mobile }) {
|
|
2657
|
-
const
|
|
3050
|
+
const isBrowser2 = typeof document !== "undefined";
|
|
2658
3051
|
const progress = useAnimation(900);
|
|
2659
|
-
const artHeight = compact ? 1 : narrow ? ART_HEIGHT * 2 : ART_HEIGHT;
|
|
3052
|
+
const artHeight = compact ? 1 : narrow && !mobile ? ART_HEIGHT * 2 : ART_HEIGHT;
|
|
2660
3053
|
const dropOffset = Math.round((1 - progress) * -artHeight);
|
|
2661
3054
|
const revealProgress = Math.max(0, Math.min(1, (progress - 0.1) / 0.7));
|
|
2662
|
-
const maxWidth = compact ? 8 : narrow ?
|
|
3055
|
+
const maxWidth = compact ? 8 : narrow ? 35 : 69;
|
|
2663
3056
|
const revealCol = Math.round(revealProgress * (maxWidth + 4)) - 2;
|
|
2664
3057
|
const taglineOpacity = Math.max(0, Math.min(1, (progress - 0.7) / 0.3));
|
|
2665
|
-
const subtitle = /* @__PURE__ */
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
3058
|
+
const subtitle = /* @__PURE__ */ jsxs38(Fragment6, { children: [
|
|
3059
|
+
/* @__PURE__ */ jsx48("text", { children: " " }),
|
|
3060
|
+
/* @__PURE__ */ jsx48("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs38("text", { style: textStyle({ fg: "#d4b0e8" }), opacity: taglineOpacity, wrapMode: "word", textAlign: "center", width: "100%", shouldFill: false, children: [
|
|
3061
|
+
"A framework for building terminal apps, built on ",
|
|
3062
|
+
/* @__PURE__ */ jsx48("a", { href: "https://opentui.com", style: { attributes: 72, fg: "#d4b0e8" }, children: "OpenTUI" }),
|
|
3063
|
+
" + React." + (mobile ? " " : "\n") + "(Gridland apps, like this website, work in the browser and terminal.)"
|
|
3064
|
+
] }) })
|
|
3065
|
+
] });
|
|
3066
|
+
if (!isBrowser2) {
|
|
3067
|
+
const art2 = compact ? "gridland" : narrow && !mobile ? gridArt + "\n" + landArt : fullArt;
|
|
3068
|
+
return /* @__PURE__ */ jsxs38("box", { flexDirection: "column", flexShrink: 0, width: "100%", alignItems: "center", shouldFill: false, children: [
|
|
3069
|
+
/* @__PURE__ */ jsx48(Gradient, { name: "instagram", children: art2 }),
|
|
3070
|
+
/* @__PURE__ */ jsx48("text", { children: " " }),
|
|
3071
|
+
/* @__PURE__ */ jsx48("box", { flexDirection: "column", alignItems: "center", width: "100%", shouldFill: false, children: /* @__PURE__ */ jsxs38("text", { style: textStyle({ fg: "#d4b0e8" }), shouldFill: false, children: [
|
|
3072
|
+
"A framework for building terminal apps, built on OpenTUI + React.",
|
|
3073
|
+
"\n",
|
|
3074
|
+
"(Gridland apps, like this website, work in the browser and terminal.)"
|
|
3075
|
+
] }) })
|
|
3076
|
+
] });
|
|
2669
3077
|
}
|
|
2670
3078
|
if (compact) {
|
|
2671
|
-
return /* @__PURE__ */
|
|
3079
|
+
return /* @__PURE__ */ jsxs38("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
3080
|
+
/* @__PURE__ */ jsx48("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx48("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: /* @__PURE__ */ jsx48(RevealGradient, { revealCol, children: "gridland" }) }) }),
|
|
3081
|
+
subtitle
|
|
3082
|
+
] });
|
|
2672
3083
|
}
|
|
2673
|
-
if (narrow) {
|
|
2674
|
-
return /* @__PURE__ */
|
|
3084
|
+
if (narrow && !mobile) {
|
|
3085
|
+
return /* @__PURE__ */ jsxs38("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
3086
|
+
/* @__PURE__ */ jsx48("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsxs38("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: [
|
|
3087
|
+
/* @__PURE__ */ jsx48(RevealGradient, { revealCol, children: gridArt }),
|
|
3088
|
+
/* @__PURE__ */ jsx48(RevealGradient, { revealCol, children: landArt })
|
|
3089
|
+
] }) }),
|
|
3090
|
+
subtitle
|
|
3091
|
+
] });
|
|
2675
3092
|
}
|
|
2676
|
-
return /* @__PURE__ */
|
|
3093
|
+
return /* @__PURE__ */ jsxs38("box", { flexDirection: "column", flexShrink: 0, width: "100%", shouldFill: false, children: [
|
|
3094
|
+
/* @__PURE__ */ jsx48("box", { height: artHeight, overflow: "hidden", position: "relative", width: "100%", flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx48("box", { position: "absolute", top: dropOffset, width: "100%", flexDirection: "column", alignItems: "center", shouldFill: false, children: /* @__PURE__ */ jsx48(RevealGradient, { revealCol, children: fullArt }) }) }),
|
|
3095
|
+
subtitle
|
|
3096
|
+
] });
|
|
2677
3097
|
}
|
|
2678
3098
|
|
|
2679
3099
|
// src/landing/matrix-background.tsx
|
|
2680
3100
|
import { useMemo as useMemo6 } from "react";
|
|
2681
3101
|
|
|
2682
3102
|
// src/landing/use-matrix.ts
|
|
2683
|
-
import { useState as
|
|
3103
|
+
import { useState as useState26, useEffect as useEffect7, useLayoutEffect, useRef as useRef12 } from "react";
|
|
2684
3104
|
var CHARS = "abcdefghijklmnopqrstuvwxyz0123456789@#$%^&*(){}[]|;:<>,.?/~`";
|
|
2685
3105
|
function randomChar() {
|
|
2686
3106
|
return CHARS[Math.floor(Math.random() * CHARS.length)];
|
|
@@ -2694,7 +3114,11 @@ function createDrop(height, seeded = false) {
|
|
|
2694
3114
|
chars: Array.from({ length }, randomChar)
|
|
2695
3115
|
};
|
|
2696
3116
|
}
|
|
2697
|
-
|
|
3117
|
+
var PULL_RADIUS = 18;
|
|
3118
|
+
var PULL_STRENGTH = 7;
|
|
3119
|
+
var RIPPLE_DURATION_MS = 3200;
|
|
3120
|
+
var RIPPLE_SPEED = 8e-3;
|
|
3121
|
+
function buildGrid(columns, width, height, mousePos, ripples, now = Date.now()) {
|
|
2698
3122
|
const grid = Array.from({ length: height }, () => Array(width).fill(" "));
|
|
2699
3123
|
const brightness = Array.from({ length: height }, () => Array(width).fill(0));
|
|
2700
3124
|
for (let x = 0; x < width; x++) {
|
|
@@ -2703,30 +3127,67 @@ function buildGrid(columns, width, height) {
|
|
|
2703
3127
|
for (let i = 0; i < drop.length; i++) {
|
|
2704
3128
|
const row = Math.floor(drop.y) - i;
|
|
2705
3129
|
if (row < 0 || row >= height) continue;
|
|
2706
|
-
|
|
2707
|
-
if (
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
3130
|
+
let renderX = x;
|
|
3131
|
+
if (mousePos) {
|
|
3132
|
+
const dx = mousePos.x - x;
|
|
3133
|
+
const dy = mousePos.y - row;
|
|
3134
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
3135
|
+
if (dist < PULL_RADIUS && dist > 0.5) {
|
|
3136
|
+
const t = 1 - dist / PULL_RADIUS;
|
|
3137
|
+
const strength = t * t * PULL_STRENGTH;
|
|
3138
|
+
renderX = Math.round(x + dx / dist * strength);
|
|
3139
|
+
renderX = Math.max(0, Math.min(width - 1, renderX));
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
3142
|
+
const b = i === 0 ? 1 : Math.max(0.15, 1 - i / drop.length);
|
|
3143
|
+
if (brightness[row][renderX] < b) {
|
|
3144
|
+
grid[row][renderX] = drop.chars[i];
|
|
3145
|
+
brightness[row][renderX] = b;
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
for (const ripple of ripples) {
|
|
3150
|
+
const elapsed = now - ripple.createdAt;
|
|
3151
|
+
if (elapsed > RIPPLE_DURATION_MS || elapsed < 0) continue;
|
|
3152
|
+
const radius = elapsed * RIPPLE_SPEED;
|
|
3153
|
+
const fade = 1 - elapsed / RIPPLE_DURATION_MS;
|
|
3154
|
+
const maxR = Math.ceil(radius) + 2;
|
|
3155
|
+
const rx = Math.round(ripple.x);
|
|
3156
|
+
const ry = Math.round(ripple.y);
|
|
3157
|
+
for (let dy = -maxR; dy <= maxR; dy++) {
|
|
3158
|
+
for (let dx = -maxR; dx <= maxR; dx++) {
|
|
3159
|
+
const cy = ry + dy;
|
|
3160
|
+
const cx = rx + dx;
|
|
3161
|
+
if (cy < 0 || cy >= height || cx < 0 || cx >= width) continue;
|
|
3162
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
3163
|
+
const ringDist = Math.abs(dist - radius);
|
|
3164
|
+
if (ringDist < 2) {
|
|
3165
|
+
const boost = (1 - ringDist / 2) * fade * 0.7;
|
|
3166
|
+
brightness[cy][cx] = Math.min(1, brightness[cy][cx] + boost);
|
|
3167
|
+
if (grid[cy][cx] === " " && boost > 0.2) {
|
|
3168
|
+
grid[cy][cx] = randomChar();
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
2711
3171
|
}
|
|
2712
3172
|
}
|
|
2713
3173
|
}
|
|
2714
3174
|
return { grid, brightness };
|
|
2715
3175
|
}
|
|
2716
|
-
function useMatrix(width, height) {
|
|
2717
|
-
const columnsRef =
|
|
2718
|
-
const [state, setState] =
|
|
3176
|
+
function useMatrix(width, height, mousePosRef, ripplesRef) {
|
|
3177
|
+
const columnsRef = useRef12([]);
|
|
3178
|
+
const [state, setState] = useState26(() => {
|
|
2719
3179
|
const columns = Array.from(
|
|
2720
3180
|
{ length: width },
|
|
2721
3181
|
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
2722
3182
|
);
|
|
2723
3183
|
columnsRef.current = columns;
|
|
2724
|
-
return buildGrid(columns, width, height);
|
|
3184
|
+
return buildGrid(columns, width, height, null, []);
|
|
2725
3185
|
});
|
|
2726
3186
|
useEffect7(() => {
|
|
2727
3187
|
if (width < 2 || height < 2) return;
|
|
2728
3188
|
const id = setInterval(() => {
|
|
2729
3189
|
const columns = columnsRef.current;
|
|
3190
|
+
const now = Date.now();
|
|
2730
3191
|
for (let x = 0; x < width; x++) {
|
|
2731
3192
|
if (columns[x] === null || columns[x] === void 0) {
|
|
2732
3193
|
if (Math.random() < 0.03) {
|
|
@@ -2744,21 +3205,29 @@ function useMatrix(width, height) {
|
|
|
2744
3205
|
columns[x] = null;
|
|
2745
3206
|
}
|
|
2746
3207
|
}
|
|
2747
|
-
|
|
3208
|
+
if (ripplesRef?.current) {
|
|
3209
|
+
ripplesRef.current = ripplesRef.current.filter(
|
|
3210
|
+
(r) => now - r.createdAt < RIPPLE_DURATION_MS
|
|
3211
|
+
);
|
|
3212
|
+
}
|
|
3213
|
+
const mousePos = mousePosRef?.current ?? null;
|
|
3214
|
+
const ripples = ripplesRef?.current ?? [];
|
|
3215
|
+
setState(buildGrid(columns, width, height, mousePos, ripples, now));
|
|
2748
3216
|
}, 80);
|
|
2749
3217
|
return () => clearInterval(id);
|
|
2750
3218
|
}, [width, height]);
|
|
2751
|
-
|
|
3219
|
+
useLayoutEffect(() => {
|
|
2752
3220
|
columnsRef.current = Array.from(
|
|
2753
3221
|
{ length: width },
|
|
2754
3222
|
() => Math.random() < 0.5 ? createDrop(height, true) : null
|
|
2755
3223
|
);
|
|
2756
|
-
setState(buildGrid(columnsRef.current, width, height));
|
|
3224
|
+
setState(buildGrid(columnsRef.current, width, height, null, []));
|
|
2757
3225
|
}, [width, height]);
|
|
2758
3226
|
return state;
|
|
2759
3227
|
}
|
|
2760
3228
|
|
|
2761
3229
|
// src/landing/matrix-background.tsx
|
|
3230
|
+
import { jsx as jsx49 } from "react/jsx-runtime";
|
|
2762
3231
|
var MUTE_LEVELS = [0.12, 0.18, 0.24, 0.3, 0.38];
|
|
2763
3232
|
var BG = hexToRgb("#1a1a2e");
|
|
2764
3233
|
function buildMutedColors(baseHex) {
|
|
@@ -2774,8 +3243,8 @@ function colorForCell(mutedColors, b) {
|
|
|
2774
3243
|
const idx = Math.min(Math.floor(b * (MUTE_LEVELS.length - 1)), MUTE_LEVELS.length - 2);
|
|
2775
3244
|
return mutedColors[idx];
|
|
2776
3245
|
}
|
|
2777
|
-
function MatrixBackground({ width, height, clearRect, clearRects }) {
|
|
2778
|
-
const { grid, brightness } = useMatrix(width, height);
|
|
3246
|
+
function MatrixBackground({ width, height, clearRect, clearRects, mousePosRef, ripplesRef }) {
|
|
3247
|
+
const { grid, brightness } = useMatrix(width, height, mousePosRef, ripplesRef);
|
|
2779
3248
|
const theme = useTheme();
|
|
2780
3249
|
const columnColors = useMemo6(
|
|
2781
3250
|
() => width > 0 ? generateGradient([theme.accent, theme.secondary, theme.primary], width) : [],
|
|
@@ -2785,85 +3254,561 @@ function MatrixBackground({ width, height, clearRect, clearRects }) {
|
|
|
2785
3254
|
() => columnColors.map(buildMutedColors),
|
|
2786
3255
|
[columnColors]
|
|
2787
3256
|
);
|
|
2788
|
-
return /* @__PURE__ */
|
|
3257
|
+
return /* @__PURE__ */ jsx49("box", { flexDirection: "column", children: grid.map((row, y) => /* @__PURE__ */ jsx49("text", { children: row.map((cell, x) => {
|
|
2789
3258
|
const inClearRect = clearRect && y >= clearRect.top && y < clearRect.top + clearRect.height && x >= clearRect.left && x < clearRect.left + clearRect.width || clearRects && clearRects.some(
|
|
2790
3259
|
(r) => y >= r.top && y < r.top + r.height && x >= r.left && x < r.left + r.width
|
|
2791
3260
|
);
|
|
2792
3261
|
const mutedColors = columnMutedColors[x];
|
|
2793
3262
|
if (cell === " " || inClearRect || !mutedColors) {
|
|
2794
|
-
return /* @__PURE__ */
|
|
3263
|
+
return /* @__PURE__ */ jsx49("span", { children: " " }, x);
|
|
2795
3264
|
}
|
|
2796
|
-
return /* @__PURE__ */
|
|
3265
|
+
return /* @__PURE__ */ jsx49(
|
|
2797
3266
|
"span",
|
|
2798
3267
|
{
|
|
2799
|
-
key: x,
|
|
2800
3268
|
style: {
|
|
2801
3269
|
fg: colorForCell(mutedColors, brightness[y][x])
|
|
2802
|
-
}
|
|
3270
|
+
},
|
|
3271
|
+
children: cell
|
|
2803
3272
|
},
|
|
2804
|
-
|
|
3273
|
+
x
|
|
3274
|
+
);
|
|
3275
|
+
}) }, y)) });
|
|
3276
|
+
}
|
|
3277
|
+
|
|
3278
|
+
// demos/ripple.tsx
|
|
3279
|
+
import { useState as useState27, useEffect as useEffect8, useRef as useRef13, useCallback as useCallback6 } from "react";
|
|
3280
|
+
import { useKeyboard as useKeyboard19 } from "@gridland/utils";
|
|
3281
|
+
import { jsx as jsx50, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3282
|
+
var DEFAULT_COLS = 40;
|
|
3283
|
+
var DEFAULT_ROWS = 10;
|
|
3284
|
+
var CHARS2 = ["\xB7", "\u2591", "\u2592", "\u2593", "\u2588"];
|
|
3285
|
+
function hexToRgb2(hex) {
|
|
3286
|
+
const h = hex.replace("#", "");
|
|
3287
|
+
return [
|
|
3288
|
+
parseInt(h.slice(0, 2), 16),
|
|
3289
|
+
parseInt(h.slice(2, 4), 16),
|
|
3290
|
+
parseInt(h.slice(4, 6), 16)
|
|
3291
|
+
];
|
|
3292
|
+
}
|
|
3293
|
+
function rgbToHex2(r, g, b) {
|
|
3294
|
+
const clamp = (v) => Math.max(0, Math.min(255, Math.round(v)));
|
|
3295
|
+
return "#" + clamp(r).toString(16).padStart(2, "0") + clamp(g).toString(16).padStart(2, "0") + clamp(b).toString(16).padStart(2, "0");
|
|
3296
|
+
}
|
|
3297
|
+
function lerp2(a, b, t) {
|
|
3298
|
+
return a + (b - a) * t;
|
|
3299
|
+
}
|
|
3300
|
+
function RippleApp({ mouseOffset = { x: 0, y: 0 }, containerWidth, containerHeight } = {}) {
|
|
3301
|
+
const theme = useTheme();
|
|
3302
|
+
const [, setTick] = useState27(0);
|
|
3303
|
+
const COLS2 = containerWidth ? containerWidth - 2 : DEFAULT_COLS;
|
|
3304
|
+
const ROWS2 = containerHeight ? Math.max(3, containerHeight - 2 - 2) : DEFAULT_ROWS;
|
|
3305
|
+
const cursorRef = useRef13({ x: Math.floor(COLS2 / 2), y: Math.floor(ROWS2 / 2) });
|
|
3306
|
+
const ripplesRef = useRef13([]);
|
|
3307
|
+
const frameRef = useRef13(0);
|
|
3308
|
+
const mousePosRef = useRef13(null);
|
|
3309
|
+
const accentRgb = hexToRgb2(theme.accent);
|
|
3310
|
+
const dimRgb = [40, 40, 50];
|
|
3311
|
+
const baseRgb = [60, 60, 70];
|
|
3312
|
+
const addRipple = useCallback6((x, y) => {
|
|
3313
|
+
ripplesRef.current = [
|
|
3314
|
+
...ripplesRef.current,
|
|
3315
|
+
{ x, y, time: frameRef.current }
|
|
3316
|
+
];
|
|
3317
|
+
}, []);
|
|
3318
|
+
useEffect8(() => {
|
|
3319
|
+
const interval = setInterval(() => {
|
|
3320
|
+
frameRef.current++;
|
|
3321
|
+
ripplesRef.current = ripplesRef.current.filter(
|
|
3322
|
+
(r) => frameRef.current - r.time < 30
|
|
3323
|
+
);
|
|
3324
|
+
setTick((t) => t + 1);
|
|
3325
|
+
}, 60);
|
|
3326
|
+
return () => clearInterval(interval);
|
|
3327
|
+
}, []);
|
|
3328
|
+
useKeyboard19((event) => {
|
|
3329
|
+
const cursor2 = cursorRef.current;
|
|
3330
|
+
if (event.name === "up") {
|
|
3331
|
+
cursorRef.current = { ...cursor2, y: Math.max(0, cursor2.y - 1) };
|
|
3332
|
+
} else if (event.name === "down") {
|
|
3333
|
+
cursorRef.current = { ...cursor2, y: Math.min(ROWS2 - 1, cursor2.y + 1) };
|
|
3334
|
+
} else if (event.name === "left") {
|
|
3335
|
+
cursorRef.current = { ...cursor2, x: Math.max(0, cursor2.x - 1) };
|
|
3336
|
+
} else if (event.name === "right") {
|
|
3337
|
+
cursorRef.current = { ...cursor2, x: Math.min(COLS2 - 1, cursor2.x + 1) };
|
|
3338
|
+
} else if (event.name === "return") {
|
|
3339
|
+
addRipple(cursorRef.current.x, cursorRef.current.y);
|
|
3340
|
+
}
|
|
3341
|
+
event.preventDefault();
|
|
3342
|
+
});
|
|
3343
|
+
const cursor = cursorRef.current;
|
|
3344
|
+
const frame = frameRef.current;
|
|
3345
|
+
const ripples = ripplesRef.current;
|
|
3346
|
+
const grid = Array.from({ length: ROWS2 }, (_, row) => /* @__PURE__ */ jsx50("text", { children: Array.from({ length: COLS2 }, (_2, col) => {
|
|
3347
|
+
const isCursor = col === cursor.x && row === cursor.y;
|
|
3348
|
+
const baseWave = Math.sin(frame * 0.08 + col * 0.3 + row * 0.5) * 0.5 + 0.5;
|
|
3349
|
+
let intensity = baseWave * 0.15;
|
|
3350
|
+
for (const ripple of ripples) {
|
|
3351
|
+
const dx = col - ripple.x;
|
|
3352
|
+
const dy = row - ripple.y;
|
|
3353
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
3354
|
+
const age = frame - ripple.time;
|
|
3355
|
+
const radius = age * 0.5;
|
|
3356
|
+
const fade = 1 - age / 30;
|
|
3357
|
+
const ringDist = Math.abs(dist - radius);
|
|
3358
|
+
if (ringDist < 1.5) {
|
|
3359
|
+
const ringIntensity = (1 - ringDist / 1.5) * fade;
|
|
3360
|
+
intensity = Math.max(intensity, ringIntensity);
|
|
3361
|
+
} else if (dist < radius) {
|
|
3362
|
+
const innerIntensity = fade * 0.3 * (1 - dist / radius);
|
|
3363
|
+
intensity = Math.max(intensity, innerIntensity);
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
intensity = Math.max(0, Math.min(1, intensity));
|
|
3367
|
+
const charIndex = Math.min(
|
|
3368
|
+
CHARS2.length - 1,
|
|
3369
|
+
Math.floor(intensity * CHARS2.length)
|
|
2805
3370
|
);
|
|
2806
|
-
|
|
3371
|
+
const char = isCursor ? "\u25C6" : CHARS2[charIndex];
|
|
3372
|
+
let fg;
|
|
3373
|
+
if (isCursor) {
|
|
3374
|
+
fg = theme.primary;
|
|
3375
|
+
} else {
|
|
3376
|
+
const r = lerp2(dimRgb[0], accentRgb[0], intensity);
|
|
3377
|
+
const g = lerp2(dimRgb[1], accentRgb[1], intensity);
|
|
3378
|
+
const b = lerp2(dimRgb[2], accentRgb[2], intensity);
|
|
3379
|
+
fg = rgbToHex2(r, g, b);
|
|
3380
|
+
}
|
|
3381
|
+
return /* @__PURE__ */ jsx50("span", { style: { fg, bold: isCursor || intensity > 0.7 }, children: char }, col);
|
|
3382
|
+
}) }, row));
|
|
3383
|
+
return /* @__PURE__ */ jsxs39("box", { flexDirection: "column", flexGrow: 1, children: [
|
|
3384
|
+
/* @__PURE__ */ jsxs39(
|
|
3385
|
+
"box",
|
|
3386
|
+
{
|
|
3387
|
+
flexDirection: "column",
|
|
3388
|
+
flexGrow: 1,
|
|
3389
|
+
paddingX: 1,
|
|
3390
|
+
onMouseMove: (e) => {
|
|
3391
|
+
const gx = e.x - mouseOffset.x - 1;
|
|
3392
|
+
const gy = e.y - mouseOffset.y - 2;
|
|
3393
|
+
if (gx >= 0 && gx < COLS2 && gy >= 0 && gy < ROWS2) {
|
|
3394
|
+
mousePosRef.current = { x: gx, y: gy };
|
|
3395
|
+
cursorRef.current = { x: gx, y: gy };
|
|
3396
|
+
}
|
|
3397
|
+
},
|
|
3398
|
+
onMouseDown: (e) => {
|
|
3399
|
+
const gx = e.x - mouseOffset.x - 1;
|
|
3400
|
+
const gy = e.y - mouseOffset.y - 2;
|
|
3401
|
+
if (gx >= 0 && gx < COLS2 && gy >= 0 && gy < ROWS2) {
|
|
3402
|
+
addRipple(gx, gy);
|
|
3403
|
+
}
|
|
3404
|
+
},
|
|
3405
|
+
children: [
|
|
3406
|
+
/* @__PURE__ */ jsx50("text", { style: { dim: true, fg: theme.muted }, children: "Click or press Enter to create ripples" }),
|
|
3407
|
+
/* @__PURE__ */ jsx50("box", { flexDirection: "column", children: grid })
|
|
3408
|
+
]
|
|
3409
|
+
}
|
|
3410
|
+
),
|
|
3411
|
+
/* @__PURE__ */ jsx50("box", { flexGrow: 1 }),
|
|
3412
|
+
/* @__PURE__ */ jsx50("box", { paddingX: 1, children: /* @__PURE__ */ jsx50(
|
|
3413
|
+
StatusBar,
|
|
3414
|
+
{
|
|
3415
|
+
items: [
|
|
3416
|
+
{ key: "\u2191\u2193\u2190\u2192", label: "move" },
|
|
3417
|
+
{ key: "enter/click", label: "ripple" }
|
|
3418
|
+
]
|
|
3419
|
+
}
|
|
3420
|
+
) })
|
|
3421
|
+
] });
|
|
3422
|
+
}
|
|
3423
|
+
|
|
3424
|
+
// demos/puzzle.tsx
|
|
3425
|
+
import { useState as useState28, useEffect as useEffect9, useRef as useRef14, useMemo as useMemo7 } from "react";
|
|
3426
|
+
import { useKeyboard as useKeyboard20 } from "@gridland/utils";
|
|
3427
|
+
import { jsx as jsx51, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3428
|
+
var COLS = 4;
|
|
3429
|
+
var ROWS = 3;
|
|
3430
|
+
var TILE_COUNT = COLS * ROWS;
|
|
3431
|
+
var DEFAULT_TILE_WIDTH = 8;
|
|
3432
|
+
var DEFAULT_TILE_HEIGHT = 3;
|
|
3433
|
+
var SOLVED = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0];
|
|
3434
|
+
var tileColors = [
|
|
3435
|
+
"#ef4444",
|
|
3436
|
+
"#f97316",
|
|
3437
|
+
"#eab308",
|
|
3438
|
+
"#22c55e",
|
|
3439
|
+
"#3b82f6",
|
|
3440
|
+
"#8b5cf6",
|
|
3441
|
+
"#ec4899",
|
|
3442
|
+
"#14b8a6",
|
|
3443
|
+
"#f43f5e",
|
|
3444
|
+
"#6366f1",
|
|
3445
|
+
"#84cc16"
|
|
3446
|
+
];
|
|
3447
|
+
function isSolved(board) {
|
|
3448
|
+
for (let i = 0; i < TILE_COUNT; i++) {
|
|
3449
|
+
if (board[i] !== SOLVED[i]) return false;
|
|
3450
|
+
}
|
|
3451
|
+
return true;
|
|
3452
|
+
}
|
|
3453
|
+
function getEmptyIndex(board) {
|
|
3454
|
+
return board.indexOf(0);
|
|
3455
|
+
}
|
|
3456
|
+
function getNeighbor(emptyIdx, direction) {
|
|
3457
|
+
const row = Math.floor(emptyIdx / COLS);
|
|
3458
|
+
const col = emptyIdx % COLS;
|
|
3459
|
+
switch (direction) {
|
|
3460
|
+
case "up":
|
|
3461
|
+
return row > 0 ? emptyIdx - COLS : null;
|
|
3462
|
+
case "down":
|
|
3463
|
+
return row < ROWS - 1 ? emptyIdx + COLS : null;
|
|
3464
|
+
case "left":
|
|
3465
|
+
return col > 0 ? emptyIdx - 1 : null;
|
|
3466
|
+
case "right":
|
|
3467
|
+
return col < COLS - 1 ? emptyIdx + 1 : null;
|
|
3468
|
+
default:
|
|
3469
|
+
return null;
|
|
3470
|
+
}
|
|
3471
|
+
}
|
|
3472
|
+
function swap(board, a, b) {
|
|
3473
|
+
const next = [...board];
|
|
3474
|
+
next[a] = board[b];
|
|
3475
|
+
next[b] = board[a];
|
|
3476
|
+
return next;
|
|
3477
|
+
}
|
|
3478
|
+
function shuffle(board, count) {
|
|
3479
|
+
let current = [...board];
|
|
3480
|
+
const directions = ["up", "down", "left", "right"];
|
|
3481
|
+
let lastDir = "";
|
|
3482
|
+
for (let i = 0; i < count; i++) {
|
|
3483
|
+
const emptyIdx = getEmptyIndex(current);
|
|
3484
|
+
const validMoves = directions.filter((d) => {
|
|
3485
|
+
if (d === lastDir) return false;
|
|
3486
|
+
return getNeighbor(emptyIdx, d) !== null;
|
|
3487
|
+
});
|
|
3488
|
+
const dir = validMoves[Math.floor(Math.random() * validMoves.length)];
|
|
3489
|
+
const neighbor = getNeighbor(emptyIdx, dir);
|
|
3490
|
+
current = swap(current, emptyIdx, neighbor);
|
|
3491
|
+
const opposites = { up: "down", down: "up", left: "right", right: "left" };
|
|
3492
|
+
lastDir = opposites[dir];
|
|
3493
|
+
}
|
|
3494
|
+
return current;
|
|
3495
|
+
}
|
|
3496
|
+
function isAdjacentToEmpty(board, tileIdx) {
|
|
3497
|
+
const emptyIdx = getEmptyIndex(board);
|
|
3498
|
+
const eRow = Math.floor(emptyIdx / COLS);
|
|
3499
|
+
const eCol = emptyIdx % COLS;
|
|
3500
|
+
const tRow = Math.floor(tileIdx / COLS);
|
|
3501
|
+
const tCol = tileIdx % COLS;
|
|
3502
|
+
return Math.abs(eRow - tRow) === 1 && eCol === tCol || Math.abs(eCol - tCol) === 1 && eRow === tRow;
|
|
3503
|
+
}
|
|
3504
|
+
function PuzzleApp({ containerWidth, containerHeight } = {}) {
|
|
3505
|
+
const theme = useTheme();
|
|
3506
|
+
const TILE_WIDTH = containerWidth ? Math.floor((containerWidth - 2) / COLS) : DEFAULT_TILE_WIDTH;
|
|
3507
|
+
const TILE_HEIGHT = containerHeight ? Math.max(3, Math.floor((containerHeight - 2 - 4) / ROWS)) : DEFAULT_TILE_HEIGHT;
|
|
3508
|
+
const [board, setBoard] = useState28(SOLVED);
|
|
3509
|
+
const [moves, setMoves] = useState28(0);
|
|
3510
|
+
const [solved, setSolved] = useState28(false);
|
|
3511
|
+
const boardRef = useRef14(board);
|
|
3512
|
+
const movesRef = useRef14(moves);
|
|
3513
|
+
boardRef.current = board;
|
|
3514
|
+
movesRef.current = moves;
|
|
3515
|
+
const doMove = (direction) => {
|
|
3516
|
+
const current = boardRef.current;
|
|
3517
|
+
if (isSolved(current) && movesRef.current > 0) return;
|
|
3518
|
+
const emptyIdx = getEmptyIndex(current);
|
|
3519
|
+
const neighbor = getNeighbor(emptyIdx, direction);
|
|
3520
|
+
if (neighbor === null) return;
|
|
3521
|
+
const next = swap(current, emptyIdx, neighbor);
|
|
3522
|
+
boardRef.current = next;
|
|
3523
|
+
movesRef.current++;
|
|
3524
|
+
setBoard(next);
|
|
3525
|
+
setMoves(movesRef.current);
|
|
3526
|
+
setSolved(isSolved(next));
|
|
3527
|
+
};
|
|
3528
|
+
const doShuffle = () => {
|
|
3529
|
+
const shuffled = shuffle(SOLVED, 30);
|
|
3530
|
+
boardRef.current = shuffled;
|
|
3531
|
+
movesRef.current = 0;
|
|
3532
|
+
setBoard(shuffled);
|
|
3533
|
+
setMoves(0);
|
|
3534
|
+
setSolved(false);
|
|
3535
|
+
};
|
|
3536
|
+
useEffect9(() => {
|
|
3537
|
+
doShuffle();
|
|
3538
|
+
}, []);
|
|
3539
|
+
useKeyboard20((event) => {
|
|
3540
|
+
if (event.name === "up") {
|
|
3541
|
+
doMove("down");
|
|
3542
|
+
event.preventDefault();
|
|
3543
|
+
} else if (event.name === "down") {
|
|
3544
|
+
doMove("up");
|
|
3545
|
+
event.preventDefault();
|
|
3546
|
+
} else if (event.name === "left") {
|
|
3547
|
+
doMove("right");
|
|
3548
|
+
event.preventDefault();
|
|
3549
|
+
} else if (event.name === "right") {
|
|
3550
|
+
doMove("left");
|
|
3551
|
+
event.preventDefault();
|
|
3552
|
+
} else if (event.key === "r") {
|
|
3553
|
+
doShuffle();
|
|
3554
|
+
event.preventDefault();
|
|
3555
|
+
}
|
|
3556
|
+
});
|
|
3557
|
+
const rows = useMemo7(() => {
|
|
3558
|
+
const result = [];
|
|
3559
|
+
for (let r = 0; r < ROWS; r++) {
|
|
3560
|
+
result.push(board.slice(r * COLS, r * COLS + COLS));
|
|
3561
|
+
}
|
|
3562
|
+
return result;
|
|
3563
|
+
}, [board]);
|
|
3564
|
+
return /* @__PURE__ */ jsxs40("box", { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
|
|
3565
|
+
/* @__PURE__ */ jsx51("text", { style: textStyle({ dim: true, fg: theme.muted }), children: "Slide tiles to solve the puzzle" }),
|
|
3566
|
+
/* @__PURE__ */ jsx51("box", { flexDirection: "column", children: rows.map((row, rowIdx) => /* @__PURE__ */ jsx51("box", { flexDirection: "row", children: row.map((tile, colIdx) => {
|
|
3567
|
+
const idx = rowIdx * COLS + colIdx;
|
|
3568
|
+
if (tile === 0) {
|
|
3569
|
+
return /* @__PURE__ */ jsx51("box", { width: TILE_WIDTH, height: TILE_HEIGHT }, idx);
|
|
3570
|
+
}
|
|
3571
|
+
const color = tileColors[tile - 1];
|
|
3572
|
+
return /* @__PURE__ */ jsx51(
|
|
3573
|
+
"box",
|
|
3574
|
+
{
|
|
3575
|
+
width: TILE_WIDTH,
|
|
3576
|
+
height: TILE_HEIGHT,
|
|
3577
|
+
border: true,
|
|
3578
|
+
borderStyle: "rounded",
|
|
3579
|
+
borderColor: solved ? theme.success : color,
|
|
3580
|
+
onMouseDown: () => {
|
|
3581
|
+
if (isAdjacentToEmpty(boardRef.current, idx)) {
|
|
3582
|
+
const emptyIdx = getEmptyIndex(boardRef.current);
|
|
3583
|
+
const next = swap(boardRef.current, emptyIdx, idx);
|
|
3584
|
+
boardRef.current = next;
|
|
3585
|
+
movesRef.current++;
|
|
3586
|
+
setBoard(next);
|
|
3587
|
+
setMoves(movesRef.current);
|
|
3588
|
+
setSolved(isSolved(next));
|
|
3589
|
+
}
|
|
3590
|
+
},
|
|
3591
|
+
children: /* @__PURE__ */ jsx51("text", { style: textStyle({
|
|
3592
|
+
fg: solved ? theme.success : color,
|
|
3593
|
+
bold: true
|
|
3594
|
+
}), children: String(tile).padStart(2) })
|
|
3595
|
+
},
|
|
3596
|
+
idx
|
|
3597
|
+
);
|
|
3598
|
+
}) }, rowIdx)) }),
|
|
3599
|
+
/* @__PURE__ */ jsx51("box", { height: 1 }),
|
|
3600
|
+
/* @__PURE__ */ jsxs40("box", { flexDirection: "row", gap: 2, children: [
|
|
3601
|
+
/* @__PURE__ */ jsxs40("text", { style: textStyle({ dim: true, fg: theme.muted }), children: [
|
|
3602
|
+
"Moves: ",
|
|
3603
|
+
moves
|
|
3604
|
+
] }),
|
|
3605
|
+
solved && moves > 0 && /* @__PURE__ */ jsx51("text", { style: textStyle({ fg: theme.success, bold: true }), children: "Solved!" })
|
|
3606
|
+
] }),
|
|
3607
|
+
/* @__PURE__ */ jsx51("box", { flexGrow: 1 }),
|
|
3608
|
+
/* @__PURE__ */ jsx51("box", { paddingX: 1, children: /* @__PURE__ */ jsx51(StatusBar, { items: [
|
|
3609
|
+
{ key: "\u2191\u2193\u2190\u2192", label: "slide" },
|
|
3610
|
+
{ key: "click", label: "slide tile" },
|
|
3611
|
+
{ key: "r", label: "shuffle" }
|
|
3612
|
+
] }) })
|
|
3613
|
+
] });
|
|
2807
3614
|
}
|
|
2808
3615
|
|
|
2809
3616
|
// src/landing/landing-app.tsx
|
|
2810
|
-
|
|
3617
|
+
import { Fragment as Fragment7, jsx as jsx52, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
3618
|
+
var DEMOS = ["ripple", "puzzle"];
|
|
3619
|
+
var TAB_HEIGHT = 2;
|
|
3620
|
+
var TAB_WIDTHS = DEMOS.map((n) => n.length + 4);
|
|
3621
|
+
var TAB_POSITIONS = [];
|
|
3622
|
+
var _pos = 0;
|
|
3623
|
+
for (const w of TAB_WIDTHS) {
|
|
3624
|
+
TAB_POSITIONS.push(_pos);
|
|
3625
|
+
_pos += w;
|
|
3626
|
+
}
|
|
3627
|
+
function LandingApp({ useKeyboard: useKeyboard23 }) {
|
|
2811
3628
|
const theme = useTheme();
|
|
2812
3629
|
const { width, height, isNarrow, isTiny, isMobile } = useBreakpoints();
|
|
2813
|
-
const
|
|
2814
|
-
const
|
|
2815
|
-
|
|
2816
|
-
|
|
3630
|
+
const [activeIndex, setActiveIndex] = useState29(0);
|
|
3631
|
+
const mousePosRef = useRef15(null);
|
|
3632
|
+
const matrixRipplesRef = useRef15([]);
|
|
3633
|
+
useKeyboard23((event) => {
|
|
3634
|
+
if (event.name === "tab") {
|
|
3635
|
+
setActiveIndex((prev) => (prev + 1) % DEMOS.length);
|
|
3636
|
+
event.preventDefault();
|
|
3637
|
+
}
|
|
3638
|
+
});
|
|
3639
|
+
const isBrowser2 = typeof document !== "undefined";
|
|
3640
|
+
const { clearRect, installLinksClearRect, boxTop } = useMemo8(() => {
|
|
3641
|
+
const logoHeight = isTiny ? 2 : isMobile ? 7 : isNarrow ? 13 : 7;
|
|
3642
|
+
const logoExtra = isBrowser2 ? 1 : 0;
|
|
2817
3643
|
const gap = isMobile ? 0 : 1;
|
|
2818
|
-
const
|
|
3644
|
+
const paddingTop = isMobile ? 1 : 3;
|
|
3645
|
+
const installLinksTop = paddingTop + logoHeight + logoExtra + gap;
|
|
2819
3646
|
const installLinksHeight = 3;
|
|
2820
|
-
const
|
|
2821
|
-
const bh = height -
|
|
3647
|
+
const boxTop2 = installLinksTop + installLinksHeight + gap + 1;
|
|
3648
|
+
const bh = height - boxTop2 - 1;
|
|
3649
|
+
const bw = Math.min(82, width - 2);
|
|
3650
|
+
const bl = Math.floor((width - bw) / 2);
|
|
2822
3651
|
return {
|
|
2823
|
-
clearRect: { top:
|
|
2824
|
-
installLinksClearRect: { top: installLinksTop, left: 1, width: width - 2, height: installLinksHeight }
|
|
3652
|
+
clearRect: { top: boxTop2, left: bl, width: bw, height: bh },
|
|
3653
|
+
installLinksClearRect: { top: installLinksTop, left: 1, width: width - 2, height: installLinksHeight },
|
|
3654
|
+
boxTop: boxTop2
|
|
2825
3655
|
};
|
|
2826
|
-
}, [width, height, isTiny, isNarrow, isMobile,
|
|
2827
|
-
|
|
3656
|
+
}, [width, height, isTiny, isNarrow, isMobile, isBrowser2]);
|
|
3657
|
+
const MAX_BOX_WIDTH = 82;
|
|
3658
|
+
const availableWidth = width - 2;
|
|
3659
|
+
const boxWidth = Math.min(MAX_BOX_WIDTH, availableWidth);
|
|
3660
|
+
const boxLeft = Math.floor((width - boxWidth) / 2);
|
|
3661
|
+
const mouseOffset = useMemo8(() => ({
|
|
3662
|
+
x: boxLeft + 1,
|
|
3663
|
+
// box left edge + border(1)
|
|
3664
|
+
y: boxTop + TAB_HEIGHT + 1
|
|
3665
|
+
// boxTop + tab rows + box top border(1)
|
|
3666
|
+
}), [boxTop, boxLeft]);
|
|
3667
|
+
const containerWidth = boxWidth - 2;
|
|
3668
|
+
const maxBoxHeight = 20;
|
|
3669
|
+
const containerHeight = Math.min(height - boxTop - 1 - TAB_HEIGHT, maxBoxHeight - TAB_HEIGHT);
|
|
3670
|
+
const activeStart = TAB_POSITIONS[activeIndex];
|
|
3671
|
+
const activeWidth = TAB_WIDTHS[activeIndex];
|
|
3672
|
+
const activeEnd = activeStart + activeWidth;
|
|
3673
|
+
const connectParts = [];
|
|
3674
|
+
if (activeStart === 0) {
|
|
3675
|
+
connectParts.push(/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: "\u2502" }, "cl"));
|
|
3676
|
+
connectParts.push(/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: " ".repeat(activeWidth - 2) }, "gap"));
|
|
3677
|
+
connectParts.push(/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: "\u2570" }, "cr"));
|
|
3678
|
+
} else {
|
|
3679
|
+
connectParts.push(
|
|
3680
|
+
/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: "\u256D" + "\u2500".repeat(activeStart - 1) }, "left")
|
|
3681
|
+
);
|
|
3682
|
+
connectParts.push(/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: "\u256F" }, "cl"));
|
|
3683
|
+
connectParts.push(/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: " ".repeat(activeWidth - 2) }, "gap"));
|
|
3684
|
+
connectParts.push(/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: "\u2570" }, "cr"));
|
|
3685
|
+
}
|
|
3686
|
+
const rightFill = boxWidth - activeEnd - 1;
|
|
3687
|
+
if (rightFill > 0) {
|
|
3688
|
+
connectParts.push(
|
|
3689
|
+
/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: "\u2500".repeat(rightFill) }, "right")
|
|
3690
|
+
);
|
|
3691
|
+
}
|
|
3692
|
+
connectParts.push(/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: "\u256E" }, "corner-r"));
|
|
3693
|
+
return /* @__PURE__ */ jsxs41("box", { width: "100%", height: "100%", position: "relative", children: [
|
|
3694
|
+
/* @__PURE__ */ jsx52(MatrixBackground, { width, height, clearRect, clearRects: isBrowser2 ? void 0 : [installLinksClearRect], mousePosRef, ripplesRef: matrixRipplesRef }),
|
|
3695
|
+
/* @__PURE__ */ jsx52(
|
|
3696
|
+
"box",
|
|
3697
|
+
{
|
|
3698
|
+
position: "absolute",
|
|
3699
|
+
top: 0,
|
|
3700
|
+
left: 0,
|
|
3701
|
+
width,
|
|
3702
|
+
height,
|
|
3703
|
+
zIndex: 1,
|
|
3704
|
+
flexDirection: "column",
|
|
3705
|
+
shouldFill: false,
|
|
3706
|
+
onMouseMove: (e) => {
|
|
3707
|
+
mousePosRef.current = { x: e.x, y: e.y };
|
|
3708
|
+
},
|
|
3709
|
+
onMouseDown: (e) => {
|
|
3710
|
+
matrixRipplesRef.current = [
|
|
3711
|
+
...matrixRipplesRef.current,
|
|
3712
|
+
{ x: e.x, y: e.y, createdAt: Date.now() }
|
|
3713
|
+
];
|
|
3714
|
+
},
|
|
3715
|
+
children: /* @__PURE__ */ jsxs41("box", { flexGrow: 1, flexDirection: "column", paddingTop: isMobile ? 1 : 3, paddingLeft: 1, paddingRight: 1, paddingBottom: 1, gap: isMobile ? 0 : 1, shouldFill: false, children: [
|
|
3716
|
+
/* @__PURE__ */ jsx52("box", { flexShrink: 0, shouldFill: false, children: /* @__PURE__ */ jsx52(Logo, { compact: isTiny, narrow: isNarrow, mobile: isMobile }) }),
|
|
3717
|
+
/* @__PURE__ */ jsxs41("box", { flexDirection: "row", flexWrap: "wrap", justifyContent: "center", gap: isMobile ? 0 : 1, flexShrink: 0, shouldFill: false, children: [
|
|
3718
|
+
!isMobile && /* @__PURE__ */ jsx52("box", { border: true, borderStyle: "rounded", borderColor: theme.border, paddingX: 1, flexDirection: "column", flexShrink: 0, children: /* @__PURE__ */ jsxs41("text", { children: [
|
|
3719
|
+
/* @__PURE__ */ jsx52("span", { style: textStyle({ dim: true }), children: "$ " }),
|
|
3720
|
+
/* @__PURE__ */ jsx52("span", { style: textStyle({ bold: true }), children: "bunx " }),
|
|
3721
|
+
/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.accent }), children: "@gridland/demo landing" })
|
|
3722
|
+
] }) }),
|
|
3723
|
+
!isMobile && /* @__PURE__ */ jsx52(InstallBox, {}),
|
|
3724
|
+
/* @__PURE__ */ jsx52(LinksBox, {})
|
|
3725
|
+
] }),
|
|
3726
|
+
/* @__PURE__ */ jsxs41("box", { flexDirection: "column", width: boxWidth, maxWidth: MAX_BOX_WIDTH, maxHeight: 20, alignSelf: "center", flexGrow: 1, children: [
|
|
3727
|
+
/* @__PURE__ */ jsx52("box", { height: 1, flexShrink: 0, flexDirection: "row", shouldFill: false, children: DEMOS.map((name2, i) => {
|
|
3728
|
+
const isActive = i === activeIndex;
|
|
3729
|
+
const w = TAB_WIDTHS[i];
|
|
3730
|
+
return /* @__PURE__ */ jsx52("box", { width: w, onMouseDown: () => setActiveIndex(i), children: /* @__PURE__ */ jsx52("text", { style: textStyle({ fg: theme.border }), children: isActive ? "\u256D" + "\u2500".repeat(w - 2) + "\u256E" : " ".repeat(w) }) }, name2);
|
|
3731
|
+
}) }),
|
|
3732
|
+
/* @__PURE__ */ jsx52("box", { height: 1, flexShrink: 0, flexDirection: "row", shouldFill: false, children: DEMOS.map((name2, i) => {
|
|
3733
|
+
const isActive = i === activeIndex;
|
|
3734
|
+
const w = TAB_WIDTHS[i];
|
|
3735
|
+
return /* @__PURE__ */ jsx52("box", { width: w, onMouseDown: () => setActiveIndex(i), children: /* @__PURE__ */ jsx52("text", { children: isActive ? /* @__PURE__ */ jsxs41(Fragment7, { children: [
|
|
3736
|
+
/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: "\u2502" }),
|
|
3737
|
+
/* @__PURE__ */ jsx52("span", { style: textStyle({ bold: true, fg: theme.foreground }), children: ` ${name2} ` }),
|
|
3738
|
+
/* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.border }), children: "\u2502" })
|
|
3739
|
+
] }) : /* @__PURE__ */ jsx52("span", { style: textStyle({ fg: theme.muted }), children: ` ${name2} ` }) }) }, name2);
|
|
3740
|
+
}) }),
|
|
3741
|
+
/* @__PURE__ */ jsxs41("box", { position: "relative", flexGrow: 1, children: [
|
|
3742
|
+
/* @__PURE__ */ jsx52("box", { position: "absolute", top: 0, left: 0, width: boxWidth, height: 1, zIndex: 2, children: /* @__PURE__ */ jsx52("text", { children: connectParts }) }),
|
|
3743
|
+
/* @__PURE__ */ jsxs41("box", { border: true, borderStyle: "rounded", borderColor: theme.border, flexGrow: 1, flexDirection: "column", overflow: "hidden", children: [
|
|
3744
|
+
activeIndex === 0 && /* @__PURE__ */ jsx52(RippleApp, { mouseOffset, containerWidth, containerHeight }),
|
|
3745
|
+
activeIndex === 1 && /* @__PURE__ */ jsx52(PuzzleApp, { containerWidth, containerHeight })
|
|
3746
|
+
] })
|
|
3747
|
+
] }),
|
|
3748
|
+
/* @__PURE__ */ jsx52("box", { height: 1 }),
|
|
3749
|
+
/* @__PURE__ */ jsx52("box", { width: "100%", alignItems: "center", flexDirection: "column", shouldFill: false, children: /* @__PURE__ */ jsxs41("text", { style: textStyle({ dim: true, fg: theme.muted }), children: [
|
|
3750
|
+
"Made with \u2764\uFE0F by ",
|
|
3751
|
+
/* @__PURE__ */ jsx52("a", { href: "https://cjroth.com", style: { attributes: 1 << 3, fg: theme.muted }, children: "Chris Roth" }),
|
|
3752
|
+
" + ",
|
|
3753
|
+
/* @__PURE__ */ jsx52("a", { href: "https://jessicacheng.studio", style: { attributes: 1 << 3, fg: theme.muted }, children: "Jessica Cheng" })
|
|
3754
|
+
] }) })
|
|
3755
|
+
] })
|
|
3756
|
+
] })
|
|
3757
|
+
}
|
|
3758
|
+
)
|
|
3759
|
+
] });
|
|
2828
3760
|
}
|
|
2829
3761
|
|
|
3762
|
+
// src/landing/matrix-rain.tsx
|
|
3763
|
+
import { jsx as jsx53 } from "react/jsx-runtime";
|
|
3764
|
+
|
|
3765
|
+
// src/landing/about-modal.tsx
|
|
3766
|
+
import { jsx as jsx54, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
3767
|
+
|
|
2830
3768
|
// demos/index.tsx
|
|
3769
|
+
import { jsx as jsx55 } from "react/jsx-runtime";
|
|
2831
3770
|
var demos = [
|
|
2832
|
-
{ name: "gradient", app: () => /* @__PURE__ */
|
|
2833
|
-
{ name: "ascii", app: () => /* @__PURE__ */
|
|
2834
|
-
{ name: "table", app: () => /* @__PURE__ */
|
|
2835
|
-
{ name: "spinner", app: () => /* @__PURE__ */
|
|
2836
|
-
{ name: "select-input", app: () => /* @__PURE__ */
|
|
2837
|
-
{ name: "multi-select", app: () => /* @__PURE__ */
|
|
2838
|
-
{ name: "prompt-input", app: () => /* @__PURE__ */
|
|
2839
|
-
{ name: "text-input", app: () => /* @__PURE__ */
|
|
2840
|
-
{ name: "link", app: () => /* @__PURE__ */
|
|
2841
|
-
{ name: "tabs", app: () => /* @__PURE__ */
|
|
2842
|
-
{ name: "status-bar", app: () => /* @__PURE__ */
|
|
2843
|
-
{ name: "modal", app: () => /* @__PURE__ */
|
|
2844
|
-
{ name: "primitives", app: () => /* @__PURE__ */
|
|
2845
|
-
{ name: "chat", app: () => /* @__PURE__ */
|
|
2846
|
-
{ name: "chain-of-thought", app: () => /* @__PURE__ */
|
|
2847
|
-
{ name: "message", app: () => /* @__PURE__ */
|
|
2848
|
-
{ name: "terminal-window", app: () => /* @__PURE__ */
|
|
2849
|
-
{ name: "focus", app: () => /* @__PURE__ */
|
|
2850
|
-
{ name: "
|
|
2851
|
-
{ name: "
|
|
2852
|
-
{ name: "
|
|
2853
|
-
{ name: "
|
|
2854
|
-
{ name: "
|
|
2855
|
-
{ name: "
|
|
3771
|
+
{ name: "gradient", app: () => /* @__PURE__ */ jsx55(GradientApp, {}) },
|
|
3772
|
+
{ name: "ascii", app: () => /* @__PURE__ */ jsx55(AsciiApp, {}) },
|
|
3773
|
+
{ name: "table", app: () => /* @__PURE__ */ jsx55(TableApp, {}) },
|
|
3774
|
+
{ name: "spinner", app: () => /* @__PURE__ */ jsx55(SpinnerApp, {}) },
|
|
3775
|
+
{ name: "select-input", app: () => /* @__PURE__ */ jsx55(SelectInputApp, {}) },
|
|
3776
|
+
{ name: "multi-select", app: () => /* @__PURE__ */ jsx55(MultiSelectApp, {}) },
|
|
3777
|
+
{ name: "prompt-input", app: () => /* @__PURE__ */ jsx55(PromptInputApp, {}) },
|
|
3778
|
+
{ name: "text-input", app: () => /* @__PURE__ */ jsx55(TextInputApp, {}) },
|
|
3779
|
+
{ name: "link", app: () => /* @__PURE__ */ jsx55(LinkApp, {}) },
|
|
3780
|
+
{ name: "tabs", app: () => /* @__PURE__ */ jsx55(TabBarApp, {}) },
|
|
3781
|
+
{ name: "status-bar", app: () => /* @__PURE__ */ jsx55(StatusBarApp, {}) },
|
|
3782
|
+
{ name: "modal", app: () => /* @__PURE__ */ jsx55(ModalApp, {}) },
|
|
3783
|
+
{ name: "primitives", app: () => /* @__PURE__ */ jsx55(PrimitivesApp, {}) },
|
|
3784
|
+
{ name: "chat", app: () => /* @__PURE__ */ jsx55(ChatApp, {}) },
|
|
3785
|
+
{ name: "chain-of-thought", app: () => /* @__PURE__ */ jsx55(ChainOfThoughtApp, {}) },
|
|
3786
|
+
{ name: "message", app: () => /* @__PURE__ */ jsx55(MessageApp, {}) },
|
|
3787
|
+
{ name: "terminal-window", app: () => /* @__PURE__ */ jsx55(TerminalWindowApp, {}) },
|
|
3788
|
+
{ name: "focus-grid", app: () => /* @__PURE__ */ jsx55(FocusGridApp, {}) },
|
|
3789
|
+
{ name: "focus-chat", app: () => /* @__PURE__ */ jsx55(FocusChatApp, {}) },
|
|
3790
|
+
{ name: "focus", app: () => /* @__PURE__ */ jsx55(FocusApp, {}) },
|
|
3791
|
+
{ name: "pointer", app: () => /* @__PURE__ */ jsx55(PointerApp, {}) },
|
|
3792
|
+
{ name: "cursor-highlight", app: () => /* @__PURE__ */ jsx55(CursorHighlightApp, {}) },
|
|
3793
|
+
{ name: "text-style", app: () => /* @__PURE__ */ jsx55(TextStyleApp, {}) },
|
|
3794
|
+
{ name: "headless", app: () => /* @__PURE__ */ jsx55(HeadlessApp, {}) },
|
|
3795
|
+
{ name: "theming", app: () => /* @__PURE__ */ jsx55(ThemingApp, {}) },
|
|
3796
|
+
{ name: "landing", app: () => /* @__PURE__ */ jsx55(LandingApp, { useKeyboard: useKeyboard21 }) },
|
|
3797
|
+
{ name: "ripple", app: () => /* @__PURE__ */ jsx55(RippleApp, {}) },
|
|
3798
|
+
{ name: "puzzle", app: () => /* @__PURE__ */ jsx55(PuzzleApp, {}) }
|
|
2856
3799
|
];
|
|
2857
3800
|
|
|
2858
3801
|
// src/run.tsx
|
|
3802
|
+
import { jsx as jsx56 } from "react/jsx-runtime";
|
|
2859
3803
|
var _renderer;
|
|
2860
3804
|
function DemoShell({ children }) {
|
|
2861
|
-
|
|
2862
|
-
if (event.
|
|
3805
|
+
useKeyboard22((event) => {
|
|
3806
|
+
if (event.defaultPrevented) return;
|
|
3807
|
+
if (event.name === "escape") {
|
|
2863
3808
|
_renderer.destroy();
|
|
2864
3809
|
}
|
|
2865
3810
|
});
|
|
2866
|
-
return /* @__PURE__ */
|
|
3811
|
+
return /* @__PURE__ */ jsx56("box", { flexDirection: "column", flexGrow: 1, children });
|
|
2867
3812
|
}
|
|
2868
3813
|
async function runDemo(name2) {
|
|
2869
3814
|
const demo = demos.find((d) => d.name === name2);
|
|
@@ -2873,7 +3818,7 @@ async function runDemo(name2) {
|
|
|
2873
3818
|
process.exit(1);
|
|
2874
3819
|
}
|
|
2875
3820
|
_renderer = await createCliRenderer({ exitOnCtrlC: true });
|
|
2876
|
-
createRoot(_renderer).render(/* @__PURE__ */
|
|
3821
|
+
createRoot(_renderer).render(/* @__PURE__ */ jsx56(DemoShell, { children: demo.app() }));
|
|
2877
3822
|
}
|
|
2878
3823
|
var name = process.argv[2];
|
|
2879
3824
|
if (name) {
|