Major UX enhancements for better user feedback and discovery: **Toast Notification System** - Beautiful toast notifications with 3 types (success/error/info) - Auto-dismiss after 3 seconds - Slide-in animation from right - Color-coded by type (green/red/blue) - Dark mode support - Close button for manual dismiss - ToastProvider context for global access - Non-blocking UI overlay **Random Font Discovery** - Shuffle button in font selector - One-click random font selection - Toast notification shows selected font - Perfect for discovering new fonts - Located next to "Select Font" header **Enhanced Font Preview** - Font name badge display - Character count statistics - Line count statistics - Better visual hierarchy - Responsive stat display **Improved Feedback** - Toast on copy: "Copied to clipboard!" - Toast on share: "Shareable URL copied!" - Toast on random: "Random font: FontName" - Error toasts for failed operations - Removed temporary text replacement **Smooth Animations** - Slide-in animation for toasts - Fade-in animation class - Custom keyframe animations - CSS utility classes - Smooth transitions throughout **Technical Improvements** - useToast custom hook - Context-based state management - Auto-cleanup with setTimeout - Unique toast IDs - TypeScript types for toast system - Proper event propagation **Better UX** - No more jarring text replacements - Non-intrusive notifications - Professional feedback system - Discoverable random feature - Informative preview stats The app now feels polished and professional with proper user feedback! 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
83 lines
2.8 KiB
TypeScript
83 lines
2.8 KiB
TypeScript
'use client';
|
|
|
|
import * as React from 'react';
|
|
import { Card } from '@/components/ui/Card';
|
|
import { Button } from '@/components/ui/Button';
|
|
import { Copy, Download, Share2 } from 'lucide-react';
|
|
import { cn } from '@/lib/utils/cn';
|
|
|
|
export interface FontPreviewProps {
|
|
text: string;
|
|
font?: string;
|
|
isLoading?: boolean;
|
|
onCopy?: () => void;
|
|
onDownload?: () => void;
|
|
onShare?: () => void;
|
|
className?: string;
|
|
}
|
|
|
|
export function FontPreview({ text, font, isLoading, onCopy, onDownload, onShare, className }: FontPreviewProps) {
|
|
const lineCount = text ? text.split('\n').length : 0;
|
|
const charCount = text ? text.length : 0;
|
|
return (
|
|
<Card className={cn('relative', className)}>
|
|
<div className="p-6">
|
|
<div className="flex items-center justify-between mb-4 flex-wrap gap-2">
|
|
<div className="flex items-center gap-2">
|
|
<h3 className="text-sm font-medium">Preview</h3>
|
|
{font && (
|
|
<span className="text-xs px-2 py-0.5 bg-primary/10 text-primary rounded-md font-mono">
|
|
{font}
|
|
</span>
|
|
)}
|
|
</div>
|
|
<div className="flex gap-2 flex-wrap">
|
|
{onCopy && (
|
|
<Button variant="outline" size="sm" onClick={onCopy}>
|
|
<Copy className="h-4 w-4" />
|
|
Copy
|
|
</Button>
|
|
)}
|
|
{onShare && (
|
|
<Button variant="outline" size="sm" onClick={onShare} title="Copy shareable URL">
|
|
<Share2 className="h-4 w-4" />
|
|
Share
|
|
</Button>
|
|
)}
|
|
{onDownload && (
|
|
<Button variant="outline" size="sm" onClick={onDownload}>
|
|
<Download className="h-4 w-4" />
|
|
Download
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{!isLoading && text && (
|
|
<div className="flex gap-4 mb-2 text-xs text-muted-foreground">
|
|
<span>{lineCount} lines</span>
|
|
<span>•</span>
|
|
<span>{charCount} chars</span>
|
|
</div>
|
|
)}
|
|
|
|
<div className="relative min-h-[200px] bg-muted/50 rounded-lg p-4 overflow-x-auto">
|
|
{isLoading ? (
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
<div className="text-sm text-muted-foreground">Generating...</div>
|
|
</div>
|
|
) : text ? (
|
|
<pre className="font-mono text-xs sm:text-sm whitespace-pre overflow-x-auto">
|
|
{text}
|
|
</pre>
|
|
) : (
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
<div className="text-sm text-muted-foreground">Your ASCII art will appear here</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|