Welcome to the Screens project tutorial! If you have ever used a command-line tool that felt clunky because it just dumped wall-of-text logs, you are in the right place.
In this first chapter, we will explore Terminal UI Rendering. We will learn how to turn a standard black-and-white terminal window into a rich, interactive interface using React.
Traditionally, writing a Command Line Interface (CLI) involves a lot of console.log() statements.
We use a library called Ink. It lets us write standard React code, but instead of rendering HTML (like <div> or <h1>), it renders text and layout codes to the terminal.
To understand this, let's look at a real feature in our project: Resuming a Session.
Imagine a screen that needs to do three things:
This is a dynamic UI. It changes based on what the application is doing.
Before we look at the code, let's define the building blocks.
Since there is no HTML in the terminal, we swap standard HTML tags for Ink components:
<Box>: Replaces <div>. It handles layout (Flexbox). It can have borders, padding, and margins.<Text>: Replaces <span> or <p>. It handles text content, colors (e.g., <Text color="green">), and styling (bold, italic).Just like in web React, we render different components based on the current state (variable values).
We don't manually clear the terminal. We simply change a state variable (e.g., setLoading(false)), and the renderer calculates what pixels (characters) need to change.
Let's look at how the ResumeConversation.tsx file handles this. We will break it down into small pieces.
When the component first mounts, we want to show a spinner so the user knows something is happening.
// Inside ResumeConversation.tsx
if (loading) {
return (
<Box>
<Spinner />
<Text> Loading conversationsโฆ</Text>
</Box>
);
}
Explanation:
loading.<Box> to hold our items together.<Spinner /> is a custom component that animates a character (like โ , โ , โ น).<Text> prints the label next to it.Once the user selects an item, we transition to a "Resuming" state.
// Inside ResumeConversation.tsx
if (resuming) {
return (
<Box>
<Spinner />
<Text> Resuming conversationโฆ</Text>
</Box>
);
}
Explanation:
If we aren't loading and aren't resuming, we show the interactive list.
// Inside ResumeConversation.tsx
return (
<LogSelector
logs={filteredLogs}
maxHeight={rows}
onSelect={onSelect}
onCancel={onCancel}
// ... other props
/>
);
Explanation:
LogSelector is a complex custom component (composed of Box and Text elements).filteredLogs) and event handlers (onSelect).maxHeight={rows} prop ensures our UI adapts to the user's terminal window size.
How does a <Box> actually get on the screen? Here is the flow of data when the application starts.
Let's look at the Doctor.tsx file to see how complex layouts are constructed using Box. This component runs diagnostic checks and displays them in a grid-like list.
// Inside Doctor.tsx
<Box flexDirection="column">
<Text bold>Diagnostics</Text>
<Text>โ Currently running: {diagnostic.version}</Text>
<Text>โ Path: {diagnostic.installationPath}</Text>
</Box>
Explanation:
flexDirection="column": This stacks the children vertically (top to bottom). This is the most common layout in CLIs.bold: This prop on <Text> adds the ANSI code for bold text (usually bright white).We can change colors dynamically based on data.
// Inside Doctor.tsx helper function
<Text>
โ {validation.name}:{" "}
<Text color={validation.status === "capped" ? "warning" : "error"}>
{validation.message}
</Text>
</Text>
Explanation:
<Text> inside <Text>. This is how you style specific words within a sentence.color prop accepts standard HTML color names or keywords like "warning" (which might map to Yellow in our theme).
You might be wondering: Where does validation.status or diagnostic.version come from?
The UI is only responsible for displaying data. The actual data handling, fetching, and logic live in the Application State.
We will cover how this data flows into our components in the next chapter: Application State Management.
In this chapter, we learned:
<Box> for layout and <Text> for content, replacing HTML tags.Now that we know how to render the screen, we need to understand how to manage the complex data that fuels these screens.
Next Chapter: Application State Management
Generated by Code IQ