Initial commit: TypoGenie - Markdown to Word document converter
This commit is contained in:
92
components/FileUpload.tsx
Normal file
92
components/FileUpload.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { Upload, FileText, AlertCircle } from 'lucide-react';
|
||||
|
||||
interface FileUploadProps {
|
||||
onFileLoaded: (content: string) => void;
|
||||
}
|
||||
|
||||
export const FileUpload: React.FC<FileUploadProps> = ({ onFileLoaded }) => {
|
||||
const [dragActive, setDragActive] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const handleFile = (file: File) => {
|
||||
setError(null);
|
||||
if (!file.name.endsWith('.md') && !file.name.endsWith('.txt') && !file.name.endsWith('.markdown')) {
|
||||
setError('Please upload a Markdown (.md) or Text (.txt) file.');
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const text = e.target?.result;
|
||||
if (typeof text === 'string') {
|
||||
onFileLoaded(text);
|
||||
}
|
||||
};
|
||||
reader.onerror = () => setError('Error reading file.');
|
||||
reader.readAsText(file);
|
||||
};
|
||||
|
||||
const handleDrag = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (e.type === 'dragenter' || e.type === 'dragover') {
|
||||
setDragActive(true);
|
||||
} else if (e.type === 'dragleave') {
|
||||
setDragActive(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleDrop = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setDragActive(false);
|
||||
if (e.dataTransfer.files && e.dataTransfer.files[0]) {
|
||||
handleFile(e.dataTransfer.files[0]);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
e.preventDefault();
|
||||
if (e.target.files && e.target.files[0]) {
|
||||
handleFile(e.target.files[0]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-xl mx-auto">
|
||||
<div
|
||||
className={`relative group flex flex-col items-center justify-center w-full h-64 border-2 border-dashed rounded-2xl transition-all duration-300 ease-in-out cursor-pointer overflow-hidden
|
||||
${dragActive ? 'border-indigo-500 bg-indigo-500/10' : 'border-zinc-700 bg-zinc-900/50 hover:border-zinc-500 hover:bg-zinc-800/50'}`}
|
||||
onDragEnter={handleDrag}
|
||||
onDragLeave={handleDrag}
|
||||
onDragOver={handleDrag}
|
||||
onDrop={handleDrop}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10"
|
||||
onChange={handleChange}
|
||||
accept=".md,.txt,.markdown"
|
||||
/>
|
||||
|
||||
<div className="flex flex-col items-center justify-center pt-5 pb-6 text-zinc-400 group-hover:text-zinc-200 transition-colors">
|
||||
<div className={`p-4 rounded-full mb-4 ${dragActive ? 'bg-indigo-500/20 text-indigo-400' : 'bg-zinc-800 text-zinc-500'}`}>
|
||||
<Upload size={32} />
|
||||
</div>
|
||||
<p className="mb-2 text-lg font-medium">
|
||||
<span className="font-semibold text-indigo-400">Click to upload</span> or drag and drop
|
||||
</p>
|
||||
<p className="text-sm text-zinc-500">Markdown or Plain Text files</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="mt-4 p-4 bg-red-900/20 border border-red-800 rounded-lg flex items-center gap-3 text-red-200 animate-in fade-in slide-in-from-top-2">
|
||||
<AlertCircle size={20} />
|
||||
<span>{error}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user