const DEFAULT_CARD_WIDTH = 32; const DEFAULT_CARD_HEIGHT = 8; type CardPresenterOptions = { width: number, height: number } const makeCardEdge = (width: number, symbols: string) => { const middlePart = Math.floor(symbols.length / 2); return ( new Array(width) .fill(symbols.at(middlePart) as string) .map((s, i, ss) => { if (i < middlePart) { return symbols.at(i); } if (i >= (ss.length - 1) - middlePart) { return symbols.at(ss.length - i - 1); } return s; }) .join('') ); }; const encloseInCard = async ( cardText: string, cardWidth: number, cardHeight: number, symbols: [string, string, string], ) => { // can't import es modules naturally, we use dynamic imports here const { default: wrapAnsi } = await import('wrap-ansi'); const lineWidth = cardWidth - (symbols[1].length - 1); const text = wrapAnsi(cardText, lineWidth, { hard: true, trim: true }); const lines = text.split('\n').map((line) => { let centeredLine = line; while (centeredLine.length < lineWidth) { // add space after centeredLine = `${centeredLine}${symbols[1].at(3) as string}`; if (centeredLine.length < lineWidth) { // add space before centeredLine = `${symbols[1].at(1) as string}${centeredLine}`; } } return centeredLine.slice(0, lineWidth); }); const displayLines = [...lines]; while (displayLines.length < cardHeight - 2) { const blank = new Array(lineWidth).fill(symbols[1].at(1) as string).join(''); displayLines.push(blank); if (displayLines.length < cardHeight - 2) { displayLines.unshift(blank); } } const cardCenter = displayLines .map((line) => ( `${symbols[1].at(0) as string}${symbols[1].at(1) as string}${line}${symbols[1].at(3) as string}${symbols[1].at(4) as string}` )) .join('\n'); return [ makeCardEdge(cardWidth, symbols[0]), cardCenter, makeCardEdge(cardWidth, symbols[2]), ].join('\n'); }; export default (options = {} as CardPresenterOptions) => async (card: string) => { const { width: cardWidthRaw = DEFAULT_CARD_WIDTH, height: cardHeightRaw = DEFAULT_CARD_HEIGHT, } = options; const cardWidth = Math.max(cardWidthRaw, DEFAULT_CARD_WIDTH); const cardHeight = Math.max(cardHeightRaw, DEFAULT_CARD_HEIGHT); const cardContents = await encloseInCard( card, cardWidth, cardHeight, [ ' ,-. ', '| A |', " `-' ", ], ); const Console = console; Console.log(cardContents); };