diff --git a/src/ui/gameUI.ts b/src/ui/gameUI.ts index 4a24050..f5800a3 100644 --- a/src/ui/gameUI.ts +++ b/src/ui/gameUI.ts @@ -9,6 +9,7 @@ import { loadingAnimation } from './visualEffects'; import { playSound } from './soundEffects'; +import { levelUI } from './levelRenderer'; export async function renderGameUI(): Promise { const gameState = getCurrentGameState(); @@ -39,15 +40,18 @@ export async function renderGameUI(): Promise { )); console.log(''); - // Render current level - await currentLevel.render(); + // Render current level in a box + await levelUI.levelContent(currentLevel.name, async () => { + await currentLevel.render(); + }); console.log(''); console.log(theme.secondary('Available commands:')); console.log(`${theme.accent('/help')} - Show help, ${theme.accent('/save')} - Save game, ${theme.accent('/menu')} - Main menu, ${theme.accent('/hint')} - Get a hint`); console.log(''); - // Get player input + // Display input box and get player input + levelUI.inputBox(); const input = await promptInput(''); // Handle special commands diff --git a/src/ui/levelRenderer.ts b/src/ui/levelRenderer.ts index 140dce3..f064d01 100644 --- a/src/ui/levelRenderer.ts +++ b/src/ui/levelRenderer.ts @@ -1,6 +1,31 @@ import { styles, drawBox, drawTable } from './uiHelpers'; import { getTheme } from './visualEffects'; +// Helper function to wrap text to fit within a width +function wrapText(text: string, maxWidth: number): string[] { + const words = text.split(' '); + const lines: string[] = []; + let currentLine = ''; + + words.forEach(word => { + // If adding this word would exceed the max width + if ((currentLine + ' ' + word).length > maxWidth && currentLine.length > 0) { + lines.push(currentLine); + currentLine = word; + } else { + // Add word to current line (with a space if not the first word) + currentLine = currentLine.length === 0 ? word : currentLine + ' ' + word; + } + }); + + // Add the last line + if (currentLine.length > 0) { + lines.push(currentLine); + } + + return lines; +} + export const levelUI = { title: (text: string) => { const theme = getTheme(); @@ -21,6 +46,65 @@ export const levelUI = { console.log(drawBox(theme.accent(title), content)); }, + // Improved level content box + levelContent: (title: string, content: () => Promise) => { + const theme = getTheme(); + const boxWidth = 76; + + // Start capturing console output + const originalLog = console.log; + let capturedOutput: string[] = []; + + console.log = (...args) => { + capturedOutput.push(args.join(' ')); + }; + + // Execute the content function and then process the output + return content().then(() => { + // Restore console.log + console.log = originalLog; + + // Process and format the captured output + let formattedLines: string[] = []; + + capturedOutput.forEach(line => { + // Skip empty lines at the beginning + if (formattedLines.length === 0 && line.trim() === '') { + return; + } + + // Handle long lines by wrapping them + if (line.length > boxWidth - 4) { + const wrappedLines = wrapText(line, boxWidth - 4); + formattedLines.push(...wrappedLines); + } else { + formattedLines.push(line); + } + }); + + // Draw the box with the formatted content + console.log('┌' + '─'.repeat(boxWidth - 2) + '┐'); + + // Title bar + console.log('│ ' + theme.accent(title.padEnd(boxWidth - 4)) + ' │'); + console.log('├' + '─'.repeat(boxWidth - 2) + '┤'); + + // Content + formattedLines.forEach(line => { + console.log('│ ' + line.padEnd(boxWidth - 4) + ' │'); + }); + + // Bottom of box + console.log('└' + '─'.repeat(boxWidth - 2) + '┘'); + }); + }, + + // Revert to the simpler input box + inputBox: () => { + const theme = getTheme(); + console.log('Enter your command below:'); + }, + terminal: (content: string) => { const theme = getTheme(); console.log(' ' + theme.secondary('┌─ Terminal ───────────────────────┐'));