feat(cli): branded top bar with mosaic windmill icon
- ASCII art mosaic windmill: 4 colored tiles (blue, purple, teal, amber) with pink center, matching the Mosaic Stack brand - 3-line info block (Claude Code style): Line 1: 'Mosaic Stack v0.0.0' Line 2: model (context) · thinking · agent name Line 3: ● host connection status - Remove bordered box in favor of open layout with icon
This commit is contained in:
@@ -3,18 +3,94 @@ import { Box, Text } from 'ink';
|
||||
|
||||
export interface TopBarProps {
|
||||
gatewayUrl: string;
|
||||
version: string;
|
||||
modelName: string | null;
|
||||
thinkingLevel: string;
|
||||
contextWindow: number;
|
||||
agentName: string;
|
||||
connected: boolean;
|
||||
connecting: boolean;
|
||||
}
|
||||
|
||||
export function TopBar({ gatewayUrl }: TopBarProps) {
|
||||
// Strip protocol for compact display
|
||||
const host = gatewayUrl.replace(/^https?:\/\//, '');
|
||||
/** Compact the URL — strip protocol */
|
||||
function compactHost(url: string): string {
|
||||
return url.replace(/^https?:\/\//, '');
|
||||
}
|
||||
|
||||
function formatContextWindow(n: number): string {
|
||||
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(0)}M`;
|
||||
if (n >= 1_000) return `${(n / 1_000).toFixed(0)}k`;
|
||||
return String(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mosaic windmill icon — 4 colored tiles + pink center
|
||||
* Colors from the Mosaic brand:
|
||||
* TL: blue (#2f80ff) TR: purple (#8b5cf6)
|
||||
* BL: amber (#f59e0b) BR: teal (#14b8a6)
|
||||
* Center: pink (#ec4899)
|
||||
*/
|
||||
function MosaicIcon() {
|
||||
return (
|
||||
<Box borderStyle="single" borderColor="gray" paddingX={1} justifyContent="space-between">
|
||||
<Text bold color="blue">
|
||||
Mosaic Stack TUI
|
||||
<Box flexDirection="column" marginRight={1}>
|
||||
<Text>
|
||||
<Text color="#2f80ff">██</Text>
|
||||
<Text> </Text>
|
||||
<Text color="#8b5cf6">██</Text>
|
||||
</Text>
|
||||
<Text>
|
||||
<Text> </Text>
|
||||
<Text color="#ec4899">██</Text>
|
||||
<Text> </Text>
|
||||
</Text>
|
||||
<Text>
|
||||
<Text color="#f59e0b">██</Text>
|
||||
<Text> </Text>
|
||||
<Text color="#14b8a6">██</Text>
|
||||
</Text>
|
||||
<Text dimColor>{host}</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export function TopBar({
|
||||
gatewayUrl,
|
||||
version,
|
||||
modelName,
|
||||
thinkingLevel,
|
||||
contextWindow,
|
||||
agentName,
|
||||
connected,
|
||||
connecting,
|
||||
}: TopBarProps) {
|
||||
const host = compactHost(gatewayUrl);
|
||||
const connectionIndicator = connected ? '●' : '○';
|
||||
const connectionColor = connected ? 'green' : connecting ? 'yellow' : 'red';
|
||||
|
||||
// Build model description line like: "claude-opus-4-6 (1M context) · default"
|
||||
const modelDisplay = modelName ?? 'awaiting model';
|
||||
const contextStr = contextWindow > 0 ? ` (${formatContextWindow(contextWindow)} context)` : '';
|
||||
const thinkingStr = thinkingLevel !== 'off' ? ` · ${thinkingLevel}` : '';
|
||||
|
||||
return (
|
||||
<Box paddingX={1} paddingY={0}>
|
||||
<MosaicIcon />
|
||||
<Box flexDirection="column">
|
||||
<Text>
|
||||
<Text bold color="#56a0ff">
|
||||
Mosaic Stack
|
||||
</Text>
|
||||
<Text dimColor> v{version}</Text>
|
||||
</Text>
|
||||
<Text dimColor>
|
||||
{modelDisplay}
|
||||
{contextStr}
|
||||
{thinkingStr} · {agentName}
|
||||
</Text>
|
||||
<Text>
|
||||
<Text color={connectionColor}>{connectionIndicator}</Text>
|
||||
<Text dimColor> {host}</Text>
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user