feat(artwork): sidebar layout, icon actions, original download URL fix

- ArtworkDownloadController: fix resolveDownloadUrl() to use correct CDN
  path: original/{h1}/{h2}/{hash}.{file_ext} (was wrong originals/h1/h2/h3/orig.webp)
  Wrap incrementDownloads() in try/catch so Redis failure can't break the response

- ArtworkPage: move ArtworkAuthor from left column to right sidebar
  Sidebar now stacks: Author → Actions → Awards (sticky top-24)
  Mobile block follows same order above main content

- ArtworkActions: replace four stacked text buttons with a compact 4-col icon grid
  Like (heart, rose when active), Save (star, amber when active),
  Share (network icon), Report (flag icon, red on hover)
  Download remains full-width orange CTA

- ArtworkAuthor: add icons to Profile (person) and Follow buttons
  Follow shows circle-check icon; Following state shows user-plus icon
This commit is contained in:
2026-02-27 11:31:32 +01:00
parent 4f9b43bbba
commit 09eadf9003
5 changed files with 190 additions and 70 deletions

View File

@@ -66,16 +66,33 @@ export default function ArtworkAuthor({ artwork, presentSq }) {
<div className="mt-4 grid grid-cols-2 gap-3">
<a
href={profileUrl}
className="inline-flex min-h-11 items-center justify-center rounded-lg border border-nova-600 px-3 py-2 text-sm text-white hover:bg-nova-800"
className="inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-nova-600 px-3 py-2 text-sm text-white hover:bg-nova-800 transition"
>
<svg className="h-4 w-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
</svg>
Profile
</a>
<button
type="button"
className={`inline-flex min-h-11 items-center justify-center rounded-lg px-3 py-2 text-sm font-semibold transition ${following ? 'border border-nova-600 text-white hover:bg-nova-800' : 'bg-accent text-deep hover:brightness-110'}`}
className={`inline-flex min-h-11 items-center justify-center gap-2 rounded-lg px-3 py-2 text-sm font-semibold transition ${following ? 'border border-nova-600 text-white hover:bg-nova-800' : 'bg-accent text-deep hover:brightness-110'}`}
onClick={onToggleFollow}
>
{following ? 'Following' : 'Follow'}
{following ? (
<>
<svg className="h-4 w-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M18 7.5v3m0 0v3m0-3h3m-3 0h-3m-2.25-4.125a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0ZM3 19.235v-.11a6.375 6.375 0 0 1 12.75 0v.109A12.318 12.318 0 0 1 9.374 21c-2.331 0-4.512-.645-6.374-1.766Z" />
</svg>
Following
</>
) : (
<>
<svg className="h-4 w-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
</svg>
Follow
</>
)}
</button>
</div>
</section>