/** * Preview Screen Component * * Displays generated assets with terminal image preview after asset generation * is complete. Shows a progress bar during generation, then displays: * - Summary of generated assets. * - Asset grid grouped by platform. * - Output directory and instructions path. * - Any errors that occurred during generation. */ import { useKeyboard } from '@opentui/react' import { useCallback, useEffect, useState } from 'react' import { generateAssets } from '../generators/asset_generator' import type { AssetGeneratorConfig, GeneratedAsset, GenerationResult, } from '../types' import { ImagePreview } from './image_preview' // ─── Theme Colors ────────────────────────────────────────────────────────── // Terminal-agnostic colors that work in both light and dark terminals. const colors = { text: 'white', textMuted: 'gray', textDim: 'gray', accent: 'cyan', accentSecondary: 'yellow', } as const // ─── Component Props ─────────────────────────────────────────────────────── interface PreviewScreenProps { config: AssetGeneratorConfig result: GenerationResult | null onBack: () => void onGenerationComplete: (result: GenerationResult) => void } // ─── Main Component ──────────────────────────────────────────────────────── /** * Preview screen displaying asset generation progress and results. */ export function PreviewScreen({ config, result, onBack, onGenerationComplete, }: PreviewScreenProps) { const [isGenerating, setIsGenerating] = useState(false) const [progress, setProgress] = useState(0) // ─── Keyboard Handler ────────────────────────────────────────────────────── useKeyboard(key => { if (key.name === 'escape' || key.name === 'backspace') { onBack() } }) // ─── Asset Generation ────────────────────────────────────────────────────── /** * Run the asset generation pipeline asynchronously. * * Updates progress state and calls onGenerationComplete when done. * Errors are logged but don't prevent partial results from displaying. */ const generateAssetsAsync = useCallback(async () => { setIsGenerating(true) setProgress(0) try { const generationResult = await generateAssets(config) setProgress(100) onGenerationComplete(generationResult) } catch (error) { console.error('Asset generation failed:', error) } finally { setIsGenerating(false) } }, [config, onGenerationComplete]) // ─── Effects ─────────────────────────────────────────────────────────────── // Trigger asset generation on mount if not already generated. useEffect(() => { if (!result && !isGenerating) { generateAssetsAsync() } }, [generateAssetsAsync, isGenerating, result]) // ─── Computed Values ─────────────────────────────────────────────────────── // Group assets by platform for organized display. const groupedAssets = result?.assets.reduce( (acc, asset) => { const platform = asset.spec.platform if (!acc[platform]) acc[platform] = [] acc[platform].push(asset) return acc }, {} as Record, ) || {} // ─── Render ──────────────────────────────────────────────────────────────── return ( {/* Header */} ASSET PREVIEW ← Back [Esc] ──────────────────────────────────────────── {/* Generation Progress */} {isGenerating && ( Generating assets... {progress}% {'█'.repeat(Math.floor(progress * 0.4))} {'░'.repeat(40 - Math.floor(progress * 0.4))} )} {/* Results */} {result && ( {/* Summary */} Generated {result.assets.length} assets Output: {result.outputDir} {result.errors && result.errors.length > 0 && ( {result.errors.length} errors occurred )} ──────────────────────────────────────────── {/* Asset Groups */} {Object.entries(groupedAssets).map(([platform, assets]) => ( {platform.toUpperCase()} ({assets.length} assets) {/* Preview grid */} {assets.slice(0, 6).map(asset => ( {asset.spec.width}×{asset.spec.height} ))} {assets.length > 6 && ( +{assets.length - 6} more )} ))} ──────────────────────────────────────────── {/* Output Information */} OUTPUT Directory: {result.outputDir} {result.instructionsPath && ( Instructions: {result.instructionsPath} )} Copy assets to your project. See README.md for details. )} {/* Errors */} {result?.errors && result.errors.length > 0 && ( ERRORS {result.errors.map(error => ( • {error} ))} )} ) }