@nanhara/hara 0.99.0 → 0.99.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/dist/tui/InputBox.js +19 -6
- package/package.json +1 -1
package/dist/tui/InputBox.js
CHANGED
|
@@ -37,8 +37,9 @@ export function footerCwd(abs, home = process.env.HOME ?? "", maxLen = 28) {
|
|
|
37
37
|
}
|
|
38
38
|
/** Compose the single dim footer line rendered below the box. Pure so the ordering/spacing (and the
|
|
39
39
|
* optional route segment) can be pinned without rendering React. Shape (codex-style status line):
|
|
40
|
-
* `<model> · <approval>[ · <route>] · <cwd> · ↑<in> ↓<out> · ctx <pct>%`.
|
|
41
|
-
*
|
|
40
|
+
* `<model> · <approval>[ · <route>] · <cwd> · ↑<in> ↓<out> · ctx <pct>%`. The session name is NOT here —
|
|
41
|
+
* it rides the input box's top-right border (see TopBorder). `ctx N%` is always present (from 0 on) so
|
|
42
|
+
* the field never pops in mid-session and shifts the layout. */
|
|
42
43
|
export function footerLine(model, s, cwdShort, route) {
|
|
43
44
|
const routeSeg = route ? ` · ${route}` : "";
|
|
44
45
|
return ` ${model} · ${s.approval}${routeSeg} · ${cwdShort} · ↑${tok(s.input)} ↓${tok(s.output)} · ctx ${s.ctxPct}%`;
|
|
@@ -48,6 +49,16 @@ export function footerLine(model, s, cwdShort, route) {
|
|
|
48
49
|
const Footer = memo(function Footer({ model, s, cwdShort, route }) {
|
|
49
50
|
return _jsx(Text, { dimColor: true, children: footerLine(model, s, cwdShort, route) });
|
|
50
51
|
});
|
|
52
|
+
// The rounded TOP edge of the input box, carrying the session name in the right corner (it "rides"
|
|
53
|
+
// the border — codex-style titled panel, and where hara has always shown it). Drawn by hand because
|
|
54
|
+
// ink's <Box borderStyle> has no title slot; the box below it renders with `borderTop={false}` and a
|
|
55
|
+
// fixed `width`, so this line supplies the top with its two corners and everything lines up exactly.
|
|
56
|
+
// Layout (total = width): `╭` + left dashes + ` ● <name> ` + `─╮`. `●` (U+25CF) is a hard 1-cell glyph
|
|
57
|
+
// (unlike the emoji-presentation `⏺`, which some terminals render 2 cells wide and would skew the corner).
|
|
58
|
+
const TopBorder = memo(function TopBorder({ name, width }) {
|
|
59
|
+
const left = Math.max(2, width - name.length - 7); // ╭(1)+ " "(1)+●(1)+" name "(len+2)+"─╮"(2)
|
|
60
|
+
return (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "╭" + "─".repeat(left) + " " }), _jsx(Text, { color: "cyan", children: "\u25CF" }), _jsx(Text, { bold: true, children: ` ${name} ` }), _jsx(Text, { dimColor: true, children: "─╮" })] }));
|
|
61
|
+
});
|
|
51
62
|
const MODE_DESC = {
|
|
52
63
|
suggest: "confirms edits & commands",
|
|
53
64
|
"auto-edit": "auto-applies edits · asks before commands",
|
|
@@ -369,9 +380,11 @@ export function InputBox({ status, cwd, model, route, width, onSubmit, onClipboa
|
|
|
369
380
|
}, { isActive });
|
|
370
381
|
const gutter = vim && mode === "normal" ? "◆ " : "› ";
|
|
371
382
|
const gutterColor = vim ? (mode === "normal" ? "yellow" : "green") : "cyan";
|
|
372
|
-
// The
|
|
373
|
-
//
|
|
374
|
-
|
|
383
|
+
// The box borders (1 each side) + paddingX (1 each side) subtract 4 cells; InputLine's deterministic
|
|
384
|
+
// wrap needs the INNER width so the cursor/continuation gutter stay exact. The box is a fixed `width={w}`
|
|
385
|
+
// with `borderTop={false}` so the hand-drawn TopBorder (with the session title) supplies the top edge
|
|
386
|
+
// + corners and everything aligns column-for-column.
|
|
387
|
+
const innerW = Math.max(1, w - 4);
|
|
375
388
|
const cwdShort = footerCwd(cwd);
|
|
376
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { borderStyle: "round", borderColor: "gray", borderDimColor: true, paddingX: 1, children: _jsx(InputLine, { value: value, cursor: cursor, width: innerW, gutter: gutter, gutterColor: gutterColor, placeholder: placeholder }) }), vim ? _jsx(Text, { dimColor: true, children: mode === "normal" ? " -- NORMAL -- i/a insert · h l 0 $ w b e move · x dd D cw p edit" : " -- INSERT -- Esc → normal" }) : null, _jsx(Footer, { model: model, s: status, cwdShort: cwdShort, route: route }), working ? _jsx(Text, { dimColor: true, children: ` ⌨ working — Enter queues your message${queued ? ` · ${queued} queued` : ""} · Esc interrupts` }) : null, popupOpen ? _jsx(MentionPopup, { items: candidates, selected: selIdx, query: mention.query }) : null, _jsx(ModeBar, { approval: status.approval })] }));
|
|
389
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(TopBorder, { name: status.sessionName || "session", width: w }), _jsx(Box, { borderStyle: "round", borderTop: false, borderColor: "gray", borderDimColor: true, paddingX: 1, width: w, children: _jsx(InputLine, { value: value, cursor: cursor, width: innerW, gutter: gutter, gutterColor: gutterColor, placeholder: placeholder }) }), vim ? _jsx(Text, { dimColor: true, children: mode === "normal" ? " -- NORMAL -- i/a insert · h l 0 $ w b e move · x dd D cw p edit" : " -- INSERT -- Esc → normal" }) : null, _jsx(Footer, { model: model, s: status, cwdShort: cwdShort, route: route }), working ? _jsx(Text, { dimColor: true, children: ` ⌨ working — Enter queues your message${queued ? ` · ${queued} queued` : ""} · Esc interrupts` }) : null, popupOpen ? _jsx(MentionPopup, { items: candidates, selected: selIdx, query: mention.query }) : null, _jsx(ModeBar, { approval: status.approval })] }));
|
|
377
390
|
}
|