llm-file-proxy / jorki /src /components /FileCards.jsx
josephrw's picture
Upload folder using huggingface_hub
55153d0 verified
Raw
History Blame Contribute Delete
5.4 kB
import { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import {
FileVideo, FileArchive, FileText, FileImage, Database,
Copy, Share2, Eye, BarChart3, Link2, Trash2, Download,
} from 'lucide-react'
import { mockFiles } from '../data/mockData.js'
const iconMap = {
video: FileVideo,
archive: FileArchive,
file: FileText,
image: FileImage,
database: Database,
}
const statusColors = {
Shared: 'text-accent',
Processing: 'text-warning',
Ready: 'text-success',
Downloaded: 'text-secondary',
}
export default function FileCards() {
const [files] = useState(mockFiles)
const [selected, setSelected] = useState(null)
const [copied, setCopied] = useState(false)
const copyUrl = (file) => {
const url = `https://jorki.ai/f/${Math.random().toString(36).slice(2, 8).toUpperCase()}`
navigator.clipboard?.writeText(url)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<div className="p-6 h-full overflow-y-auto thin-scrollbar">
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
{files.map((file, i) => {
const Icon = iconMap[file.icon] || FileText
return (
<motion.div
key={file.name}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, delay: i * 0.05 }}
whileHover={{ y: -4, scale: 1.01 }}
onHoverStart={() => setSelected(file.name)}
onHoverEnd={() => setSelected(null)}
className="glass rounded-2xl p-5 group cursor-pointer"
>
{/* Header */}
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl glass-orange flex items-center justify-center">
<Icon className="w-5 h-5 text-primary" />
</div>
<div>
<div className="text-sm font-medium">{file.name}</div>
<div className="text-[10px] text-secondary">{file.size}</div>
</div>
</div>
<span className={`text-[10px] font-mono ${statusColors[file.status]}`}>
{file.status}
</span>
</div>
{/* Stats */}
<div className="flex items-center gap-4 mb-4 text-[10px] text-secondary">
<span className="flex items-center gap-1">
<Download className="w-3 h-3" />
{file.downloads} downloads
</span>
<span className="flex items-center gap-1">
<Link2 className="w-3 h-3" />
{file.status === 'Shared' ? 'Public' : 'Private'}
</span>
</div>
{/* Actions */}
<AnimatePresence>
{selected === file.name && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
className="flex items-center gap-2"
>
<button
onClick={() => copyUrl(file)}
className="flex-1 flex items-center justify-center gap-1.5 px-3 py-2 rounded-xl glass hover:glass-orange text-xs transition-all"
>
{copied ? <span className="text-success">Copied!</span> : (
<><Copy className="w-3 h-3" /> Copy URL</>
)}
</button>
<button className="flex items-center justify-center w-9 h-9 rounded-xl glass hover:glass-orange transition-all">
<Share2 className="w-3.5 h-3.5" />
</button>
<button className="flex items-center justify-center w-9 h-9 rounded-xl glass hover:glass-orange transition-all">
<Eye className="w-3.5 h-3.5" />
</button>
<button className="flex items-center justify-center w-9 h-9 rounded-xl glass hover:glass-orange transition-all">
<BarChart3 className="w-3.5 h-3.5" />
</button>
</motion.div>
)}
</AnimatePresence>
{selected !== file.name && (
<div className="flex items-center justify-between text-[10px] text-secondary/50">
<span>Hover for actions</span>
<span className="font-mono">jorki.ai/f/···</span>
</div>
)}
</motion.div>
)
})}
</div>
{/* Upload zone */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.3 }}
className="mt-4 glass rounded-2xl p-8 flex flex-col items-center justify-center border-2 border-dashed border-white/10 hover:border-primary/30 transition-all cursor-pointer"
>
<FileArchive className="w-8 h-8 text-secondary/40 mb-2" />
<span className="text-sm text-secondary">Drop files here to index and share</span>
</motion.div>
</div>
)
}