File size: 12,597 Bytes
a9702eb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
import React from 'react';
import { UploadStatus } from './types';
import { FileUploader } from './components/FileUploader';
import { UploadList } from './components/UploadList';
import { Upload, Rocket, Database, ShieldCheck, Zap, LayoutGrid, CheckCircle2, HelpCircle, Terminal } from 'lucide-react';
import { useFileUpload } from './hooks/useFileUpload';
export default function App() {
const {
files,
isUploading,
addFiles,
removeFile,
updateFilePath,
startUpload
} = useFileUpload();
const hasPendingFiles = files.some(f => f.status === UploadStatus.IDLE || f.status === UploadStatus.ERROR);
return (
<div className="min-h-screen bg-white font-sans selection:bg-indigo-100 selection:text-indigo-900">
{/* Decorative Background */}
<div className="fixed inset-0 z-0 pointer-events-none overflow-hidden">
<div className="absolute top-[-10%] left-[-10%] w-[40%] h-[40%] rounded-full bg-indigo-100/50 blur-[120px]" />
<div className="absolute bottom-[10%] right-[-5%] w-[30%] h-[30%] rounded-full bg-purple-100/50 blur-[100px]" />
</div>
{/* Navbar */}
<header className="fixed top-0 w-full z-50 glass-effect border-b border-gray-100/50">
<div className="max-w-6xl mx-auto px-6 h-16 flex items-center justify-between">
<div className="flex items-center gap-2">
<div className="bg-gradient-to-r from-indigo-600 to-violet-600 p-2 rounded-lg text-white">
<Rocket className="w-5 h-5" />
</div>
<span className="text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-gray-900 to-gray-600">
DataTwan
</span>
</div>
<nav className="hidden md:flex items-center gap-8 text-sm font-medium text-gray-600">
<a href="#upload" className="hover:text-indigo-600 transition-colors">Upload</a>
<a href="#features" className="hover:text-indigo-600 transition-colors">Features</a>
<a href="#faq" className="hover:text-indigo-600 transition-colors">FAQ</a>
<a
href="https://huggingface.co/TwanAPI/DataTwan"
target="_blank"
rel="noreferrer"
className="px-4 py-2 rounded-full bg-gray-900 text-white hover:bg-gray-800 transition-colors"
>
View Repository
</a>
</nav>
</div>
</header>
<main className="relative z-10 pt-24 pb-20">
{/* Hero Section */}
<section className="max-w-4xl mx-auto px-6 text-center mb-16">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-indigo-50 border border-indigo-100 text-indigo-600 text-xs font-semibold uppercase tracking-wide mb-6">
<span className="w-2 h-2 rounded-full bg-indigo-500 animate-pulse" />
V2.0 is Live: Faster Uploads
</div>
<h1 className="text-4xl md:text-6xl font-extrabold text-gray-900 tracking-tight mb-6">
The Ultimate <span className="text-transparent bg-clip-text bg-gradient-to-r from-indigo-600 to-violet-600">Hugging Face</span> Dataset Uploader
</h1>
<p className="text-lg md:text-xl text-gray-600 mb-8 max-w-2xl mx-auto leading-relaxed">
Drag, drop, and deploy your machine learning datasets securely to the cloud.
Optimized for large files, bulk processing, and ease of use.
</p>
</section>
{/* Upload Container */}
<section id="upload" className="max-w-3xl mx-auto px-6 mb-24">
<div className="bg-white/80 backdrop-blur-xl rounded-3xl shadow-2xl border border-white/20 ring-1 ring-black/5 p-2 md:p-8">
{/* File Uploader Component */}
<div className="mb-8">
<FileUploader
onFilesAdded={addFiles}
disabled={isUploading}
/>
</div>
{/* Queue List */}
<div className="mb-6">
<UploadList
files={files}
onRemove={removeFile}
onPathChange={updateFilePath}
/>
</div>
{/* Action Button */}
{files.length > 0 && (
<div className="flex justify-end">
<button
onClick={startUpload}
disabled={!hasPendingFiles || isUploading}
className={`
group relative overflow-hidden flex items-center gap-3 px-8 py-4 rounded-xl font-bold shadow-lg transition-all duration-300
${!hasPendingFiles || isUploading
? 'bg-gray-100 text-gray-400 cursor-not-allowed'
: 'bg-gradient-to-r from-indigo-600 to-violet-600 text-white hover:shadow-indigo-200 hover:shadow-xl hover:-translate-y-1 active:translate-y-0'}
`}
>
{isUploading ? (
<>
<div className="absolute inset-0 bg-white/20 animate-[shimmer_2s_infinite]" />
<Rocket className="w-5 h-5 animate-spin" />
<span>Processing Files...</span>
</>
) : (
<>
<Upload className="w-5 h-5 group-hover:scale-110 transition-transform" />
<span>Start Secure Upload</span>
</>
)}
</button>
</div>
)}
</div>
</section>
{/* SEO Content: Features */}
<section id="features" className="max-w-6xl mx-auto px-6 py-16">
<div className="text-center mb-12">
<h2 className="text-3xl font-bold text-gray-900">Why use DataTwan?</h2>
<p className="text-gray-500 mt-2">Built for Data Scientists and ML Engineers</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
<div className="p-6 bg-white rounded-2xl shadow-sm border border-gray-100 hover:shadow-md transition-shadow">
<div className="w-12 h-12 bg-blue-50 rounded-xl flex items-center justify-center mb-4 text-blue-600">
<ShieldCheck className="w-6 h-6" />
</div>
<h3 className="text-lg font-bold text-gray-900 mb-2">Secure API Proxy</h3>
<p className="text-gray-600 text-sm leading-relaxed">
Your files are routed through a secure backend proxy. Credentials are never exposed to the client-side browser, ensuring maximum security for your repositories.
</p>
</div>
<div className="p-6 bg-white rounded-2xl shadow-sm border border-gray-100 hover:shadow-md transition-shadow">
<div className="w-12 h-12 bg-purple-50 rounded-xl flex items-center justify-center mb-4 text-purple-600">
<Zap className="w-6 h-6" />
</div>
<h3 className="text-lg font-bold text-gray-900 mb-2">Lightning Fast</h3>
<p className="text-gray-600 text-sm leading-relaxed">
Optimized for speed. Our bulk upload algorithm handles multiple files simultaneously, reducing the time it takes to push your datasets to Hugging Face.
</p>
</div>
<div className="p-6 bg-white rounded-2xl shadow-sm border border-gray-100 hover:shadow-md transition-shadow">
<div className="w-12 h-12 bg-indigo-50 rounded-xl flex items-center justify-center mb-4 text-indigo-600">
<Terminal className="w-6 h-6" />
</div>
<h3 className="text-lg font-bold text-gray-900 mb-2">Auto-Formatting</h3>
<p className="text-gray-600 text-sm leading-relaxed">
Automatic filename sanitization. Timestamps are added, and special characters are converted to English slugs to ensure compatibility with Linux/Unix systems.
</p>
</div>
</div>
</section>
{/* SEO Content: FAQ */}
<section id="faq" className="max-w-4xl mx-auto px-6 py-16 bg-gray-50 rounded-3xl my-12">
<div className="text-center mb-10">
<h2 className="text-3xl font-bold text-gray-900">Frequently Asked Questions</h2>
</div>
<div className="space-y-4">
<details className="group bg-white rounded-xl shadow-sm border border-gray-200">
<summary className="flex justify-between items-center font-medium cursor-pointer list-none p-6 text-gray-900">
<span>Is this tool free to use?</span>
<span className="transition group-open:rotate-180">
<HelpCircle className="w-5 h-5 text-gray-400" />
</span>
</summary>
<div className="text-gray-600 px-6 pb-6 text-sm leading-relaxed border-t border-gray-100 pt-4">
Yes, DataTwan Uploader is 100% free. It utilizes the standard Hugging Face API to manage your datasets without any hidden costs.
</div>
</details>
<details className="group bg-white rounded-xl shadow-sm border border-gray-200">
<summary className="flex justify-between items-center font-medium cursor-pointer list-none p-6 text-gray-900">
<span>What types of files can I upload?</span>
<span className="transition group-open:rotate-180">
<HelpCircle className="w-5 h-5 text-gray-400" />
</span>
</summary>
<div className="text-gray-600 px-6 pb-6 text-sm leading-relaxed border-t border-gray-100 pt-4">
You can upload any file type supported by Hugging Face (JSON, CSV, Parquet, Images, Text, etc.). The tool automatically sanitizes filenames to prevent errors.
</div>
</details>
<details className="group bg-white rounded-xl shadow-sm border border-gray-200">
<summary className="flex justify-between items-center font-medium cursor-pointer list-none p-6 text-gray-900">
<span>Where are my files stored?</span>
<span className="transition group-open:rotate-180">
<HelpCircle className="w-5 h-5 text-gray-400" />
</span>
</summary>
<div className="text-gray-600 px-6 pb-6 text-sm leading-relaxed border-t border-gray-100 pt-4">
Files are uploaded directly to the <strong>TwanAPI/DataTwan</strong> repository on Hugging Face. We do not store your files on our servers; they are streamed directly to the destination.
</div>
</details>
</div>
</section>
</main>
{/* Footer */}
<footer className="bg-gray-900 text-gray-400 py-12 border-t border-gray-800">
<div className="max-w-6xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center gap-6">
<div className="flex items-center gap-2">
<Rocket className="w-5 h-5 text-indigo-500" />
<span className="text-white font-bold text-lg">DataTwan</span>
</div>
<div className="text-sm">
© {new Date().getFullYear()} DataTwan. All rights reserved.
</div>
<div className="flex gap-6">
<a href="#" className="hover:text-white transition-colors">Privacy Policy</a>
<a href="#" className="hover:text-white transition-colors">Terms of Service</a>
</div>
</div>
</footer>
</div>
);
} |