Spaces:
Running
Running
Upload 9 files
Browse files- App.tsx +140 -0
- README.md +20 -10
- index.html +71 -0
- index.tsx +15 -0
- metadata.json +5 -0
- package.json +29 -0
- tsconfig.json +20 -0
- types.ts +31 -0
- vite.config.ts +6 -0
App.tsx
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React from 'react';
|
| 2 |
+
import { UploadStatus } from './types';
|
| 3 |
+
import { FileUploader } from './components/FileUploader';
|
| 4 |
+
import { UploadList } from './components/UploadList';
|
| 5 |
+
import { Upload, Rocket, Database, ShieldCheck, Zap, LayoutGrid } from 'lucide-react';
|
| 6 |
+
import { useFileUpload } from './hooks/useFileUpload';
|
| 7 |
+
|
| 8 |
+
export default function App() {
|
| 9 |
+
const {
|
| 10 |
+
files,
|
| 11 |
+
isUploading,
|
| 12 |
+
addFiles,
|
| 13 |
+
removeFile,
|
| 14 |
+
updateFilePath,
|
| 15 |
+
startUpload
|
| 16 |
+
} = useFileUpload();
|
| 17 |
+
|
| 18 |
+
const hasPendingFiles = files.some(f => f.status === UploadStatus.IDLE || f.status === UploadStatus.ERROR);
|
| 19 |
+
|
| 20 |
+
return (
|
| 21 |
+
<div className="min-h-screen bg-gray-50 flex flex-col font-sans">
|
| 22 |
+
{/* Header */}
|
| 23 |
+
<header className="bg-white border-b border-gray-200 sticky top-0 z-20 shadow-sm">
|
| 24 |
+
<div className="max-w-5xl mx-auto px-6 py-4 flex items-center justify-between">
|
| 25 |
+
<div className="flex items-center gap-3">
|
| 26 |
+
<div className="bg-gradient-to-br from-yellow-400 to-orange-500 p-2.5 rounded-xl shadow-md">
|
| 27 |
+
<Rocket className="w-6 h-6 text-white" />
|
| 28 |
+
</div>
|
| 29 |
+
<div>
|
| 30 |
+
<h1 className="text-xl font-bold text-gray-900 leading-tight tracking-tight">DataTwan Uploader</h1>
|
| 31 |
+
<p className="text-xs text-gray-500 font-medium flex items-center gap-1.5">
|
| 32 |
+
<span className="w-2 h-2 rounded-full bg-green-500 animate-pulse"></span>
|
| 33 |
+
Secure Connection Active
|
| 34 |
+
</p>
|
| 35 |
+
</div>
|
| 36 |
+
</div>
|
| 37 |
+
<div className="flex items-center gap-4">
|
| 38 |
+
<nav className="hidden md:flex items-center gap-6 text-sm font-medium text-gray-600">
|
| 39 |
+
<a href="#features" className="hover:text-yellow-600 transition-colors">Features</a>
|
| 40 |
+
<a href="#about" className="hover:text-yellow-600 transition-colors">About</a>
|
| 41 |
+
</nav>
|
| 42 |
+
</div>
|
| 43 |
+
</div>
|
| 44 |
+
</header>
|
| 45 |
+
|
| 46 |
+
{/* Main Content */}
|
| 47 |
+
<main className="flex-grow w-full max-w-3xl mx-auto px-6 py-12 space-y-8">
|
| 48 |
+
|
| 49 |
+
{/* Intro */}
|
| 50 |
+
<section className="text-center mb-10">
|
| 51 |
+
<h2 className="text-3xl font-extrabold text-gray-900 mb-4">
|
| 52 |
+
Upload Datasets to Hugging Face
|
| 53 |
+
</h2>
|
| 54 |
+
<p className="text-gray-600 text-lg leading-relaxed">
|
| 55 |
+
The fastest, most secure way to manage your machine learning datasets.
|
| 56 |
+
Bulk upload files directly to the <strong>DataTwan</strong> repository.
|
| 57 |
+
</p>
|
| 58 |
+
</section>
|
| 59 |
+
|
| 60 |
+
{/* Upload Area */}
|
| 61 |
+
<div className="bg-white p-1 rounded-2xl shadow-sm border border-gray-200">
|
| 62 |
+
<div className="p-8">
|
| 63 |
+
<h3 className="text-lg font-semibold text-gray-800 flex items-center gap-2 mb-6">
|
| 64 |
+
<Upload className="w-5 h-5 text-blue-500" />
|
| 65 |
+
Select Dataset Files
|
| 66 |
+
</h3>
|
| 67 |
+
<FileUploader
|
| 68 |
+
onFilesAdded={addFiles}
|
| 69 |
+
disabled={isUploading}
|
| 70 |
+
/>
|
| 71 |
+
</div>
|
| 72 |
+
</div>
|
| 73 |
+
|
| 74 |
+
{/* File Queue */}
|
| 75 |
+
<div id="queue">
|
| 76 |
+
<UploadList
|
| 77 |
+
files={files}
|
| 78 |
+
onRemove={removeFile}
|
| 79 |
+
onPathChange={updateFilePath}
|
| 80 |
+
/>
|
| 81 |
+
</div>
|
| 82 |
+
|
| 83 |
+
{/* Upload Action */}
|
| 84 |
+
{files.length > 0 && (
|
| 85 |
+
<div className="flex justify-end pt-2">
|
| 86 |
+
<button
|
| 87 |
+
onClick={startUpload}
|
| 88 |
+
disabled={!hasPendingFiles || isUploading}
|
| 89 |
+
className={`
|
| 90 |
+
flex items-center gap-2 px-10 py-4 rounded-xl font-bold shadow-lg transform transition-all text-lg
|
| 91 |
+
${!hasPendingFiles || isUploading
|
| 92 |
+
? 'bg-gray-100 text-gray-400 cursor-not-allowed border border-gray-200'
|
| 93 |
+
: 'bg-gradient-to-r from-yellow-400 to-orange-500 text-white hover:shadow-orange-200 hover:shadow-xl hover:-translate-y-0.5 active:translate-y-0'}
|
| 94 |
+
`}
|
| 95 |
+
>
|
| 96 |
+
{isUploading ? (
|
| 97 |
+
<>
|
| 98 |
+
<Rocket className="w-6 h-6 animate-pulse" />
|
| 99 |
+
Uploading...
|
| 100 |
+
</>
|
| 101 |
+
) : (
|
| 102 |
+
<>
|
| 103 |
+
<Upload className="w-6 h-6" />
|
| 104 |
+
Start Secure Upload
|
| 105 |
+
</>
|
| 106 |
+
)}
|
| 107 |
+
</button>
|
| 108 |
+
</div>
|
| 109 |
+
)}
|
| 110 |
+
</main>
|
| 111 |
+
|
| 112 |
+
{/* SEO Footer */}
|
| 113 |
+
<footer className="bg-white border-t border-gray-200 mt-12 py-12">
|
| 114 |
+
<div className="max-w-5xl mx-auto px-6 grid md:grid-cols-2 gap-12">
|
| 115 |
+
<article id="about" className="space-y-4">
|
| 116 |
+
<h3 className="text-lg font-bold text-gray-900 flex items-center gap-2">
|
| 117 |
+
<Database className="w-5 h-5 text-yellow-500" />
|
| 118 |
+
About DataTwan Uploader
|
| 119 |
+
</h3>
|
| 120 |
+
<p className="text-gray-600 text-sm leading-relaxed">
|
| 121 |
+
DataTwan Uploader is a premier <strong>Hugging Face Dataset Management Tool</strong>.
|
| 122 |
+
We streamline pushing large datasets to the cloud with enterprise-grade reliability.
|
| 123 |
+
</p>
|
| 124 |
+
</article>
|
| 125 |
+
<article id="features" className="space-y-4">
|
| 126 |
+
<h3 className="text-lg font-bold text-gray-900 flex items-center gap-2">
|
| 127 |
+
<Zap className="w-5 h-5 text-yellow-500" />
|
| 128 |
+
Features
|
| 129 |
+
</h3>
|
| 130 |
+
<ul className="space-y-3 text-sm text-gray-600">
|
| 131 |
+
<li className="flex gap-2 items-center"><ShieldCheck className="w-4 h-4 text-green-500"/> Secure Proxy Upload Technology</li>
|
| 132 |
+
<li className="flex gap-2 items-center"><LayoutGrid className="w-4 h-4 text-blue-500"/> Bulk File Processing</li>
|
| 133 |
+
<li className="flex gap-2 items-center"><Rocket className="w-4 h-4 text-orange-500"/> Optimized for High Performance</li>
|
| 134 |
+
</ul>
|
| 135 |
+
</article>
|
| 136 |
+
</div>
|
| 137 |
+
</footer>
|
| 138 |
+
</div>
|
| 139 |
+
);
|
| 140 |
+
}
|
README.md
CHANGED
|
@@ -1,10 +1,20 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<div align="center">
|
| 2 |
+
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
|
| 3 |
+
</div>
|
| 4 |
+
|
| 5 |
+
# Run and deploy your AI Studio app
|
| 6 |
+
|
| 7 |
+
This contains everything you need to run your app locally.
|
| 8 |
+
|
| 9 |
+
View your app in AI Studio: https://ai.studio/apps/drive/1ze_cSnjsTlEMs0ohdHMtGIuvNxtA4x4w
|
| 10 |
+
|
| 11 |
+
## Run Locally
|
| 12 |
+
|
| 13 |
+
**Prerequisites:** Node.js
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
1. Install dependencies:
|
| 17 |
+
`npm install`
|
| 18 |
+
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
|
| 19 |
+
3. Run the app:
|
| 20 |
+
`npm run dev`
|
index.html
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
+
|
| 7 |
+
<!-- Primary SEO Meta Tags -->
|
| 8 |
+
<title>DataTwan - Free Hugging Face Dataset Uploader & Manager</title>
|
| 9 |
+
<meta name="description" content="Upload datasets efficiently to Hugging Face with DataTwan. A fast, secure, and free tool for managing machine learning datasets. Support for bulk uploads directly to DataTwan repositories." />
|
| 10 |
+
<meta name="keywords" content="Hugging Face uploader, dataset upload, DataTwan, machine learning datasets, AI data management, bulk file upload, Hugging Face API" />
|
| 11 |
+
<meta name="author" content="DataTwan" />
|
| 12 |
+
<meta name="robots" content="index, follow" />
|
| 13 |
+
|
| 14 |
+
<!-- Open Graph / Facebook -->
|
| 15 |
+
<meta property="og:type" content="website" />
|
| 16 |
+
<meta property="og:url" content="https://datatwan-uploader.com/" />
|
| 17 |
+
<meta property="og:title" content="DataTwan - Hugging Face Dataset Uploader" />
|
| 18 |
+
<meta property="og:description" content="The easiest way to upload and manage datasets on Hugging Face. Secure, fast, and optimized for ML workflows." />
|
| 19 |
+
<meta property="og:site_name" content="DataTwan Uploader" />
|
| 20 |
+
|
| 21 |
+
<!-- Twitter -->
|
| 22 |
+
<meta property="twitter:card" content="summary_large_image" />
|
| 23 |
+
<meta property="twitter:title" content="DataTwan - Hugging Face Dataset Uploader" />
|
| 24 |
+
<meta property="twitter:description" content="Upload datasets efficiently to Hugging Face with DataTwan. Secure and fast bulk uploading." />
|
| 25 |
+
|
| 26 |
+
<!-- Structured Data for Google (JSON-LD) -->
|
| 27 |
+
<script type="application/ld+json">
|
| 28 |
+
{
|
| 29 |
+
"@context": "https://schema.org",
|
| 30 |
+
"@type": "WebApplication",
|
| 31 |
+
"name": "DataTwan Uploader",
|
| 32 |
+
"url": "https://datatwan-uploader.com",
|
| 33 |
+
"description": "A professional tool to upload files directly to Hugging Face repositories.",
|
| 34 |
+
"applicationCategory": "DeveloperApplication",
|
| 35 |
+
"operatingSystem": "Any browser",
|
| 36 |
+
"offers": {
|
| 37 |
+
"@type": "Offer",
|
| 38 |
+
"price": "0",
|
| 39 |
+
"priceCurrency": "USD"
|
| 40 |
+
},
|
| 41 |
+
"featureList": "Bulk upload, Hugging Face Integration, Dataset Management"
|
| 42 |
+
}
|
| 43 |
+
</script>
|
| 44 |
+
|
| 45 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 46 |
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
| 47 |
+
<style>
|
| 48 |
+
body {
|
| 49 |
+
font-family: 'Inter', sans-serif;
|
| 50 |
+
}
|
| 51 |
+
</style>
|
| 52 |
+
<script type="importmap">
|
| 53 |
+
{
|
| 54 |
+
"imports": {
|
| 55 |
+
"react/": "https://aistudiocdn.com/react@^19.2.0/",
|
| 56 |
+
"react": "https://aistudiocdn.com/react@^19.2.0",
|
| 57 |
+
"react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
|
| 58 |
+
"lucide-react": "https://aistudiocdn.com/lucide-react@^0.555.0",
|
| 59 |
+
"vite": "https://aistudiocdn.com/vite@^7.2.4",
|
| 60 |
+
"@vitejs/plugin-react": "https://aistudiocdn.com/@vitejs/plugin-react@^5.1.1",
|
| 61 |
+
"@huggingface/hub": "https://aistudiocdn.com/@huggingface/hub@^2.7.1"
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
</script>
|
| 65 |
+
<link rel="stylesheet" href="/index.css">
|
| 66 |
+
</head>
|
| 67 |
+
<body class="bg-gray-50 text-gray-900 antialiased flex flex-col min-h-screen">
|
| 68 |
+
<div id="root" class="flex-grow"></div>
|
| 69 |
+
<script type="module" src="/index.tsx"></script>
|
| 70 |
+
</body>
|
| 71 |
+
</html>
|
index.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React from 'react';
|
| 2 |
+
import ReactDOM from 'react-dom/client';
|
| 3 |
+
import App from './App';
|
| 4 |
+
|
| 5 |
+
const rootElement = document.getElementById('root');
|
| 6 |
+
if (!rootElement) {
|
| 7 |
+
throw new Error("Could not find root element to mount to");
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
const root = ReactDOM.createRoot(rootElement);
|
| 11 |
+
root.render(
|
| 12 |
+
<React.StrictMode>
|
| 13 |
+
<App />
|
| 14 |
+
</React.StrictMode>
|
| 15 |
+
);
|
metadata.json
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "HF Hub Uploader",
|
| 3 |
+
"description": "A professional tool to upload files directly to Hugging Face repositories using the @huggingface/hub library.",
|
| 4 |
+
"requestFramePermissions": []
|
| 5 |
+
}
|
package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "datatwan-uploader",
|
| 3 |
+
"private": true,
|
| 4 |
+
"version": "1.0.0",
|
| 5 |
+
"type": "module",
|
| 6 |
+
"scripts": {
|
| 7 |
+
"dev": "vite",
|
| 8 |
+
"build": "tsc && vite build",
|
| 9 |
+
"preview": "vite preview"
|
| 10 |
+
},
|
| 11 |
+
"dependencies": {
|
| 12 |
+
"react": "^18.2.0",
|
| 13 |
+
"react-dom": "^18.2.0",
|
| 14 |
+
"lucide-react": "^0.344.0",
|
| 15 |
+
"@huggingface/hub": "^0.15.1",
|
| 16 |
+
"clsx": "^2.1.0",
|
| 17 |
+
"tailwind-merge": "^2.2.1"
|
| 18 |
+
},
|
| 19 |
+
"devDependencies": {
|
| 20 |
+
"@types/react": "^18.2.64",
|
| 21 |
+
"@types/react-dom": "^18.2.21",
|
| 22 |
+
"@vitejs/plugin-react": "^4.2.1",
|
| 23 |
+
"autoprefixer": "^10.4.18",
|
| 24 |
+
"postcss": "^8.4.35",
|
| 25 |
+
"tailwindcss": "^3.4.1",
|
| 26 |
+
"typescript": "^5.2.2",
|
| 27 |
+
"vite": "^5.1.4"
|
| 28 |
+
}
|
| 29 |
+
}
|
tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"compilerOptions": {
|
| 3 |
+
"target": "ES2020",
|
| 4 |
+
"useDefineForClassFields": true,
|
| 5 |
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
| 6 |
+
"module": "ESNext",
|
| 7 |
+
"skipLibCheck": true,
|
| 8 |
+
"moduleResolution": "bundler",
|
| 9 |
+
"allowImportingTsExtensions": true,
|
| 10 |
+
"resolveJsonModule": true,
|
| 11 |
+
"isolatedModules": true,
|
| 12 |
+
"noEmit": true,
|
| 13 |
+
"jsx": "react-jsx",
|
| 14 |
+
"strict": true,
|
| 15 |
+
"noUnusedLocals": false,
|
| 16 |
+
"noUnusedParameters": false,
|
| 17 |
+
"noFallthroughCasesInSwitch": true
|
| 18 |
+
},
|
| 19 |
+
"include": ["**/*.ts", "**/*.tsx"]
|
| 20 |
+
}
|
types.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export type RepoType = 'model' | 'dataset' | 'space';
|
| 2 |
+
|
| 3 |
+
export interface HFConfig {
|
| 4 |
+
token: string;
|
| 5 |
+
repo: string;
|
| 6 |
+
repoType: RepoType;
|
| 7 |
+
}
|
| 8 |
+
|
| 9 |
+
export enum UploadStatus {
|
| 10 |
+
IDLE = 'IDLE',
|
| 11 |
+
UPLOADING = 'UPLOADING',
|
| 12 |
+
SUCCESS = 'SUCCESS',
|
| 13 |
+
ERROR = 'ERROR',
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
export interface FileItem {
|
| 17 |
+
id: string;
|
| 18 |
+
file: File;
|
| 19 |
+
status: UploadStatus;
|
| 20 |
+
path: string; // Destination path in repo
|
| 21 |
+
error?: string;
|
| 22 |
+
url?: string; // URL to the file after upload
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
export interface RemoteFile {
|
| 26 |
+
path: string;
|
| 27 |
+
size: number;
|
| 28 |
+
url: string;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
export type UploadCallback = (id: string, status: UploadStatus, error?: string, url?: string) => void;
|
vite.config.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { defineConfig } from 'vite';
|
| 2 |
+
import react from '@vitejs/plugin-react';
|
| 3 |
+
|
| 4 |
+
export default defineConfig({
|
| 5 |
+
plugins: [react()],
|
| 6 |
+
});
|