'use client'; import * as React from 'react'; import { TextInput } from './TextInput'; import { FontPreview } from './FontPreview'; import { FontSelector } from './FontSelector'; import { textToAscii } from '@/lib/ascii/asciiService'; import { getFontList } from '@/lib/ascii/fontLoader'; import { debounce } from '@/lib/utils/debounce'; import { addRecentFont } from '@/lib/storage/favorites'; import { decodeFromUrl, updateUrl, getShareableUrl } from '@/lib/utils/urlSharing'; import { toast } from 'sonner'; import type { ASCIIFont } from '@/types/ascii'; import { cn } from '@/lib/utils'; type Tab = 'editor' | 'preview'; export function ASCIIConverter() { const [text, setText] = React.useState('ASCII'); const [selectedFont, setSelectedFont] = React.useState('Standard'); const [asciiArt, setAsciiArt] = React.useState(''); const [fonts, setFonts] = React.useState([]); const [isLoading, setIsLoading] = React.useState(false); const [tab, setTab] = React.useState('editor'); const commentedTextRef = React.useRef(''); React.useEffect(() => { getFontList().then(setFonts); const urlState = decodeFromUrl(); if (urlState) { if (urlState.text) setText(urlState.text); if (urlState.font) setSelectedFont(urlState.font); } }, []); const generateAsciiArt = React.useMemo( () => debounce(async (inputText: string, fontName: string) => { if (!inputText) { setAsciiArt(''); setIsLoading(false); return; } setIsLoading(true); try { const result = await textToAscii(inputText, fontName); setAsciiArt(result); } catch { setAsciiArt('Error generating ASCII art. Please try a different font.'); } finally { setIsLoading(false); } }, 300), [] ); React.useEffect(() => { generateAsciiArt(text, selectedFont); if (selectedFont) addRecentFont(selectedFont); updateUrl(text, selectedFont); }, [text, selectedFont, generateAsciiArt]); const handleCopy = async () => { if (!asciiArt) return; try { await navigator.clipboard.writeText(commentedTextRef.current || asciiArt); toast.success('Copied to clipboard!'); } catch { toast.error('Failed to copy'); } }; const handleDownload = () => { if (!asciiArt) return; const blob = new Blob([commentedTextRef.current || asciiArt], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `ascii-${selectedFont}-${Date.now()}.txt`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }; const handleShare = async () => { try { await navigator.clipboard.writeText(getShareableUrl(text, selectedFont)); toast.success('Shareable URL copied!'); } catch { toast.error('Failed to copy URL'); } }; const handleRandomFont = () => { if (!fonts.length) return; const font = fonts[Math.floor(Math.random() * fonts.length)]; setSelectedFont(font.name); toast.info(`Font: ${font.name}`); }; return (
{/* ── Mobile tab switcher ────────────────────────────────── */}
{(['editor', 'preview'] as Tab[]).map((t) => ( ))}
{/* ── Main layout ────────────────────────────────────────── */}
{/* Left panel: text input + font selector */}
{/* Text input */}
Text
{/* Font selector — fills remaining height */}
{/* Right panel: preview */}
{ commentedTextRef.current = t; }, [] )} />
); }