Studio: make grid checkbox rectangular and commit table changes
This commit is contained in:
141
resources/js/Pages/Studio/StudioDashboard.jsx
Normal file
141
resources/js/Pages/Studio/StudioDashboard.jsx
Normal file
@@ -0,0 +1,141 @@
|
||||
import React from 'react'
|
||||
import { usePage, Link } from '@inertiajs/react'
|
||||
import StudioLayout from '../../Layouts/StudioLayout'
|
||||
|
||||
const kpiConfig = [
|
||||
{ key: 'total_artworks', label: 'Total Artworks', icon: 'fa-images', color: 'text-blue-400', link: '/studio/artworks' },
|
||||
{ key: 'views_30d', label: 'Views (30d)', icon: 'fa-eye', color: 'text-emerald-400', link: null },
|
||||
{ key: 'favourites_30d', label: 'Favourites (30d)', icon: 'fa-heart', color: 'text-pink-400', link: null },
|
||||
{ key: 'shares_30d', label: 'Shares (30d)', icon: 'fa-share-nodes', color: 'text-amber-400', link: null },
|
||||
{ key: 'followers', label: 'Followers', icon: 'fa-user-group', color: 'text-purple-400', link: null },
|
||||
]
|
||||
|
||||
function KpiCard({ config, value }) {
|
||||
const content = (
|
||||
<div className="bg-nova-900/60 border border-white/10 rounded-2xl p-5 hover:border-white/20 hover:shadow-lg hover:shadow-accent/5 transition-all duration-300 cursor-pointer group">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<div className={`w-10 h-10 rounded-xl bg-white/5 flex items-center justify-center ${config.color} group-hover:scale-110 transition-transform`}>
|
||||
<i className={`fa-solid ${config.icon}`} />
|
||||
</div>
|
||||
<span className="text-xs font-medium text-slate-400 uppercase tracking-wider">{config.label}</span>
|
||||
</div>
|
||||
<p className="text-3xl font-bold text-white tabular-nums">
|
||||
{typeof value === 'number' ? value.toLocaleString() : value}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
|
||||
if (config.link) {
|
||||
return <Link href={config.link}>{content}</Link>
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
function TopPerformerCard({ artwork }) {
|
||||
return (
|
||||
<div className="bg-nova-900/60 border border-white/10 rounded-2xl p-4 hover:border-white/20 hover:shadow-lg hover:shadow-accent/5 transition-all duration-300 group">
|
||||
<div className="flex items-start gap-3">
|
||||
{artwork.thumb_url && (
|
||||
<img
|
||||
src={artwork.thumb_url}
|
||||
alt={artwork.title}
|
||||
className="w-16 h-16 rounded-xl object-cover bg-nova-800 flex-shrink-0 group-hover:scale-105 transition-transform"
|
||||
loading="lazy"
|
||||
/>
|
||||
)}
|
||||
<div className="min-w-0 flex-1">
|
||||
<h4 className="text-sm font-semibold text-white truncate" title={artwork.title}>
|
||||
{artwork.title}
|
||||
</h4>
|
||||
<div className="flex flex-wrap items-center gap-3 mt-1.5">
|
||||
<span className="text-xs text-slate-400">
|
||||
❤️ {artwork.favourites?.toLocaleString()}
|
||||
</span>
|
||||
<span className="text-xs text-slate-400">
|
||||
🔗 {artwork.shares?.toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
{artwork.heat_score > 5 && (
|
||||
<span className="inline-flex items-center gap-1 mt-2 px-2 py-0.5 rounded-md text-[10px] font-medium bg-orange-500/20 text-orange-400 border border-orange-500/30">
|
||||
<i className="fa-solid fa-fire" /> Rising
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function RecentComment({ comment }) {
|
||||
return (
|
||||
<div className="flex items-start gap-3 py-3 border-b border-white/5 last:border-0">
|
||||
<div className="w-8 h-8 rounded-full bg-white/10 flex items-center justify-center text-xs text-slate-400 flex-shrink-0">
|
||||
<i className="fa-solid fa-comment" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-sm text-white">
|
||||
<span className="font-medium text-accent">{comment.author_name}</span>
|
||||
{' '}on{' '}
|
||||
<span className="text-slate-300">{comment.artwork_title}</span>
|
||||
</p>
|
||||
<p className="text-xs text-slate-500 mt-0.5 line-clamp-2">{comment.body}</p>
|
||||
<p className="text-[10px] text-slate-600 mt-1">
|
||||
{new Date(comment.created_at).toLocaleDateString()}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function StudioDashboard() {
|
||||
const { props } = usePage()
|
||||
const { kpis, topPerformers, recentComments } = props
|
||||
|
||||
return (
|
||||
<StudioLayout title="Studio Overview">
|
||||
{/* KPI Cards */}
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-4 mb-8">
|
||||
{kpiConfig.map((config) => (
|
||||
<KpiCard key={config.key} config={config} value={kpis?.[config.key] ?? 0} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Top Performers */}
|
||||
<div className="mb-8">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h2 className="text-lg font-bold text-white">Your Top Performers</h2>
|
||||
<span className="text-xs text-slate-500">Last 7 days</span>
|
||||
</div>
|
||||
{topPerformers?.length > 0 ? (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{topPerformers.map((art) => (
|
||||
<TopPerformerCard key={art.id} artwork={art} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="bg-nova-900/40 border border-white/10 rounded-2xl p-8 text-center">
|
||||
<p className="text-slate-500 text-sm">No artworks yet. Upload your first creation!</p>
|
||||
<Link
|
||||
href="/upload"
|
||||
className="inline-flex items-center gap-2 mt-4 px-5 py-2.5 rounded-xl bg-accent hover:bg-accent/90 text-white text-sm font-semibold transition-all shadow-lg shadow-accent/25"
|
||||
>
|
||||
<i className="fa-solid fa-cloud-arrow-up" /> Upload
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Recent Comments */}
|
||||
<div>
|
||||
<h2 className="text-lg font-bold text-white mb-4">Recent Comments</h2>
|
||||
<div className="bg-nova-900/40 border border-white/10 rounded-2xl p-4">
|
||||
{recentComments?.length > 0 ? (
|
||||
recentComments.map((c) => <RecentComment key={c.id} comment={c} />)
|
||||
) : (
|
||||
<p className="text-slate-500 text-sm text-center py-4">No comments yet</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</StudioLayout>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user