diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx index 229804c..28aff08 100644 --- a/client/src/pages/home.tsx +++ b/client/src/pages/home.tsx @@ -183,21 +183,75 @@ function MosaicHeading({ children }: { children: React.ReactNode }) { } function MobileMosaic({ latest, popular, focalPoints }: { latest: Article[]; popular?: Article[]; focalPoints?: Record }) { - const l = (latest || []).slice(0, 3); + const pageSize = 3; + const pool = (latest || []).slice(0, 9); + const totalPages = Math.max(1, Math.ceil(pool.length / pageSize)); + + const [page, setPage] = useState(0); + const [displayPage, setDisplayPage] = useState(0); + const [fading, setFading] = useState(false); + const [paused, setPaused] = useState(false); + + const changePage = useCallback((newPage: number) => { + if (newPage === displayPage) return; + setFading(true); + setTimeout(() => { + setDisplayPage(newPage); + setFading(false); + }, 300); + }, [displayPage]); + + useEffect(() => { + changePage(page); + }, [page]); + + useEffect(() => { + if (paused || totalPages <= 1) return; + const timer = setInterval(() => setPage((p) => (p + 1) % totalPages), 8000); + return () => clearInterval(timer); + }, [paused, totalPages]); + + const l = pool.slice(displayPage * pageSize, displayPage * pageSize + pageSize); if (l.length === 0) return null; - const p = (popular || []).filter((a) => !l.some((x) => x.id === a.id)).slice(0, 3); + + const usedIds = new Set(pool.map((a) => a.id)); + const p = (popular || []).filter((a) => !usedIds.has(a.id)).slice(0, 3); + + const nextStart = ((displayPage + 1) % totalPages) * pageSize; + const preload = pool.slice(nextStart, nextStart + pageSize); + return (
-
+
setPaused(true)}> Neueste Artikel -
- {l.slice(0, 2).map((a) => ( - - ))} + {preload.length > 0 && ( + + )} +
+
+ {l.slice(0, 2).map((a) => ( + + ))} +
+ {l[2] && ( +
+ +
+ )}
- {l[2] && ( -
- + {totalPages > 1 && ( +
+ {Array.from({ length: totalPages }).map((_, i) => ( +
)}