Files
seedpgp-web/src/components/PgpKeyInput.tsx
LC mac 05edb3c231 feat: seedpgp v1.1.0 - BIP39 mnemonic PGP encryption tool
- Implement cv25519 PGP encryption/decryption
- Add Base45 encoding with CRC16 integrity checks
- Create SEEDPGP1 frame format for QR codes
- Support BIP39 passphrase flag indicator
- Add comprehensive test suite with Trezor BIP39 vectors
- 15 passing tests covering all core functionality
2026-01-28 02:34:50 +08:00

85 lines
2.9 KiB
TypeScript

import React, { useState } from 'react';
import { Upload } from 'lucide-react';
import type { LucideIcon } from "lucide-react";
interface PgpKeyInputProps {
value: string;
onChange: (value: string) => void;
placeholder: string;
label: string;
icon?: LucideIcon;
}
export const PgpKeyInput: React.FC<PgpKeyInputProps> = ({
value,
onChange,
placeholder,
label,
icon: Icon
}) => {
const [isDragging, setIsDragging] = useState(false);
const handleDragOver = (e: React.DragEvent) => {
e.preventDefault();
setIsDragging(true);
};
const handleDragLeave = (e: React.DragEvent) => {
e.preventDefault();
setIsDragging(false);
};
const handleDrop = (e: React.DragEvent) => {
e.preventDefault();
setIsDragging(false);
const file = e.dataTransfer.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
if (event.target?.result) {
onChange(event.target.result as string);
}
};
reader.readAsText(file);
}
};
return (
<div className="space-y-2">
<label className="text-sm font-semibold text-slate-700 flex items-center justify-between">
<span className="flex items-center gap-2">
{Icon && <Icon size={14} />} {label}
</span>
<span className="text-[10px] text-slate-400 font-normal bg-slate-100 px-2 py-0.5 rounded-full border border-slate-200">
Drag & Drop .asc file
</span>
</label>
<div
className={`relative transition-all duration-200 ${isDragging ? 'scale-[1.01]' : ''}`}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
>
<textarea
className={`w-full h-40 p-3 bg-slate-50 border rounded-xl text-xs font-mono transition-colors resize-none focus:outline-none focus:ring-2 focus:ring-blue-500 ${isDragging ? 'border-blue-500 bg-blue-50' : 'border-slate-200'
}`}
placeholder={placeholder}
value={value}
onChange={(e) => onChange(e.target.value)}
/>
{isDragging && (
<div className="absolute inset-0 flex items-center justify-center bg-blue-50/90 rounded-xl border-2 border-dashed border-blue-500 pointer-events-none z-10">
<div className="text-blue-600 font-bold flex flex-col items-center animate-bounce">
<Upload size={24} />
<span className="text-sm mt-2">Drop Key File Here</span>
</div>
</div>
)}
</div>
</div>
);
};