feat: increase gallery grid from 4 to 5 columns per row on desktopfeat: increase gallery grid from 4 to 5 columns per row on desktop

This commit is contained in:
2026-02-25 19:11:23 +01:00
parent 5c97488e80
commit 0032aec02f
131 changed files with 15674 additions and 597 deletions

View File

@@ -1,43 +1,118 @@
import React from 'react'
import React, { useState, useCallback } from 'react'
import { createRoot } from 'react-dom/client'
import ArtworkHero from '../components/artwork/ArtworkHero'
import ArtworkMeta from '../components/artwork/ArtworkMeta'
import ArtworkActions from '../components/artwork/ArtworkActions'
import ArtworkAwards from '../components/artwork/ArtworkAwards'
import ArtworkStats from '../components/artwork/ArtworkStats'
import ArtworkTags from '../components/artwork/ArtworkTags'
import ArtworkAuthor from '../components/artwork/ArtworkAuthor'
import ArtworkRelated from '../components/artwork/ArtworkRelated'
import ArtworkDescription from '../components/artwork/ArtworkDescription'
import ArtworkComments from '../components/artwork/ArtworkComments'
import ArtworkNavigator from '../components/viewer/ArtworkNavigator'
import ArtworkViewer from '../components/viewer/ArtworkViewer'
function ArtworkPage({ artwork: initialArtwork, related: initialRelated, presentMd: initialMd, presentLg: initialLg, presentXl: initialXl, presentSq: initialSq, canonicalUrl: initialCanonical, isAuthenticated = false, comments: initialComments = [] }) {
const [viewerOpen, setViewerOpen] = useState(false)
const openViewer = useCallback(() => setViewerOpen(true), [])
const closeViewer = useCallback(() => setViewerOpen(false), [])
// Navigable state — updated on client-side navigation
const [artwork, setArtwork] = useState(initialArtwork)
const [presentMd, setPresentMd] = useState(initialMd)
const [presentLg, setPresentLg] = useState(initialLg)
const [presentXl, setPresentXl] = useState(initialXl)
const [presentSq, setPresentSq] = useState(initialSq)
const [related, setRelated] = useState(initialRelated)
const [comments, setComments] = useState(initialComments)
const [canonicalUrl, setCanonicalUrl] = useState(initialCanonical)
// Nav arrow state — populated by ArtworkNavigator once neighbors resolve
const [navState, setNavState] = useState({ hasPrev: false, hasNext: false, navigatePrev: null, navigateNext: null })
/**
* Called by ArtworkNavigator after a successful no-reload navigation.
* data = ArtworkResource JSON from /api/artworks/{id}/page
*/
const handleNavigate = useCallback((data) => {
setArtwork(data)
setPresentMd(data.thumbs?.md ?? null)
setPresentLg(data.thumbs?.lg ?? null)
setPresentXl(data.thumbs?.xl ?? null)
setPresentSq(data.thumbs?.sq ?? null)
setRelated([]) // cleared on navigation; user can scroll down for related
setComments([]) // cleared; per-page server data
setCanonicalUrl(data.canonical_url ?? window.location.href)
setViewerOpen(false) // close viewer when navigating away
}, [])
function ArtworkPage({ artwork, related, presentMd, presentLg, presentXl, presentSq, canonicalUrl }) {
if (!artwork) return null
const initialAwards = artwork?.awards ?? null
return (
<main className="mx-auto w-full max-w-screen-xl px-4 pb-24 pt-10 sm:px-6 lg:px-8 lg:pb-12">
<ArtworkHero artwork={artwork} presentMd={presentMd} presentLg={presentLg} presentXl={presentXl} />
<>
<main className="mx-auto w-full max-w-screen-xl px-4 pb-24 pt-10 sm:px-6 lg:px-8 lg:pb-12">
<ArtworkHero
artwork={artwork}
presentMd={presentMd}
presentLg={presentLg}
presentXl={presentXl}
onOpenViewer={openViewer}
hasPrev={navState.hasPrev}
hasNext={navState.hasNext}
onPrev={navState.navigatePrev}
onNext={navState.navigateNext}
/>
<div className="mt-6 lg:hidden">
<ArtworkActions artwork={artwork} canonicalUrl={canonicalUrl} mobilePriority />
</div>
<div className="mt-8 grid grid-cols-1 gap-8 lg:grid-cols-3">
<div className="space-y-6 lg:col-span-2">
<ArtworkMeta artwork={artwork} />
<ArtworkAuthor artwork={artwork} presentSq={presentSq} />
<ArtworkStats artwork={artwork} />
<ArtworkTags artwork={artwork} />
<ArtworkDescription artwork={artwork} />
<div className="mt-6 lg:hidden">
<ArtworkActions artwork={artwork} canonicalUrl={canonicalUrl} mobilePriority />
<div className="mt-4">
<ArtworkAwards artwork={artwork} initialAwards={initialAwards} isAuthenticated={isAuthenticated} />
</div>
</div>
<aside className="hidden space-y-6 lg:block">
<div className="sticky top-24">
<ArtworkActions artwork={artwork} canonicalUrl={canonicalUrl} />
<div className="mt-8 grid grid-cols-1 gap-8 lg:grid-cols-3">
<div className="space-y-6 lg:col-span-2">
<ArtworkMeta artwork={artwork} />
<ArtworkAuthor artwork={artwork} presentSq={presentSq} />
<ArtworkStats artwork={artwork} />
<ArtworkTags artwork={artwork} />
<ArtworkDescription artwork={artwork} />
<ArtworkComments comments={comments} />
</div>
</aside>
</div>
<ArtworkRelated related={related} />
</main>
<aside className="hidden space-y-6 lg:block">
<div className="sticky top-24">
<ArtworkActions artwork={artwork} canonicalUrl={canonicalUrl} />
<div className="mt-4">
<ArtworkAwards artwork={artwork} initialAwards={initialAwards} isAuthenticated={isAuthenticated} />
</div>
</div>
</aside>
</div>
<ArtworkRelated related={related} />
</main>
{/* Artwork navigator — prev/next arrows, keyboard, swipe, no page reload */}
<ArtworkNavigator
artworkId={artwork.id}
onNavigate={handleNavigate}
onOpenViewer={openViewer}
onReady={setNavState}
/>
{/* Fullscreen viewer modal */}
<ArtworkViewer
isOpen={viewerOpen}
onClose={closeViewer}
artwork={artwork}
presentLg={presentLg}
presentXl={presentXl}
/>
</>
)
}
@@ -62,6 +137,8 @@ if (el) {
presentXl={parse('presentXl')}
presentSq={parse('presentSq')}
canonicalUrl={parse('canonical', '')}
isAuthenticated={parse('isAuthenticated', false)}
comments={parse('comments', [])}
/>,
)
}