feat(tui): add ASCII art banner on startup
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
// ASCII art banner for Flynn TUI startup
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flynn ASCII art banner using block characters.
|
||||||
|
* Raw art lines without any color codes — callers apply their own styling.
|
||||||
|
*/
|
||||||
|
export const FLYNN_BANNER = `
|
||||||
|
███████╗██╗ ██╗ ██╗███╗ ██╗███╗ ██╗
|
||||||
|
██╔════╝██║ ╚██╗ ██╔╝████╗ ██║████╗ ██║
|
||||||
|
█████╗ ██║ ╚████╔╝ ██╔██╗ ██║██╔██╗ ██║
|
||||||
|
██╔══╝ ██║ ╚██╔╝ ██║╚██╗██║██║╚██╗██║
|
||||||
|
██║ ███████╗ ██║ ██║ ╚████║██║ ╚████║
|
||||||
|
╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚═╝ ╚═══╝`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the banner with ANSI color codes for terminal output.
|
||||||
|
* Uses orange (208) for the art and dim for the box frame.
|
||||||
|
*/
|
||||||
|
export function getColoredBanner(): string {
|
||||||
|
const orange = '\x1b[38;5;208m';
|
||||||
|
const reset = '\x1b[0m';
|
||||||
|
|
||||||
|
return `${orange}${FLYNN_BANNER}${reset}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns plain banner lines for use in Ink/React components.
|
||||||
|
* Each line is returned individually for flexible rendering.
|
||||||
|
*/
|
||||||
|
export function getBannerLines(): string[] {
|
||||||
|
return FLYNN_BANNER.split('\n').filter((line) => line.length > 0);
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import { Box, Text, Static } from 'ink';
|
|||||||
import type { Message } from '../../../models/types.js';
|
import type { Message } from '../../../models/types.js';
|
||||||
import { getMessageText } from '../../../models/media.js';
|
import { getMessageText } from '../../../models/media.js';
|
||||||
import { renderMarkdown } from '../markdown.js';
|
import { renderMarkdown } from '../markdown.js';
|
||||||
|
import { getBannerLines } from '../banner.js';
|
||||||
|
|
||||||
export interface MessageListProps {
|
export interface MessageListProps {
|
||||||
messages: Message[];
|
messages: Message[];
|
||||||
@@ -80,7 +81,12 @@ export const MessageList = memo(function MessageList({
|
|||||||
return (
|
return (
|
||||||
<Box flexDirection="column" flexGrow={1} paddingX={1} overflowY="hidden">
|
<Box flexDirection="column" flexGrow={1} paddingX={1} overflowY="hidden">
|
||||||
{visibleMessages.length === 0 && !streamingContent ? (
|
{visibleMessages.length === 0 && !streamingContent ? (
|
||||||
<Text color="gray">No messages yet. Start typing to chat with Flynn.</Text>
|
<Box flexDirection="column" alignItems="center" justifyContent="center" flexGrow={1}>
|
||||||
|
{getBannerLines().map((line, i) => (
|
||||||
|
<Text key={i} color="#ff8c00">{line}</Text>
|
||||||
|
))}
|
||||||
|
<Text color="gray">{'\n'}Start typing to chat with Flynn.</Text>
|
||||||
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Static items={visibleMessages}>
|
<Static items={visibleMessages}>
|
||||||
|
|||||||
@@ -13,5 +13,6 @@ export {
|
|||||||
|
|
||||||
export { renderMarkdown } from './markdown.js';
|
export { renderMarkdown } from './markdown.js';
|
||||||
export { parseCommand as parseCommandUtil, getHelpText, resolveModelAlias } from './commands.js';
|
export { parseCommand as parseCommandUtil, getHelpText, resolveModelAlias } from './commands.js';
|
||||||
|
export { FLYNN_BANNER, getColoredBanner, getBannerLines } from './banner.js';
|
||||||
|
|
||||||
export { App, StatusBar, MessageList, InputBar } from './components/index.js';
|
export { App, StatusBar, MessageList, InputBar } from './components/index.js';
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { OllamaClient, LlamaCppClient } from '../../models/index.js';
|
|||||||
import { createClientFromConfig } from '../../daemon/index.js';
|
import { createClientFromConfig } from '../../daemon/index.js';
|
||||||
import { loginGitHub } from '../../auth/index.js';
|
import { loginGitHub } from '../../auth/index.js';
|
||||||
import type { PairingManager } from '../../channels/pairing.js';
|
import type { PairingManager } from '../../channels/pairing.js';
|
||||||
|
import { getColoredBanner } from './banner.js';
|
||||||
|
|
||||||
export { parseCommand, type Command };
|
export { parseCommand, type Command };
|
||||||
|
|
||||||
@@ -125,7 +126,8 @@ export class MinimalTui {
|
|||||||
readline.emitKeypressEvents(process.stdin);
|
readline.emitKeypressEvents(process.stdin);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`${colors.orange}${colors.bold}Flynn TUI${colors.reset} ${colors.dim}(minimal mode)${colors.reset}`);
|
console.log(getColoredBanner());
|
||||||
|
console.log(`\n${colors.orange}${colors.bold}Flynn TUI${colors.reset} ${colors.dim}(minimal mode)${colors.reset}`);
|
||||||
console.log(`${colors.gray}Type /help for commands, /fullscreen for panel mode${colors.reset}\n`);
|
console.log(`${colors.gray}Type /help for commands, /fullscreen for panel mode${colors.reset}\n`);
|
||||||
|
|
||||||
await this.promptLoop();
|
await this.promptLoop();
|
||||||
|
|||||||
Reference in New Issue
Block a user