@miadi/chronicle-tui 0.9.1 → 0.10.0
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 +33 -23
- package/dist/App.d.ts +2 -0
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +113 -51
- package/dist/App.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/sessions.d.ts +26 -0
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js +58 -2
- package/dist/sessions.js.map +1 -1
- package/dist/tide.d.ts +1 -1
- package/dist/tide.d.ts.map +1 -1
- package/dist/tide.js +1 -1
- package/dist/tide.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -36,8 +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
|
|
40
|
-
| `F`, `X` | with
|
|
39
|
+
| `T` | this machine's tmux sessions, the episode in focus's first. Inside tmux: Enter shows one on the right, `+` adds one below it (two at most), `e` goes to its episode; the list stays open. Outside tmux, Enter hands the terminal over until you detach |
|
|
40
|
+
| `F`, `X` | with sessions on the right: focus them in turn (Alt+s in one comes back); detach them all (they go on). Inside a split, `prefix prefix d` detaches that one; its border says so |
|
|
41
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 |
|
|
42
42
|
| `?` | all keys · `q` quits from the main view (in a window it closes the window) · `Q` quits from any window, except while typing the filter · Ctrl+C quits too |
|
|
43
43
|
|
|
@@ -99,30 +99,40 @@ miadi-chronicle --url https://miadi.tail3b11eb.ts.net
|
|
|
99
99
|
Write actions declare `effect: "write"` and are offered only when the app said
|
|
100
100
|
it would record them.
|
|
101
101
|
|
|
102
|
-
##
|
|
102
|
+
## Sessions on the right
|
|
103
103
|
|
|
104
104
|
Run the browser inside tmux and `T` lists the sessions on this machine, each
|
|
105
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.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
106
|
+
name carries), the sessions of the episode in focus first. The list stays open
|
|
107
|
+
while you work with it:
|
|
108
|
+
|
|
109
|
+
- **Enter** shows the session on the right of the browser, live, as a client of
|
|
110
|
+
its own (`env -u TMUX tmux attach`). Whatever was on the right is detached
|
|
111
|
+
first, so Enter on the next session swaps it in.
|
|
112
|
+
- **`+`** adds the session below the one on the right, up to two (`MAX_BESIDE`).
|
|
113
|
+
- **`e`** closes the list and goes to the session's episode.
|
|
114
|
+
- **`F`** focuses the sessions on the right in turn; you type in them directly.
|
|
115
|
+
**Alt+s** in a split brings the focus back to the browser, where the list
|
|
116
|
+
is. The key is bound in tmux only while a split is open, acts only in a
|
|
117
|
+
split's pane (anywhere else it passes the key on), is left alone when you
|
|
118
|
+
bound it to something already, and is removed with the last split. Set
|
|
119
|
+
`MIADI_CHRONICLE_RETURN_KEY` to another tmux key, or `none`. `prefix ;`
|
|
120
|
+
(tmux's last pane) comes back too.
|
|
121
|
+
- **`X`** detaches every session on the right. `prefix prefix d` inside a split
|
|
122
|
+
detaches that one (the prefix once goes to your tmux, twice to the session's
|
|
123
|
+
client). Either way the sessions go on, and with the last split the window's
|
|
124
|
+
border goes back as it was.
|
|
125
|
+
|
|
126
|
+
Each split's border names its session and says how to come back. The header
|
|
127
|
+
shows `⇆ <session> · <command> · <idle>` for each. The episodes of the
|
|
128
|
+
sessions on the right are read every 5 s, and a file changed in the last 15
|
|
129
|
+
minutes is marked ●, so you see what an agent is touching.
|
|
130
|
+
|
|
131
|
+
While you type in a split it is that session's most recent client, so the
|
|
132
|
+
session's window takes the split's size, as with any tmux client, until its
|
|
133
|
+
own client is used again. The browser never types into a session; only your
|
|
134
|
+
keys reach it, and tmux never inherits a token. Outside tmux, Enter runs
|
|
135
|
+
`tmux attach` in this terminal and `prefix d` brings you back.
|
|
126
136
|
|
|
127
137
|
## Inquiries and the companion seat
|
|
128
138
|
|
package/dist/App.d.ts
CHANGED
|
@@ -29,5 +29,7 @@ export interface AppProps {
|
|
|
29
29
|
/** Environment keys `--env` loaded: an opener never inherits them. */
|
|
30
30
|
withheld?: readonly string[];
|
|
31
31
|
}
|
|
32
|
+
/** How many sessions the right side holds, one above the other. */
|
|
33
|
+
export declare const MAX_BESIDE = 2;
|
|
32
34
|
export declare function App(props: AppProps): React.JSX.Element;
|
|
33
35
|
//# sourceMappingURL=App.d.ts.map
|
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;AA2FrB,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;AAUD,mEAAmE;AACnE,eAAO,MAAM,UAAU,IAAI,CAAA;AAkI3B,wBAAgB,GAAG,CAAC,KAAK,EAAE,QAAQ,qBAm4DlC"}
|
package/dist/App.js
CHANGED
|
@@ -21,10 +21,12 @@ 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 { ISSUE_REF, weaveInquiry, wovenMessage, 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,
|
|
24
|
+
import { attachHere, closePane, focusPane, idleFor, insideTmux, listSessions, openBeside, markWindow, labelSplit, unmarkSplit, returnKey, keyLabel, bindReturnKey, unbindReturnKey, orderSessions, paneAlive, tmuxEnv, } from "./sessions.js";
|
|
25
25
|
import { VISITOR, wheelDoors, loadChronicle, loadDetail, loadText, openUrl, qrLines, search, visibleRows, } from "./data.js";
|
|
26
26
|
import { ageOf, clamp, fileView, filterRows, formatDate, screenLineOf, windowOf, wrapSegments, } from "./model.js";
|
|
27
27
|
import { clean, cleanLine, link } from "./text.js";
|
|
28
|
+
/** How many sessions the right side holds, one above the other. */
|
|
29
|
+
export const MAX_BESIDE = 2;
|
|
28
30
|
const DIRECTION_MARK = { east: "E", south: "S", west: "W", north: "N" };
|
|
29
31
|
const DIRECTION_COLOR = { east: "yellow", south: "red", west: "blue", north: "white" };
|
|
30
32
|
function Segments({ segments, selectedRef }) {
|
|
@@ -676,32 +678,40 @@ export function App(props) {
|
|
|
676
678
|
const d = derive();
|
|
677
679
|
return o.sessions && d.s.chronicle ? orderSessions(o.sessions, d.visible, d.s.chronicle.root, o.episode, o.own) : [];
|
|
678
680
|
};
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
* back as it was, and the chronicle returns to where it was before the session
|
|
682
|
-
* took it to its episode, unless the person moved on since.
|
|
683
|
-
*/
|
|
681
|
+
const env = () => tmuxEnv(process.env, withheld);
|
|
682
|
+
/** Every split is gone: the window's border goes back as it was, and the return key is unbound unless another split uses it. */
|
|
684
683
|
const endBeside = async (message) => {
|
|
685
684
|
const beside = ui.current.beside;
|
|
686
685
|
if (!beside)
|
|
687
686
|
return;
|
|
688
|
-
|
|
689
|
-
const stillThere = beside.jumped && d.s.view === "files" && d.currentRow?.name === beside.episode && d.s.history.length > 0;
|
|
690
|
-
set({ beside: undefined });
|
|
691
|
-
if (stillThere)
|
|
692
|
-
back();
|
|
693
|
-
set({ status: message });
|
|
687
|
+
set({ beside: undefined, status: message });
|
|
694
688
|
if (beside.mark)
|
|
695
|
-
await unmarkSplit(beside.mark,
|
|
689
|
+
await unmarkSplit(beside.mark, env());
|
|
690
|
+
if (beside.returnKey)
|
|
691
|
+
await unbindReturnKey(beside.returnKey, env());
|
|
696
692
|
};
|
|
693
|
+
/** `X`: detach every session on the right; they go on. */
|
|
697
694
|
const closeBeside = async () => {
|
|
698
695
|
const beside = ui.current.beside;
|
|
699
696
|
if (!beside)
|
|
700
697
|
return;
|
|
701
|
-
|
|
702
|
-
|
|
698
|
+
for (const slot of beside.slots)
|
|
699
|
+
await closePane(slot.paneId, env());
|
|
700
|
+
const names = beside.slots.map((slot) => slot.session).join(" and ");
|
|
701
|
+
await endBeside(`Detached ${names}; ${beside.slots.length > 1 ? "they go" : "it goes"} on.`);
|
|
703
702
|
};
|
|
704
|
-
|
|
703
|
+
/** The sessions list shows what is on the right: read tmux again after a change. */
|
|
704
|
+
const refreshSessionsList = async () => {
|
|
705
|
+
const sessions = await listSessions(env());
|
|
706
|
+
const stack = ui.current.overlays.map((entry) => (entry.overlay.type === "sessions" ? { id: entry.id, overlay: { ...entry.overlay, sessions } } : entry));
|
|
707
|
+
set({ overlays: stack, status: ui.current.status });
|
|
708
|
+
};
|
|
709
|
+
/**
|
|
710
|
+
* Show a session on the right. `below` adds it under the ones there (up to
|
|
711
|
+
* MAX_BESIDE); otherwise it takes the right side alone, detaching what was
|
|
712
|
+
* there. The sessions list stays open, so the next one is a key away.
|
|
713
|
+
*/
|
|
714
|
+
const openSession = async (row, below = false) => {
|
|
705
715
|
const name = row.session.name;
|
|
706
716
|
if (row.own)
|
|
707
717
|
return set({ status: `${name} is this browser's own session.` });
|
|
@@ -709,58 +719,92 @@ export function App(props) {
|
|
|
709
719
|
// Outside tmux the terminal itself is handed over, and comes back on detach.
|
|
710
720
|
let outcome = { ok: false };
|
|
711
721
|
await suspendTerminal(() => {
|
|
712
|
-
outcome = attachHere(name,
|
|
722
|
+
outcome = attachHere(name, env());
|
|
713
723
|
});
|
|
714
724
|
return set({ status: outcome.ok ? `Back from ${name}.` : cleanLine(outcome.message ?? `Could not attach ${name}.`) });
|
|
715
725
|
}
|
|
716
|
-
|
|
717
|
-
|
|
726
|
+
const current = ui.current.beside;
|
|
727
|
+
if (current?.slots.some((slot) => slot.session === name))
|
|
728
|
+
return set({ status: `${name} is already on the right.` });
|
|
729
|
+
if (below && current && current.slots.length >= MAX_BESIDE) {
|
|
730
|
+
return set({ status: `${MAX_BESIDE} sessions are on the right already: Enter shows ${name} alone, X detaches them.` });
|
|
731
|
+
}
|
|
732
|
+
const adding = below && current && current.slots.length > 0;
|
|
718
733
|
try {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
734
|
+
let slots = current?.slots ?? [];
|
|
735
|
+
if (!adding) {
|
|
736
|
+
for (const slot of slots)
|
|
737
|
+
await closePane(slot.paneId, env());
|
|
738
|
+
slots = [];
|
|
739
|
+
}
|
|
740
|
+
const paneId = adding ? await openBeside(name, { below: true, pane: slots[slots.length - 1].paneId, env: env() }) : await openBeside(name, { env: env() });
|
|
741
|
+
// The border names the session and says how to come back; a window that refuses it still works.
|
|
742
|
+
const mark = current?.mark ?? (await markWindow(paneId, env()).catch(() => undefined));
|
|
743
|
+
const wanted = returnKey();
|
|
744
|
+
const key = current?.returnKey ?? (wanted && (await bindReturnKey(wanted, env()).catch(() => false)) ? wanted : undefined);
|
|
745
|
+
await labelSplit(paneId, name, { returnTo: process.env.TMUX_PANE, returnKey: key, env: env() }).catch(() => { });
|
|
746
|
+
const slot = { session: name, paneId, episode: row.episode, info: row.session };
|
|
747
|
+
set({ beside: { slots: [...slots, slot], mark, returnKey: key, focus: 0 } });
|
|
748
|
+
const back = key ? `${keyLabel(key)} in it comes back here` : "prefix ; comes back here";
|
|
749
|
+
set({ status: `${name} is on the right${adding ? ", below" : ""} · F focuses it, ${back} · X detaches ${adding ? "both" : "it"}.` });
|
|
750
|
+
await refreshSessionsList();
|
|
729
751
|
}
|
|
730
752
|
catch (error) {
|
|
731
|
-
set({
|
|
753
|
+
set({ status: cleanLine(`Could not open ${name}: ${error.message}`) });
|
|
732
754
|
}
|
|
733
755
|
};
|
|
734
|
-
|
|
735
|
-
|
|
756
|
+
/** `F`: focus the sessions on the right in turn. */
|
|
757
|
+
const focusBeside = () => {
|
|
758
|
+
const beside = ui.current.beside;
|
|
759
|
+
if (!beside?.slots.length)
|
|
760
|
+
return;
|
|
761
|
+
const slot = beside.slots[beside.focus % beside.slots.length];
|
|
762
|
+
set({ beside: { ...beside, focus: beside.focus + 1 } });
|
|
763
|
+
focusPane(slot.paneId, env()).catch((error) => set({ status: cleanLine(error.message) }));
|
|
764
|
+
};
|
|
765
|
+
// While sessions are on the right: every second, which splits are still there (a detach inside one closes it);
|
|
766
|
+
// every five, what each session runs and what changed in its episode.
|
|
736
767
|
const besideTick = useRef(0);
|
|
737
768
|
useEffect(() => {
|
|
738
769
|
const timer = setInterval(async () => {
|
|
739
770
|
const beside = ui.current.beside;
|
|
740
771
|
if (!beside)
|
|
741
772
|
return;
|
|
742
|
-
const
|
|
743
|
-
if (
|
|
744
|
-
|
|
745
|
-
|
|
773
|
+
const alive = await Promise.all(beside.slots.map((slot) => paneAlive(slot.paneId, env())));
|
|
774
|
+
if (ui.current.beside !== beside)
|
|
775
|
+
return;
|
|
776
|
+
const gone = beside.slots.filter((_, index) => !alive[index]);
|
|
777
|
+
if (gone.length) {
|
|
778
|
+
const left = beside.slots.filter((_, index) => alive[index]);
|
|
779
|
+
const names = gone.map((slot) => slot.session).join(" and ");
|
|
780
|
+
if (left.length === 0)
|
|
781
|
+
await endBeside(`Detached from ${names}; back in the chronicle. ${gone.length > 1 ? "They go" : "It goes"} on.`);
|
|
782
|
+
else
|
|
783
|
+
set({ beside: { ...beside, slots: left }, status: `Detached from ${names}; ${left.map((slot) => slot.session).join(" and ")} stays on the right.` });
|
|
784
|
+
void refreshSessionsList();
|
|
746
785
|
return;
|
|
747
786
|
}
|
|
748
787
|
if (++besideTick.current % 5 !== 0)
|
|
749
788
|
return;
|
|
750
|
-
const
|
|
751
|
-
if (ui.current.beside
|
|
789
|
+
const sessions = await listSessions(env());
|
|
790
|
+
if (ui.current.beside !== beside)
|
|
752
791
|
return;
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
792
|
+
for (const slot of beside.slots)
|
|
793
|
+
if (slot.episode)
|
|
794
|
+
details.current.delete(`${ui.current.access.mayWrite}:${slot.episode}`);
|
|
795
|
+
const slots = beside.slots.map((slot) => ({ ...slot, info: sessions.find((session) => session.name === slot.session) ?? slot.info }));
|
|
796
|
+
set({ beside: { ...beside, slots }, status: ui.current.status });
|
|
756
797
|
}, 1_000);
|
|
757
798
|
return () => {
|
|
758
799
|
clearInterval(timer);
|
|
759
800
|
const beside = ui.current.beside;
|
|
760
801
|
if (beside) {
|
|
761
|
-
|
|
802
|
+
for (const slot of beside.slots)
|
|
803
|
+
void closePane(slot.paneId, env());
|
|
762
804
|
if (beside.mark)
|
|
763
|
-
void unmarkSplit(beside.mark,
|
|
805
|
+
void unmarkSplit(beside.mark, env());
|
|
806
|
+
if (beside.returnKey)
|
|
807
|
+
void unbindReturnKey(beside.returnKey, env());
|
|
764
808
|
}
|
|
765
809
|
};
|
|
766
810
|
}, []);
|
|
@@ -901,8 +945,21 @@ export function App(props) {
|
|
|
901
945
|
if (key.upArrow || input === "k")
|
|
902
946
|
return updateTop({ ...top, selected: clamp(top.selected - 1, rows.length) });
|
|
903
947
|
const row = rows[clamp(top.selected, rows.length)];
|
|
948
|
+
// Enter: this session alone on the right. +: below the one there. The list stays, for the next one.
|
|
904
949
|
if (row && (key.return || input === "l" || key.rightArrow))
|
|
905
950
|
return void openSession(row);
|
|
951
|
+
if (row && input === "+")
|
|
952
|
+
return void openSession(row, true);
|
|
953
|
+
if (input === "X")
|
|
954
|
+
return void closeBeside();
|
|
955
|
+
if (input === "F")
|
|
956
|
+
return focusBeside();
|
|
957
|
+
if (row && input === "e") {
|
|
958
|
+
if (!row.episode || !derive().rowByName(row.episode))
|
|
959
|
+
return set({ status: `${row.session.name} works in no episode you can see.` });
|
|
960
|
+
set({ overlays: [] });
|
|
961
|
+
return jumpTo(row.episode);
|
|
962
|
+
}
|
|
906
963
|
return;
|
|
907
964
|
}
|
|
908
965
|
if (top.type === "inquiries") {
|
|
@@ -1126,10 +1183,8 @@ export function App(props) {
|
|
|
1126
1183
|
return forward();
|
|
1127
1184
|
if (key.escape && s.relateFrom)
|
|
1128
1185
|
return set({ relateFrom: undefined, status: "No longer relating." });
|
|
1129
|
-
if (s.beside && input === "F")
|
|
1130
|
-
|
|
1131
|
-
return;
|
|
1132
|
-
}
|
|
1186
|
+
if (s.beside && input === "F")
|
|
1187
|
+
return focusBeside();
|
|
1133
1188
|
if (s.beside && input === "X")
|
|
1134
1189
|
return void closeBeside();
|
|
1135
1190
|
if (key.escape || key.leftArrow || input === "h" || key.backspace)
|
|
@@ -1277,8 +1332,13 @@ export function App(props) {
|
|
|
1277
1332
|
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) => {
|
|
1278
1333
|
const isSelected = listWindow.start + index === clamp(top.selected, rows.length);
|
|
1279
1334
|
const where = row.episode ? episodeLabel(row.episode) : "";
|
|
1280
|
-
|
|
1281
|
-
|
|
1335
|
+
const slot = s.beside?.slots.findIndex((candidate) => candidate.session === row.session.name) ?? -1;
|
|
1336
|
+
return (_jsxs(Text, { wrap: "truncate-end", inverse: isSelected, children: [slot >= 0 ? _jsx(Text, { color: "cyan", children: slot === 0 ? "⇆ " : "⇣ " }) : null, _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));
|
|
1337
|
+
}), _jsx(Text, { color: "gray", wrap: "truncate-end", children: insideTmux()
|
|
1338
|
+
? compact
|
|
1339
|
+
? `⏎ right · + below · e · ${s.beside ? "F X · " : ""}Esc`
|
|
1340
|
+
: `↑↓ · ⏎ on the right · + below it (up to ${MAX_BESIDE}) · e its episode${s.beside ? " · F focus · X detach" : ""} · Esc`
|
|
1341
|
+
: "↑↓ · ⏎ open · e its episode · Esc" })] }));
|
|
1282
1342
|
}
|
|
1283
1343
|
if (top.type === "inquiries") {
|
|
1284
1344
|
const view = top.view;
|
|
@@ -1380,7 +1440,7 @@ export function App(props) {
|
|
|
1380
1440
|
if (s.overlays.length)
|
|
1381
1441
|
return compact ? "Esc · Q" : "Esc back Q quit";
|
|
1382
1442
|
if (s.beside && !compact)
|
|
1383
|
-
return "F focus
|
|
1443
|
+
return "T sessions F focus right X detach all ? keys q quit";
|
|
1384
1444
|
if (s.beside)
|
|
1385
1445
|
return "F X ? q";
|
|
1386
1446
|
if (view === "file")
|
|
@@ -1416,6 +1476,8 @@ export function App(props) {
|
|
|
1416
1476
|
? "…"
|
|
1417
1477
|
: "read-only"
|
|
1418
1478
|
: "";
|
|
1419
|
-
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: [` · ⇆
|
|
1479
|
+
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: [` · ⇆ `, s.beside.slots
|
|
1480
|
+
.map((slot) => `${cleanLine(slot.session)}${slot.info ? ` · ${cleanLine(slot.info.command)} · ${idleFor(slot.info.activity)}` : ""}`)
|
|
1481
|
+
.join(" | ")] })) : 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 })] })] }));
|
|
1420
1482
|
}
|
|
1421
1483
|
//# sourceMappingURL=App.js.map
|