import React, { useMemo } from "react"; import { Box, Text, useStdout } from "ink"; import { rainbowColors } from "./colors"; import { MASK_WIDTH, buildMaskGrid, buildTitleGrid, canRenderTitle, pixelsToRuns, titleWidth, type Run, } from "./pixels"; const GREEN = "#7BD74F"; const PINK = "#E58AFF"; const GREEN_LINES = ["Assistant IA en ligne de commande,", "propulsé par Ink et vos modèles de langage."]; const PINK_LINES = ["Un seul agent, plusieurs modes :", "le modèle de votre choix."]; const MASK_LINES = pixelsToRuns(buildMaskGrid()); const GAP = 3; function PixelBlock({ lines }: { lines: Run[][] }) { return ( {lines.map((runs, y) => ( {runs.map((r, i) => ( {r.text} ))} ))} ); } /** Repli pour un terminal étroit : cadre à double bordure, titre centré en dégradé arc-en-ciel. */ function CompactBanner({ title, columns }: { title: string; columns: number }) { const chars = [...title]; const colors = rainbowColors(chars.length); return ( {chars.map((ch, i) => ( {ch} ))} ); } /** * Bannière d'accueil : masque pixel-art à gauche, titre pixel arc-en-ciel à droite, puis deux textes * (vert, rose). Selon la largeur du terminal : complète, sans masque, ou cadre compact. */ export function Banner({ title }: { title: string }) { const { stdout } = useStdout(); const columns = stdout?.columns ?? 80; const titleLines = useMemo( () => (canRenderTitle(title) ? pixelsToRuns(buildTitleGrid(title)) : null), [title], ); if (!titleLines || columns < titleWidth(title) + 2) { return ; } const right = ( {GREEN_LINES.map((line) => ( {line} ))} {PINK_LINES.map((line) => ( {line} ))} ); if (columns < MASK_WIDTH + GAP + titleWidth(title)) return right; return ( {right} ); }