refact: ink based terminal view (#17)

This commit is contained in:
Morten Olsen
2025-05-19 16:22:59 +02:00
committed by GitHub
parent 4514972880
commit 11f76a7378
17 changed files with 772 additions and 116 deletions

69
src/cli/ui/ui.tsx Normal file
View File

@@ -0,0 +1,69 @@
import { Box, render, Text, useApp, useInput } from "ink"
import { ScrollableMarkdown } from './components/scrollable-markdown.js';
import { useStateValue, State, StateProvider } from './state/state.js';
import { useEffect, useState } from "react";
import { useTerminalHeight } from "./hooks/terminal.js";
const MarkdownView = () => {
const markdown = useStateValue((state) => state.markdown);
const error = useStateValue((state) => state.error);
return (
<Box flexGrow={1} flexDirection="column">
<Box flexDirection="column" flexGrow={1} overflow="hidden">
<ScrollableMarkdown markdownContent={markdown} />
</Box>
{error && (
<Box flexDirection="column" padding={1}>
<Text color="red">{error}</Text>
</Box>
)}
</Box>
);
}
const App = () => {
const { exit } = useApp();
const height = useTerminalHeight();
useInput((_input, key) => {
if (key.escape) {
process.exit(0);
}
});
useEffect(
() => {
const enterAltScreenCommand = "\x1b[?1049h";
const leaveAltScreenCommand = "\x1b[?1049l";
process.stdout.write(enterAltScreenCommand);
const onExit = () => {
exit();
process.stdout.write(leaveAltScreenCommand);
}
process.on("exit", onExit);
return () => {
process.stdout.write(leaveAltScreenCommand);
process.off("exit", onExit);
}
}, []
);
return (
<Box height={height} flexDirection="column">
<MarkdownView />
<Box>
<Text>Press esc to exit</Text>
</Box>
</Box>
)
}
const renderUI = (state: State) => {
render(
<StateProvider state={state}>
<App />
</StateProvider>
);
}
export { renderUI, State }