Current state with latest updates

This commit is contained in:
2026-08-23 13:28:34 +02:00
parent 5af95f6533
commit f52879edbb
74 changed files with 5174 additions and 960 deletions
@@ -324,7 +324,6 @@ export default function FeaturedArtworksAdmin() {
const { props } = usePage()
const composerRef = React.useRef(null)
const rosterRef = React.useRef(null)
const loadMoreRef = React.useRef(null)
const endpoints = props.endpoints || {}
const capabilities = props.capabilities || {}
const seo = props.seo || {}
@@ -344,7 +343,7 @@ export default function FeaturedArtworksAdmin() {
const [selectedArtwork, setSelectedArtwork] = React.useState(null)
const [editingId, setEditingId] = React.useState(null)
const [form, setForm] = React.useState(emptyForm())
const [visibleCount, setVisibleCount] = React.useState(PAGE_SIZE)
const [currentPage, setCurrentPage] = React.useState(1)
React.useEffect(() => {
setEntries(Array.isArray(props.entries) ? props.entries : [])
@@ -353,7 +352,7 @@ export default function FeaturedArtworksAdmin() {
}, [props.entries, props.stats, props.winner])
React.useEffect(() => {
setVisibleCount(PAGE_SIZE)
setCurrentPage(1)
}, [deferredListQuery, filter, sortDirection, sortKey])
function scrollToSection(ref) {
@@ -631,27 +630,13 @@ export default function FeaturedArtworksAdmin() {
.sort((left, right) => compareEntries(left, right, sortKey, sortDirection))
}, [deferredListQuery, entries, filter, sortDirection, sortKey])
const visibleEntries = React.useMemo(() => filteredEntries.slice(0, visibleCount), [filteredEntries, visibleCount])
const hasMoreEntries = visibleEntries.length < filteredEntries.length
const totalPages = Math.max(1, Math.ceil(filteredEntries.length / PAGE_SIZE))
const visibleEntries = React.useMemo(() => filteredEntries.slice((currentPage - 1) * PAGE_SIZE, currentPage * PAGE_SIZE), [filteredEntries, currentPage])
React.useEffect(() => {
if (!hasMoreEntries || typeof IntersectionObserver === 'undefined' || !loadMoreRef.current) {
return undefined
}
const observer = new IntersectionObserver((observerEntries) => {
if (observerEntries.some((observerEntry) => observerEntry.isIntersecting)) {
setVisibleCount((current) => Math.min(current + PAGE_SIZE, filteredEntries.length))
}
}, { rootMargin: '320px 0px' })
observer.observe(loadMoreRef.current)
return () => observer.disconnect()
}, [filteredEntries.length, hasMoreEntries, visibleCount])
function loadMoreEntries() {
setVisibleCount((current) => Math.min(current + PAGE_SIZE, filteredEntries.length))
function goToPage(next) {
const page = Math.max(1, Math.min(totalPages, next))
setCurrentPage(page)
if (typeof window !== 'undefined') window.scrollTo({ top: 0, behavior: 'smooth' })
}
return (
@@ -900,20 +885,27 @@ export default function FeaturedArtworksAdmin() {
</article>
))}
{hasMoreEntries ? (
<div ref={loadMoreRef} className="rounded-[24px] border border-dashed border-white/10 bg-black/20 px-5 py-6 text-center">
<div className="text-sm text-slate-300">Loading more rows as you reach the bottom.</div>
{filteredEntries.length > PAGE_SIZE ? (
<div className="mt-6 flex items-center justify-center gap-4">
<button
type="button"
onClick={loadMoreEntries}
className="mt-4 rounded-full border border-white/10 px-4 py-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-100 transition hover:border-white/20 hover:bg-white/5"
onClick={() => goToPage(currentPage - 1)}
disabled={currentPage === 1}
className="rounded-full border border-white/10 px-4 py-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-100 transition disabled:opacity-50 disabled:cursor-not-allowed hover:border-white/20 hover:bg-white/5"
>
Load 24 more
Previous
</button>
<div className="text-sm text-slate-300">Page {currentPage} of {totalPages}</div>
<button
type="button"
onClick={() => goToPage(currentPage + 1)}
disabled={currentPage === totalPages}
className="rounded-full border border-white/10 px-4 py-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-100 transition disabled:opacity-50 disabled:cursor-not-allowed hover:border-white/20 hover:bg-white/5"
>
Next
</button>
</div>
) : filteredEntries.length > PAGE_SIZE ? (
<div className="text-center text-xs font-semibold uppercase tracking-[0.18em] text-slate-500">
All matching rows loaded
</div>
) : null}
</div>