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">
                &copy; {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>
  );
}