mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
import { DynamicBorder } from "@mariozechner/pi-coding-agent";
|
|
import {
|
|
Container,
|
|
Key,
|
|
matchesKey,
|
|
type SelectItem,
|
|
SelectList,
|
|
Text,
|
|
} from "@mariozechner/pi-tui";
|
|
|
|
type CustomUiContext = {
|
|
ui: {
|
|
custom: <T>(
|
|
render: (
|
|
tui: { requestRender: () => void },
|
|
theme: {
|
|
fg: (tone: string, text: string) => string;
|
|
bold: (text: string) => string;
|
|
},
|
|
kb: unknown,
|
|
done: () => void,
|
|
) => {
|
|
render: (width: number) => string;
|
|
invalidate: () => void;
|
|
handleInput: (data: string) => void;
|
|
},
|
|
) => Promise<T>;
|
|
};
|
|
};
|
|
|
|
export async function showPagedSelectList(params: {
|
|
ctx: CustomUiContext;
|
|
title: string;
|
|
items: SelectItem[];
|
|
onSelect: (item: SelectItem) => void;
|
|
}): Promise<void> {
|
|
await params.ctx.ui.custom<void>((tui, theme, _kb, done) => {
|
|
const container = new Container();
|
|
|
|
container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
|
|
container.addChild(new Text(theme.fg("accent", theme.bold(params.title)), 0, 0));
|
|
|
|
const visibleRows = Math.min(params.items.length, 15);
|
|
let currentIndex = 0;
|
|
|
|
const selectList = new SelectList(params.items, visibleRows, {
|
|
selectedPrefix: (text) => theme.fg("accent", text),
|
|
selectedText: (text) => text,
|
|
description: (text) => theme.fg("muted", text),
|
|
scrollInfo: (text) => theme.fg("dim", text),
|
|
noMatch: (text) => theme.fg("warning", text),
|
|
});
|
|
selectList.onSelect = (item) => params.onSelect(item);
|
|
selectList.onCancel = () => done();
|
|
selectList.onSelectionChange = (item) => {
|
|
currentIndex = params.items.indexOf(item);
|
|
};
|
|
container.addChild(selectList);
|
|
|
|
container.addChild(
|
|
new Text(theme.fg("dim", " ↑↓ navigate • ←→ page • enter open • esc close"), 0, 0),
|
|
);
|
|
container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
|
|
|
|
return {
|
|
render: (width) => container.render(width),
|
|
invalidate: () => container.invalidate(),
|
|
handleInput: (data) => {
|
|
if (matchesKey(data, Key.left)) {
|
|
currentIndex = Math.max(0, currentIndex - visibleRows);
|
|
selectList.setSelectedIndex(currentIndex);
|
|
} else if (matchesKey(data, Key.right)) {
|
|
currentIndex = Math.min(params.items.length - 1, currentIndex + visibleRows);
|
|
selectList.setSelectedIndex(currentIndex);
|
|
} else {
|
|
selectList.handleInput(data);
|
|
}
|
|
tui.requestRender();
|
|
},
|
|
};
|
|
});
|
|
}
|