From c03a3c6d89bfc7ea25a4e42cba14e7a2171e172b Mon Sep 17 00:00:00 2001 From: TerryM Date: Thu, 28 May 2026 18:28:28 +0800 Subject: [PATCH] feat: add latest updates carousel controls --- src/pages/Home/index.tsx | 106 +++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 20 deletions(-) diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx index 07cf491..cbcbe5b 100644 --- a/src/pages/Home/index.tsx +++ b/src/pages/Home/index.tsx @@ -1,4 +1,4 @@ -import { ChevronRight } from "lucide-react"; +import { ChevronLeft, ChevronRight } from "lucide-react"; import { useLocation } from "react-router-dom"; import { useEffect, useRef, useState } from "react"; import { getJSON, itemsOrEmpty, type Category } from "../../api"; @@ -54,9 +54,11 @@ export function Home() { const [categoryUnavailableOpen, setCategoryUnavailableOpen] = useState(false); const [err, setErr] = useState(null); const recRowRef = useRef(null); + const latestRowRef = useRef(null); const categoryRowRef = useRef(null); const [activeCategoryPage, setActiveCategoryPage] = useState(0); const [canScrollRec, setCanScrollRec] = useState(false); + const [canScrollLatest, setCanScrollLatest] = useState(false); const [recScroll, setRecScroll] = useState({ ratio: 1, progress: 0 }); useEffect(() => { @@ -67,7 +69,7 @@ export function Home() { Promise.all([ getJSON(`/api/categories${catQ}`), getJSON<{ items: Post[] }>(`/api/posts/recommended${postQ}&limit=12`), - getJSON<{ items: Post[] }>(`/api/posts${postQ}&sort=latest&limit=5`), + getJSON<{ items: Post[] }>(`/api/posts${postQ}&sort=latest&limit=12`), getJSON<{ items: Post[] }>( `/api/posts${postQ}&tag=popular&limit=5`, ).catch((): { items: Post[] } => ({ items: [] })), @@ -166,6 +168,31 @@ export function Home() { recRowRef.current?.scrollBy({ left: dir * 280, behavior: "smooth" }); }; + useEffect(() => { + const row = latestRowRef.current; + if (!row) { + setCanScrollLatest(false); + return; + } + + const update = () => { + setCanScrollLatest(row.scrollWidth > row.clientWidth + 1); + }; + + update(); + const resizeObserver = new ResizeObserver(update); + resizeObserver.observe(row); + row.addEventListener("scroll", update, { passive: true }); + return () => { + resizeObserver.disconnect(); + row.removeEventListener("scroll", update); + }; + }, [latest.length]); + + const scrollLatest = (dir: 1 | -1) => { + latestRowRef.current?.scrollBy({ left: dir * 360, behavior: "smooth" }); + }; + useEffect(() => { if (!hash) return; const id = hash.slice(1); @@ -351,14 +378,24 @@ export function Home() { ))} {canScrollRec ? ( - + <> + + + ) : null} @@ -376,16 +413,45 @@ export function Home() { ))} -
- {latest.map((r) => ( - - ))} - {Array.from({ length: latestPlaceholderCount }).map((_, index) => ( - - ))} +
+
+ {latest.map((r) => ( +
+ +
+ ))} + {Array.from({ length: latestPlaceholderCount }).map((_, index) => ( +
+ +
+ ))} +
+ {canScrollLatest ? ( + <> + + + + ) : null}