Implement creator studio and upload updates

This commit is contained in:
2026-04-04 10:12:02 +02:00
parent 1da7d3bf88
commit 0b216b7ecd
15107 changed files with 31206 additions and 626514 deletions

View File

@@ -1,7 +1,8 @@
import React, { useState, useCallback, useEffect } from 'react'
import React, { useState, useCallback, useEffect, useMemo } from 'react'
import { createRoot } from 'react-dom/client'
import axios from 'axios'
import ArtworkHero from '../components/artwork/ArtworkHero'
import ArtworkMediaStrip from '../components/artwork/ArtworkMediaStrip'
import ArtworkMeta from '../components/artwork/ArtworkMeta'
import ArtworkAwards from '../components/artwork/ArtworkAwards'
import ArtworkTags from '../components/artwork/ArtworkTags'
@@ -40,6 +41,7 @@ function ArtworkPage({ artwork: initialArtwork, related: initialRelated, present
const [related, setRelated] = useState(initialRelated)
const [comments, setComments] = useState(initialComments)
const [canonicalUrl, setCanonicalUrl] = useState(initialCanonical)
const [selectedMediaId, setSelectedMediaId] = useState('cover')
// Nav arrow state — populated by ArtworkNavigator once neighbors resolve
const [navState, setNavState] = useState({ hasPrev: false, hasNext: false, navigatePrev: null, navigateNext: null })
@@ -68,11 +70,48 @@ function ArtworkPage({ artwork: initialArtwork, related: initialRelated, present
setRelated([]) // cleared on navigation; user can scroll down for related
setComments([]) // cleared; per-page server data
setCanonicalUrl(data.canonical_url ?? window.location.href)
setSelectedMediaId('cover')
setViewerOpen(false) // close viewer when navigating away
}, [])
if (!artwork) return null
const mediaItems = useMemo(() => {
const coverItem = {
id: 'cover',
label: 'Cover art',
thumbUrl: presentSq?.url || presentMd?.url || presentLg?.url || artwork?.thumbs?.sq?.url || artwork?.thumbs?.md?.url || null,
mdUrl: presentMd?.url || artwork?.thumbs?.md?.url || null,
lgUrl: presentLg?.url || artwork?.thumbs?.lg?.url || null,
xlUrl: presentXl?.url || artwork?.thumbs?.xl?.url || null,
width: Number(artwork?.dimensions?.width || artwork?.width || 0) || null,
height: Number(artwork?.dimensions?.height || artwork?.height || 0) || null,
}
const screenshotItems = Array.isArray(artwork?.screenshots)
? artwork.screenshots.map((item, index) => ({
id: item.id || `shot-${index + 1}`,
label: item.label || `Screenshot ${index + 1}`,
thumbUrl: item.thumb_url || item.url || null,
mdUrl: item.url || item.thumb_url || null,
lgUrl: item.url || item.thumb_url || null,
xlUrl: item.url || item.thumb_url || null,
width: null,
height: null,
}))
: []
return [coverItem, ...screenshotItems].filter((item) => Boolean(item.thumbUrl || item.lgUrl || item.xlUrl))
}, [artwork, presentMd, presentLg, presentXl, presentSq])
const selectedMedia = mediaItems.find((item) => item.id === selectedMediaId) || mediaItems[0] || null
useEffect(() => {
if (!selectedMedia && mediaItems.length > 0) {
setSelectedMediaId(mediaItems[0].id)
}
}, [mediaItems, selectedMedia])
const initialAwards = artwork?.awards ?? null
return (
@@ -82,15 +121,24 @@ function ArtworkPage({ artwork: initialArtwork, related: initialRelated, present
<div id="artwork-hero-anchor" className="mx-auto w-full max-w-screen-2xl px-3 sm:px-6 lg:px-8">
<ArtworkHero
artwork={artwork}
presentMd={presentMd}
presentLg={presentLg}
presentXl={presentXl}
presentMd={selectedMedia?.mdUrl ? { url: selectedMedia.mdUrl } : presentMd}
presentLg={selectedMedia?.lgUrl ? { url: selectedMedia.lgUrl } : presentLg}
presentXl={selectedMedia?.xlUrl ? { url: selectedMedia.xlUrl } : presentXl}
mediaWidth={selectedMedia?.width ?? null}
mediaHeight={selectedMedia?.height ?? null}
mediaKey={selectedMedia?.id || 'cover'}
onOpenViewer={openViewer}
hasPrev={navState.hasPrev}
hasNext={navState.hasNext}
onPrev={navState.navigatePrev}
onNext={navState.navigateNext}
/>
<ArtworkMediaStrip
items={mediaItems}
selectedId={selectedMedia?.id || 'cover'}
onSelect={setSelectedMediaId}
/>
</div>
{/* ── Centered action bar with stat counts ────────────────────── */}
@@ -181,8 +229,8 @@ function ArtworkPage({ artwork: initialArtwork, related: initialRelated, present
isOpen={viewerOpen}
onClose={closeViewer}
artwork={artwork}
presentLg={presentLg}
presentXl={presentXl}
presentLg={selectedMedia?.lgUrl ? { url: selectedMedia.lgUrl } : presentLg}
presentXl={selectedMedia?.xlUrl ? { url: selectedMedia.xlUrl } : presentXl}
/>
</>
)