refactor: unify artwork card rendering

This commit is contained in:
2026-03-17 14:49:20 +01:00
parent 78151aabfe
commit 980a15f66e
30 changed files with 1145 additions and 656 deletions

View File

@@ -1,71 +0,0 @@
import React from 'react'
/**
* Compact artwork card for embedding inside a PostCard.
* Shows thumbnail, title and original author with attribution.
*/
export default function EmbeddedArtworkCard({ artwork }) {
if (!artwork) return null
const artUrl = `/art/${artwork.id}/${slugify(artwork.title)}`
const authorUrl = `/@${artwork.author.username}`
const handleCardClick = (e) => {
// Don't navigate when clicking the author link
if (e.defaultPrevented) return
window.location.href = artUrl
}
const handleKeyDown = (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
window.location.href = artUrl
}
}
return (
// Outer element is a div to avoid <a> inside <a> — navigation handled via onClick
<div
role="link"
tabIndex={0}
aria-label={artwork.title}
onClick={handleCardClick}
onKeyDown={handleKeyDown}
className="group flex gap-3 rounded-xl border border-white/[0.08] bg-black/30 p-3 hover:border-sky-500/30 transition-colors cursor-pointer"
>
{/* Thumbnail */}
<div className="w-20 h-16 rounded-lg overflow-hidden shrink-0 bg-white/5">
{artwork.thumb_url ? (
<img
src={artwork.thumb_url}
alt={artwork.title}
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
loading="lazy"
/>
) : (
<div className="w-full h-full flex items-center justify-center text-slate-600">
<i className="fa-solid fa-image" />
</div>
)}
</div>
{/* Meta */}
<div className="flex flex-col justify-center min-w-0">
<p className="text-sm font-medium text-white/90 truncate">{artwork.title}</p>
<a
href={authorUrl}
onClick={(e) => e.stopPropagation()}
className="text-xs text-slate-400 hover:text-sky-400 transition-colors mt-0.5 truncate"
>
<i className="fa-solid fa-user-circle fa-fw mr-1 opacity-60" />
by {artwork.author.name || `@${artwork.author.username}`}
</a>
<span className="text-[10px] text-slate-600 mt-1 uppercase tracking-wider">Artwork</span>
</div>
</div>
)
}
function slugify(str) {
return (str || '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')
}

View File

@@ -1,7 +1,7 @@
import React, { useState } from 'react'
import PostActions from './PostActions'
import PostComments from './PostComments'
import EmbeddedArtworkCard from './EmbeddedArtworkCard'
import ArtworkCard from '../artwork/ArtworkCard'
import VisibilityPill from './VisibilityPill'
import LinkPreviewCard from './LinkPreviewCard'
@@ -329,7 +329,7 @@ export default function PostCard({ post, isLoggedIn = false, viewerUsername = nu
{/* Artwork share embed */}
{postData.type === 'artwork_share' && postData.artwork && (
<EmbeddedArtworkCard artwork={postData.artwork} />
<ArtworkCard artwork={postData.artwork} variant="embed" showActions={false} showStats={false} />
)}
</div>