feat(tui): add markdown rendering and scroll support to MessageList

This commit is contained in:
William Valentin
2026-02-05 10:56:23 -08:00
parent 7391b50d6d
commit 0490d2fe39
+42 -14
View File
@@ -1,29 +1,57 @@
import React from 'react';
import { Box, Text } from 'ink';
import type { Message } from '../../../models/types.js';
import { renderMarkdown } from '../markdown.js';
export interface MessageListProps {
messages: Message[];
maxHeight?: number;
scrollOffset?: number;
streamingContent?: string;
}
export function MessageList({ messages, maxHeight = 20 }: MessageListProps): React.ReactElement {
// Show only recent messages that fit
const visibleMessages = messages.slice(-maxHeight);
export function MessageList({
messages,
scrollOffset = 0,
streamingContent,
}: MessageListProps): React.ReactElement {
// Calculate visible area (approximate, Ink handles overflow)
const visibleMessages = messages.slice(scrollOffset);
return (
<Box flexDirection="column" flexGrow={1} paddingX={1}>
{visibleMessages.length === 0 ? (
<Box flexDirection="column" flexGrow={1} paddingX={1} overflowY="hidden">
{visibleMessages.length === 0 && !streamingContent ? (
<Text color="gray">No messages yet. Start typing to chat with Flynn.</Text>
) : (
visibleMessages.map((message, index) => (
<Box key={index} marginBottom={1}>
<Text color={message.role === 'user' ? 'blue' : 'green'}>
{message.role === 'user' ? 'You: ' : 'Flynn: '}
</Text>
<Text wrap="wrap">{message.content}</Text>
</Box>
))
<>
{visibleMessages.map((message, index) => (
<Box key={`${scrollOffset + index}-${message.role}`} marginBottom={1} flexDirection="column">
<Text color={message.role === 'user' ? 'blue' : 'green'} bold>
{message.role === 'user' ? 'You:' : 'Flynn:'}
</Text>
<Box marginLeft={1}>
<Text wrap="wrap">
{message.role === 'assistant'
? renderMarkdown(message.content)
: message.content}
</Text>
</Box>
</Box>
))}
{streamingContent && (
<Box marginBottom={1} flexDirection="column">
<Text color="green" bold>Flynn:</Text>
<Box marginLeft={1}>
<Text wrap="wrap">{streamingContent}</Text>
<Text color="yellow">|</Text>
</Box>
</Box>
)}
</>
)}
{messages.length > 0 && scrollOffset > 0 && (
<Box position="absolute" marginTop={-1}>
<Text color="gray">{scrollOffset} more above</Text>
</Box>
)}
</Box>
);