All checks were successful
ci/woodpecker/push/ci Pipeline was successful
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
100 lines
2.5 KiB
TypeScript
100 lines
2.5 KiB
TypeScript
import React from 'react';
|
||
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;
|
||
}
|
||
|
||
/** 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 3×3 icon — brand tiles with black gaps (windmill cross pattern)
|
||
*
|
||
* Layout:
|
||
* blue ·· purple
|
||
* ·· pink ··
|
||
* amber ·· teal
|
||
*/
|
||
// Two-space gap between tiles (extracted to avoid prettier collapse)
|
||
const GAP = ' ';
|
||
|
||
function MosaicIcon() {
|
||
return (
|
||
<Box flexDirection="column" marginRight={2}>
|
||
<Text>
|
||
<Text color="#2f80ff">██</Text>
|
||
<Text>{GAP}</Text>
|
||
<Text color="#8b5cf6">██</Text>
|
||
</Text>
|
||
<Text>
|
||
<Text>{GAP}</Text>
|
||
<Text color="#ec4899">██</Text>
|
||
</Text>
|
||
<Text>
|
||
<Text color="#f59e0b">██</Text>
|
||
<Text>{GAP}</Text>
|
||
<Text color="#14b8a6">██</Text>
|
||
</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} marginBottom={1}>
|
||
<MosaicIcon />
|
||
<Box flexDirection="column" flexGrow={1}>
|
||
<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>
|
||
);
|
||
}
|