mirror of
https://github.com/kccleoc/seedpgp-web.git
synced 2026-03-07 09:57:50 +08:00
- Eliminate all white/light boxes and backgrounds - Fix drag-drop zone with neon cyberpunk colors (#00f0ff, #ff006e, #16213e) - Fix restored mnemonic display with matrix green (#39ff14) - Fix security options panel with dark gradient - Fix all remaining slate-700/slate-800 labels to cyberpunk neon - Fix info banners and text colors - Update badge components with cyberpunk color scheme - Apply consistent dark theme across all components
121 lines
4.3 KiB
TypeScript
121 lines
4.3 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { Download } from 'lucide-react';
|
|
import QRCode from 'qrcode';
|
|
|
|
interface QrDisplayProps {
|
|
value: string | Uint8Array;
|
|
}
|
|
|
|
export const QrDisplay: React.FC<QrDisplayProps> = ({ value }) => {
|
|
const [dataUrl, setDataUrl] = useState('');
|
|
const [debugInfo, setDebugInfo] = useState('');
|
|
|
|
useEffect(() => {
|
|
if (!value) {
|
|
setDataUrl('');
|
|
return;
|
|
}
|
|
|
|
const generateQR = async () => {
|
|
try {
|
|
console.log('🎨 QrDisplay generating QR for:', value);
|
|
console.log(' - Type:', value instanceof Uint8Array ? 'Uint8Array' : typeof value);
|
|
console.log(' - Length:', value.length);
|
|
|
|
if (value instanceof Uint8Array) {
|
|
console.log(' - Hex:', Array.from(value).map(b => b.toString(16).padStart(2, '0')).join(''));
|
|
|
|
// Create canvas manually for precise control
|
|
const canvas = document.createElement('canvas');
|
|
|
|
// Use the toCanvas method with Uint8Array directly
|
|
await QRCode.toCanvas(canvas, [{
|
|
data: value,
|
|
mode: 'byte'
|
|
}], {
|
|
errorCorrectionLevel: 'L',
|
|
width: 512,
|
|
margin: 4,
|
|
color: {
|
|
dark: '#000000',
|
|
light: '#FFFFFF'
|
|
}
|
|
});
|
|
|
|
const url = canvas.toDataURL('image/png');
|
|
setDataUrl(url);
|
|
setDebugInfo(`Binary QR: ${value.length} bytes`);
|
|
console.log('✅ Binary QR generated successfully');
|
|
} else {
|
|
// For string data
|
|
console.log(' - String data:', value.slice(0, 50));
|
|
|
|
const url = await QRCode.toDataURL(value, {
|
|
errorCorrectionLevel: 'L',
|
|
type: 'image/png',
|
|
width: 512,
|
|
margin: 4,
|
|
color: {
|
|
dark: '#000000',
|
|
light: '#FFFFFF'
|
|
}
|
|
});
|
|
|
|
setDataUrl(url);
|
|
setDebugInfo(`String QR: ${value.length} chars`);
|
|
console.log('✅ String QR generated successfully');
|
|
}
|
|
} catch (err) {
|
|
console.error('❌ QR generation error:', err);
|
|
setDebugInfo(`Error: ${err}`);
|
|
}
|
|
};
|
|
|
|
generateQR();
|
|
}, [value]);
|
|
|
|
const handleDownload = () => {
|
|
if (!dataUrl) return;
|
|
|
|
const now = new Date();
|
|
const date = now.toISOString().split('T')[0];
|
|
const time = now.toTimeString().split(' ')[0].replace(/:/g, '');
|
|
const filename = `SeedPGP_${date}_${time}.png`;
|
|
|
|
const link = document.createElement('a');
|
|
link.href = dataUrl;
|
|
link.download = filename;
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
};
|
|
|
|
if (!dataUrl) return null;
|
|
|
|
return (
|
|
<div className="border-4 border-[#00f0ff] rounded-xl shadow-[0_0_40px_rgba(0,240,255,0.6)] p-4 bg-[#0a0a0f] space-y-4">
|
|
<div className="bg-[#16213e] p-6 rounded-lg inline-block shadow-[0_0_20px_rgba(0,240,255,0.3)] border-2 border-[#00f0ff]/30">
|
|
<img src={dataUrl} alt="QR Code" className="w-full h-auto" />
|
|
</div>
|
|
|
|
{debugInfo && (
|
|
<div className="text-xs text-[#6ef3f7] font-mono">
|
|
{debugInfo}
|
|
</div>
|
|
)}
|
|
|
|
<button
|
|
onClick={handleDownload}
|
|
className="flex items-center gap-2 px-4 py-2 bg-[#00f0ff] hover:bg-[#00f0ff]/80 text-[#0a0a0f] rounded-lg transition-all hover:shadow-[0_0_15px_rgba(0,240,255,0.5)]"
|
|
>
|
|
<Download size={16} />
|
|
Download QR Code
|
|
</button>
|
|
|
|
<p className="text-xs text-[#6ef3f7]">
|
|
Downloads as: SeedPGP_{new Date().toISOString().split('T')[0]}_HHMMSS.png
|
|
</p>
|
|
</div>
|
|
);
|
|
};
|