Add upload capability to AssetLibrary modal
- Added Upload button to asset selection modal - Users can now upload files directly when selecting images - Works for Veo first/last frames, reference images, etc. - Auto-selects uploaded file in single-select mode - Shows upload progress indicator 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4b096f45cb
commit
321dec4029
1 changed files with 63 additions and 7 deletions
|
|
@ -1,8 +1,9 @@
|
|||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import api from '@/lib/api';
|
||||
import api, { assetsApi } from '@/lib/api';
|
||||
import { clsx } from 'clsx';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import {
|
||||
X,
|
||||
Search,
|
||||
|
|
@ -13,7 +14,9 @@ import {
|
|||
Check,
|
||||
Loader2,
|
||||
FolderOpen,
|
||||
Upload,
|
||||
} from 'lucide-react';
|
||||
import FileUpload from './FileUpload';
|
||||
|
||||
interface Asset {
|
||||
id: string;
|
||||
|
|
@ -59,6 +62,8 @@ export default function AssetLibrary({
|
|||
const [page, setPage] = useState(1);
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const [selectedAssets, setSelectedAssets] = useState<Set<string>>(new Set());
|
||||
const [showUpload, setShowUpload] = useState(false);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
|
|
@ -108,6 +113,25 @@ export default function AssetLibrary({
|
|||
onClose();
|
||||
};
|
||||
|
||||
const handleUpload = async (file: File) => {
|
||||
setUploading(true);
|
||||
try {
|
||||
const response = await assetsApi.upload(file);
|
||||
toast.success('File uploaded!');
|
||||
loadAssets(); // Reload to show new file
|
||||
// Auto-select the new file
|
||||
if (!multiple) {
|
||||
onSelect(response.data);
|
||||
setShowUpload(false);
|
||||
onClose();
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error('Failed to upload file');
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
|
|
@ -119,12 +143,21 @@ export default function AssetLibrary({
|
|||
<FolderOpen className="w-5 h-5 text-forge-yellow" />
|
||||
<h2 className="text-lg font-semibold text-white">{title}</h2>
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-2 text-gray-400 hover:text-white transition-colors"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => setShowUpload(!showUpload)}
|
||||
className="px-3 py-2 bg-forge-yellow/10 text-forge-yellow rounded-lg hover:bg-forge-yellow/20 transition-colors flex items-center gap-2 text-sm"
|
||||
>
|
||||
<Upload className="w-4 h-4" />
|
||||
Upload New
|
||||
</button>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-2 text-gray-400 hover:text-white transition-colors"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Filters */}
|
||||
|
|
@ -184,6 +217,29 @@ export default function AssetLibrary({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* Upload Section */}
|
||||
{showUpload && (
|
||||
<div className="p-4 border-b border-gray-800">
|
||||
<FileUpload
|
||||
onUpload={handleUpload}
|
||||
accept={
|
||||
fileTypes.includes('image')
|
||||
? { 'image/*': ['.png', '.jpg', '.jpeg', '.webp', '.gif'] }
|
||||
: fileTypes.includes('video')
|
||||
? { 'video/*': ['.mp4', '.webm', '.mov'] }
|
||||
: { 'audio/*': ['.mp3', '.wav', '.ogg'] }
|
||||
}
|
||||
label="Drop file here or click to upload"
|
||||
/>
|
||||
{uploading && (
|
||||
<div className="mt-2 flex items-center gap-2 text-forge-yellow text-sm">
|
||||
<Loader2 className="w-4 h-4 animate-spin" />
|
||||
Uploading...
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Asset Grid */}
|
||||
<div className="flex-1 overflow-y-auto p-4">
|
||||
{loading ? (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue