deckhearth/components/DashboardFeaturedCollection.js
varutasu b9e840ff3a
Realign dashboard home nav and wire honest ownership stats (#164)
Flatten authenticated sidebar IA, move admin to the profile menu, right-align TopSearchBar actions, and replace placeholder dashboard panels with data from /api/user/stats and /api/user-cards.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-15 16:47:59 -05:00

119 lines
4.2 KiB
JavaScript

import Link from 'next/link';
import { VOCAB } from '../lib/collection-vocabulary.js';
/**
* Recently added cards grid on /dashboard (formerly Featured Collection).
*/
export default function DashboardFeaturedCollection({ cards = [], loading = false }) {
const slots = Array.from({ length: 8 }, (_, idx) => cards[idx] || null);
return (
<section className="glass-panel rounded-2xl p-5 sm:p-6">
<header className="flex items-center justify-between mb-4">
<h2
className="text-lg font-bold flex items-center gap-2"
style={{ color: 'var(--text-primary)' }}
>
<span
className="inline-flex h-5 w-5 items-center justify-center rounded-md"
style={{
background:
'linear-gradient(135deg, rgb(255, 140, 30) 0%, rgb(216, 67, 21) 100%)',
}}
aria-hidden="true"
>
<svg className="h-3.5 w-3.5" viewBox="0 0 24 24" fill="rgb(255, 255, 255)">
<path d="M12 2c-.5 3.5-3.5 5.5-3.5 9 0 2.5 1.5 4 3.5 4s3.5-1.5 3.5-4c0-1.5-1-3-2-4 1 2 .5 4-.5 5-1 1-2-1-1-3 .5-1 1.5-3 0-7z" />
</svg>
</span>
Recently added
</h2>
<Link
href="/my-cards"
className="text-sm font-medium hover:underline focus:outline-none focus:ring-2 rounded-md px-1"
style={{
color: 'var(--accent-ember)',
'--tw-ring-color': 'var(--accent-ember)',
}}
>
View all in {VOCAB.MY_COLLECTION}
</Link>
</header>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
{slots.map((card, idx) => {
if (loading) {
return (
<div
key={`loading-${idx}`}
className="aspect-[2.5/3.5] rounded-lg motion-essential animate-pulse"
style={{ backgroundColor: 'var(--bg-tertiary)' }}
aria-hidden="true"
/>
);
}
if (!card) {
return (
<Link
key={`empty-${idx}`}
href="/cards"
className="aspect-[2.5/3.5] rounded-lg flex flex-col items-center justify-center text-center p-2 transition-colors focus:outline-none focus:ring-2"
style={{
border: '2px dashed var(--border)',
color: 'var(--text-secondary)',
'--tw-ring-color': 'var(--accent-ember)',
}}
>
<svg
className="h-6 w-6 mb-1"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
/>
</svg>
<span className="text-xs font-medium">Add card</span>
</Link>
);
}
const cardId = card.card_id ?? card.id;
return (
<Link
key={cardId ?? idx}
href={`/card/${cardId}`}
className="card-grid-outer-glow aspect-[2.5/3.5] rounded-lg overflow-hidden block transition-transform hover:scale-105 focus:outline-none focus:ring-2"
style={{
backgroundColor: 'var(--bg-tertiary)',
'--tw-ring-color': 'var(--accent-ember)',
}}
aria-label={card.name ?? 'Card'}
>
{card.image_url ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={card.image_url}
alt={card.name ?? ''}
className="w-full h-full object-cover"
loading="lazy"
/>
) : (
<div
className="w-full h-full flex items-center justify-center text-center p-2 text-xs"
style={{ color: 'var(--text-secondary)' }}
>
{card.name ?? 'Card'}
</div>
)}
</Link>
);
})}
</div>
</section>
);
}