@miadi/chronicle-tui 0.7.0 → 0.8.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/README.md +23 -0
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +104 -3
- package/dist/App.js.map +1 -1
- package/dist/actions.d.ts +11 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +19 -0
- package/dist/actions.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/sessions.d.ts +76 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +148 -0
- package/dist/sessions.js.map +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -36,6 +36,8 @@ On Termux, install with `--ignore-scripts`. Node 22 or later.
|
|
|
36
36
|
| `v` | hold a Miadi review in the episode (writer token) |
|
|
37
37
|
| `i` | the episode's inquiries and, when you may write, the shelf: Enter attaches one, a dry run first, `y` confirms |
|
|
38
38
|
| `t` | the episode's companion seat (Mia) through tide: the plan first, `y` runs it only when it would act, `A` asks again archiving the running session |
|
|
39
|
+
| `T` | this machine's tmux sessions, the episode in focus's first. Inside tmux, Enter opens one beside the chronicle; outside, it hands the terminal over until you detach |
|
|
40
|
+
| `F`, `X` | with a session beside: focus it (prefix+arrow comes back); close the split (the session goes on) |
|
|
39
41
|
| `L` | relate episodes: `L` marks the one in focus, move to the other, `L` again, say why (relates to or continues from, one way or both). Esc forgets the mark |
|
|
40
42
|
| `?` | all keys · `q` quits |
|
|
41
43
|
|
|
@@ -97,6 +99,27 @@ miadi-chronicle --url https://miadi.tail3b11eb.ts.net
|
|
|
97
99
|
Write actions declare `effect: "write"` and are offered only when the app said
|
|
98
100
|
it would record them.
|
|
99
101
|
|
|
102
|
+
## A session beside the chronicle
|
|
103
|
+
|
|
104
|
+
Run the browser inside tmux and `T` lists the sessions on this machine, each
|
|
105
|
+
with the episode it works in (the vessel its pane is in, or the number its
|
|
106
|
+
name carries), the sessions of the episode in focus first. Enter on one:
|
|
107
|
+
|
|
108
|
+
- **inside tmux**, tmux splits the browser's window and shows that session in
|
|
109
|
+
the split, live, as a client of its own (`env -u TMUX tmux attach`). You type
|
|
110
|
+
in it directly. The prefix once moves between the panes; the session's own
|
|
111
|
+
tmux keys take the prefix twice. The browser jumps to the session's episode
|
|
112
|
+
and keeps it current: its files are read again every 5 s, and a file changed
|
|
113
|
+
in the last 15 minutes is marked ●, so you see what the agent is touching.
|
|
114
|
+
The header shows `⇆ <session> · <command> · <idle>`. `F` focuses the split,
|
|
115
|
+
`X` closes it, and the session goes on, as it does when you detach inside it.
|
|
116
|
+
- **outside tmux**, the browser steps aside and runs `tmux attach` in this
|
|
117
|
+
terminal; `prefix d` brings you back to the same screen.
|
|
118
|
+
|
|
119
|
+
While you type in it, the split is that session's most recent client, so its
|
|
120
|
+
window takes the split's size, as with any tmux client. The browser never types
|
|
121
|
+
into a session; only your keys reach it, and tmux never inherits a token.
|
|
122
|
+
|
|
100
123
|
## Inquiries and the companion seat
|
|
101
124
|
|
|
102
125
|
Both show what would happen before anything does, and act only on `y`:
|
package/dist/App.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../src/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAiD,MAAM,OAAO,CAAA;AAIrE,OAAO,EAML,KAAK,eAAe,EAIrB,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../src/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAiD,MAAM,OAAO,CAAA;AAIrE,OAAO,EAML,KAAK,eAAe,EAIrB,MAAM,cAAc,CAAA;AAmFrB,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAA;IACpC,kFAAkF;IAClF,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,sEAAsE;IACtE,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7B;AAyHD,wBAAgB,GAAG,CAAC,KAAK,EAAE,QAAQ,qBA8yDlC"}
|
package/dist/App.js
CHANGED
|
@@ -21,6 +21,7 @@ import { BOARD_LABELS, ROOM_LABELS, answeredMessage, checkAnswer, filterBoard, l
|
|
|
21
21
|
import { CEREMONY_TYPES, DIARY_PHASES, DIRECTIONS, ENTRY_TYPES, PHASE_LABELS, ceremonyHeadline, ceremonyLines, circleEntries, closeCeremony, mayWitness, openCeremony, readCeremony, readCircle, scrollTo, speak, splitLearnings, typeLabel, whenOf, witness, writeDiary, } from "./circles.js";
|
|
22
22
|
import { THREAD, attachInquiry, attachedMessage, previewLines, readInquiries } from "./inquiries.js";
|
|
23
23
|
import { companionLines, companionPlan, planActs, ranMessage, runCompanion } from "./tide.js";
|
|
24
|
+
import { attachHere, closePane, focusPane, idleFor, insideTmux, listSessions, openBeside, orderSessions, paneAlive, tmuxEnv, } from "./sessions.js";
|
|
24
25
|
import { VISITOR, wheelDoors, loadChronicle, loadDetail, loadText, openUrl, qrLines, search, visibleRows, } from "./data.js";
|
|
25
26
|
import { ageOf, clamp, fileView, filterRows, formatDate, screenLineOf, windowOf, wrapSegments, } from "./model.js";
|
|
26
27
|
import { clean, cleanLine, link } from "./text.js";
|
|
@@ -88,7 +89,7 @@ const PLAIN_KEY = {
|
|
|
88
89
|
};
|
|
89
90
|
export function App(props) {
|
|
90
91
|
const { root, actions: extra = [], url, withheld = [] } = props;
|
|
91
|
-
const { exit } = useApp();
|
|
92
|
+
const { exit, suspendTerminal } = useApp();
|
|
92
93
|
const { columns, rows } = useWindowSize();
|
|
93
94
|
const [, render] = useReducer((n) => n + 1, 0);
|
|
94
95
|
const ui = useRef({
|
|
@@ -670,6 +671,70 @@ export function App(props) {
|
|
|
670
671
|
set({ status: cleanLine(`The seat did not open: ${error.message}`) });
|
|
671
672
|
});
|
|
672
673
|
};
|
|
674
|
+
// ── a tmux session beside the chronicle ───────────────────────────────────
|
|
675
|
+
const sessionRowsOf = (o) => {
|
|
676
|
+
const d = derive();
|
|
677
|
+
return o.sessions && d.s.chronicle ? orderSessions(o.sessions, d.visible, d.s.chronicle.root, o.episode, o.own) : [];
|
|
678
|
+
};
|
|
679
|
+
const closeBeside = async (message) => {
|
|
680
|
+
const beside = ui.current.beside;
|
|
681
|
+
if (!beside)
|
|
682
|
+
return;
|
|
683
|
+
set({ beside: undefined, status: message ?? `Closed the split; ${beside.session} goes on.` });
|
|
684
|
+
await closePane(beside.paneId, tmuxEnv(process.env, withheld));
|
|
685
|
+
};
|
|
686
|
+
const openSession = async (row) => {
|
|
687
|
+
const name = row.session.name;
|
|
688
|
+
if (row.own)
|
|
689
|
+
return set({ status: `${name} is this browser's own session.` });
|
|
690
|
+
if (!insideTmux()) {
|
|
691
|
+
// Outside tmux the terminal itself is handed over, and comes back on detach.
|
|
692
|
+
let outcome = { ok: false };
|
|
693
|
+
await suspendTerminal(() => {
|
|
694
|
+
outcome = attachHere(name, tmuxEnv(process.env, withheld));
|
|
695
|
+
});
|
|
696
|
+
return set({ status: outcome.ok ? `Back from ${name}.` : cleanLine(outcome.message ?? `Could not attach ${name}.`) });
|
|
697
|
+
}
|
|
698
|
+
if (ui.current.beside)
|
|
699
|
+
await closePane(ui.current.beside.paneId, tmuxEnv(process.env, withheld));
|
|
700
|
+
try {
|
|
701
|
+
const paneId = await openBeside(name, { env: tmuxEnv(process.env, withheld) });
|
|
702
|
+
set({ beside: { session: name, paneId, episode: row.episode, info: row.session }, overlays: [] });
|
|
703
|
+
// The chronicle side shows the episode the session works in.
|
|
704
|
+
if (row.episode && derive().rowByName(row.episode))
|
|
705
|
+
jumpTo(row.episode);
|
|
706
|
+
set({ status: `${name} is beside you · F focuses it, prefix+arrow comes back · X closes the split, the session goes on.` });
|
|
707
|
+
}
|
|
708
|
+
catch (error) {
|
|
709
|
+
set({ beside: undefined, status: cleanLine(`Could not open ${name}: ${error.message}`) });
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
// While a session is beside the chronicle: is the split still there, what does the session run, what changed in its episode.
|
|
713
|
+
useEffect(() => {
|
|
714
|
+
const timer = setInterval(async () => {
|
|
715
|
+
const beside = ui.current.beside;
|
|
716
|
+
if (!beside)
|
|
717
|
+
return;
|
|
718
|
+
const env = tmuxEnv(process.env, withheld);
|
|
719
|
+
if (!(await paneAlive(beside.paneId, env))) {
|
|
720
|
+
if (ui.current.beside?.paneId === beside.paneId)
|
|
721
|
+
set({ beside: undefined, status: `The split closed; ${beside.session} goes on.` });
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
const info = (await listSessions(env)).find((session) => session.name === beside.session);
|
|
725
|
+
if (ui.current.beside?.paneId !== beside.paneId)
|
|
726
|
+
return;
|
|
727
|
+
if (beside.episode)
|
|
728
|
+
details.current.delete(`${ui.current.access.mayWrite}:${beside.episode}`);
|
|
729
|
+
set({ beside: { ...beside, info: info ?? beside.info }, status: ui.current.status });
|
|
730
|
+
}, 5_000);
|
|
731
|
+
return () => {
|
|
732
|
+
clearInterval(timer);
|
|
733
|
+
const beside = ui.current.beside;
|
|
734
|
+
if (beside)
|
|
735
|
+
void closePane(beside.paneId, tmuxEnv(process.env, withheld));
|
|
736
|
+
};
|
|
737
|
+
}, []);
|
|
673
738
|
// ── keys ─────────────────────────────────────────────────────────────────
|
|
674
739
|
// A paste into an input arrives whole, line breaks kept (bracketed paste).
|
|
675
740
|
const pasteActive = ui.current.overlays[ui.current.overlays.length - 1]?.overlay.type === "input";
|
|
@@ -797,6 +862,17 @@ export function App(props) {
|
|
|
797
862
|
}, (error) => updateById(handle, (o) => (o.type === "confirm" ? { ...o, busy: false, error: cleanLine(error.message) } : o)));
|
|
798
863
|
return;
|
|
799
864
|
}
|
|
865
|
+
if (top.type === "sessions") {
|
|
866
|
+
const rows = sessionRowsOf(top);
|
|
867
|
+
if (key.downArrow || input === "j")
|
|
868
|
+
return updateTop({ ...top, selected: clamp(top.selected + 1, rows.length) });
|
|
869
|
+
if (key.upArrow || input === "k")
|
|
870
|
+
return updateTop({ ...top, selected: clamp(top.selected - 1, rows.length) });
|
|
871
|
+
const row = rows[clamp(top.selected, rows.length)];
|
|
872
|
+
if (row && (key.return || input === "l" || key.rightArrow))
|
|
873
|
+
return void openSession(row);
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
800
876
|
if (top.type === "inquiries") {
|
|
801
877
|
const handle = topHandle();
|
|
802
878
|
const items = top.view?.shelf?.items ?? [];
|
|
@@ -1018,6 +1094,16 @@ export function App(props) {
|
|
|
1018
1094
|
return forward();
|
|
1019
1095
|
if (key.escape && s.relateFrom)
|
|
1020
1096
|
return set({ relateFrom: undefined, status: "No longer relating." });
|
|
1097
|
+
if (s.beside && input === "F") {
|
|
1098
|
+
focusPane(s.beside.paneId, tmuxEnv(process.env, withheld)).catch((error) => set({ status: cleanLine(error.message) }));
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
if (s.beside && input === "X")
|
|
1102
|
+
return void closeBeside();
|
|
1103
|
+
if (input === "q" && s.beside) {
|
|
1104
|
+
void closeBeside();
|
|
1105
|
+
return exit();
|
|
1106
|
+
}
|
|
1021
1107
|
if (key.escape || key.leftArrow || input === "h" || key.backspace)
|
|
1022
1108
|
return back();
|
|
1023
1109
|
if (input === "?")
|
|
@@ -1088,7 +1174,7 @@ export function App(props) {
|
|
|
1088
1174
|
const fileWindow = windowOf(d.files, clamp(s.fileSel, d.files.length), Math.max(1, bodyHeight - fixedLines));
|
|
1089
1175
|
const detailPane = (_jsx(Box, { flexDirection: "column", width: rightWidth, height: bodyHeight, overflow: "hidden", paddingLeft: compact ? 0 : 1, children: _jsx(Box, { flexDirection: "column", flexShrink: 0, children: s.view === "attention" ? (d.boardItem ? itemBody(d.boardItem, rightWidth - 1) : _jsx(Text, { color: "gray", children: "Nothing selected." })) : d.currentRow ? (_jsxs(_Fragment, { children: [_jsx(Box, { height: titleLines, overflow: "hidden", flexShrink: 0, children: _jsxs(Text, { bold: true, wrap: "wrap", children: [_jsx(Text, { color: "yellow", children: d.currentRow.number ?? "·" }), " ", d.currentRow.title] }) }), _jsxs(Text, { color: "gray", wrap: "truncate-end", children: [[formatDate(d.currentRow.date), d.currentRow.status, d.currentRow.type].filter(Boolean).join(" · "), d.currentRow.structured ? "" : " · no episode.yaml", d.currentRow.audience === "community" ? " · community" : ""] }), _jsxs(Text, { color: "green", wrap: "truncate-end", children: ["reading: ", d.currentRow.readings.direction, " \u00B7 ", d.currentRow.readings.theme, " \u00B7 ", d.currentRow.readings.arc] }), openHere ? _jsxs(Text, { color: "yellow", children: ["? ", openHere, " open question", openHere === 1 ? "" : "s", " \u00B7 a"] }) : null, lineage ? _jsxs(Text, { color: "cyan", wrap: "truncate-end", children: ["\u2197 ", lineage] }) : null, goal ? (_jsx(Box, { height: goalLines, overflow: "hidden", flexShrink: 0, children: _jsx(Text, { wrap: "wrap", children: goal }) })) : null, d.detail?.error ? _jsx(Text, { color: "red", children: cleanLine(d.detail.error) }) : null, _jsxs(Text, { color: "gray", wrap: "truncate-end", children: ["── ", d.files.length, d.files.length >= MAX_FILES ? "+" : "", " file", d.files.length === 1 ? "" : "s", s.view === "files" ? "" : " · Enter", " ──"] }), fileWindow.items.map((file, index) => {
|
|
1090
1176
|
const isSelected = s.view === "files" && fileWindow.start + index === clamp(s.fileSel, d.files.length);
|
|
1091
|
-
return (_jsxs(Text, { wrap: "truncate-start", inverse: isSelected, color: file.kind === "text" ? "blue" : "gray", children: [cleanLine(file.relativePath), file.kind === "text" ? "" : ` · ${file.kind}`] }, file.relativePath));
|
|
1177
|
+
return (_jsxs(Text, { wrap: "truncate-start", inverse: isSelected, color: file.kind === "text" ? "blue" : "gray", children: [Date.now() - Date.parse(file.modifiedAt) < 15 * 60_000 ? _jsx(Text, { color: "green", children: "\u25CF " }) : null, cleanLine(file.relativePath), file.kind === "text" ? "" : ` · ${file.kind}`] }, file.relativePath));
|
|
1092
1178
|
})] })) : (_jsx(Text, { color: "gray", children: "Nothing selected." })) }) }));
|
|
1093
1179
|
const fileBody = s.open ? (_jsxs(Box, { flexDirection: "column", height: bodyHeight, overflow: "hidden", children: [s.open.empty ? _jsx(Text, { color: "gray", children: "(empty file)" }) : null, s.open.view.lines.slice(s.open.scroll, s.open.scroll + bodyHeight).map((line, index) => (_jsx(Segments, { segments: line.segments, selectedRef: s.open.refSel }, s.open.scroll + index)))] })) : null;
|
|
1094
1180
|
/** How many screen rows these lines take inside an overlay. */
|
|
@@ -1149,6 +1235,17 @@ export function App(props) {
|
|
|
1149
1235
|
const room = Math.max(1, bodyHeight - 2 - (2 + (top.busy ? 1 : 0) + (top.error ? 1 : 0)));
|
|
1150
1236
|
return box("red", _jsxs(_Fragment, { children: [_jsx(Text, { bold: true, wrap: "truncate-end", children: cleanLine(top.title) }), _jsx(Box, { flexDirection: "column", height: Math.min(room, rowsOf(top.lines.map((line) => cleanLine(line.text)))), overflow: "hidden", flexShrink: 0, children: _jsx(Box, { flexDirection: "column", flexShrink: 0, children: top.lines.map((line, index) => (_jsx(Text, { wrap: "wrap", color: line.tone === "warn" ? "yellow" : line.tone === "meta" ? "gray" : undefined, children: cleanLine(line.text) }, index))) }) }), top.busy ? _jsx(Text, { color: "gray", children: "Working\u2026" }) : null, top.error ? _jsx(Text, { color: "red", wrap: "wrap", children: cleanLine(top.error) }) : null, _jsxs(Text, { wrap: "truncate-end", children: [top.yes && !top.busy ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: "red", bold: true, children: "y" }), " ", top.yes, " \u00B7", " "] })) : null, _jsx(Text, { color: "gray", children: top.busy ? "" : "Esc cancels" })] })] }));
|
|
1151
1237
|
}
|
|
1238
|
+
if (top.type === "sessions") {
|
|
1239
|
+
const rows = sessionRowsOf(top);
|
|
1240
|
+
const listWindow = windowOf(rows, clamp(top.selected, rows.length), Math.max(1, bodyHeight - 5));
|
|
1241
|
+
const focusLabel = top.episode ? episodeLabel(top.episode) : "";
|
|
1242
|
+
const now = Date.now() / 1000;
|
|
1243
|
+
return box("green", _jsxs(_Fragment, { children: [_jsxs(Text, { bold: true, wrap: "truncate-end", children: ["Sessions", " ", _jsxs(Text, { color: "gray", children: ["\u00B7 ", insideTmux() ? "Enter opens one beside the chronicle" : "Enter hands this terminal to it; prefix d comes back"] })] }), !top.sessions && !top.error ? _jsx(Text, { color: "gray", children: "Asking tmux\u2026" }) : null, top.error ? _jsx(Text, { color: "red", wrap: "wrap", children: cleanLine(top.error) }) : null, rows.length && focusLabel ? (_jsxs(Text, { color: "gray", wrap: "truncate-end", children: [rows.some((row) => row.here) ? `${focusLabel} first` : `none works in ${focusLabel}`, " \u00B7 \u25CF has a client \u00B7 \u25CB has none"] })) : null, listWindow.items.map((row, index) => {
|
|
1244
|
+
const isSelected = listWindow.start + index === clamp(top.selected, rows.length);
|
|
1245
|
+
const where = row.episode ? episodeLabel(row.episode) : "";
|
|
1246
|
+
return (_jsxs(Text, { wrap: "truncate-end", inverse: isSelected, children: [_jsx(Text, { color: row.session.attached ? "green" : "gray", children: row.session.attached ? "●" : "○" }), " ", _jsx(Text, { bold: row.here, children: cleanLine(row.session.name) }), _jsx(Text, { color: "gray", children: [where, cleanLine(row.session.command), idleFor(row.session.activity, now), row.own ? "this browser" : ""].filter(Boolean).map((part) => ` · ${part}`).join("") })] }, row.session.name));
|
|
1247
|
+
}), _jsx(Text, { color: "gray", wrap: "truncate-end", children: "\u2191\u2193 \u00B7 \u23CE open \u00B7 Esc" })] }));
|
|
1248
|
+
}
|
|
1152
1249
|
if (top.type === "inquiries") {
|
|
1153
1250
|
const view = top.view;
|
|
1154
1251
|
const items = view?.shelf?.items ?? [];
|
|
@@ -1248,6 +1345,10 @@ export function App(props) {
|
|
|
1248
1345
|
const view = s.view;
|
|
1249
1346
|
if (s.overlays.length)
|
|
1250
1347
|
return "Esc back";
|
|
1348
|
+
if (s.beside && !compact)
|
|
1349
|
+
return "F focus beside X close split ? keys q quit";
|
|
1350
|
+
if (s.beside)
|
|
1351
|
+
return "F X ? q";
|
|
1251
1352
|
if (view === "file")
|
|
1252
1353
|
return compact ? "Tab ref · Esc · q" : "Tab next reference ⇧Tab previous Esc back ? keys q quit";
|
|
1253
1354
|
if (view === "attention")
|
|
@@ -1281,6 +1382,6 @@ export function App(props) {
|
|
|
1281
1382
|
? "…"
|
|
1282
1383
|
: "read-only"
|
|
1283
1384
|
: "";
|
|
1284
|
-
return (_jsxs(Box, { flexDirection: "column", height: rows, width: columns, children: [_jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { bold: true, color: "yellow", children: "miadi-chronicle" }), " ", _jsx(Text, { color: "gray", children: where }), readerLabel ? _jsx(Text, { color: s.reader ? "green" : "gray", children: ` · ${readerLabel}` }) : null] }), _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { color: s.inputMode ? "yellow" : "gray", children: "/ " }), cleanLine(s.query), s.inputMode ? _jsx(Text, { inverse: true, children: " " }) : null, " ", s.view === "attention" ? (_jsx(Text, { color: "gray", children: "attention" })) : (_jsxs(_Fragment, { children: [_jsx(Text, { color: s.searchMode === "title" ? "yellow" : "gray", children: "title" }), _jsx(Text, { color: "gray", children: compact ? "|" : " | " }), _jsx(Text, { color: s.searchMode === "full" ? "yellow" : "gray", children: compact ? "full" : "full text" })] })), s.view === "list" ? _jsxs(Text, { color: "gray", children: [" \u00B7 ", d.filtered.length] }) : null, s.relateFrom ? _jsxs(Text, { color: "red", children: [" \u00B7 relating ", episodeLabel(s.relateFrom), " \u2192 L"] }) : null, s.view === "attention" ? _jsxs(Text, { color: "gray", children: [" \u00B7 ", d.board.length] }) : null] }), _jsx(Box, { flexDirection: "row", height: bodyHeight, overflow: "hidden", children: body }), _jsx(Text, { color: "gray", wrap: "truncate-end", children: s.status }), _jsxs(Text, { wrap: "truncate-end", children: [(s.overlays.length ? [] : available).map((action) => (_jsxs(Text, { children: [_jsx(Text, { color: action.effect === "write" ? "red" : "yellow", children: action.key === "Enter" ? "⏎" : action.key }), " ", action.label, " "] }, action.id))), _jsx(Text, { color: "gray", children: hints })] })] }));
|
|
1385
|
+
return (_jsxs(Box, { flexDirection: "column", height: rows, width: columns, children: [_jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { bold: true, color: "yellow", children: "miadi-chronicle" }), " ", _jsx(Text, { color: "gray", children: where }), s.beside ? (_jsxs(Text, { color: "cyan", children: [` · ⇆ ${cleanLine(s.beside.session)}`, s.beside.info ? ` · ${cleanLine(s.beside.info.command)} · ${idleFor(s.beside.info.activity)}` : ""] })) : null, readerLabel ? _jsx(Text, { color: s.reader ? "green" : "gray", children: ` · ${readerLabel}` }) : null] }), _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { color: s.inputMode ? "yellow" : "gray", children: "/ " }), cleanLine(s.query), s.inputMode ? _jsx(Text, { inverse: true, children: " " }) : null, " ", s.view === "attention" ? (_jsx(Text, { color: "gray", children: "attention" })) : (_jsxs(_Fragment, { children: [_jsx(Text, { color: s.searchMode === "title" ? "yellow" : "gray", children: "title" }), _jsx(Text, { color: "gray", children: compact ? "|" : " | " }), _jsx(Text, { color: s.searchMode === "full" ? "yellow" : "gray", children: compact ? "full" : "full text" })] })), s.view === "list" ? _jsxs(Text, { color: "gray", children: [" \u00B7 ", d.filtered.length] }) : null, s.relateFrom ? _jsxs(Text, { color: "red", children: [" \u00B7 relating ", episodeLabel(s.relateFrom), " \u2192 L"] }) : null, s.view === "attention" ? _jsxs(Text, { color: "gray", children: [" \u00B7 ", d.board.length] }) : null] }), _jsx(Box, { flexDirection: "row", height: bodyHeight, overflow: "hidden", children: body }), _jsx(Text, { color: "gray", wrap: "truncate-end", children: s.status }), _jsxs(Text, { wrap: "truncate-end", children: [(s.overlays.length ? [] : available).map((action) => (_jsxs(Text, { children: [_jsx(Text, { color: action.effect === "write" ? "red" : "yellow", children: action.key === "Enter" ? "⏎" : action.key }), " ", action.label, " "] }, action.id))), _jsx(Text, { color: "gray", children: hints })] })] }));
|
|
1285
1386
|
}
|
|
1286
1387
|
//# sourceMappingURL=App.js.map
|