Files
kit-ui/components/qrcode/QRPreview.tsx

115 lines
3.8 KiB
TypeScript
Raw Normal View History

'use client';
import { Copy, Share2, Image as ImageIcon, FileCode, QrCode } from 'lucide-react';
import { cn, actionBtn, cardBtn } from '@/lib/utils';
import type { ExportSize } from '@/types/qrcode';
interface QRPreviewProps {
svgString: string;
isGenerating: boolean;
exportSize: ExportSize;
onExportSizeChange: (size: ExportSize) => void;
onCopyImage: () => void;
onShare: () => void;
onDownloadPng: () => void;
onDownloadSvg: () => void;
}
const EXPORT_SIZES: { value: ExportSize; label: string }[] = [
{ value: 256, label: '256' },
{ value: 512, label: '512' },
{ value: 1024, label: '1k' },
{ value: 2048, label: '2k' },
];
export function QRPreview({
svgString,
isGenerating,
exportSize,
onExportSizeChange,
onCopyImage,
onShare,
onDownloadPng,
onDownloadSvg,
}: QRPreviewProps) {
return (
<div className="glass rounded-xl p-4 flex flex-col flex-1 min-h-0 overflow-hidden">
{/* Action bar */}
<div className="flex items-center gap-1.5 mb-4 shrink-0 flex-wrap">
<span className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest mr-auto">
Preview
</span>
<button onClick={onCopyImage} disabled={!svgString} className={cardBtn}>
<Copy className="w-3 h-3" />Copy
</button>
<button onClick={onShare} disabled={!svgString} className={cardBtn}>
<Share2 className="w-3 h-3" />Share
</button>
{/* PNG + inline size selector */}
<div className="flex items-center glass rounded-md border border-border/30">
<button
onClick={onDownloadPng}
disabled={!svgString}
className="flex items-center gap-1 pl-2.5 pr-1.5 py-1 text-xs text-muted-foreground hover:text-primary transition-all disabled:opacity-40 disabled:cursor-not-allowed border-r border-border/20"
>
<ImageIcon className="w-3 h-3" />PNG
</button>
<div className="flex items-center px-1 gap-0.5">
{EXPORT_SIZES.map(({ value, label }) => (
<button
key={value}
onClick={() => onExportSizeChange(value)}
className={cn(
'text-[9px] font-mono px-1.5 py-0.5 rounded transition-all',
exportSize === value
? 'text-primary bg-primary/10'
: 'text-muted-foreground/40 hover:text-muted-foreground'
)}
>
{label}
</button>
))}
</div>
</div>
<button onClick={onDownloadSvg} disabled={!svgString} className={cardBtn}>
<FileCode className="w-3 h-3" />SVG
</button>
</div>
{/* QR canvas */}
<div
className="flex-1 min-h-0 rounded-xl flex items-center justify-center"
style={{
backgroundImage: 'repeating-conic-gradient(rgba(255,255,255,0.025) 0% 25%, transparent 0% 50%)',
backgroundSize: '16px 16px',
}}
>
{isGenerating ? (
<div className="w-56 h-56 rounded-xl bg-white/5 animate-pulse" />
) : svgString ? (
<div
className="w-full max-w-sm aspect-square [&>svg]:w-full [&>svg]:h-full p-6"
dangerouslySetInnerHTML={{ __html: svgString }}
/>
) : (
<div className="flex flex-col items-center gap-3 text-center">
<div className="w-14 h-14 rounded-full bg-primary/10 flex items-center justify-center">
<QrCode className="w-6 h-6 text-primary/40" />
</div>
<div>
<p className="text-sm font-medium text-foreground/40">No QR code yet</p>
<p className="text-[10px] text-muted-foreground/30 font-mono mt-1">Enter text or a URL to generate</p>
</div>
</div>
)}
</div>
</div>
);
}