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 {
|
export interface TopBarProps {
|
||||||
gatewayUrl: string;
|
gatewayUrl: string;
|
||||||
|
version: string;
|
||||||
|
modelName: string | null;
|
||||||
|
thinkingLevel: string;
|
||||||
|
contextWindow: number;
|
||||||
|
agentName: string;
|
||||||
|
connected: boolean;
|
||||||
|
connecting: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TopBar({ gatewayUrl }: TopBarProps) {
|
/** Compact the URL — strip protocol */
|
||||||
// Strip protocol for compact display
|
function compactHost(url: string): string {
|
||||||
const host = gatewayUrl.replace(/^https?:\/\//, '');
|
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 (
|
return (
|
||||||
<Box borderStyle="single" borderColor="gray" paddingX={1} justifyContent="space-between">
|
<Box flexDirection="column" marginRight={1}>
|
||||||
<Text bold color="blue">
|
<Text>
|
||||||
Mosaic Stack TUI
|
<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>
|
||||||
<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>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user