fix: align homepage section titles and unify download button color

- Wrap the Categories and Popular sections in the same responsive
  max-width container (820/1080/1180) used by Official and Latest, so all
  four section titles line up vertically on desktop.
- Official carousel arrows: hide the arrow at the edge already reached, and
  snap one card per click (reveal the next/previous card fully, keeping a
  small peek) instead of a fixed-pixel scroll.
- Show the pagination dots on desktop too (was mobile-only).
- RecommendedCard download button icon: text-ark-gold -> text-white to match
  the file bubble / popular / video download buttons.

Desktop-scoped; mobile layout unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
TerryM
2026-05-31 02:32:15 +08:00
parent 320e09cc87
commit e35573083a
2 changed files with 48 additions and 13 deletions

View File

@@ -196,8 +196,39 @@ export function Home() {
};
}, [rec.length]);
// Reveal one more card per click, fully, inside the arrow "lanes" (the left
// and right padding the arrows float in) so the edge card is never half-shown
// or tucked under an arrow.
// - Right arrow: bring the first card clipped on the right so its RIGHT edge
// rests just left of the right arrow.
// - Left arrow: bring the last card clipped on the left so its LEFT edge
// rests just right of the left arrow.
const scrollRec = (dir: 1 | -1) => {
recRowRef.current?.scrollBy({ left: dir * 280, behavior: "smooth" });
const row = recRowRef.current;
if (!row) return;
const children = Array.from(row.children) as HTMLElement[];
if (children.length === 0) return;
const rowLeft = row.getBoundingClientRect().left;
const style = getComputedStyle(row);
const padLeft = parseFloat(style.paddingLeft) || 0;
const padRight = parseFloat(style.paddingRight) || 0;
const epsilon = 2;
let delta: number;
if (dir === 1) {
const laneRight = row.clientWidth - padRight;
const next = children
.map((c) => c.getBoundingClientRect().right - rowLeft)
.find((right) => right > laneRight + epsilon);
delta = next !== undefined ? next - laneRight : 0;
} else {
const lefts = children
.map((c) => c.getBoundingClientRect().left - rowLeft)
.filter((left) => left < padLeft - epsilon);
delta = lefts.length ? lefts[lefts.length - 1] - padLeft : -row.scrollLeft;
}
const maxScroll = Math.max(0, row.scrollWidth - row.clientWidth);
const target = Math.max(0, Math.min(maxScroll, row.scrollLeft + delta));
row.scrollTo({ left: target, behavior: "smooth" });
};
useEffect(() => {
@@ -241,6 +272,7 @@ export function Home() {
<Reveal delay={0}>
<section id="categories" className="scroll-mt-16 md:scroll-mt-24">
<div className="mx-auto max-w-full md:max-w-[820px] lg:max-w-[1080px] xl:max-w-[1180px]">
<div className="px-4 md:px-0">
<SectionHeader
title={t("categorySection")}
@@ -331,6 +363,7 @@ export function Home() {
</Reveal>
))}
</div>
</div>
</section>
</Reveal>
@@ -358,7 +391,7 @@ export function Home() {
))}
</div>
<div
className="flex h-[30px] items-center justify-center gap-1.5 md:hidden"
className="flex h-[30px] items-center justify-center gap-1.5"
aria-label="Recommended pagination"
>
{Array.from({ length: recommendedDotCount }).map((_, index) => (
@@ -439,15 +472,17 @@ export function Home() {
{hasPopular ? (
<Reveal>
<section id="popular" className="scroll-mt-16 md:scroll-mt-24">
<div className="px-4 md:px-0">
<SectionHeader
title={t("popularSection")}
viewAllTo="/browse?sort=popular"
viewAllLabel={t("viewAll")}
/>
</div>
<div className="mt-2.5 md:mt-7">
<PopularRankList posts={popularPosts} categories={cats} />
<div className="mx-auto max-w-full md:max-w-[820px] lg:max-w-[1080px] xl:max-w-[1180px]">
<div className="px-4 md:px-0">
<SectionHeader
title={t("popularSection")}
viewAllTo="/browse?sort=popular"
viewAllLabel={t("viewAll")}
/>
</div>
<div className="mt-2.5 md:mt-7">
<PopularRankList posts={popularPosts} categories={cats} />
</div>
</div>
</section>
</Reveal>