categories v1 finished

This commit is contained in:
2026-03-17 20:13:33 +01:00
parent 7da0fd39f7
commit 1a62fcb81d
10 changed files with 807 additions and 63 deletions

View File

@@ -0,0 +1,86 @@
import React from 'react'
const CONTENT_TYPE_STYLES = {
wallpapers: {
badge: 'from-cyan-400/90 to-sky-500/90',
overlay: 'from-sky-950/10 via-slate-950/12 to-slate-950/92',
glow: 'group-hover:shadow-[0_0_28px_rgba(34,211,238,0.18)]',
},
skins: {
badge: 'from-orange-400/90 to-amber-500/90',
overlay: 'from-orange-950/10 via-slate-950/12 to-slate-950/92',
glow: 'group-hover:shadow-[0_0_28px_rgba(251,146,60,0.18)]',
},
photography: {
badge: 'from-emerald-400/90 to-teal-500/90',
overlay: 'from-emerald-950/10 via-slate-950/12 to-slate-950/92',
glow: 'group-hover:shadow-[0_0_28px_rgba(16,185,129,0.18)]',
},
other: {
badge: 'from-fuchsia-400/90 to-rose-500/90',
overlay: 'from-rose-950/10 via-slate-950/12 to-slate-950/92',
glow: 'group-hover:shadow-[0_0_28px_rgba(244,114,182,0.18)]',
},
default: {
badge: 'from-cyan-400/90 to-orange-400/90',
overlay: 'from-slate-900/10 via-slate-950/12 to-slate-950/92',
glow: 'group-hover:shadow-[0_0_28px_rgba(125,211,252,0.16)]',
},
}
const countFormatter = new Intl.NumberFormat()
function formatArtworkCount(count) {
return `${countFormatter.format(Number(count || 0))} artworks`
}
export default function CategoryCard({ category, index = 0 }) {
const contentTypeSlug = category?.content_type?.slug || 'default'
const contentTypeName = category?.content_type?.name || 'Category'
const styles = CONTENT_TYPE_STYLES[contentTypeSlug] || CONTENT_TYPE_STYLES.default
return (
<a
href={category?.url || '/categories'}
aria-label={`Browse ${category?.name || 'category'} category`}
className={[
'group relative block cursor-pointer rounded-2xl overflow-hidden',
'transition duration-300 ease-out hover:-translate-y-1 hover:scale-[1.01]',
styles.glow,
].join(' ')}
style={{ animationDelay: `${Math.min(index, 8) * 60}ms` }}
>
<div className="relative aspect-[4/5] overflow-hidden rounded-2xl border border-white/10 bg-slate-950/80">
<img
src={category?.cover_image}
alt={`Cover artwork for ${category?.name || 'category'}`}
loading="lazy"
className="h-full w-full object-cover transition duration-500 group-hover:scale-110"
/>
<div className={`absolute inset-0 bg-gradient-to-b ${styles.overlay} transition duration-500 group-hover:from-black/20 group-hover:to-black/90`} />
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top,rgba(255,255,255,0.22),transparent_42%)] opacity-0 transition duration-500 group-hover:opacity-100" />
<div className="absolute inset-x-0 top-0 flex items-center justify-between gap-3 p-4">
<span className={`inline-flex rounded-full bg-gradient-to-r ${styles.badge} px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-950 shadow-[0_10px_24px_rgba(0,0,0,0.24)]`}>
{contentTypeName}
</span>
<span className="rounded-full border border-white/15 bg-black/25 px-3 py-1 text-[11px] font-medium uppercase tracking-[0.18em] text-white/78 backdrop-blur">
{formatArtworkCount(category?.artwork_count)}
</span>
</div>
<div className="absolute inset-x-0 bottom-0 p-4 sm:p-5">
<div className="rounded-[22px] border border-white/10 bg-black/30 p-4 backdrop-blur-md transition duration-300 group-hover:border-white/20 group-hover:bg-black/42">
<div className="mb-3 h-px w-14 bg-gradient-to-r from-white/70 to-transparent transition duration-300 group-hover:w-24" />
<h3 className="text-lg font-semibold tracking-[-0.02em] text-white sm:text-xl">
{category?.name}
</h3>
<p className="mt-2 text-sm leading-6 text-white/65">
Explore {category?.name} across wallpapers, skins, themes, and digital art collections.
</p>
</div>
</div>
</div>
</a>
)
}