babavoss 0.12.6 → 0.13.1
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/gui/babavoss-web.js +4 -1
- package/gui/{chunk-9gmmm54v.js → chunk-qgzmajan.js} +619 -574
- package/gui/gui.js +1538 -277
- package/gui/theme.css +2007 -1128
- package/index.ts +1 -1
- package/package.json +5 -5
- package/src/{promptware → agents}/compile.ts +23 -31
- package/src/{promptware → agents}/define.ts +2 -2
- package/src/{promptware → agents}/disk.ts +7 -4
- package/src/{promptware → agents}/sync.ts +2 -2
- package/src/{promptware → agents}/system.ts +17 -17
- package/src/baba/check.ts +3 -3
- package/src/baba/config.ts +5 -2
- package/src/baba/init.ts +13 -18
- package/src/baba/node.ts +2 -2
- package/src/baba/project.ts +2 -2
- package/src/baba/requirements.ts +39 -0
- package/src/baba/setup.ts +30 -0
- package/src/baba/worker.ts +13 -5
- package/src/build/mdx.ts +4 -4
- package/src/build/project.ts +6 -1
- package/src/build/views.ts +3 -3
- package/src/desktop/desktop.css +35 -39
- package/src/desktop/index.ts +9 -7
- package/src/desktop/keys.ts +153 -0
- package/src/desktop/view.tsx +174 -130
- package/src/door/core.ts +2 -2
- package/src/ecs/baba.ts +27 -17
- package/src/generated/build.ts +1 -1
- package/src/gui/gui.tsx +21 -31
- package/src/gui/index.ts +6 -2
- package/src/gui/{promptware.tsx → instructions.tsx} +12 -12
- package/src/gui/levels.tsx +241 -59
- package/src/gui/lockup.ts +11 -0
- package/src/gui/settings.tsx +241 -0
- package/src/gui/setup.tsx +77 -0
- package/src/gui/theme.css +205 -58
- package/src/gui/theme.ts +9 -5
- package/src/gui/voss-settings.ts +48 -0
- package/src/gui/wizard.tsx +17 -40
- package/src/guide/add-a-desktop.mdx +7 -7
- package/src/guide/index.ts +4 -4
- package/src/guide/write-a-system.mdx +3 -3
- package/src/guide/{write-promptware.mdx → write-agentic-instructions.mdx} +17 -24
- package/src/http/server.ts +140 -17
- package/src/{prompt → instructions}/evals.ts +1 -1
- package/src/{prompt → instructions}/index.ts +9 -8
- package/src/{prompt → instructions}/jsx-runtime.ts +3 -3
- package/src/mcp/main.ts +3 -3
- package/src/mcp/tools.ts +4 -4
- package/src/runtime/harness.ts +2 -2
- package/src/server/edge.ts +31 -3
- package/src/server/main.ts +2 -1
- package/src/server/messages.ts +47 -7
- package/src/shell/run.ts +18 -18
- package/src/spec/index.ts +1 -1
- package/src/web/core.tsx +2 -2
- package/src/web/index.tsx +1 -1
- package/src/desktop/bob.ts +0 -76
- /package/src/{promptware → agents}/markdown.d.ts +0 -0
- /package/src/{prompt → instructions}/jsx-dev-runtime.ts +0 -0
- /package/src/{prompt → instructions}/mdx.d.ts +0 -0
package/gui/gui.js
CHANGED
|
@@ -6,7 +6,8 @@ import {
|
|
|
6
6
|
ApiError,
|
|
7
7
|
Button,
|
|
8
8
|
Desktop,
|
|
9
|
-
|
|
9
|
+
DesktopSkeleton,
|
|
10
|
+
Eyes,
|
|
10
11
|
FieldError,
|
|
11
12
|
Input,
|
|
12
13
|
Maker,
|
|
@@ -19,23 +20,28 @@ import {
|
|
|
19
20
|
accept,
|
|
20
21
|
api,
|
|
21
22
|
apiHeaders,
|
|
23
|
+
bindingNote,
|
|
24
|
+
bindingOf,
|
|
22
25
|
canonicalPath,
|
|
23
26
|
collect,
|
|
24
27
|
describeType,
|
|
25
28
|
effect,
|
|
29
|
+
formatBinding,
|
|
26
30
|
formatFailure,
|
|
27
31
|
isApps,
|
|
32
|
+
isMac,
|
|
33
|
+
keyCommands,
|
|
34
|
+
keymapOf,
|
|
28
35
|
matchRoute,
|
|
36
|
+
normalBinding,
|
|
29
37
|
plan,
|
|
30
38
|
resource,
|
|
31
39
|
s,
|
|
32
40
|
system,
|
|
33
41
|
tableOf,
|
|
34
|
-
useBaba,
|
|
35
42
|
useBabaState,
|
|
36
|
-
useResource,
|
|
37
43
|
useScope
|
|
38
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-qgzmajan.js";
|
|
39
45
|
import {
|
|
40
46
|
require_jsx_runtime
|
|
41
47
|
} from "./chunk-pk09y98y.js";
|
|
@@ -47,7 +53,7 @@ import {
|
|
|
47
53
|
} from "./chunk-wwqypxre.js";
|
|
48
54
|
|
|
49
55
|
// src/gui/gui.tsx
|
|
50
|
-
var
|
|
56
|
+
var import_react9 = __toESM(require_react(), 1);
|
|
51
57
|
var import_client = __toESM(require_client(), 1);
|
|
52
58
|
|
|
53
59
|
// src/desktop/icons.ts
|
|
@@ -386,7 +392,7 @@ function desktop(options) {
|
|
|
386
392
|
}
|
|
387
393
|
}),
|
|
388
394
|
p.action("desktop-settings", {
|
|
389
|
-
summary: "set the baba's theme, the
|
|
395
|
+
summary: "set the baba's own theme, as its frames in the Maker show it; voss's pages follow the theme in voss's settings",
|
|
390
396
|
args: { ...sessionArg, theme: s.optional(s.enum(...themes)) },
|
|
391
397
|
run: (w, a) => {
|
|
392
398
|
sync(w);
|
|
@@ -825,21 +831,21 @@ function Output({ value }) {
|
|
|
825
831
|
});
|
|
826
832
|
}
|
|
827
833
|
|
|
828
|
-
// src/gui/
|
|
834
|
+
// src/gui/instructions.tsx
|
|
829
835
|
var import_react3 = __toESM(require_react(), 1);
|
|
830
836
|
var jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
|
|
831
|
-
function
|
|
837
|
+
function Instructions({ manifest }) {
|
|
832
838
|
const { fire, read, ready, round } = useBabaState();
|
|
833
839
|
const [plan2, setPlan] = import_react3.useState(null);
|
|
834
840
|
const [error, setError] = import_react3.useState(null);
|
|
835
841
|
import_react3.useEffect(() => {
|
|
836
842
|
if (ready)
|
|
837
|
-
read("
|
|
843
|
+
read("agents-plan").then((p) => setPlan(p), setError);
|
|
838
844
|
}, [ready, round]);
|
|
839
845
|
if (!("pwStatus" in manifest.resources))
|
|
840
846
|
return /* @__PURE__ */ jsx_runtime3.jsx("p", {
|
|
841
847
|
className: "bv-muted",
|
|
842
|
-
children: "This baba has no
|
|
848
|
+
children: "This baba has no agents system."
|
|
843
849
|
});
|
|
844
850
|
if (!ready)
|
|
845
851
|
return /* @__PURE__ */ jsx_runtime3.jsx("p", {
|
|
@@ -872,7 +878,7 @@ function Promptware({ manifest }) {
|
|
|
872
878
|
children: [
|
|
873
879
|
/* @__PURE__ */ jsx_runtime3.jsx(Button, {
|
|
874
880
|
variant: "primary",
|
|
875
|
-
onClick: () => void act("
|
|
881
|
+
onClick: () => void act("agents-sync", {}).catch(() => {}),
|
|
876
882
|
children: "Sync now"
|
|
877
883
|
}),
|
|
878
884
|
plan2 && /* @__PURE__ */ jsx_runtime3.jsxs("span", {
|
|
@@ -903,17 +909,17 @@ function Promptware({ manifest }) {
|
|
|
903
909
|
});
|
|
904
910
|
}
|
|
905
911
|
function Declared({ manifest }) {
|
|
906
|
-
const pw = manifest.
|
|
912
|
+
const pw = manifest.instructions;
|
|
907
913
|
const skills = Object.entries(pw.skills);
|
|
908
914
|
return /* @__PURE__ */ jsx_runtime3.jsxs("section", {
|
|
909
915
|
className: "gui-section",
|
|
910
916
|
children: [
|
|
911
917
|
/* @__PURE__ */ jsx_runtime3.jsx("h2", {
|
|
912
|
-
children: "
|
|
918
|
+
children: "Instructions"
|
|
913
919
|
}),
|
|
914
920
|
!pw.context && skills.length === 0 && pw.hooks.length === 0 && /* @__PURE__ */ jsx_runtime3.jsx("p", {
|
|
915
921
|
className: "bv-muted",
|
|
916
|
-
children: "Nothing declared yet: give the baba a `context(...)`, a `skill(...)` or a `hook(...)` under
|
|
922
|
+
children: "Nothing declared yet: give the baba a `context(...)`, a `skill(...)` or a `hook(...)` under `.baba/agents/`."
|
|
917
923
|
}),
|
|
918
924
|
pw.context && /* @__PURE__ */ jsx_runtime3.jsxs("p", {
|
|
919
925
|
className: "bv-muted",
|
|
@@ -944,7 +950,7 @@ function Declared({ manifest }) {
|
|
|
944
950
|
}),
|
|
945
951
|
/* @__PURE__ */ jsx_runtime3.jsx("p", {
|
|
946
952
|
className: "bv-muted",
|
|
947
|
-
children: "The
|
|
953
|
+
children: "The agentic instructions is the baba's code: edit it under .baba/agents/; the files below follow."
|
|
948
954
|
})
|
|
949
955
|
]
|
|
950
956
|
});
|
|
@@ -982,11 +988,11 @@ function Harness({ manifest }) {
|
|
|
982
988
|
/* @__PURE__ */ jsx_runtime3.jsxs("p", {
|
|
983
989
|
className: "bv-muted",
|
|
984
990
|
children: [
|
|
985
|
-
"
|
|
991
|
+
"The .mdx files under .baba/agents/, each ",
|
|
986
992
|
/* @__PURE__ */ jsx_runtime3.jsx("code", {
|
|
987
|
-
children:
|
|
993
|
+
children: 'export const prompt = { kind: "context" | "skill", … }'
|
|
988
994
|
}),
|
|
989
|
-
"."
|
|
995
|
+
"; voss reads them on its own."
|
|
990
996
|
]
|
|
991
997
|
})
|
|
992
998
|
]
|
|
@@ -994,19 +1000,7 @@ function Harness({ manifest }) {
|
|
|
994
1000
|
}
|
|
995
1001
|
|
|
996
1002
|
// src/gui/levels.tsx
|
|
997
|
-
var
|
|
998
|
-
|
|
999
|
-
// src/gui/theme.ts
|
|
1000
|
-
var themeKey = "babavoss.theme";
|
|
1001
|
-
var early = `try{var t=localStorage.getItem(${JSON.stringify(themeKey)});if(t==="light"||t==="dark")document.documentElement.dataset.theme=t}catch(e){}`;
|
|
1002
|
-
function theme() {
|
|
1003
|
-
try {
|
|
1004
|
-
const v = localStorage.getItem(themeKey);
|
|
1005
|
-
if (v === "light" || v === "dark")
|
|
1006
|
-
return v;
|
|
1007
|
-
} catch {}
|
|
1008
|
-
return "system";
|
|
1009
|
-
}
|
|
1003
|
+
var import_react7 = __toESM(require_react(), 1);
|
|
1010
1004
|
|
|
1011
1005
|
// src/gui/wizard.tsx
|
|
1012
1006
|
var import_react4 = __toESM(require_react(), 1);
|
|
@@ -1039,7 +1033,6 @@ var short = (path, home, max = 52) => {
|
|
|
1039
1033
|
}
|
|
1040
1034
|
return t;
|
|
1041
1035
|
};
|
|
1042
|
-
var slug = (s2) => s2.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
1043
1036
|
var isTyping = (e) => e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || e.target instanceof HTMLSelectElement;
|
|
1044
1037
|
var Svg = ({ children, size = 16 }) => /* @__PURE__ */ jsx_runtime4.jsx("svg", {
|
|
1045
1038
|
width: size,
|
|
@@ -1115,15 +1108,12 @@ function useInView(list, active) {
|
|
|
1115
1108
|
list.current?.querySelector(`[data-i="${active}"]`)?.scrollIntoView({ block: "nearest" });
|
|
1116
1109
|
}, [list, active]);
|
|
1117
1110
|
}
|
|
1118
|
-
function Folders({ home, start, onBack,
|
|
1111
|
+
function Folders({ home, start, onBack, pick }) {
|
|
1119
1112
|
const [at, setAt] = import_react4.useState(null);
|
|
1120
1113
|
const [loading, setLoading] = import_react4.useState(true);
|
|
1121
1114
|
const [error, setError] = import_react4.useState(null);
|
|
1122
|
-
const [busy, setBusy] = import_react4.useState(null);
|
|
1123
1115
|
const [filter, setFilter] = import_react4.useState("");
|
|
1124
1116
|
const [active, setActive] = import_react4.useState(0);
|
|
1125
|
-
const [name, setName] = import_react4.useState("");
|
|
1126
|
-
const [title, setTitle] = import_react4.useState("");
|
|
1127
1117
|
const list = import_react4.useRef(null);
|
|
1128
1118
|
const filterRef = import_react4.useRef(null);
|
|
1129
1119
|
const homeDir = at?.home || home;
|
|
@@ -1135,9 +1125,6 @@ function Folders({ home, start, onBack, onOpened, onVerb }) {
|
|
|
1135
1125
|
setAt(b);
|
|
1136
1126
|
setError(null);
|
|
1137
1127
|
setFilter("");
|
|
1138
|
-
setName("");
|
|
1139
|
-
setTitle("");
|
|
1140
|
-
onVerb?.(b.known ? "open" : b.baba ? "remember" : "make");
|
|
1141
1128
|
if (!(document.activeElement instanceof HTMLInputElement) || document.activeElement === filterRef.current)
|
|
1142
1129
|
filterRef.current?.focus();
|
|
1143
1130
|
setActive(back >= 0 ? back + (b.parent ? 1 : 0) : 0);
|
|
@@ -1155,26 +1142,9 @@ function Folders({ home, start, onBack, onOpened, onVerb }) {
|
|
|
1155
1142
|
];
|
|
1156
1143
|
const cur = Math.min(active, Math.max(0, rows.length - 1));
|
|
1157
1144
|
useInView(list, cur);
|
|
1158
|
-
const act =
|
|
1159
|
-
if (
|
|
1160
|
-
|
|
1161
|
-
if (at.known) {
|
|
1162
|
-
const p = await getJson("/api/projects");
|
|
1163
|
-
const own = p.projects.find((x) => x.dir === at.path);
|
|
1164
|
-
if (own)
|
|
1165
|
-
onOpened(own.name);
|
|
1166
|
-
return;
|
|
1167
|
-
}
|
|
1168
|
-
const init = !at.baba;
|
|
1169
|
-
setBusy(init ? "Making the baba and installing its packages…" : "Opening the baba…");
|
|
1170
|
-
setError(null);
|
|
1171
|
-
try {
|
|
1172
|
-
const made = await postJson("/api/projects/add", { dir: at.path, init, ...name.trim() ? { name: name.trim() } : {}, ...title.trim() ? { title: title.trim() } : {} });
|
|
1173
|
-
onOpened(made.name);
|
|
1174
|
-
} catch (e) {
|
|
1175
|
-
setError(String(e instanceof Error ? e.message : e));
|
|
1176
|
-
setBusy(null);
|
|
1177
|
-
}
|
|
1145
|
+
const act = () => {
|
|
1146
|
+
if (at && !at.known)
|
|
1147
|
+
pick(at.path);
|
|
1178
1148
|
};
|
|
1179
1149
|
const enter = (i) => {
|
|
1180
1150
|
const r = rows[i];
|
|
@@ -1183,7 +1153,7 @@ function Folders({ home, start, onBack, onOpened, onVerb }) {
|
|
|
1183
1153
|
};
|
|
1184
1154
|
import_react4.useEffect(() => {
|
|
1185
1155
|
const key = (e) => {
|
|
1186
|
-
if (
|
|
1156
|
+
if (document.querySelector(".desktop-launcher"))
|
|
1187
1157
|
return;
|
|
1188
1158
|
const inField = isTyping(e) && e.target !== filterRef.current;
|
|
1189
1159
|
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
@@ -1236,7 +1206,6 @@ function Folders({ home, start, onBack, onOpened, onVerb }) {
|
|
|
1236
1206
|
}, [at, homeDir]);
|
|
1237
1207
|
const shown = crumbs.length > 5 ? [crumbs[0], { label: "…", path: crumbs[crumbs.length - 4].path }, ...crumbs.slice(-3)] : crumbs;
|
|
1238
1208
|
const here = at ? short(at.path, homeDir, 44) : "";
|
|
1239
|
-
const leaf = at ? at.path.split("/").filter(Boolean).pop() ?? "" : "";
|
|
1240
1209
|
return /* @__PURE__ */ jsx_runtime4.jsxs("div", {
|
|
1241
1210
|
className: "pk-pane pk-fade",
|
|
1242
1211
|
children: [
|
|
@@ -1245,7 +1214,7 @@ function Folders({ home, start, onBack, onOpened, onVerb }) {
|
|
|
1245
1214
|
children: [
|
|
1246
1215
|
/* @__PURE__ */ jsx_runtime4.jsx("span", {
|
|
1247
1216
|
className: "pk-strip-title",
|
|
1248
|
-
children: "
|
|
1217
|
+
children: "Choose a folder"
|
|
1249
1218
|
}),
|
|
1250
1219
|
/* @__PURE__ */ jsx_runtime4.jsx("span", {
|
|
1251
1220
|
className: "pk-gap"
|
|
@@ -1437,21 +1406,17 @@ function Folders({ home, start, onBack, onOpened, onVerb }) {
|
|
|
1437
1406
|
title: at?.path,
|
|
1438
1407
|
children: here
|
|
1439
1408
|
}),
|
|
1440
|
-
".
|
|
1409
|
+
". Add it to the list."
|
|
1441
1410
|
]
|
|
1442
1411
|
}) : /* @__PURE__ */ jsx_runtime4.jsxs(jsx_runtime4.Fragment, {
|
|
1443
1412
|
children: [
|
|
1444
|
-
"
|
|
1413
|
+
"There is no baba in ",
|
|
1445
1414
|
/* @__PURE__ */ jsx_runtime4.jsx("span", {
|
|
1446
1415
|
className: "pk-here",
|
|
1447
1416
|
title: at?.path,
|
|
1448
1417
|
children: here
|
|
1449
1418
|
}),
|
|
1450
|
-
",
|
|
1451
|
-
/* @__PURE__ */ jsx_runtime4.jsx("code", {
|
|
1452
|
-
children: ".baba/"
|
|
1453
|
-
}),
|
|
1454
|
-
" beside what is there."
|
|
1419
|
+
" yet: added, it is set up first."
|
|
1455
1420
|
]
|
|
1456
1421
|
})
|
|
1457
1422
|
})
|
|
@@ -1460,68 +1425,16 @@ function Folders({ home, start, onBack, onOpened, onVerb }) {
|
|
|
1460
1425
|
/* @__PURE__ */ jsx_runtime4.jsxs("div", {
|
|
1461
1426
|
className: "pk-dock-line",
|
|
1462
1427
|
children: [
|
|
1463
|
-
at && !at.baba && /* @__PURE__ */ jsx_runtime4.jsxs(jsx_runtime4.Fragment, {
|
|
1464
|
-
children: [
|
|
1465
|
-
/* @__PURE__ */ jsx_runtime4.jsxs("label", {
|
|
1466
|
-
className: "pk-field",
|
|
1467
|
-
children: [
|
|
1468
|
-
/* @__PURE__ */ jsx_runtime4.jsx("span", {
|
|
1469
|
-
children: "Name"
|
|
1470
|
-
}),
|
|
1471
|
-
/* @__PURE__ */ jsx_runtime4.jsx("input", {
|
|
1472
|
-
value: name,
|
|
1473
|
-
placeholder: slug(leaf) || "baba",
|
|
1474
|
-
spellCheck: false,
|
|
1475
|
-
disabled: !!busy,
|
|
1476
|
-
onChange: (e) => setName(e.target.value),
|
|
1477
|
-
onKeyDown: (e) => {
|
|
1478
|
-
if (e.key === "Enter") {
|
|
1479
|
-
e.preventDefault();
|
|
1480
|
-
act();
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
})
|
|
1484
|
-
]
|
|
1485
|
-
}),
|
|
1486
|
-
/* @__PURE__ */ jsx_runtime4.jsxs("label", {
|
|
1487
|
-
className: "pk-field is-wide",
|
|
1488
|
-
children: [
|
|
1489
|
-
/* @__PURE__ */ jsx_runtime4.jsx("span", {
|
|
1490
|
-
children: "Title"
|
|
1491
|
-
}),
|
|
1492
|
-
/* @__PURE__ */ jsx_runtime4.jsx("input", {
|
|
1493
|
-
value: title,
|
|
1494
|
-
placeholder: name.trim() || slug(leaf) || "baba",
|
|
1495
|
-
disabled: !!busy,
|
|
1496
|
-
onChange: (e) => setTitle(e.target.value),
|
|
1497
|
-
onKeyDown: (e) => {
|
|
1498
|
-
if (e.key === "Enter") {
|
|
1499
|
-
e.preventDefault();
|
|
1500
|
-
act();
|
|
1501
|
-
}
|
|
1502
|
-
}
|
|
1503
|
-
})
|
|
1504
|
-
]
|
|
1505
|
-
})
|
|
1506
|
-
]
|
|
1507
|
-
}),
|
|
1508
|
-
busy && /* @__PURE__ */ jsx_runtime4.jsxs("span", {
|
|
1509
|
-
className: "pk-busy",
|
|
1510
|
-
children: [
|
|
1511
|
-
/* @__PURE__ */ jsx_runtime4.jsx(Spinner, {}),
|
|
1512
|
-
busy
|
|
1513
|
-
]
|
|
1514
|
-
}),
|
|
1515
1428
|
/* @__PURE__ */ jsx_runtime4.jsx("span", {
|
|
1516
1429
|
className: "pk-gap"
|
|
1517
1430
|
}),
|
|
1518
1431
|
/* @__PURE__ */ jsx_runtime4.jsxs("button", {
|
|
1519
1432
|
type: "button",
|
|
1520
1433
|
className: "pk-primary",
|
|
1521
|
-
disabled: !at ||
|
|
1522
|
-
onClick:
|
|
1434
|
+
disabled: !at || loading || at.known,
|
|
1435
|
+
onClick: act,
|
|
1523
1436
|
children: [
|
|
1524
|
-
|
|
1437
|
+
at?.known ? "Already in the list" : "Add this folder",
|
|
1525
1438
|
/* @__PURE__ */ jsx_runtime4.jsx("kbd", {
|
|
1526
1439
|
className: "pk-kbd is-on-primary",
|
|
1527
1440
|
children: "⌘↵"
|
|
@@ -1567,76 +1480,1448 @@ function Marked({ text, words }) {
|
|
|
1567
1480
|
});
|
|
1568
1481
|
}
|
|
1569
1482
|
|
|
1570
|
-
// src/gui/
|
|
1483
|
+
// src/gui/setup.tsx
|
|
1484
|
+
var import_react5 = __toESM(require_react(), 1);
|
|
1485
|
+
|
|
1486
|
+
// src/baba/requirements.ts
|
|
1487
|
+
var PAGE_WORDS = new Set(["api", "assets", "view", "ws"]);
|
|
1488
|
+
var requirements = [
|
|
1489
|
+
{
|
|
1490
|
+
key: "name",
|
|
1491
|
+
title: "Name",
|
|
1492
|
+
summary: "The baba's address and its name at the shell: voss serves it at /NAME/, and the CLI reaches it as voss NAME from anywhere."
|
|
1493
|
+
}
|
|
1494
|
+
];
|
|
1495
|
+
var NAME = /^[a-z][a-z0-9-]*$/;
|
|
1496
|
+
function requirementError(key, value, taken = []) {
|
|
1497
|
+
if (key === "name") {
|
|
1498
|
+
if (!value)
|
|
1499
|
+
return "A baba needs a name.";
|
|
1500
|
+
if (!NAME.test(value))
|
|
1501
|
+
return "Lowercase letters, digits and dashes, starting with a letter.";
|
|
1502
|
+
if (PAGE_WORDS.has(value))
|
|
1503
|
+
return `/${value}/ is the page's own address; choose another.`;
|
|
1504
|
+
if (taken.includes(value))
|
|
1505
|
+
return `Another baba is already called ${value}.`;
|
|
1506
|
+
}
|
|
1507
|
+
return null;
|
|
1508
|
+
}
|
|
1509
|
+
var nameFrom = (dir) => (dir.split("/").filter(Boolean).pop() ?? "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").replace(/^[^a-z]+/, "");
|
|
1510
|
+
|
|
1511
|
+
// src/gui/setup.tsx
|
|
1571
1512
|
var jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
|
|
1572
|
-
function
|
|
1573
|
-
const
|
|
1513
|
+
function SetupWizard({ entry, home, taken, onCancel, onDone }) {
|
|
1514
|
+
const asks = requirements.filter((r) => entry.missing.includes(r.key));
|
|
1515
|
+
const steps = [...asks.map((r) => ({ kind: "ask", r })), { kind: "done" }];
|
|
1516
|
+
const [at, setAt] = import_react5.useState(0);
|
|
1517
|
+
const [values, setValues] = import_react5.useState(() => ({ name: nameFrom(entry.dir) }));
|
|
1518
|
+
const [busy, setBusy] = import_react5.useState(false);
|
|
1519
|
+
const [error, setError] = import_react5.useState(null);
|
|
1520
|
+
const field = import_react5.useRef(null), primary = import_react5.useRef(null);
|
|
1521
|
+
const step = steps[at];
|
|
1522
|
+
const why = (k) => requirementError(k, values[k] ?? "", taken);
|
|
1523
|
+
const blocked = step.kind === "ask" && why(step.r.key) !== null;
|
|
1574
1524
|
import_react5.useEffect(() => {
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1525
|
+
if (field.current) {
|
|
1526
|
+
field.current.focus();
|
|
1527
|
+
field.current.select();
|
|
1528
|
+
} else
|
|
1529
|
+
primary.current?.focus();
|
|
1530
|
+
}, [at]);
|
|
1531
|
+
const next = async () => {
|
|
1532
|
+
if (busy || blocked)
|
|
1533
|
+
return;
|
|
1534
|
+
if (step.kind === "ask") {
|
|
1535
|
+
setAt(at + 1);
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
setBusy(true);
|
|
1539
|
+
setError(null);
|
|
1540
|
+
try {
|
|
1541
|
+
const j = await postJson("/api/projects/setup", { dir: entry.dir, values });
|
|
1542
|
+
if (j.name)
|
|
1543
|
+
onDone(j.name);
|
|
1544
|
+
else
|
|
1545
|
+
throw new Error("voss kept it to set up: it still lacks something");
|
|
1546
|
+
} catch (e) {
|
|
1547
|
+
setError(String(e instanceof Error ? e.message : e));
|
|
1548
|
+
setBusy(false);
|
|
1549
|
+
}
|
|
1550
|
+
};
|
|
1551
|
+
const back = () => {
|
|
1552
|
+
if (busy)
|
|
1553
|
+
return;
|
|
1554
|
+
if (at > 0)
|
|
1555
|
+
setAt(at - 1);
|
|
1556
|
+
else
|
|
1557
|
+
onCancel();
|
|
1558
|
+
};
|
|
1559
|
+
import_react5.useEffect(() => {
|
|
1560
|
+
const key = (e) => {
|
|
1561
|
+
if (e.key === "Escape") {
|
|
1562
|
+
e.preventDefault();
|
|
1563
|
+
back();
|
|
1564
|
+
}
|
|
1565
|
+
};
|
|
1566
|
+
addEventListener("keydown", key);
|
|
1567
|
+
return () => removeEventListener("keydown", key);
|
|
1568
|
+
});
|
|
1569
|
+
const where = tilde(entry.dir, home);
|
|
1570
|
+
return /* @__PURE__ */ jsx_runtime5.jsxs("form", {
|
|
1571
|
+
className: "sw-card",
|
|
1572
|
+
"aria-label": "Set up a baba",
|
|
1573
|
+
onSubmit: (e) => {
|
|
1574
|
+
e.preventDefault();
|
|
1575
|
+
next();
|
|
1576
|
+
},
|
|
1577
|
+
children: [
|
|
1578
|
+
/* @__PURE__ */ jsx_runtime5.jsxs("header", {
|
|
1579
|
+
className: "sw-head",
|
|
1580
|
+
children: [
|
|
1581
|
+
/* @__PURE__ */ jsx_runtime5.jsx(Eyes, {
|
|
1582
|
+
size: 28
|
|
1583
|
+
}),
|
|
1584
|
+
/* @__PURE__ */ jsx_runtime5.jsxs("div", {
|
|
1585
|
+
className: "sw-head-text",
|
|
1586
|
+
children: [
|
|
1587
|
+
/* @__PURE__ */ jsx_runtime5.jsx("h1", {
|
|
1588
|
+
children: "Set up a baba"
|
|
1589
|
+
}),
|
|
1590
|
+
/* @__PURE__ */ jsx_runtime5.jsx("p", {
|
|
1591
|
+
title: entry.dir,
|
|
1592
|
+
children: where
|
|
1593
|
+
})
|
|
1594
|
+
]
|
|
1595
|
+
})
|
|
1596
|
+
]
|
|
1597
|
+
}),
|
|
1598
|
+
/* @__PURE__ */ jsx_runtime5.jsx("ol", {
|
|
1599
|
+
className: "sw-steps",
|
|
1600
|
+
"aria-label": "Steps",
|
|
1601
|
+
children: steps.map((s2, i) => /* @__PURE__ */ jsx_runtime5.jsxs("li", {
|
|
1602
|
+
className: i === at ? "is-here" : i < at ? "is-done" : undefined,
|
|
1603
|
+
"aria-current": i === at ? "step" : undefined,
|
|
1604
|
+
children: [
|
|
1605
|
+
/* @__PURE__ */ jsx_runtime5.jsx("span", {
|
|
1606
|
+
className: "sw-step-dot",
|
|
1607
|
+
children: i + 1
|
|
1608
|
+
}),
|
|
1609
|
+
s2.kind === "ask" ? s2.r.title : entry.baba ? "Save" : "Create"
|
|
1610
|
+
]
|
|
1611
|
+
}, i))
|
|
1612
|
+
}),
|
|
1613
|
+
/* @__PURE__ */ jsx_runtime5.jsxs("div", {
|
|
1614
|
+
className: "sw-body",
|
|
1615
|
+
children: [
|
|
1616
|
+
step.kind === "ask" ? /* @__PURE__ */ jsx_runtime5.jsxs(jsx_runtime5.Fragment, {
|
|
1617
|
+
children: [
|
|
1618
|
+
/* @__PURE__ */ jsx_runtime5.jsx("label", {
|
|
1619
|
+
className: "sw-label",
|
|
1620
|
+
htmlFor: "sw-field",
|
|
1621
|
+
children: step.r.title
|
|
1622
|
+
}),
|
|
1623
|
+
/* @__PURE__ */ jsx_runtime5.jsx("p", {
|
|
1624
|
+
className: "sw-summary",
|
|
1625
|
+
children: step.r.summary
|
|
1626
|
+
}),
|
|
1627
|
+
/* @__PURE__ */ jsx_runtime5.jsx("input", {
|
|
1628
|
+
id: "sw-field",
|
|
1629
|
+
ref: field,
|
|
1630
|
+
className: `sw-input${why(step.r.key) ? " is-wrong" : ""}`,
|
|
1631
|
+
value: values[step.r.key] ?? "",
|
|
1632
|
+
spellCheck: false,
|
|
1633
|
+
autoComplete: "off",
|
|
1634
|
+
disabled: busy,
|
|
1635
|
+
onChange: (e) => setValues({ ...values, [step.r.key]: e.target.value.toLowerCase() })
|
|
1636
|
+
}),
|
|
1637
|
+
/* @__PURE__ */ jsx_runtime5.jsx("p", {
|
|
1638
|
+
className: `sw-hint${why(step.r.key) ? " is-wrong" : ""}`,
|
|
1639
|
+
children: why(step.r.key) ?? /* @__PURE__ */ jsx_runtime5.jsxs(jsx_runtime5.Fragment, {
|
|
1640
|
+
children: [
|
|
1641
|
+
"It opens at ",
|
|
1642
|
+
/* @__PURE__ */ jsx_runtime5.jsxs("code", {
|
|
1643
|
+
children: [
|
|
1644
|
+
"/",
|
|
1645
|
+
values[step.r.key],
|
|
1646
|
+
"/"
|
|
1647
|
+
]
|
|
1648
|
+
}),
|
|
1649
|
+
"."
|
|
1650
|
+
]
|
|
1651
|
+
})
|
|
1652
|
+
})
|
|
1653
|
+
]
|
|
1654
|
+
}) : /* @__PURE__ */ jsx_runtime5.jsxs(jsx_runtime5.Fragment, {
|
|
1655
|
+
children: [
|
|
1656
|
+
/* @__PURE__ */ jsx_runtime5.jsx("p", {
|
|
1657
|
+
className: "sw-summary",
|
|
1658
|
+
children: entry.baba ? /* @__PURE__ */ jsx_runtime5.jsxs(jsx_runtime5.Fragment, {
|
|
1659
|
+
children: [
|
|
1660
|
+
"voss writes what it needs into ",
|
|
1661
|
+
/* @__PURE__ */ jsx_runtime5.jsx("code", {
|
|
1662
|
+
children: ".baba/package.json"
|
|
1663
|
+
}),
|
|
1664
|
+
" and leaves the rest of it as it is."
|
|
1665
|
+
]
|
|
1666
|
+
}) : /* @__PURE__ */ jsx_runtime5.jsxs(jsx_runtime5.Fragment, {
|
|
1667
|
+
children: [
|
|
1668
|
+
"voss makes a baba here: ",
|
|
1669
|
+
/* @__PURE__ */ jsx_runtime5.jsx("code", {
|
|
1670
|
+
children: ".baba/"
|
|
1671
|
+
}),
|
|
1672
|
+
" beside what the folder holds, with a first system and its spec, then installs its packages. It takes a moment."
|
|
1673
|
+
]
|
|
1674
|
+
})
|
|
1675
|
+
}),
|
|
1676
|
+
/* @__PURE__ */ jsx_runtime5.jsxs("dl", {
|
|
1677
|
+
className: "sw-review",
|
|
1678
|
+
children: [
|
|
1679
|
+
asks.map((r) => /* @__PURE__ */ jsx_runtime5.jsxs("div", {
|
|
1680
|
+
children: [
|
|
1681
|
+
/* @__PURE__ */ jsx_runtime5.jsx("dt", {
|
|
1682
|
+
children: r.title
|
|
1683
|
+
}),
|
|
1684
|
+
/* @__PURE__ */ jsx_runtime5.jsx("dd", {
|
|
1685
|
+
children: /* @__PURE__ */ jsx_runtime5.jsx("code", {
|
|
1686
|
+
children: values[r.key]
|
|
1687
|
+
})
|
|
1688
|
+
})
|
|
1689
|
+
]
|
|
1690
|
+
}, r.key)),
|
|
1691
|
+
/* @__PURE__ */ jsx_runtime5.jsxs("div", {
|
|
1692
|
+
children: [
|
|
1693
|
+
/* @__PURE__ */ jsx_runtime5.jsx("dt", {
|
|
1694
|
+
children: "Folder"
|
|
1695
|
+
}),
|
|
1696
|
+
/* @__PURE__ */ jsx_runtime5.jsx("dd", {
|
|
1697
|
+
children: /* @__PURE__ */ jsx_runtime5.jsx("code", {
|
|
1698
|
+
title: entry.dir,
|
|
1699
|
+
children: where
|
|
1700
|
+
})
|
|
1701
|
+
})
|
|
1702
|
+
]
|
|
1703
|
+
})
|
|
1704
|
+
]
|
|
1705
|
+
})
|
|
1706
|
+
]
|
|
1707
|
+
}),
|
|
1708
|
+
error && /* @__PURE__ */ jsx_runtime5.jsx("p", {
|
|
1709
|
+
className: "sw-error",
|
|
1710
|
+
role: "alert",
|
|
1711
|
+
children: error
|
|
1712
|
+
})
|
|
1713
|
+
]
|
|
1714
|
+
}),
|
|
1715
|
+
/* @__PURE__ */ jsx_runtime5.jsxs("footer", {
|
|
1716
|
+
className: "sw-foot",
|
|
1717
|
+
children: [
|
|
1718
|
+
/* @__PURE__ */ jsx_runtime5.jsx("button", {
|
|
1719
|
+
type: "button",
|
|
1720
|
+
className: "sw-button is-quiet",
|
|
1721
|
+
disabled: busy,
|
|
1722
|
+
onClick: back,
|
|
1723
|
+
children: at > 0 ? "Back" : "Cancel"
|
|
1724
|
+
}),
|
|
1725
|
+
/* @__PURE__ */ jsx_runtime5.jsx("span", {
|
|
1726
|
+
className: "sw-gap"
|
|
1727
|
+
}),
|
|
1728
|
+
busy && /* @__PURE__ */ jsx_runtime5.jsxs("span", {
|
|
1729
|
+
className: "sw-busy",
|
|
1730
|
+
children: [
|
|
1731
|
+
/* @__PURE__ */ jsx_runtime5.jsx("span", {
|
|
1732
|
+
className: "pk-spin",
|
|
1733
|
+
"aria-hidden": "true"
|
|
1734
|
+
}),
|
|
1735
|
+
entry.baba ? "Saving…" : "Installing packages…"
|
|
1736
|
+
]
|
|
1737
|
+
}),
|
|
1738
|
+
/* @__PURE__ */ jsx_runtime5.jsx("button", {
|
|
1739
|
+
ref: primary,
|
|
1740
|
+
type: "submit",
|
|
1741
|
+
className: "sw-button is-primary",
|
|
1742
|
+
disabled: busy || blocked,
|
|
1743
|
+
children: step.kind === "ask" ? "Continue" : entry.baba ? "Save and open" : "Create and open"
|
|
1744
|
+
})
|
|
1745
|
+
]
|
|
1746
|
+
})
|
|
1747
|
+
]
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
// src/gui/voss-settings.ts
|
|
1752
|
+
var import_react6 = __toESM(require_react(), 1);
|
|
1753
|
+
|
|
1754
|
+
// src/gui/theme.ts
|
|
1755
|
+
var themeKey = "babavoss.theme";
|
|
1756
|
+
var early = `try{var t=localStorage.getItem(${JSON.stringify(themeKey)});if(t==="light"||t==="dark")document.documentElement.dataset.theme=t}catch(e){}`;
|
|
1757
|
+
var deskColors = { light: "#ECE4D8", dark: "#151312" };
|
|
1758
|
+
var firstPaint = `html{background:${deskColors.light};color-scheme:light dark}@media (prefers-color-scheme:dark){html:not([data-theme="light"]){background:${deskColors.dark}}}html[data-theme="dark"]{background:${deskColors.dark}}`;
|
|
1759
|
+
function setTheme(next) {
|
|
1760
|
+
try {
|
|
1761
|
+
if (next === "system")
|
|
1762
|
+
localStorage.removeItem(themeKey);
|
|
1763
|
+
else
|
|
1764
|
+
localStorage.setItem(themeKey, next);
|
|
1765
|
+
} catch {}
|
|
1766
|
+
if (next === "system")
|
|
1767
|
+
delete document.documentElement.dataset.theme;
|
|
1768
|
+
else
|
|
1769
|
+
document.documentElement.dataset.theme = next;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
// src/gui/voss-settings.ts
|
|
1773
|
+
var current = null;
|
|
1774
|
+
var saves = 0;
|
|
1775
|
+
var listeners = new Set;
|
|
1776
|
+
var publish = (s2) => {
|
|
1777
|
+
current = s2;
|
|
1778
|
+
setTheme(s2.theme);
|
|
1779
|
+
for (const l of listeners)
|
|
1780
|
+
l();
|
|
1781
|
+
};
|
|
1782
|
+
async function fetchSettings() {
|
|
1783
|
+
const at = saves;
|
|
1784
|
+
try {
|
|
1785
|
+
const r = await fetch("/api/settings", { headers: apiHeaders() });
|
|
1786
|
+
if (r.ok) {
|
|
1787
|
+
const s2 = await r.json();
|
|
1788
|
+
if (at === saves)
|
|
1789
|
+
publish(s2);
|
|
1790
|
+
}
|
|
1791
|
+
} catch {}
|
|
1792
|
+
}
|
|
1793
|
+
async function saveSettings(change) {
|
|
1794
|
+
saves++;
|
|
1795
|
+
const r = await fetch("/api/settings", { method: "POST", headers: { "content-type": "application/json", ...apiHeaders() }, body: JSON.stringify(change) });
|
|
1796
|
+
const j = await r.json();
|
|
1797
|
+
if (!r.ok || j.error)
|
|
1798
|
+
throw new Error(j.error?.message ?? r.statusText);
|
|
1799
|
+
publish(j);
|
|
1800
|
+
return j;
|
|
1801
|
+
}
|
|
1802
|
+
var watching = 0;
|
|
1803
|
+
function useVossSettings() {
|
|
1804
|
+
import_react6.useEffect(() => {
|
|
1805
|
+
if (watching++ === 0) {
|
|
1806
|
+
fetchSettings();
|
|
1807
|
+
addEventListener("focus", onFront);
|
|
1808
|
+
document.addEventListener("visibilitychange", onFront);
|
|
1809
|
+
}
|
|
1810
|
+
return () => {
|
|
1811
|
+
if (--watching === 0) {
|
|
1812
|
+
removeEventListener("focus", onFront);
|
|
1813
|
+
document.removeEventListener("visibilitychange", onFront);
|
|
1814
|
+
}
|
|
1815
|
+
};
|
|
1816
|
+
}, []);
|
|
1817
|
+
return import_react6.useSyncExternalStore((l) => {
|
|
1818
|
+
listeners.add(l);
|
|
1819
|
+
return () => listeners.delete(l);
|
|
1820
|
+
}, () => current);
|
|
1821
|
+
}
|
|
1822
|
+
var onFront = () => {
|
|
1823
|
+
if (document.visibilityState === "visible")
|
|
1824
|
+
fetchSettings();
|
|
1825
|
+
};
|
|
1826
|
+
|
|
1827
|
+
// src/gui/lockup.ts
|
|
1828
|
+
var lockup = {
|
|
1829
|
+
viewBox: "0 0 745 160",
|
|
1830
|
+
tile: { x: 50, y: 30, width: 100, height: 100, rx: 50 },
|
|
1831
|
+
symbol: { transform: "translate(50.00 30.00) scale(1.0000)", eyes: [{ cx: 39.772, cy: 50, r: 18 }, { cx: 77.5, cy: 50, r: 12.728 }] },
|
|
1832
|
+
word: { transform: "translate(195.00 114.90)", d: "M8 0L8-69.80L32.30-69.80Q42.20-69.80 47.55-64.85Q52.90-59.90 52.90-51.40Q52.90-45.40 49.95-41.80Q47-38.20 41.60-36.60L41.60-36.10Q47.90-34.60 51.55-30.65Q55.20-26.70 55.20-19.50Q55.20-15.10 53.75-11.55Q52.30-8 49.65-5.40Q47-2.80 43.25-1.40Q39.50 0 34.80 0L8 0M20.80-9.50L30.80-9.50Q36.30-9.50 39.05-11.55Q41.80-13.60 41.80-18.60L41.80-21.90Q41.80-26.80 39.05-28.85Q36.30-30.90 30.80-30.90L20.80-30.90L20.80-9.50M20.80-40L29.10-40Q34.40-40 36.95-41.90Q39.50-43.80 39.50-48.50L39.50-51.80Q39.50-56.50 36.95-58.40Q34.40-60.30 29.10-60.30L20.80-60.30 M116.50 0L109 0Q104.30 0 101.75-2.35Q99.20-4.70 98.70-8.90L98.20-8.90Q96.80-4.10 92.70-1.45Q88.60 1.20 82.60 1.20Q74.80 1.20 70.20-2.90Q65.60-7 65.60-14.30Q65.60-29.90 88.50-29.90L97.60-29.90L97.60-33.30Q97.60-38.20 95.20-40.70Q92.80-43.20 87.40-43.20Q82.50-43.20 79.50-41.30Q76.50-39.40 74.40-36.40L67.10-42.60Q69.50-46.90 74.85-49.85Q80.20-52.80 88.70-52.80Q98.90-52.80 104.65-48.05Q110.40-43.30 110.40-33.90L110.40-9.60L116.50-9.60L116.50 0M86.90-7.60Q91.50-7.60 94.55-9.75Q97.60-11.90 97.60-15.60L97.60-22.50L88.80-22.50Q78.30-22.50 78.30-15.90L78.30-13.90Q78.30-10.80 80.60-9.20Q82.90-7.60 86.90-7.60 M126.90 0L126.90-74L139.70-74L139.70-42.50L140.40-42.50Q142.50-47.20 146.15-50Q149.80-52.80 155.80-52.80Q160.20-52.80 163.85-51.15Q167.50-49.50 170.10-46.15Q172.70-42.80 174.10-37.70Q175.50-32.60 175.50-25.80Q175.50-19 174.10-13.90Q172.70-8.80 170.10-5.45Q167.50-2.10 163.85-0.45Q160.20 1.20 155.80 1.20Q149.80 1.20 146.15-1.60Q142.50-4.40 140.40-9.10L139.70-9.10L139.70 0L126.90 0M150.40-9Q156-9 159.05-12.40Q162.10-15.80 162.10-21.70L162.10-29.90Q162.10-35.80 159.05-39.20Q156-42.60 150.40-42.60Q146-42.60 142.85-40.45Q139.70-38.30 139.70-33.90L139.70-17.70Q139.70-13.30 142.85-11.15Q146-9 150.40-9 M236.50 0L229 0Q224.30 0 221.75-2.35Q219.20-4.70 218.70-8.90L218.20-8.90Q216.80-4.10 212.70-1.45Q208.60 1.20 202.60 1.20Q194.80 1.20 190.20-2.90Q185.60-7 185.60-14.30Q185.60-29.90 208.50-29.90L217.60-29.90L217.60-33.30Q217.60-38.20 215.20-40.70Q212.80-43.20 207.40-43.20Q202.50-43.20 199.50-41.30Q196.50-39.40 194.40-36.40L187.10-42.60Q189.50-46.90 194.85-49.85Q200.20-52.80 208.70-52.80Q218.90-52.80 224.65-48.05Q230.40-43.30 230.40-33.90L230.40-9.60L236.50-9.60L236.50 0M206.90-7.60Q211.50-7.60 214.55-9.75Q217.60-11.90 217.60-15.60L217.60-22.50L208.80-22.50Q198.30-22.50 198.30-15.90L198.30-13.90Q198.30-10.80 200.60-9.20Q202.90-7.60 206.90-7.60 M299.20 0L280.80 0L261.70-69.80L276.10-69.80L284.80-34.50L289.90-12.50L290.60-12.50L295.80-34.50L304.60-69.80L318.30-69.80 M350 1.20Q344.10 1.20 339.45-0.70Q334.80-2.60 331.55-6.10Q328.30-9.60 326.55-14.60Q324.80-19.60 324.80-25.80Q324.80-32 326.55-37Q328.30-42 331.55-45.50Q334.80-49 339.45-50.90Q344.10-52.80 350-52.80Q355.80-52.80 360.50-50.90Q365.20-49 368.45-45.50Q371.70-42 373.45-37Q375.20-32 375.20-25.80Q375.20-19.60 373.45-14.60Q371.70-9.60 368.45-6.10Q365.20-2.60 360.50-0.70Q355.80 1.20 350 1.20M350-8.60Q355.50-8.60 358.70-11.95Q361.90-15.30 361.90-21.80L361.90-29.80Q361.90-36.30 358.70-39.65Q355.50-43 350-43Q344.50-43 341.30-39.65Q338.10-36.30 338.10-29.80L338.10-21.80Q338.10-15.30 341.30-11.95Q344.50-8.60 350-8.60 M409.80 1.20Q401.30 1.20 395.10-1.45Q388.90-4.10 385.40-8.60L392.90-15.40Q396.10-11.90 400.25-10Q404.40-8.10 409.90-8.10Q414.70-8.10 417.60-9.70Q420.50-11.30 420.50-14.60Q420.50-17.40 418.55-18.40Q416.60-19.40 413.40-19.90L405.10-21.20Q401.90-21.70 398.85-22.65Q395.80-23.60 393.45-25.30Q391.10-27 389.70-29.65Q388.30-32.30 388.30-36.10Q388.30-44.20 394.35-48.50Q400.40-52.80 411-52.80Q418.50-52.80 423.75-50.70Q429-48.60 432.40-44.80L425.70-37.40Q423.50-39.80 419.85-41.65Q416.20-43.50 410.60-43.50Q400.80-43.50 400.80-37.40Q400.80-34.60 402.80-33.55Q404.80-32.50 408-32L416.20-30.70Q419.50-30.20 422.55-29.25Q425.60-28.30 427.95-26.60Q430.30-24.90 431.70-22.30Q433.10-19.70 433.10-15.90Q433.10-7.90 426.95-3.35Q420.80 1.20 409.80 1.20 M469.80 1.20Q461.30 1.20 455.10-1.45Q448.90-4.10 445.40-8.60L452.90-15.40Q456.10-11.90 460.25-10Q464.40-8.10 469.90-8.10Q474.70-8.10 477.60-9.70Q480.50-11.30 480.50-14.60Q480.50-17.40 478.55-18.40Q476.60-19.40 473.40-19.90L465.10-21.20Q461.90-21.70 458.85-22.65Q455.80-23.60 453.45-25.30Q451.10-27 449.70-29.65Q448.30-32.30 448.30-36.10Q448.30-44.20 454.35-48.50Q460.40-52.80 471-52.80Q478.50-52.80 483.75-50.70Q489-48.60 492.40-44.80L485.70-37.40Q483.50-39.80 479.85-41.65Q476.20-43.50 470.60-43.50Q460.80-43.50 460.80-37.40Q460.80-34.60 462.80-33.55Q464.80-32.50 468-32L476.20-30.70Q479.50-30.20 482.55-29.25Q485.60-28.30 487.95-26.60Q490.30-24.90 491.70-22.30Q493.10-19.70 493.10-15.90Q493.10-7.90 486.95-3.35Q480.80 1.20 469.80 1.20" }
|
|
1833
|
+
};
|
|
1834
|
+
|
|
1835
|
+
// src/gui/levels.tsx
|
|
1836
|
+
var jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
|
|
1837
|
+
function useProjects() {
|
|
1838
|
+
const [listed, setListed] = import_react7.useState(null);
|
|
1839
|
+
const reload = async () => {
|
|
1840
|
+
const j = await getJson("/api/projects");
|
|
1841
|
+
const l = { projects: j.projects, pending: j.pending ?? [], home: j.home ?? "" };
|
|
1842
|
+
setListed(l);
|
|
1843
|
+
return l;
|
|
1844
|
+
};
|
|
1845
|
+
import_react7.useEffect(() => {
|
|
1846
|
+
reload().catch(() => setListed({ projects: [], pending: [], home: "" }));
|
|
1847
|
+
}, []);
|
|
1848
|
+
return { listed, reload, set: setListed };
|
|
1849
|
+
}
|
|
1850
|
+
function pickerRows(projects, pending) {
|
|
1851
|
+
const all = [
|
|
1852
|
+
...projects.map((p) => ({ kind: "baba", p, dir: p.dir ?? "", depth: 0 })),
|
|
1853
|
+
...pending.map((e) => ({ kind: "pending", e, dir: e.dir, depth: 0 }))
|
|
1854
|
+
];
|
|
1855
|
+
const parentOf = (r) => r.kind === "baba" ? r.p.parent : r.e.parent;
|
|
1856
|
+
const names = new Set(projects.map((p) => p.name));
|
|
1857
|
+
const out = [];
|
|
1858
|
+
const place = (r, depth) => {
|
|
1859
|
+
out.push({ ...r, depth });
|
|
1860
|
+
if (r.kind === "baba")
|
|
1861
|
+
for (const c of all.filter((x) => parentOf(x) === r.p.name))
|
|
1862
|
+
place(c, depth + 1);
|
|
1863
|
+
};
|
|
1864
|
+
for (const r of all) {
|
|
1865
|
+
const up = parentOf(r);
|
|
1866
|
+
if (!up || !names.has(up))
|
|
1867
|
+
place(r, 0);
|
|
1868
|
+
}
|
|
1869
|
+
return out;
|
|
1870
|
+
}
|
|
1871
|
+
var href = (name) => `/${encodeURIComponent(name)}/`;
|
|
1872
|
+
var setupHref = (dir) => `/?setup=${encodeURIComponent(dir)}`;
|
|
1873
|
+
var setupAsked = () => new URLSearchParams(location.search).get("setup");
|
|
1874
|
+
function Root() {
|
|
1875
|
+
const { listed, reload, set } = useProjects();
|
|
1876
|
+
useVossSettings();
|
|
1877
|
+
const [asked, setAsked] = import_react7.useState(setupAsked);
|
|
1878
|
+
import_react7.useEffect(() => {
|
|
1879
|
+
const back = () => setAsked(setupAsked());
|
|
1880
|
+
addEventListener("popstate", back);
|
|
1881
|
+
return () => removeEventListener("popstate", back);
|
|
1882
|
+
}, []);
|
|
1883
|
+
const go = (dir) => {
|
|
1884
|
+
history.pushState(null, "", dir ? setupHref(dir) : "/");
|
|
1885
|
+
setAsked(dir);
|
|
1886
|
+
};
|
|
1887
|
+
import_react7.useEffect(() => {
|
|
1888
|
+
document.title = asked ? "Set up · voss" : "voss";
|
|
1889
|
+
}, [asked]);
|
|
1890
|
+
const ready = asked ? listed?.projects.find((p) => p.dir === asked) : undefined;
|
|
1891
|
+
import_react7.useEffect(() => {
|
|
1892
|
+
if (ready)
|
|
1893
|
+
location.replace(href(ready.name));
|
|
1894
|
+
}, [ready]);
|
|
1895
|
+
if (!listed || ready)
|
|
1896
|
+
return /* @__PURE__ */ jsx_runtime6.jsx("div", {
|
|
1897
|
+
className: "gui-view rt"
|
|
1582
1898
|
});
|
|
1899
|
+
if (asked) {
|
|
1900
|
+
const entry = listed.pending.find((e) => e.dir === asked);
|
|
1901
|
+
return /* @__PURE__ */ jsx_runtime6.jsx("div", {
|
|
1902
|
+
className: "gui-view rt rt-center",
|
|
1903
|
+
children: entry && !entry.error ? /* @__PURE__ */ jsx_runtime6.jsx(SetupWizard, {
|
|
1904
|
+
entry,
|
|
1905
|
+
home: listed.home,
|
|
1906
|
+
taken: listed.projects.map((p) => p.name),
|
|
1907
|
+
onCancel: () => go(null),
|
|
1908
|
+
onDone: (name) => location.assign(href(name))
|
|
1909
|
+
}) : /* @__PURE__ */ jsx_runtime6.jsxs("div", {
|
|
1910
|
+
className: "sw-card sw-gone",
|
|
1911
|
+
children: [
|
|
1912
|
+
/* @__PURE__ */ jsx_runtime6.jsx("p", {
|
|
1913
|
+
children: entry?.error ? /* @__PURE__ */ jsx_runtime6.jsxs(jsx_runtime6.Fragment, {
|
|
1914
|
+
children: [
|
|
1915
|
+
"The baba in ",
|
|
1916
|
+
/* @__PURE__ */ jsx_runtime6.jsx("code", {
|
|
1917
|
+
children: tilde(asked, listed.home)
|
|
1918
|
+
}),
|
|
1919
|
+
" did not open: ",
|
|
1920
|
+
entry.error
|
|
1921
|
+
]
|
|
1922
|
+
}) : /* @__PURE__ */ jsx_runtime6.jsxs(jsx_runtime6.Fragment, {
|
|
1923
|
+
children: [
|
|
1924
|
+
"voss does not remember ",
|
|
1925
|
+
/* @__PURE__ */ jsx_runtime6.jsx("code", {
|
|
1926
|
+
children: tilde(asked, listed.home)
|
|
1927
|
+
}),
|
|
1928
|
+
"."
|
|
1929
|
+
]
|
|
1930
|
+
})
|
|
1931
|
+
}),
|
|
1932
|
+
/* @__PURE__ */ jsx_runtime6.jsx("button", {
|
|
1933
|
+
type: "button",
|
|
1934
|
+
className: "sw-button",
|
|
1935
|
+
onClick: () => go(null),
|
|
1936
|
+
children: "Back to the babas"
|
|
1937
|
+
})
|
|
1938
|
+
]
|
|
1939
|
+
})
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
return /* @__PURE__ */ jsx_runtime6.jsx(Picker, {
|
|
1943
|
+
listed,
|
|
1944
|
+
reload,
|
|
1945
|
+
set,
|
|
1946
|
+
setup: go
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1949
|
+
function VossVersion() {
|
|
1950
|
+
const [v, setV] = import_react7.useState(null);
|
|
1951
|
+
import_react7.useEffect(() => {
|
|
1952
|
+
getJson("/api/voss").then(setV, () => {});
|
|
1953
|
+
}, []);
|
|
1954
|
+
if (!v)
|
|
1955
|
+
return null;
|
|
1956
|
+
return /* @__PURE__ */ jsx_runtime6.jsxs("span", {
|
|
1957
|
+
className: "rt-version",
|
|
1958
|
+
title: v.sha ? `voss ${v.version}, ${v.sha.slice(0, 12)}` : `voss ${v.version}`,
|
|
1959
|
+
children: [
|
|
1960
|
+
/* @__PURE__ */ jsx_runtime6.jsxs("span", {
|
|
1961
|
+
className: "rt-version-text",
|
|
1962
|
+
children: [
|
|
1963
|
+
"v",
|
|
1964
|
+
v.version
|
|
1965
|
+
]
|
|
1966
|
+
}),
|
|
1967
|
+
v.dev && /* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
1968
|
+
className: "rt-tag",
|
|
1969
|
+
children: /* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
1970
|
+
className: "rt-version-text",
|
|
1971
|
+
children: "checkout"
|
|
1972
|
+
})
|
|
1973
|
+
})
|
|
1974
|
+
]
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1977
|
+
function Lockup() {
|
|
1978
|
+
const t = lockup.tile, w = Number(lockup.viewBox.split(" ")[2]);
|
|
1979
|
+
return /* @__PURE__ */ jsx_runtime6.jsxs("svg", {
|
|
1980
|
+
className: "rt-lockup",
|
|
1981
|
+
viewBox: `${t.x} ${t.y} ${w - 2 * t.x} ${t.height}`,
|
|
1982
|
+
role: "img",
|
|
1983
|
+
"aria-label": "Baba Voss",
|
|
1984
|
+
children: [
|
|
1985
|
+
/* @__PURE__ */ jsx_runtime6.jsxs("mask", {
|
|
1986
|
+
id: "rt-lockup-eyes",
|
|
1987
|
+
maskUnits: "userSpaceOnUse",
|
|
1988
|
+
x: t.x,
|
|
1989
|
+
y: t.y,
|
|
1990
|
+
width: t.width,
|
|
1991
|
+
height: t.height,
|
|
1992
|
+
children: [
|
|
1993
|
+
/* @__PURE__ */ jsx_runtime6.jsx("rect", {
|
|
1994
|
+
x: t.x,
|
|
1995
|
+
y: t.y,
|
|
1996
|
+
width: t.width,
|
|
1997
|
+
height: t.height,
|
|
1998
|
+
fill: "#fff"
|
|
1999
|
+
}),
|
|
2000
|
+
/* @__PURE__ */ jsx_runtime6.jsx("g", {
|
|
2001
|
+
transform: lockup.symbol.transform,
|
|
2002
|
+
fill: "#000",
|
|
2003
|
+
children: lockup.symbol.eyes.map((e, i) => /* @__PURE__ */ jsx_runtime6.jsx("circle", {
|
|
2004
|
+
...e
|
|
2005
|
+
}, i))
|
|
2006
|
+
})
|
|
2007
|
+
]
|
|
2008
|
+
}),
|
|
2009
|
+
/* @__PURE__ */ jsx_runtime6.jsx("rect", {
|
|
2010
|
+
...t,
|
|
2011
|
+
fill: "currentColor",
|
|
2012
|
+
mask: "url(#rt-lockup-eyes)"
|
|
2013
|
+
}),
|
|
2014
|
+
/* @__PURE__ */ jsx_runtime6.jsx("path", {
|
|
2015
|
+
fill: "currentColor",
|
|
2016
|
+
transform: lockup.word.transform,
|
|
2017
|
+
d: lockup.word.d
|
|
2018
|
+
})
|
|
2019
|
+
]
|
|
2020
|
+
});
|
|
2021
|
+
}
|
|
2022
|
+
var Cross = () => /* @__PURE__ */ jsx_runtime6.jsx("svg", {
|
|
2023
|
+
viewBox: "0 0 16 16",
|
|
2024
|
+
width: "16",
|
|
2025
|
+
height: "16",
|
|
2026
|
+
"aria-hidden": "true",
|
|
2027
|
+
children: /* @__PURE__ */ jsx_runtime6.jsx("path", {
|
|
2028
|
+
d: "M4.5 4.5l7 7M11.5 4.5l-7 7",
|
|
2029
|
+
stroke: "currentColor",
|
|
2030
|
+
strokeWidth: "1.5",
|
|
2031
|
+
strokeLinecap: "round"
|
|
2032
|
+
})
|
|
2033
|
+
});
|
|
2034
|
+
var Glyph = ({ children }) => /* @__PURE__ */ jsx_runtime6.jsx("svg", {
|
|
2035
|
+
width: "16",
|
|
2036
|
+
height: "16",
|
|
2037
|
+
viewBox: "0 0 16 16",
|
|
2038
|
+
fill: "none",
|
|
2039
|
+
stroke: "currentColor",
|
|
2040
|
+
strokeWidth: "1.4",
|
|
2041
|
+
strokeLinecap: "round",
|
|
2042
|
+
strokeLinejoin: "round",
|
|
2043
|
+
"aria-hidden": "true",
|
|
2044
|
+
children
|
|
2045
|
+
});
|
|
2046
|
+
var FolderGlyph2 = () => /* @__PURE__ */ jsx_runtime6.jsx(Glyph, {
|
|
2047
|
+
children: /* @__PURE__ */ jsx_runtime6.jsx("path", {
|
|
2048
|
+
d: "M2 4.5c0-.6.4-1 1-1h3l1.5 1.5H13c.6 0 1 .4 1 1V12c0 .6-.4 1-1 1H3c-.6 0-1-.4-1-1z"
|
|
2049
|
+
})
|
|
2050
|
+
});
|
|
2051
|
+
var Plus = () => /* @__PURE__ */ jsx_runtime6.jsx("svg", {
|
|
2052
|
+
viewBox: "0 0 16 16",
|
|
2053
|
+
width: "16",
|
|
2054
|
+
height: "16",
|
|
2055
|
+
"aria-hidden": "true",
|
|
2056
|
+
children: /* @__PURE__ */ jsx_runtime6.jsx("path", {
|
|
2057
|
+
d: "M8 3.5v9M3.5 8h9",
|
|
2058
|
+
stroke: "currentColor",
|
|
2059
|
+
strokeWidth: "1.6",
|
|
2060
|
+
strokeLinecap: "round"
|
|
2061
|
+
})
|
|
2062
|
+
});
|
|
2063
|
+
var SetupGlyph = () => /* @__PURE__ */ jsx_runtime6.jsx(Glyph, {
|
|
2064
|
+
children: /* @__PURE__ */ jsx_runtime6.jsx("circle", {
|
|
2065
|
+
cx: "8",
|
|
2066
|
+
cy: "8",
|
|
2067
|
+
r: "5.5",
|
|
2068
|
+
strokeDasharray: "2.2 2"
|
|
2069
|
+
})
|
|
2070
|
+
});
|
|
2071
|
+
var WarnGlyph = () => /* @__PURE__ */ jsx_runtime6.jsxs(Glyph, {
|
|
2072
|
+
children: [
|
|
2073
|
+
/* @__PURE__ */ jsx_runtime6.jsx("path", {
|
|
2074
|
+
d: "M8 2.5l6 10.5H2z"
|
|
2075
|
+
}),
|
|
2076
|
+
/* @__PURE__ */ jsx_runtime6.jsx("path", {
|
|
2077
|
+
d: "M8 6.5v3M8 11.2v.1"
|
|
2078
|
+
})
|
|
2079
|
+
]
|
|
2080
|
+
});
|
|
2081
|
+
var message = (e) => String(e instanceof Error ? e.message : e);
|
|
2082
|
+
function Picker({ listed, reload, set, setup }) {
|
|
2083
|
+
const { home } = listed;
|
|
2084
|
+
const rows = import_react7.useMemo(() => pickerRows(listed.projects, listed.pending), [listed]);
|
|
2085
|
+
const [browsing, setBrowsing] = import_react7.useState(false);
|
|
2086
|
+
const [error, setError] = import_react7.useState(null);
|
|
2087
|
+
const [opened, setOpened] = import_react7.useState(null);
|
|
2088
|
+
const [forgot, setForgot] = import_react7.useState(null);
|
|
2089
|
+
import_react7.useEffect(() => {
|
|
2090
|
+
if (!forgot)
|
|
2091
|
+
return;
|
|
2092
|
+
const t = setTimeout(() => setForgot(null), 6000);
|
|
2093
|
+
return () => clearTimeout(t);
|
|
2094
|
+
}, [forgot]);
|
|
2095
|
+
const list = import_react7.useRef(null);
|
|
2096
|
+
const answer = (j) => set({ projects: j.projects, pending: j.pending, home });
|
|
2097
|
+
const add = async (dir) => {
|
|
2098
|
+
setError(null);
|
|
2099
|
+
try {
|
|
2100
|
+
const j = await postJson("/api/projects/add", { dir });
|
|
2101
|
+
answer(j);
|
|
2102
|
+
setBrowsing(false);
|
|
2103
|
+
const waiting = j.pending.find((e) => e.dir === j.dir);
|
|
2104
|
+
if (waiting && !waiting.error)
|
|
2105
|
+
setup(j.dir);
|
|
2106
|
+
return true;
|
|
2107
|
+
} catch (e) {
|
|
2108
|
+
setError(message(e));
|
|
2109
|
+
return false;
|
|
2110
|
+
}
|
|
2111
|
+
};
|
|
2112
|
+
const forget = async (r) => {
|
|
2113
|
+
setError(null);
|
|
2114
|
+
try {
|
|
2115
|
+
answer(await postJson("/api/projects/remove", { dir: r.dir }));
|
|
2116
|
+
setForgot({ dir: r.dir, label: r.kind === "baba" ? r.p.title : tilde(r.dir, home) });
|
|
2117
|
+
} catch (e) {
|
|
2118
|
+
setError(message(e));
|
|
2119
|
+
reload();
|
|
2120
|
+
}
|
|
2121
|
+
};
|
|
2122
|
+
const undo = async () => {
|
|
2123
|
+
const f = forgot;
|
|
2124
|
+
setForgot(null);
|
|
2125
|
+
if (f)
|
|
2126
|
+
try {
|
|
2127
|
+
answer(await postJson("/api/projects/add", { dir: f.dir }));
|
|
2128
|
+
} catch (e) {
|
|
2129
|
+
setError(message(e));
|
|
2130
|
+
}
|
|
2131
|
+
};
|
|
2132
|
+
const open = (r) => {
|
|
2133
|
+
if (r.kind === "baba")
|
|
2134
|
+
location.assign(href(r.p.name));
|
|
2135
|
+
else if (!r.e.error)
|
|
2136
|
+
setup(r.dir);
|
|
2137
|
+
else
|
|
2138
|
+
setOpened(opened === r.dir ? null : r.dir);
|
|
2139
|
+
};
|
|
2140
|
+
const move = (e) => {
|
|
2141
|
+
if (e.key !== "ArrowDown" && e.key !== "ArrowUp")
|
|
2142
|
+
return;
|
|
2143
|
+
const all = [...list.current?.querySelectorAll("[data-row]") ?? []];
|
|
2144
|
+
const field = document.querySelector(".rt-add input");
|
|
2145
|
+
if (field)
|
|
2146
|
+
all.push(field);
|
|
2147
|
+
const i = all.indexOf(document.activeElement);
|
|
2148
|
+
if (i < 0)
|
|
2149
|
+
return;
|
|
2150
|
+
e.preventDefault();
|
|
2151
|
+
all[(i + (e.key === "ArrowDown" ? 1 : -1) + all.length) % all.length]?.focus();
|
|
2152
|
+
};
|
|
2153
|
+
return /* @__PURE__ */ jsx_runtime6.jsxs("div", {
|
|
2154
|
+
className: "gui-view rt",
|
|
2155
|
+
onKeyDown: move,
|
|
2156
|
+
children: [
|
|
2157
|
+
/* @__PURE__ */ jsx_runtime6.jsxs("div", {
|
|
2158
|
+
className: "rt-column",
|
|
2159
|
+
children: [
|
|
2160
|
+
/* @__PURE__ */ jsx_runtime6.jsxs("header", {
|
|
2161
|
+
className: "rt-mark",
|
|
2162
|
+
children: [
|
|
2163
|
+
/* @__PURE__ */ jsx_runtime6.jsxs("h1", {
|
|
2164
|
+
children: [
|
|
2165
|
+
/* @__PURE__ */ jsx_runtime6.jsx(Lockup, {}),
|
|
2166
|
+
/* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
2167
|
+
className: "rt-hidden",
|
|
2168
|
+
children: "voss"
|
|
2169
|
+
})
|
|
2170
|
+
]
|
|
2171
|
+
}),
|
|
2172
|
+
/* @__PURE__ */ jsx_runtime6.jsx(VossVersion, {})
|
|
2173
|
+
]
|
|
2174
|
+
}),
|
|
2175
|
+
browsing ? /* @__PURE__ */ jsx_runtime6.jsx("div", {
|
|
2176
|
+
className: "rt-browse",
|
|
2177
|
+
children: /* @__PURE__ */ jsx_runtime6.jsx(Folders, {
|
|
2178
|
+
home,
|
|
2179
|
+
pick: (dir) => void add(dir),
|
|
2180
|
+
onBack: () => setBrowsing(false)
|
|
2181
|
+
})
|
|
2182
|
+
}) : /* @__PURE__ */ jsx_runtime6.jsxs(jsx_runtime6.Fragment, {
|
|
2183
|
+
children: [
|
|
2184
|
+
/* @__PURE__ */ jsx_runtime6.jsxs("ul", {
|
|
2185
|
+
ref: list,
|
|
2186
|
+
className: "rt-list",
|
|
2187
|
+
"aria-label": "Babas",
|
|
2188
|
+
children: [
|
|
2189
|
+
rows.map((r) => {
|
|
2190
|
+
const label = r.kind === "baba" ? r.p.title : r.dir.split("/").filter(Boolean).pop() || r.dir;
|
|
2191
|
+
const failed = r.kind === "pending" && !!r.e.error;
|
|
2192
|
+
return /* @__PURE__ */ jsx_runtime6.jsxs("li", {
|
|
2193
|
+
className: `rt-row${failed ? " is-failed" : ""}`,
|
|
2194
|
+
style: { "--depth": r.depth },
|
|
2195
|
+
children: [
|
|
2196
|
+
/* @__PURE__ */ jsx_runtime6.jsxs("button", {
|
|
2197
|
+
type: "button",
|
|
2198
|
+
"data-row": true,
|
|
2199
|
+
className: "rt-row-main",
|
|
2200
|
+
title: r.kind === "baba" ? `Open ${r.p.title}` : failed ? "Show why it did not open" : `Set up the baba in ${tilde(r.dir, home)}`,
|
|
2201
|
+
onClick: () => open(r),
|
|
2202
|
+
children: [
|
|
2203
|
+
/* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
2204
|
+
className: "rt-row-icon",
|
|
2205
|
+
children: r.kind === "baba" ? /* @__PURE__ */ jsx_runtime6.jsx(Eyes, {
|
|
2206
|
+
size: 16
|
|
2207
|
+
}) : failed ? /* @__PURE__ */ jsx_runtime6.jsx(WarnGlyph, {}) : /* @__PURE__ */ jsx_runtime6.jsx(SetupGlyph, {})
|
|
2208
|
+
}),
|
|
2209
|
+
/* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
2210
|
+
className: "rt-row-label",
|
|
2211
|
+
children: label
|
|
2212
|
+
}),
|
|
2213
|
+
r.kind === "pending" && /* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
2214
|
+
className: `rt-tag${failed ? " is-failed" : ""}`,
|
|
2215
|
+
children: failed ? "Did not open" : "Set up"
|
|
2216
|
+
}),
|
|
2217
|
+
/* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
2218
|
+
className: "rt-row-note",
|
|
2219
|
+
children: short(r.dir, home, 44)
|
|
2220
|
+
})
|
|
2221
|
+
]
|
|
2222
|
+
}),
|
|
2223
|
+
/* @__PURE__ */ jsx_runtime6.jsx("button", {
|
|
2224
|
+
type: "button",
|
|
2225
|
+
className: "rt-row-forget",
|
|
2226
|
+
"aria-label": `Forget ${label}`,
|
|
2227
|
+
title: `Forget ${label}: voss stops running it; its files stay`,
|
|
2228
|
+
onClick: () => void forget(r),
|
|
2229
|
+
children: /* @__PURE__ */ jsx_runtime6.jsx(Cross, {})
|
|
2230
|
+
}),
|
|
2231
|
+
failed && opened === r.dir && r.kind === "pending" && /* @__PURE__ */ jsx_runtime6.jsx("p", {
|
|
2232
|
+
className: "rt-row-error",
|
|
2233
|
+
children: r.e.error
|
|
2234
|
+
})
|
|
2235
|
+
]
|
|
2236
|
+
}, r.dir);
|
|
2237
|
+
}),
|
|
2238
|
+
!rows.length && /* @__PURE__ */ jsx_runtime6.jsx("li", {
|
|
2239
|
+
className: "rt-empty",
|
|
2240
|
+
children: "No babas yet. Add a folder to start one."
|
|
2241
|
+
})
|
|
2242
|
+
]
|
|
2243
|
+
}),
|
|
2244
|
+
/* @__PURE__ */ jsx_runtime6.jsx(AddField, {
|
|
2245
|
+
home,
|
|
2246
|
+
onAdd: add,
|
|
2247
|
+
onBrowse: () => {
|
|
2248
|
+
setError(null);
|
|
2249
|
+
setBrowsing(true);
|
|
2250
|
+
}
|
|
2251
|
+
})
|
|
2252
|
+
]
|
|
2253
|
+
}),
|
|
2254
|
+
error && /* @__PURE__ */ jsx_runtime6.jsx("p", {
|
|
2255
|
+
className: "rt-error",
|
|
2256
|
+
role: "alert",
|
|
2257
|
+
children: error
|
|
2258
|
+
})
|
|
2259
|
+
]
|
|
2260
|
+
}),
|
|
2261
|
+
forgot && /* @__PURE__ */ jsx_runtime6.jsxs("div", {
|
|
2262
|
+
className: "rt-toast",
|
|
2263
|
+
role: "status",
|
|
2264
|
+
children: [
|
|
2265
|
+
"Forgot ",
|
|
2266
|
+
forgot.label,
|
|
2267
|
+
". Its files stay.",
|
|
2268
|
+
/* @__PURE__ */ jsx_runtime6.jsx("button", {
|
|
2269
|
+
type: "button",
|
|
2270
|
+
onClick: () => void undo(),
|
|
2271
|
+
children: "Undo"
|
|
2272
|
+
})
|
|
2273
|
+
]
|
|
2274
|
+
})
|
|
2275
|
+
]
|
|
2276
|
+
});
|
|
2277
|
+
}
|
|
2278
|
+
function AddField({ home, onAdd, onBrowse }) {
|
|
2279
|
+
const [text, setText] = import_react7.useState("");
|
|
2280
|
+
const [dirs, setDirs] = import_react7.useState([]);
|
|
2281
|
+
const [at, setAt] = import_react7.useState(-1);
|
|
2282
|
+
const [busy, setBusy] = import_react7.useState(false);
|
|
2283
|
+
const expand = (t) => t === "~" ? home : t.startsWith("~/") ? home + t.slice(1) : t;
|
|
2284
|
+
const full = expand(text.trim());
|
|
2285
|
+
const cut = full.lastIndexOf("/");
|
|
2286
|
+
const parent = cut < 0 ? "" : full.slice(0, cut) || "/", leaf = cut < 0 ? full : full.slice(cut + 1);
|
|
2287
|
+
import_react7.useEffect(() => {
|
|
2288
|
+
if (!parent.startsWith("/")) {
|
|
2289
|
+
setDirs([]);
|
|
2290
|
+
return;
|
|
2291
|
+
}
|
|
2292
|
+
let live = true;
|
|
2293
|
+
const t = setTimeout(() => {
|
|
2294
|
+
getJson(`/api/dirs?path=${encodeURIComponent(parent)}`).then((b) => {
|
|
2295
|
+
if (live)
|
|
2296
|
+
setDirs(b.dirs);
|
|
2297
|
+
}, () => {
|
|
2298
|
+
if (live)
|
|
2299
|
+
setDirs([]);
|
|
2300
|
+
});
|
|
2301
|
+
}, 100);
|
|
1583
2302
|
return () => {
|
|
1584
2303
|
live = false;
|
|
2304
|
+
clearTimeout(t);
|
|
1585
2305
|
};
|
|
2306
|
+
}, [parent]);
|
|
2307
|
+
const shown = dirs.filter((d) => d.name.toLowerCase().startsWith(leaf.toLowerCase()) && d.path !== full).slice(0, 6);
|
|
2308
|
+
const take = (d) => {
|
|
2309
|
+
setText(`${tilde(d.path, home)}/`);
|
|
2310
|
+
setAt(-1);
|
|
2311
|
+
};
|
|
2312
|
+
const submit = async () => {
|
|
2313
|
+
const dir = full.replace(/\/+$/, "") || "/";
|
|
2314
|
+
if (!dir.startsWith("/") || busy)
|
|
2315
|
+
return;
|
|
2316
|
+
setBusy(true);
|
|
2317
|
+
if (await onAdd(dir))
|
|
2318
|
+
setText("");
|
|
2319
|
+
setBusy(false);
|
|
2320
|
+
};
|
|
2321
|
+
return /* @__PURE__ */ jsx_runtime6.jsxs("div", {
|
|
2322
|
+
className: "rt-add",
|
|
2323
|
+
children: [
|
|
2324
|
+
/* @__PURE__ */ jsx_runtime6.jsxs("label", {
|
|
2325
|
+
className: "rt-add-field",
|
|
2326
|
+
children: [
|
|
2327
|
+
/* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
2328
|
+
className: "rt-row-icon",
|
|
2329
|
+
children: /* @__PURE__ */ jsx_runtime6.jsx(FolderGlyph2, {})
|
|
2330
|
+
}),
|
|
2331
|
+
/* @__PURE__ */ jsx_runtime6.jsx("input", {
|
|
2332
|
+
value: text,
|
|
2333
|
+
placeholder: "Add a folder: type its path, ~/…",
|
|
2334
|
+
spellCheck: false,
|
|
2335
|
+
autoComplete: "off",
|
|
2336
|
+
"aria-label": "Add a folder by its path",
|
|
2337
|
+
disabled: busy,
|
|
2338
|
+
onChange: (e) => {
|
|
2339
|
+
setText(e.target.value);
|
|
2340
|
+
setAt(-1);
|
|
2341
|
+
},
|
|
2342
|
+
onKeyDown: (e) => {
|
|
2343
|
+
if (e.key === "Tab" && !e.shiftKey && shown.length && text.trim()) {
|
|
2344
|
+
e.preventDefault();
|
|
2345
|
+
take(shown[Math.max(0, at)]);
|
|
2346
|
+
} else if ((e.key === "ArrowDown" || e.key === "ArrowUp") && shown.length && text.trim()) {
|
|
2347
|
+
e.preventDefault();
|
|
2348
|
+
e.stopPropagation();
|
|
2349
|
+
const next = at + (e.key === "ArrowDown" ? 1 : -1);
|
|
2350
|
+
setAt(next < -1 ? shown.length - 1 : next >= shown.length ? -1 : next);
|
|
2351
|
+
} else if (e.key === "Enter") {
|
|
2352
|
+
e.preventDefault();
|
|
2353
|
+
if (at >= 0 && shown[at])
|
|
2354
|
+
take(shown[at]);
|
|
2355
|
+
else
|
|
2356
|
+
submit();
|
|
2357
|
+
} else if (e.key === "Escape" && text) {
|
|
2358
|
+
e.preventDefault();
|
|
2359
|
+
setText("");
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
}),
|
|
2363
|
+
/* @__PURE__ */ jsx_runtime6.jsx("button", {
|
|
2364
|
+
type: "button",
|
|
2365
|
+
className: "rt-add-browse",
|
|
2366
|
+
onClick: onBrowse,
|
|
2367
|
+
children: "Browse"
|
|
2368
|
+
}),
|
|
2369
|
+
/* @__PURE__ */ jsx_runtime6.jsx("button", {
|
|
2370
|
+
type: "button",
|
|
2371
|
+
className: "rt-add-go",
|
|
2372
|
+
"aria-label": busy ? "Adding the folder" : "Add the folder",
|
|
2373
|
+
title: "Add the folder (↵)",
|
|
2374
|
+
disabled: busy || !full.startsWith("/"),
|
|
2375
|
+
onClick: () => void submit(),
|
|
2376
|
+
children: busy ? /* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
2377
|
+
className: "pk-spin",
|
|
2378
|
+
"aria-hidden": "true"
|
|
2379
|
+
}) : /* @__PURE__ */ jsx_runtime6.jsx(Plus, {})
|
|
2380
|
+
})
|
|
2381
|
+
]
|
|
2382
|
+
}),
|
|
2383
|
+
shown.length > 0 && text.trim() && /* @__PURE__ */ jsx_runtime6.jsx("ul", {
|
|
2384
|
+
className: "rt-suggest",
|
|
2385
|
+
role: "listbox",
|
|
2386
|
+
"aria-label": "Folders",
|
|
2387
|
+
children: shown.map((d, i) => /* @__PURE__ */ jsx_runtime6.jsx("li", {
|
|
2388
|
+
role: "option",
|
|
2389
|
+
"aria-selected": i === at,
|
|
2390
|
+
children: /* @__PURE__ */ jsx_runtime6.jsxs("button", {
|
|
2391
|
+
type: "button",
|
|
2392
|
+
className: i === at ? "is-active" : undefined,
|
|
2393
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
2394
|
+
onClick: () => take(d),
|
|
2395
|
+
children: [
|
|
2396
|
+
/* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
2397
|
+
className: "rt-row-icon",
|
|
2398
|
+
children: d.baba ? /* @__PURE__ */ jsx_runtime6.jsx(Eyes, {
|
|
2399
|
+
size: 14
|
|
2400
|
+
}) : /* @__PURE__ */ jsx_runtime6.jsx(FolderGlyph2, {})
|
|
2401
|
+
}),
|
|
2402
|
+
d.name,
|
|
2403
|
+
d.known ? /* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
2404
|
+
className: "rt-tag",
|
|
2405
|
+
children: "in the list"
|
|
2406
|
+
}) : d.baba ? /* @__PURE__ */ jsx_runtime6.jsx("span", {
|
|
2407
|
+
className: "rt-tag",
|
|
2408
|
+
children: "baba"
|
|
2409
|
+
}) : null
|
|
2410
|
+
]
|
|
2411
|
+
})
|
|
2412
|
+
}, d.path))
|
|
2413
|
+
})
|
|
2414
|
+
]
|
|
2415
|
+
});
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
// src/gui/settings.tsx
|
|
2419
|
+
var import_react8 = __toESM(require_react(), 1);
|
|
2420
|
+
var jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
|
|
2421
|
+
var pages = [
|
|
2422
|
+
{ level: "baba", path: "/", title: "Profile" },
|
|
2423
|
+
{ level: "voss", path: "/appearance", title: "Appearance" },
|
|
2424
|
+
{ level: "voss", path: "/keyboard", title: "Keyboard" },
|
|
2425
|
+
{ level: "voss", path: "/about", title: "About" }
|
|
2426
|
+
];
|
|
2427
|
+
var SettingsBaba = import_react8.createContext(undefined);
|
|
2428
|
+
function Settings({ path, navigate, setTitle }) {
|
|
2429
|
+
const baba = import_react8.useContext(SettingsBaba);
|
|
2430
|
+
const page = pages.find((p) => p.path === path) ?? pages[0];
|
|
2431
|
+
import_react8.useEffect(() => {
|
|
2432
|
+
setTitle("Settings");
|
|
1586
2433
|
}, []);
|
|
1587
|
-
|
|
2434
|
+
const link = (p) => /* @__PURE__ */ jsx_runtime7.jsx("button", {
|
|
2435
|
+
type: "button",
|
|
2436
|
+
className: `gui-settings-link${p === page ? " is-active" : ""}`,
|
|
2437
|
+
"aria-current": p === page ? "page" : undefined,
|
|
2438
|
+
onClick: () => navigate(p.path),
|
|
2439
|
+
children: p.title
|
|
2440
|
+
}, p.path);
|
|
2441
|
+
return /* @__PURE__ */ jsx_runtime7.jsxs("div", {
|
|
2442
|
+
className: "gui-settings",
|
|
2443
|
+
children: [
|
|
2444
|
+
/* @__PURE__ */ jsx_runtime7.jsxs("nav", {
|
|
2445
|
+
className: "gui-settings-nav",
|
|
2446
|
+
"aria-label": "Settings",
|
|
2447
|
+
children: [
|
|
2448
|
+
/* @__PURE__ */ jsx_runtime7.jsx("h2", {
|
|
2449
|
+
className: "gui-settings-level",
|
|
2450
|
+
children: "Baba"
|
|
2451
|
+
}),
|
|
2452
|
+
pages.filter((p) => p.level === "baba").map(link),
|
|
2453
|
+
/* @__PURE__ */ jsx_runtime7.jsx("h2", {
|
|
2454
|
+
className: "gui-settings-level",
|
|
2455
|
+
children: "voss"
|
|
2456
|
+
}),
|
|
2457
|
+
pages.filter((p) => p.level === "voss").map(link)
|
|
2458
|
+
]
|
|
2459
|
+
}),
|
|
2460
|
+
/* @__PURE__ */ jsx_runtime7.jsxs("section", {
|
|
2461
|
+
className: "gui-settings-page",
|
|
2462
|
+
"aria-labelledby": "gui-settings-title",
|
|
2463
|
+
children: [
|
|
2464
|
+
/* @__PURE__ */ jsx_runtime7.jsx("header", {
|
|
2465
|
+
className: "gui-settings-head",
|
|
2466
|
+
children: /* @__PURE__ */ jsx_runtime7.jsx("h1", {
|
|
2467
|
+
id: "gui-settings-title",
|
|
2468
|
+
children: page.title
|
|
2469
|
+
})
|
|
2470
|
+
}),
|
|
2471
|
+
page.path === "/" ? /* @__PURE__ */ jsx_runtime7.jsx(Profile, {
|
|
2472
|
+
baba
|
|
2473
|
+
}) : page.path === "/appearance" ? /* @__PURE__ */ jsx_runtime7.jsx(Appearance, {}) : page.path === "/keyboard" ? /* @__PURE__ */ jsx_runtime7.jsx(Keyboard, {}) : /* @__PURE__ */ jsx_runtime7.jsx(About, {
|
|
2474
|
+
baba
|
|
2475
|
+
})
|
|
2476
|
+
]
|
|
2477
|
+
})
|
|
2478
|
+
]
|
|
2479
|
+
});
|
|
1588
2480
|
}
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
2481
|
+
function Setting({ title, summary, children }) {
|
|
2482
|
+
return /* @__PURE__ */ jsx_runtime7.jsxs("div", {
|
|
2483
|
+
className: "gui-setting",
|
|
2484
|
+
children: [
|
|
2485
|
+
/* @__PURE__ */ jsx_runtime7.jsxs("div", {
|
|
2486
|
+
className: "gui-setting-text",
|
|
2487
|
+
children: [
|
|
2488
|
+
/* @__PURE__ */ jsx_runtime7.jsx("div", {
|
|
2489
|
+
className: "gui-setting-title",
|
|
2490
|
+
children: title
|
|
2491
|
+
}),
|
|
2492
|
+
summary && /* @__PURE__ */ jsx_runtime7.jsx("div", {
|
|
2493
|
+
className: "gui-setting-summary",
|
|
2494
|
+
children: summary
|
|
2495
|
+
})
|
|
2496
|
+
]
|
|
2497
|
+
}),
|
|
2498
|
+
/* @__PURE__ */ jsx_runtime7.jsx("div", {
|
|
2499
|
+
className: "gui-setting-control",
|
|
2500
|
+
children
|
|
2501
|
+
})
|
|
2502
|
+
]
|
|
1599
2503
|
});
|
|
1600
|
-
rows.push({ entity: 2, key: NEW, title: "New baba", group: "Make", icon: "plus", many: false, order: projects.length, drawing: plus });
|
|
1601
|
-
return rows;
|
|
1602
2504
|
}
|
|
1603
|
-
var
|
|
1604
|
-
function
|
|
1605
|
-
const
|
|
1606
|
-
const
|
|
1607
|
-
const
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
2505
|
+
var message2 = (e) => String(e instanceof Error ? e.message : e).replace(/^Error: /, "");
|
|
2506
|
+
function Appearance() {
|
|
2507
|
+
const settings = useVossSettings();
|
|
2508
|
+
const current2 = settings?.theme ?? "system";
|
|
2509
|
+
const [error, setError] = import_react8.useState(null);
|
|
2510
|
+
return /* @__PURE__ */ jsx_runtime7.jsx("div", {
|
|
2511
|
+
className: "gui-settings-list",
|
|
2512
|
+
children: /* @__PURE__ */ jsx_runtime7.jsx(Setting, {
|
|
2513
|
+
title: "Theme",
|
|
2514
|
+
summary: /* @__PURE__ */ jsx_runtime7.jsxs(jsx_runtime7.Fragment, {
|
|
2515
|
+
children: [
|
|
2516
|
+
"System follows this computer's light or dark appearance.",
|
|
2517
|
+
error && /* @__PURE__ */ jsx_runtime7.jsx("span", {
|
|
2518
|
+
className: "gui-setting-note is-error",
|
|
2519
|
+
children: error
|
|
2520
|
+
})
|
|
2521
|
+
]
|
|
2522
|
+
}),
|
|
2523
|
+
children: /* @__PURE__ */ jsx_runtime7.jsx("div", {
|
|
2524
|
+
className: "gui-choices",
|
|
2525
|
+
role: "radiogroup",
|
|
2526
|
+
"aria-label": "Theme",
|
|
2527
|
+
children: themes.map((t) => /* @__PURE__ */ jsx_runtime7.jsx(Button, {
|
|
2528
|
+
variant: t === current2 ? "default" : "quiet",
|
|
2529
|
+
role: "radio",
|
|
2530
|
+
"aria-checked": t === current2,
|
|
2531
|
+
disabled: !settings,
|
|
2532
|
+
onClick: () => {
|
|
2533
|
+
setError(null);
|
|
2534
|
+
saveSettings({ theme: t }).catch((e) => setError(message2(e)));
|
|
2535
|
+
},
|
|
2536
|
+
children: t[0].toUpperCase() + t.slice(1)
|
|
2537
|
+
}, t))
|
|
2538
|
+
})
|
|
2539
|
+
})
|
|
2540
|
+
});
|
|
2541
|
+
}
|
|
2542
|
+
function Keyboard() {
|
|
2543
|
+
const settings = useVossSettings();
|
|
2544
|
+
const keymap = keymapOf(settings?.keys);
|
|
2545
|
+
const remapped = Object.keys(settings?.keys ?? {}).length > 0;
|
|
2546
|
+
const [error, setError] = import_react8.useState(null);
|
|
2547
|
+
const change = (keys, id) => {
|
|
2548
|
+
setError(null);
|
|
2549
|
+
saveSettings({ keys }).catch((e) => setError({ id, message: message2(e) }));
|
|
1613
2550
|
};
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
2551
|
+
return /* @__PURE__ */ jsx_runtime7.jsxs("div", {
|
|
2552
|
+
className: "gui-settings-list",
|
|
2553
|
+
children: [
|
|
2554
|
+
keyCommands.map((c) => {
|
|
2555
|
+
const binding = keymap[c.id], own = settings?.keys?.[c.id] !== undefined;
|
|
2556
|
+
const note = error?.id === c.id ? error.message : binding && bindingNote(binding);
|
|
2557
|
+
return /* @__PURE__ */ jsx_runtime7.jsxs(Setting, {
|
|
2558
|
+
title: c.title,
|
|
2559
|
+
summary: /* @__PURE__ */ jsx_runtime7.jsxs(jsx_runtime7.Fragment, {
|
|
2560
|
+
children: [
|
|
2561
|
+
c.summary,
|
|
2562
|
+
note && /* @__PURE__ */ jsx_runtime7.jsx("span", {
|
|
2563
|
+
className: `gui-setting-note${error?.id === c.id ? " is-error" : ""}`,
|
|
2564
|
+
children: note
|
|
2565
|
+
})
|
|
2566
|
+
]
|
|
2567
|
+
}),
|
|
2568
|
+
children: [
|
|
2569
|
+
/* @__PURE__ */ jsx_runtime7.jsx(KeyRecorder, {
|
|
2570
|
+
label: c.title,
|
|
2571
|
+
binding,
|
|
2572
|
+
onRecord: (b) => {
|
|
2573
|
+
const other = keyCommands.find((o) => o.id !== c.id && keymap[o.id] === b);
|
|
2574
|
+
if (other)
|
|
2575
|
+
setError({ id: c.id, message: `${formatBinding(b)} already runs ${other.title}.` });
|
|
2576
|
+
else
|
|
2577
|
+
change({ [c.id]: b }, c.id);
|
|
2578
|
+
},
|
|
2579
|
+
onInvalid: (m) => setError({ id: c.id, message: m })
|
|
2580
|
+
}),
|
|
2581
|
+
/* @__PURE__ */ jsx_runtime7.jsx(Button, {
|
|
2582
|
+
variant: "quiet",
|
|
2583
|
+
className: own ? "" : "is-hidden",
|
|
2584
|
+
disabled: !own,
|
|
2585
|
+
title: c.default ? `Back to ${formatBinding(c.default)}` : "Back to no key",
|
|
2586
|
+
onClick: () => change({ [c.id]: null }, c.id),
|
|
2587
|
+
children: "Reset"
|
|
2588
|
+
})
|
|
2589
|
+
]
|
|
2590
|
+
}, c.id);
|
|
2591
|
+
}),
|
|
2592
|
+
/* @__PURE__ */ jsx_runtime7.jsxs("p", {
|
|
2593
|
+
className: "gui-settings-foot bv-muted",
|
|
2594
|
+
children: [
|
|
2595
|
+
"Click a key, then press the new one; Escape cancels. The launcher's arrows, Enter and Escape are fixed.",
|
|
2596
|
+
remapped && /* @__PURE__ */ jsx_runtime7.jsxs(jsx_runtime7.Fragment, {
|
|
2597
|
+
children: [
|
|
2598
|
+
" ",
|
|
2599
|
+
/* @__PURE__ */ jsx_runtime7.jsx(Button, {
|
|
2600
|
+
variant: "quiet",
|
|
2601
|
+
onClick: () => change(Object.fromEntries(keyCommands.map((c) => [c.id, null])), null),
|
|
2602
|
+
children: "Reset all"
|
|
2603
|
+
})
|
|
2604
|
+
]
|
|
2605
|
+
}),
|
|
2606
|
+
error?.id === null && /* @__PURE__ */ jsx_runtime7.jsx("span", {
|
|
2607
|
+
className: "gui-setting-note is-error",
|
|
2608
|
+
children: error.message
|
|
2609
|
+
})
|
|
2610
|
+
]
|
|
1636
2611
|
})
|
|
2612
|
+
]
|
|
2613
|
+
});
|
|
2614
|
+
}
|
|
2615
|
+
function Profile({ baba }) {
|
|
2616
|
+
const [name, setName] = import_react8.useState(baba?.name ?? "");
|
|
2617
|
+
const [taken, setTaken] = import_react8.useState([]);
|
|
2618
|
+
const [busy, setBusy] = import_react8.useState(false);
|
|
2619
|
+
const [error, setError] = import_react8.useState(null);
|
|
2620
|
+
import_react8.useEffect(() => {
|
|
2621
|
+
fetch("/api/projects", { headers: apiHeaders() }).then((r) => r.json()).then((j) => setTaken(j.projects.map((p) => p.name).filter((n) => n !== baba?.name)), () => {});
|
|
2622
|
+
}, [baba?.name]);
|
|
2623
|
+
if (!baba)
|
|
2624
|
+
return /* @__PURE__ */ jsx_runtime7.jsx("p", {
|
|
2625
|
+
className: "bv-muted",
|
|
2626
|
+
children: "…"
|
|
2627
|
+
});
|
|
2628
|
+
const why = name === baba.name ? null : requirementError("name", name, taken);
|
|
2629
|
+
const changed = name !== baba.name && !why;
|
|
2630
|
+
const save = async () => {
|
|
2631
|
+
if (!changed || busy)
|
|
2632
|
+
return;
|
|
2633
|
+
setBusy(true);
|
|
2634
|
+
setError(null);
|
|
2635
|
+
try {
|
|
2636
|
+
const r = await fetch("/api/projects/rename", { method: "POST", headers: { "content-type": "application/json", ...apiHeaders() }, body: JSON.stringify({ name: baba.name, to: name }) });
|
|
2637
|
+
const j = await r.json();
|
|
2638
|
+
if (!r.ok || j.error || !j.name)
|
|
2639
|
+
throw new Error(j.error?.message ?? "voss did not open it again");
|
|
2640
|
+
location.assign(`/${encodeURIComponent(j.name)}/settings`);
|
|
2641
|
+
} catch (e) {
|
|
2642
|
+
setError(message2(e));
|
|
2643
|
+
setBusy(false);
|
|
2644
|
+
}
|
|
2645
|
+
};
|
|
2646
|
+
return /* @__PURE__ */ jsx_runtime7.jsx("form", {
|
|
2647
|
+
className: "gui-settings-list",
|
|
2648
|
+
onSubmit: (e) => {
|
|
2649
|
+
e.preventDefault();
|
|
2650
|
+
save();
|
|
2651
|
+
},
|
|
2652
|
+
children: /* @__PURE__ */ jsx_runtime7.jsxs(Setting, {
|
|
2653
|
+
title: "Name",
|
|
2654
|
+
summary: /* @__PURE__ */ jsx_runtime7.jsxs(jsx_runtime7.Fragment, {
|
|
2655
|
+
children: [
|
|
2656
|
+
"What voss calls this baba, at ",
|
|
2657
|
+
/* @__PURE__ */ jsx_runtime7.jsxs("code", {
|
|
2658
|
+
children: [
|
|
2659
|
+
"/",
|
|
2660
|
+
baba.name,
|
|
2661
|
+
"/"
|
|
2662
|
+
]
|
|
2663
|
+
}),
|
|
2664
|
+
" and as ",
|
|
2665
|
+
/* @__PURE__ */ jsx_runtime7.jsxs("code", {
|
|
2666
|
+
children: [
|
|
2667
|
+
"voss ",
|
|
2668
|
+
baba.name
|
|
2669
|
+
]
|
|
2670
|
+
}),
|
|
2671
|
+
" on the CLI; not its folder's name, which stays as it is.",
|
|
2672
|
+
why || error ? /* @__PURE__ */ jsx_runtime7.jsx("span", {
|
|
2673
|
+
className: "gui-setting-note is-error",
|
|
2674
|
+
children: why ?? error
|
|
2675
|
+
}) : changed && /* @__PURE__ */ jsx_runtime7.jsxs("span", {
|
|
2676
|
+
className: "gui-setting-note",
|
|
2677
|
+
children: [
|
|
2678
|
+
"Renamed, it moves to ",
|
|
2679
|
+
/* @__PURE__ */ jsx_runtime7.jsxs("code", {
|
|
2680
|
+
children: [
|
|
2681
|
+
"/",
|
|
2682
|
+
name,
|
|
2683
|
+
"/"
|
|
2684
|
+
]
|
|
2685
|
+
}),
|
|
2686
|
+
"; links to ",
|
|
2687
|
+
/* @__PURE__ */ jsx_runtime7.jsxs("code", {
|
|
2688
|
+
children: [
|
|
2689
|
+
"/",
|
|
2690
|
+
baba.name,
|
|
2691
|
+
"/"
|
|
2692
|
+
]
|
|
2693
|
+
}),
|
|
2694
|
+
" stop working."
|
|
2695
|
+
]
|
|
2696
|
+
})
|
|
2697
|
+
]
|
|
2698
|
+
}),
|
|
2699
|
+
children: [
|
|
2700
|
+
/* @__PURE__ */ jsx_runtime7.jsx("input", {
|
|
2701
|
+
className: "gui-name",
|
|
2702
|
+
value: name,
|
|
2703
|
+
spellCheck: false,
|
|
2704
|
+
autoComplete: "off",
|
|
2705
|
+
"aria-label": "Name",
|
|
2706
|
+
disabled: busy,
|
|
2707
|
+
onChange: (e) => setName(e.target.value.toLowerCase())
|
|
2708
|
+
}),
|
|
2709
|
+
/* @__PURE__ */ jsx_runtime7.jsx(Button, {
|
|
2710
|
+
variant: changed ? "primary" : "quiet",
|
|
2711
|
+
type: "submit",
|
|
2712
|
+
disabled: !changed || busy,
|
|
2713
|
+
children: busy ? "Renaming…" : "Rename"
|
|
2714
|
+
})
|
|
2715
|
+
]
|
|
2716
|
+
})
|
|
2717
|
+
});
|
|
2718
|
+
}
|
|
2719
|
+
function KeyRecorder({ label, binding, onRecord, onInvalid }) {
|
|
2720
|
+
const [recording, setRecording] = import_react8.useState(false);
|
|
2721
|
+
const ref = import_react8.useRef(null);
|
|
2722
|
+
return /* @__PURE__ */ jsx_runtime7.jsx("button", {
|
|
2723
|
+
ref,
|
|
2724
|
+
type: "button",
|
|
2725
|
+
className: `gui-key${recording ? " is-recording" : ""}`,
|
|
2726
|
+
"aria-label": recording ? `Press the new key for ${label}` : `${label}: ${binding ? formatBinding(binding) : "no key"}, click to ${binding ? "change" : "set one"}`,
|
|
2727
|
+
onClick: () => setRecording((r) => !r),
|
|
2728
|
+
onBlur: () => setRecording(false),
|
|
2729
|
+
onKeyDown: (e) => {
|
|
2730
|
+
if (!recording)
|
|
2731
|
+
return;
|
|
2732
|
+
e.preventDefault();
|
|
2733
|
+
e.stopPropagation();
|
|
2734
|
+
if (e.key === "Escape" && !e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey) {
|
|
2735
|
+
setRecording(false);
|
|
2736
|
+
return;
|
|
2737
|
+
}
|
|
2738
|
+
const pressed = bindingOf(e.nativeEvent);
|
|
2739
|
+
if (!pressed)
|
|
2740
|
+
return;
|
|
2741
|
+
const b = normalBinding(pressed);
|
|
2742
|
+
setRecording(false);
|
|
2743
|
+
if (!b)
|
|
2744
|
+
onInvalid(`${formatBinding(pressed)} is typing, not a command: hold ${isMac() ? "⌘, ⌥ or ⌃" : "Ctrl or Alt"} with it.`);
|
|
2745
|
+
else if (b !== binding)
|
|
2746
|
+
onRecord(b);
|
|
2747
|
+
},
|
|
2748
|
+
children: recording ? "Press keys…" : binding ? formatBinding(binding) : /* @__PURE__ */ jsx_runtime7.jsx("span", {
|
|
2749
|
+
className: "gui-key-none",
|
|
2750
|
+
children: "Not set"
|
|
1637
2751
|
})
|
|
1638
2752
|
});
|
|
1639
2753
|
}
|
|
2754
|
+
var tilde2 = (path, home) => home && (path === home || path.startsWith(`${home}/`)) ? `~${path.slice(home.length)}` : path;
|
|
2755
|
+
function Fact({ name, value, copy, mono }) {
|
|
2756
|
+
const [copied, setCopied] = import_react8.useState(false);
|
|
2757
|
+
return /* @__PURE__ */ jsx_runtime7.jsxs("div", {
|
|
2758
|
+
className: "gui-fact",
|
|
2759
|
+
children: [
|
|
2760
|
+
/* @__PURE__ */ jsx_runtime7.jsx("dt", {
|
|
2761
|
+
children: name
|
|
2762
|
+
}),
|
|
2763
|
+
/* @__PURE__ */ jsx_runtime7.jsxs("dd", {
|
|
2764
|
+
className: mono ? "is-mono" : undefined,
|
|
2765
|
+
children: [
|
|
2766
|
+
/* @__PURE__ */ jsx_runtime7.jsx("span", {
|
|
2767
|
+
className: "gui-fact-value",
|
|
2768
|
+
title: copy,
|
|
2769
|
+
children: value
|
|
2770
|
+
}),
|
|
2771
|
+
copy && /* @__PURE__ */ jsx_runtime7.jsx("button", {
|
|
2772
|
+
type: "button",
|
|
2773
|
+
className: "gui-fact-copy",
|
|
2774
|
+
"aria-label": `Copy ${name}`,
|
|
2775
|
+
title: copied ? "Copied" : "Copy",
|
|
2776
|
+
onClick: () => {
|
|
2777
|
+
navigator.clipboard?.writeText(copy).then(() => {
|
|
2778
|
+
setCopied(true);
|
|
2779
|
+
setTimeout(() => setCopied(false), 1200);
|
|
2780
|
+
});
|
|
2781
|
+
},
|
|
2782
|
+
children: copied ? "Copied" : "Copy"
|
|
2783
|
+
})
|
|
2784
|
+
]
|
|
2785
|
+
})
|
|
2786
|
+
]
|
|
2787
|
+
});
|
|
2788
|
+
}
|
|
2789
|
+
function Facts({ title, rows }) {
|
|
2790
|
+
return /* @__PURE__ */ jsx_runtime7.jsxs("section", {
|
|
2791
|
+
className: "gui-facts",
|
|
2792
|
+
children: [
|
|
2793
|
+
/* @__PURE__ */ jsx_runtime7.jsx("h2", {
|
|
2794
|
+
children: title
|
|
2795
|
+
}),
|
|
2796
|
+
/* @__PURE__ */ jsx_runtime7.jsx("dl", {
|
|
2797
|
+
children: rows.filter((r) => !!r).map((r) => /* @__PURE__ */ jsx_runtime7.jsx(Fact, {
|
|
2798
|
+
...r
|
|
2799
|
+
}, r.name))
|
|
2800
|
+
})
|
|
2801
|
+
]
|
|
2802
|
+
});
|
|
2803
|
+
}
|
|
2804
|
+
function About({ baba }) {
|
|
2805
|
+
const [p, setP] = import_react8.useState(null);
|
|
2806
|
+
const [failed, setFailed] = import_react8.useState(null);
|
|
2807
|
+
const [copied, setCopied] = import_react8.useState(false);
|
|
2808
|
+
import_react8.useEffect(() => {
|
|
2809
|
+
let live = true;
|
|
2810
|
+
fetch("/api/projects", { headers: apiHeaders() }).then(async (r) => {
|
|
2811
|
+
if (!r.ok)
|
|
2812
|
+
throw new Error(r.statusText);
|
|
2813
|
+
return r.json();
|
|
2814
|
+
}).then((x) => {
|
|
2815
|
+
if (live)
|
|
2816
|
+
setP(x);
|
|
2817
|
+
}, (e) => {
|
|
2818
|
+
if (live)
|
|
2819
|
+
setFailed(String(e));
|
|
2820
|
+
});
|
|
2821
|
+
return () => {
|
|
2822
|
+
live = false;
|
|
2823
|
+
};
|
|
2824
|
+
}, []);
|
|
2825
|
+
if (failed)
|
|
2826
|
+
return /* @__PURE__ */ jsx_runtime7.jsxs("p", {
|
|
2827
|
+
className: "bv-error",
|
|
2828
|
+
children: [
|
|
2829
|
+
"voss did not answer: ",
|
|
2830
|
+
failed
|
|
2831
|
+
]
|
|
2832
|
+
});
|
|
2833
|
+
if (!p)
|
|
2834
|
+
return /* @__PURE__ */ jsx_runtime7.jsx("p", {
|
|
2835
|
+
className: "bv-muted",
|
|
2836
|
+
children: "…"
|
|
2837
|
+
});
|
|
2838
|
+
const { voss, home } = p, a = voss.about;
|
|
2839
|
+
const here = baba && p.projects.find((x) => x.name === baba.name);
|
|
2840
|
+
const path = (name, full) => ({ name, value: tilde2(full, home), copy: full, mono: true });
|
|
2841
|
+
const m = baba?.manifest;
|
|
2842
|
+
const sections = [
|
|
2843
|
+
{ title: "voss", rows: [
|
|
2844
|
+
{ name: "Version", value: /* @__PURE__ */ jsx_runtime7.jsxs(jsx_runtime7.Fragment, {
|
|
2845
|
+
children: [
|
|
2846
|
+
voss.version,
|
|
2847
|
+
voss.dev && /* @__PURE__ */ jsx_runtime7.jsx("span", {
|
|
2848
|
+
className: "gui-fact-tag",
|
|
2849
|
+
children: "checkout"
|
|
2850
|
+
}),
|
|
2851
|
+
voss.stale && voss.installed && /* @__PURE__ */ jsx_runtime7.jsxs("span", {
|
|
2852
|
+
className: "gui-fact-tag is-warn",
|
|
2853
|
+
children: [
|
|
2854
|
+
voss.installed.version,
|
|
2855
|
+
" installed, restart to update"
|
|
2856
|
+
]
|
|
2857
|
+
})
|
|
2858
|
+
]
|
|
2859
|
+
}), copy: voss.version },
|
|
2860
|
+
{ name: "Commit", value: voss.sha ? voss.sha.slice(0, 12) : voss.dev ? "the working tree" : "not stamped", ...voss.sha ? { copy: voss.sha, mono: true } : {} },
|
|
2861
|
+
voss.at && { name: "Packed", value: new Date(voss.at).toLocaleString() },
|
|
2862
|
+
{ name: "Address", value: location.origin, copy: location.origin, mono: true },
|
|
2863
|
+
{ name: "Process", value: `pid ${voss.pid}${a ? `, since ${new Date(a.started).toLocaleString()}` : ""}` },
|
|
2864
|
+
{ name: "Runs as", value: voss.kept ? "the user service" : "a command, until it stops" }
|
|
2865
|
+
] },
|
|
2866
|
+
...a ? [
|
|
2867
|
+
{ title: "Runtime", rows: [
|
|
2868
|
+
{ name: "Bun", value: a.runtime.bun, copy: a.runtime.bun },
|
|
2869
|
+
{ name: "Platform", value: `${a.runtime.platform} ${a.runtime.arch}` },
|
|
2870
|
+
path("Executable", a.runtime.executable)
|
|
2871
|
+
] },
|
|
2872
|
+
{ title: "Installation", rows: [
|
|
2873
|
+
path("Framework", a.framework),
|
|
2874
|
+
a.cli && path("CLI", a.cli),
|
|
2875
|
+
path("State", a.root),
|
|
2876
|
+
path("Registry", a.registry),
|
|
2877
|
+
path("Page token", a.token),
|
|
2878
|
+
a.service && path("User service", a.service.file),
|
|
2879
|
+
a.service && path("Service log", a.service.log)
|
|
2880
|
+
] }
|
|
2881
|
+
] : [],
|
|
2882
|
+
...baba ? [{ title: "This baba", rows: [
|
|
2883
|
+
{ name: "Name", value: baba.name, copy: baba.name, mono: true },
|
|
2884
|
+
{ name: "Title", value: baba.title },
|
|
2885
|
+
here && path("Directory", here.dir),
|
|
2886
|
+
here && path("Code", `${here.dir}/.baba`),
|
|
2887
|
+
here?.parent && { name: "Inside", value: here.parent },
|
|
2888
|
+
{ name: "Generation", value: String(baba.gen) },
|
|
2889
|
+
m && { name: "Contract", value: `${m.systems.length} systems, ${Object.keys(m.actions).length} actions, ${Object.keys(m.queries).length} queries, ${(m.apps ?? []).length} apps` },
|
|
2890
|
+
baba.error && { name: "Load", value: /* @__PURE__ */ jsx_runtime7.jsx("span", {
|
|
2891
|
+
className: "gui-fact-error",
|
|
2892
|
+
children: baba.error
|
|
2893
|
+
}) }
|
|
2894
|
+
] }] : []
|
|
2895
|
+
];
|
|
2896
|
+
const report = sections.map((s2) => [`# ${s2.title}`, ...s2.rows.filter((r) => !!r).map((r) => `${r.name}: ${r.copy ?? (typeof r.value === "string" ? r.value : "")}`)].join(`
|
|
2897
|
+
`)).join(`
|
|
2898
|
+
|
|
2899
|
+
`);
|
|
2900
|
+
return /* @__PURE__ */ jsx_runtime7.jsxs("div", {
|
|
2901
|
+
className: "gui-about",
|
|
2902
|
+
children: [
|
|
2903
|
+
sections.map((s2) => /* @__PURE__ */ jsx_runtime7.jsx(Facts, {
|
|
2904
|
+
...s2
|
|
2905
|
+
}, s2.title)),
|
|
2906
|
+
/* @__PURE__ */ jsx_runtime7.jsxs("p", {
|
|
2907
|
+
className: "gui-settings-foot bv-muted",
|
|
2908
|
+
children: [
|
|
2909
|
+
/* @__PURE__ */ jsx_runtime7.jsx(Button, {
|
|
2910
|
+
variant: "quiet",
|
|
2911
|
+
onClick: () => {
|
|
2912
|
+
navigator.clipboard?.writeText(report).then(() => {
|
|
2913
|
+
setCopied(true);
|
|
2914
|
+
setTimeout(() => setCopied(false), 1200);
|
|
2915
|
+
});
|
|
2916
|
+
},
|
|
2917
|
+
children: copied ? "Copied" : "Copy all"
|
|
2918
|
+
}),
|
|
2919
|
+
"As plain text, for a bug report."
|
|
2920
|
+
]
|
|
2921
|
+
})
|
|
2922
|
+
]
|
|
2923
|
+
});
|
|
2924
|
+
}
|
|
1640
2925
|
|
|
1641
2926
|
// src/kernel/names.ts
|
|
1642
2927
|
var buildName = (b) => b.dev ? "source" : b.version || b.sha || "unstamped";
|
|
@@ -1649,7 +2934,7 @@ function tellApart(a, b) {
|
|
|
1649
2934
|
}
|
|
1650
2935
|
|
|
1651
2936
|
// src/gui/gui.tsx
|
|
1652
|
-
var
|
|
2937
|
+
var jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
|
|
1653
2938
|
var scope = document.querySelector('meta[name="voss-scope"]')?.getAttribute("content") ?? "";
|
|
1654
2939
|
async function describe(name, since, signal) {
|
|
1655
2940
|
const r = await fetch(`/api/describe/${encodeURIComponent(name)}${since ? `?since=${since}` : ""}`, { signal, headers: apiHeaders() });
|
|
@@ -1659,9 +2944,9 @@ async function describe(name, since, signal) {
|
|
|
1659
2944
|
return d;
|
|
1660
2945
|
}
|
|
1661
2946
|
function useDescribed(name) {
|
|
1662
|
-
const [d, setD] =
|
|
1663
|
-
const [failed, setFailed] =
|
|
1664
|
-
|
|
2947
|
+
const [d, setD] = import_react9.useState(null);
|
|
2948
|
+
const [failed, setFailed] = import_react9.useState(null);
|
|
2949
|
+
import_react9.useEffect(() => {
|
|
1665
2950
|
const ctl = new AbortController;
|
|
1666
2951
|
(async () => {
|
|
1667
2952
|
let since = 0;
|
|
@@ -1686,9 +2971,9 @@ function useDescribed(name) {
|
|
|
1686
2971
|
}
|
|
1687
2972
|
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
1688
2973
|
function Stale() {
|
|
1689
|
-
const [b, setB] =
|
|
1690
|
-
const [restarting, setRestarting] =
|
|
1691
|
-
|
|
2974
|
+
const [b, setB] = import_react9.useState(null);
|
|
2975
|
+
const [restarting, setRestarting] = import_react9.useState(false);
|
|
2976
|
+
import_react9.useEffect(() => {
|
|
1692
2977
|
let live = true;
|
|
1693
2978
|
const tick = async () => {
|
|
1694
2979
|
try {
|
|
@@ -1732,27 +3017,27 @@ function Stale() {
|
|
|
1732
3017
|
}
|
|
1733
3018
|
setRestarting(false);
|
|
1734
3019
|
};
|
|
1735
|
-
return /* @__PURE__ */
|
|
3020
|
+
return /* @__PURE__ */ jsx_runtime8.jsx("div", {
|
|
1736
3021
|
className: "gui-stale",
|
|
1737
3022
|
role: "status",
|
|
1738
|
-
children: restarting ? /* @__PURE__ */
|
|
3023
|
+
children: restarting ? /* @__PURE__ */ jsx_runtime8.jsx("span", {
|
|
1739
3024
|
children: "Restarting voss…"
|
|
1740
|
-
}) : /* @__PURE__ */
|
|
3025
|
+
}) : /* @__PURE__ */ jsx_runtime8.jsxs(jsx_runtime8.Fragment, {
|
|
1741
3026
|
children: [
|
|
1742
|
-
/* @__PURE__ */
|
|
3027
|
+
/* @__PURE__ */ jsx_runtime8.jsxs("span", {
|
|
1743
3028
|
children: [
|
|
1744
3029
|
"voss ",
|
|
1745
|
-
/* @__PURE__ */
|
|
3030
|
+
/* @__PURE__ */ jsx_runtime8.jsx("b", {
|
|
1746
3031
|
children: installed
|
|
1747
3032
|
}),
|
|
1748
3033
|
" is installed; this page runs on ",
|
|
1749
|
-
/* @__PURE__ */
|
|
3034
|
+
/* @__PURE__ */ jsx_runtime8.jsx("b", {
|
|
1750
3035
|
children: running
|
|
1751
3036
|
}),
|
|
1752
3037
|
". Changes on disk wait for the restart."
|
|
1753
3038
|
]
|
|
1754
3039
|
}),
|
|
1755
|
-
/* @__PURE__ */
|
|
3040
|
+
/* @__PURE__ */ jsx_runtime8.jsx(Button, {
|
|
1756
3041
|
onClick: () => void restart(),
|
|
1757
3042
|
children: "Restart to update"
|
|
1758
3043
|
})
|
|
@@ -1765,8 +3050,8 @@ function Host() {
|
|
|
1765
3050
|
const { d, failed } = useDescribed(scope);
|
|
1766
3051
|
const parts = location.pathname.split("/").filter(Boolean);
|
|
1767
3052
|
const to = d && parts.length === 2 && !(d.manifest?.apps ?? []).some((a) => a.key === parts[1]) ? moved[parts[1]] : undefined;
|
|
1768
|
-
const [, moveOn] =
|
|
1769
|
-
|
|
3053
|
+
const [, moveOn] = import_react9.useState(0);
|
|
3054
|
+
import_react9.useEffect(() => {
|
|
1770
3055
|
if (to) {
|
|
1771
3056
|
history.replaceState(null, "", `/${encodeURIComponent(scope)}/${to}${location.search}${location.hash}`);
|
|
1772
3057
|
moveOn((n) => n + 1);
|
|
@@ -1775,17 +3060,24 @@ function Host() {
|
|
|
1775
3060
|
if (to)
|
|
1776
3061
|
return null;
|
|
1777
3062
|
if (!d)
|
|
1778
|
-
return /* @__PURE__ */
|
|
3063
|
+
return failed ? /* @__PURE__ */ jsx_runtime8.jsx("div", {
|
|
1779
3064
|
className: "gui-page",
|
|
1780
|
-
children: /* @__PURE__ */
|
|
3065
|
+
children: /* @__PURE__ */ jsx_runtime8.jsxs("p", {
|
|
1781
3066
|
className: "bv-muted",
|
|
1782
|
-
children:
|
|
3067
|
+
children: [
|
|
3068
|
+
scope,
|
|
3069
|
+
" did not answer: ",
|
|
3070
|
+
failed
|
|
3071
|
+
]
|
|
1783
3072
|
})
|
|
3073
|
+
}) : /* @__PURE__ */ jsx_runtime8.jsx("div", {
|
|
3074
|
+
className: "gui-view",
|
|
3075
|
+
children: /* @__PURE__ */ jsx_runtime8.jsx(DesktopSkeleton, {})
|
|
1784
3076
|
});
|
|
1785
3077
|
if (!d.manifest)
|
|
1786
|
-
return /* @__PURE__ */
|
|
3078
|
+
return /* @__PURE__ */ jsx_runtime8.jsx("div", {
|
|
1787
3079
|
className: "gui-page",
|
|
1788
|
-
children: /* @__PURE__ */
|
|
3080
|
+
children: /* @__PURE__ */ jsx_runtime8.jsxs("p", {
|
|
1789
3081
|
className: "bv-error",
|
|
1790
3082
|
children: [
|
|
1791
3083
|
d.title,
|
|
@@ -1794,23 +3086,23 @@ function Host() {
|
|
|
1794
3086
|
]
|
|
1795
3087
|
})
|
|
1796
3088
|
});
|
|
1797
|
-
return /* @__PURE__ */
|
|
3089
|
+
return /* @__PURE__ */ jsx_runtime8.jsx(ShellPage, {
|
|
1798
3090
|
d
|
|
1799
3091
|
});
|
|
1800
3092
|
}
|
|
1801
3093
|
function Failure({ f }) {
|
|
1802
|
-
return /* @__PURE__ */
|
|
3094
|
+
return /* @__PURE__ */ jsx_runtime8.jsxs("div", {
|
|
1803
3095
|
className: "gui-notice",
|
|
1804
3096
|
role: "alert",
|
|
1805
3097
|
children: [
|
|
1806
|
-
/* @__PURE__ */
|
|
3098
|
+
/* @__PURE__ */ jsx_runtime8.jsxs("strong", {
|
|
1807
3099
|
children: [
|
|
1808
3100
|
"The interface did not ",
|
|
1809
3101
|
f.stage === "build" ? "build" : f.stage === "load" ? "load" : "render",
|
|
1810
3102
|
"."
|
|
1811
3103
|
]
|
|
1812
3104
|
}),
|
|
1813
|
-
/* @__PURE__ */
|
|
3105
|
+
/* @__PURE__ */ jsx_runtime8.jsx("pre", {
|
|
1814
3106
|
className: "gui-failure",
|
|
1815
3107
|
children: formatFailure(f)
|
|
1816
3108
|
})
|
|
@@ -1838,9 +3130,9 @@ async function loadView(name, v) {
|
|
|
1838
3130
|
}
|
|
1839
3131
|
function useInterface(d) {
|
|
1840
3132
|
const v = d.view && !d.view.error ? d.view.v : undefined;
|
|
1841
|
-
const [view, setView] =
|
|
1842
|
-
const [failure, setFailure] =
|
|
1843
|
-
|
|
3133
|
+
const [view, setView] = import_react9.useState(() => v !== undefined ? loaded.get(v) ?? null : null);
|
|
3134
|
+
const [failure, setFailure] = import_react9.useState(null);
|
|
3135
|
+
import_react9.useEffect(() => {
|
|
1844
3136
|
if (v === undefined)
|
|
1845
3137
|
return;
|
|
1846
3138
|
let live = true;
|
|
@@ -1857,7 +3149,7 @@ function useInterface(d) {
|
|
|
1857
3149
|
live = false;
|
|
1858
3150
|
};
|
|
1859
3151
|
}, [d.name, v]);
|
|
1860
|
-
|
|
3152
|
+
import_react9.useEffect(() => {
|
|
1861
3153
|
if (!view)
|
|
1862
3154
|
return;
|
|
1863
3155
|
const links = view.css.map((href2) => {
|
|
@@ -1876,51 +3168,49 @@ function useInterface(d) {
|
|
|
1876
3168
|
}
|
|
1877
3169
|
var useShellSystem = (apps) => {
|
|
1878
3170
|
const key = JSON.stringify(apps ?? []);
|
|
1879
|
-
return
|
|
3171
|
+
return import_react9.useMemo(() => desktop({ apps: apps ?? [] }), [key]);
|
|
1880
3172
|
};
|
|
1881
3173
|
function ShellPage({ d }) {
|
|
1882
3174
|
const { view, failure } = useInterface(d);
|
|
1883
3175
|
const system2 = useShellSystem(d.manifest?.apps);
|
|
3176
|
+
const person = useVossSettings();
|
|
1884
3177
|
const manifest = d.manifest;
|
|
1885
|
-
const components =
|
|
1886
|
-
const pending = () => failure ? /* @__PURE__ */
|
|
3178
|
+
const components = import_react9.useMemo(() => {
|
|
3179
|
+
const pending = () => failure ? /* @__PURE__ */ jsx_runtime8.jsx(Failure, {
|
|
1887
3180
|
f: failure
|
|
1888
|
-
}) :
|
|
1889
|
-
className: "desktop-empty bv-muted",
|
|
1890
|
-
children: "…"
|
|
1891
|
-
});
|
|
3181
|
+
}) : null;
|
|
1892
3182
|
const out = {
|
|
1893
|
-
maker: ({ path, navigate, setTitle }) => /* @__PURE__ */
|
|
3183
|
+
maker: ({ path, navigate, setTitle }) => /* @__PURE__ */ jsx_runtime8.jsx(Maker, {
|
|
1894
3184
|
specs: [],
|
|
1895
3185
|
title: d.title,
|
|
1896
3186
|
path,
|
|
1897
3187
|
navigate,
|
|
1898
3188
|
setTitle
|
|
1899
3189
|
}),
|
|
1900
|
-
state: () => /* @__PURE__ */
|
|
3190
|
+
state: () => /* @__PURE__ */ jsx_runtime8.jsxs("section", {
|
|
1901
3191
|
className: "gui-app",
|
|
1902
3192
|
children: [
|
|
1903
|
-
d.error && /* @__PURE__ */
|
|
3193
|
+
d.error && /* @__PURE__ */ jsx_runtime8.jsxs("p", {
|
|
1904
3194
|
className: "bv-error",
|
|
1905
3195
|
children: [
|
|
1906
3196
|
"The code did not load; the last generation serves: ",
|
|
1907
3197
|
d.error
|
|
1908
3198
|
]
|
|
1909
3199
|
}),
|
|
1910
|
-
/* @__PURE__ */
|
|
3200
|
+
/* @__PURE__ */ jsx_runtime8.jsx(Inspector, {
|
|
1911
3201
|
manifest
|
|
1912
3202
|
})
|
|
1913
3203
|
]
|
|
1914
3204
|
}),
|
|
1915
|
-
contract: () => /* @__PURE__ */
|
|
3205
|
+
contract: () => /* @__PURE__ */ jsx_runtime8.jsx("section", {
|
|
1916
3206
|
className: "gui-app",
|
|
1917
|
-
children: /* @__PURE__ */
|
|
3207
|
+
children: /* @__PURE__ */ jsx_runtime8.jsx(Runner, {
|
|
1918
3208
|
manifest
|
|
1919
3209
|
})
|
|
1920
3210
|
}),
|
|
1921
|
-
|
|
3211
|
+
instructions: () => /* @__PURE__ */ jsx_runtime8.jsx("section", {
|
|
1922
3212
|
className: "gui-app",
|
|
1923
|
-
children: /* @__PURE__ */
|
|
3213
|
+
children: /* @__PURE__ */ jsx_runtime8.jsx(Instructions, {
|
|
1924
3214
|
manifest
|
|
1925
3215
|
})
|
|
1926
3216
|
}),
|
|
@@ -1929,7 +3219,7 @@ function ShellPage({ d }) {
|
|
|
1929
3219
|
for (const sc of manifest.apps ?? []) {
|
|
1930
3220
|
if (sc.key in out)
|
|
1931
3221
|
continue;
|
|
1932
|
-
out[sc.key] = sc.key === "view" && !view?.apps[sc.key] ? view?.View ? view.View : !d.view ? () => /* @__PURE__ */
|
|
3222
|
+
out[sc.key] = sc.key === "view" && !view?.apps[sc.key] ? view?.View ? view.View : !d.view ? () => /* @__PURE__ */ jsx_runtime8.jsx("p", {
|
|
1933
3223
|
className: "desktop-empty bv-muted",
|
|
1934
3224
|
children: "This baba has no interface.tsx yet: its apps are voss's."
|
|
1935
3225
|
}) : pending : pending;
|
|
@@ -1938,65 +3228,36 @@ function ShellPage({ d }) {
|
|
|
1938
3228
|
out[k] = v;
|
|
1939
3229
|
return out;
|
|
1940
3230
|
}, [view, failure, system2, manifest, d.error, d.view, d.title]);
|
|
1941
|
-
return /* @__PURE__ */
|
|
3231
|
+
return /* @__PURE__ */ jsx_runtime8.jsx("div", {
|
|
1942
3232
|
className: "gui-view",
|
|
1943
|
-
children: /* @__PURE__ */
|
|
1944
|
-
|
|
3233
|
+
children: /* @__PURE__ */ jsx_runtime8.jsx(ViewBoundary, {
|
|
3234
|
+
reset: view,
|
|
3235
|
+
fallback: (f) => /* @__PURE__ */ jsx_runtime8.jsx("div", {
|
|
1945
3236
|
className: "gui-page",
|
|
1946
|
-
children: /* @__PURE__ */
|
|
3237
|
+
children: /* @__PURE__ */ jsx_runtime8.jsx(Failure, {
|
|
1947
3238
|
f
|
|
1948
3239
|
})
|
|
1949
3240
|
}),
|
|
1950
|
-
children: /* @__PURE__ */
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
}
|
|
1959
|
-
function Settings() {
|
|
1960
|
-
const system2 = import_react6.useMemo(() => desktop({}), []);
|
|
1961
|
-
const current = useResource(system2.desktopSettings)?.theme ?? "system";
|
|
1962
|
-
const { fire } = useBaba();
|
|
1963
|
-
return /* @__PURE__ */ jsx_runtime6.jsxs("section", {
|
|
1964
|
-
className: "gui-app",
|
|
1965
|
-
children: [
|
|
1966
|
-
/* @__PURE__ */ jsx_runtime6.jsx("h2", {
|
|
1967
|
-
children: "Theme"
|
|
1968
|
-
}),
|
|
1969
|
-
/* @__PURE__ */ jsx_runtime6.jsx("p", {
|
|
1970
|
-
className: "bv-muted",
|
|
1971
|
-
children: "The theme every page of this baba shows, kept in its state."
|
|
1972
|
-
}),
|
|
1973
|
-
/* @__PURE__ */ jsx_runtime6.jsx("div", {
|
|
1974
|
-
className: "gui-choices",
|
|
1975
|
-
role: "radiogroup",
|
|
1976
|
-
"aria-label": "Theme",
|
|
1977
|
-
children: themes.map((t) => /* @__PURE__ */ jsx_runtime6.jsx(Button, {
|
|
1978
|
-
variant: t === current ? "default" : "quiet",
|
|
1979
|
-
role: "radio",
|
|
1980
|
-
"aria-checked": t === current,
|
|
1981
|
-
onClick: () => void fire("desktop-settings", { theme: t }),
|
|
1982
|
-
children: t
|
|
1983
|
-
}, t))
|
|
1984
|
-
}),
|
|
1985
|
-
/* @__PURE__ */ jsx_runtime6.jsx("h2", {
|
|
1986
|
-
children: "voss"
|
|
1987
|
-
}),
|
|
1988
|
-
/* @__PURE__ */ jsx_runtime6.jsx("p", {
|
|
1989
|
-
children: /* @__PURE__ */ jsx_runtime6.jsx("a", {
|
|
1990
|
-
href: "/",
|
|
1991
|
-
children: "All babas"
|
|
3241
|
+
children: /* @__PURE__ */ jsx_runtime8.jsx(SettingsBaba.Provider, {
|
|
3242
|
+
value: d,
|
|
3243
|
+
children: /* @__PURE__ */ jsx_runtime8.jsx(Desktop, {
|
|
3244
|
+
system: system2,
|
|
3245
|
+
apps: components,
|
|
3246
|
+
title: d.title,
|
|
3247
|
+
root: { label: "voss", href: "/" },
|
|
3248
|
+
settings: person
|
|
1992
3249
|
})
|
|
1993
3250
|
})
|
|
1994
|
-
|
|
3251
|
+
})
|
|
1995
3252
|
});
|
|
1996
3253
|
}
|
|
1997
3254
|
|
|
1998
|
-
class ViewBoundary extends
|
|
3255
|
+
class ViewBoundary extends import_react9.Component {
|
|
1999
3256
|
state = { failure: null };
|
|
3257
|
+
componentDidUpdate(before) {
|
|
3258
|
+
if (before.reset !== this.props.reset && this.state.failure)
|
|
3259
|
+
this.setState({ failure: null });
|
|
3260
|
+
}
|
|
2000
3261
|
static getDerivedStateFromError(err) {
|
|
2001
3262
|
return { failure: { stage: "render", message: err instanceof Error ? err.message : String(err), detail: err instanceof Error ? err.stack : undefined } };
|
|
2002
3263
|
}
|
|
@@ -2004,12 +3265,12 @@ class ViewBoundary extends import_react6.Component {
|
|
|
2004
3265
|
return this.state.failure ? this.props.fallback(this.state.failure) : this.props.children;
|
|
2005
3266
|
}
|
|
2006
3267
|
}
|
|
2007
|
-
import_client.createRoot(document.getElementById("root")).render(/* @__PURE__ */
|
|
3268
|
+
import_client.createRoot(document.getElementById("root")).render(/* @__PURE__ */ jsx_runtime8.jsxs(import_react9.StrictMode, {
|
|
2008
3269
|
children: [
|
|
2009
|
-
scope ? /* @__PURE__ */
|
|
3270
|
+
scope ? /* @__PURE__ */ jsx_runtime8.jsx(ScopeProvider, {
|
|
2010
3271
|
value: scope,
|
|
2011
|
-
children: /* @__PURE__ */
|
|
2012
|
-
}) : /* @__PURE__ */
|
|
2013
|
-
/* @__PURE__ */
|
|
3272
|
+
children: /* @__PURE__ */ jsx_runtime8.jsx(Host, {})
|
|
3273
|
+
}) : /* @__PURE__ */ jsx_runtime8.jsx(Root, {}),
|
|
3274
|
+
/* @__PURE__ */ jsx_runtime8.jsx(Stale, {})
|
|
2014
3275
|
]
|
|
2015
3276
|
}));
|