feat: align figma browse and category sections
This commit is contained in:
@@ -26,6 +26,8 @@ export function Home() {
|
||||
const [latest, setLatest] = useState<PostBackedResource[]>([]);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
const recRowRef = useRef<HTMLDivElement>(null);
|
||||
const categoryRowRef = useRef<HTMLDivElement>(null);
|
||||
const [activeCategoryPage, setActiveCategoryPage] = useState(0);
|
||||
const [canScrollRec, setCanScrollRec] = useState(false);
|
||||
const [recScroll, setRecScroll] = useState({ ratio: 1, progress: 0 });
|
||||
|
||||
@@ -58,6 +60,31 @@ export function Home() {
|
||||
const iconKeyForResource = (r: PostBackedResource) =>
|
||||
cats.find((c) => c.id === r.categoryId)?.iconKey ?? "folder";
|
||||
|
||||
const categoryPages: Category[][] = [];
|
||||
for (let index = 0; index < cats.length; index += 9) {
|
||||
categoryPages.push(cats.slice(index, index + 9));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const row = categoryRowRef.current;
|
||||
if (!row) return;
|
||||
|
||||
const update = () => {
|
||||
const width = row.clientWidth || 1;
|
||||
const next = Math.round(row.scrollLeft / width);
|
||||
setActiveCategoryPage((prev) => (prev === next ? prev : next));
|
||||
};
|
||||
|
||||
update();
|
||||
row.addEventListener("scroll", update, { passive: true });
|
||||
return () => row.removeEventListener("scroll", update);
|
||||
}, [cats.length]);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveCategoryPage(0);
|
||||
categoryRowRef.current?.scrollTo({ left: 0 });
|
||||
}, [lang]);
|
||||
|
||||
useEffect(() => {
|
||||
const row = recRowRef.current;
|
||||
if (!row) {
|
||||
@@ -113,7 +140,70 @@ export function Home() {
|
||||
viewAllTo="/browse"
|
||||
viewAllLabel={t("viewAll")}
|
||||
/>
|
||||
<div className="mt-7 grid grid-cols-3 gap-3 min-[440px]:gap-3.5 md:grid-cols-5 md:gap-3 lg:grid-cols-6 xl:grid-cols-7 xl:gap-4">
|
||||
|
||||
<div className="md:hidden">
|
||||
<div
|
||||
ref={categoryRowRef}
|
||||
className="flex snap-x snap-mandatory overflow-x-auto overflow-y-hidden scroll-smooth [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
||||
aria-label={t("categorySection")}
|
||||
>
|
||||
{categoryPages.map((page, pageIndex) => (
|
||||
<div
|
||||
key={`category-page-${pageIndex}`}
|
||||
className="grid w-full shrink-0 snap-start grid-cols-3 gap-2"
|
||||
>
|
||||
{page.map((c) => (
|
||||
<Link
|
||||
key={c.id}
|
||||
to={`/category/${c.slug}`}
|
||||
className="group flex h-[88px] min-w-0 flex-col items-center justify-center gap-2 rounded-xl bg-[#1D1E23] px-4 py-3 text-center transition hover:bg-[#252630] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ark-gold/80 focus-visible:ring-offset-2 focus-visible:ring-offset-ark-bg"
|
||||
>
|
||||
<CategoryIcon
|
||||
iconKey={c.iconKey}
|
||||
categorySlug={c.slug}
|
||||
className="h-9 w-9 shrink-0 text-ark-gold"
|
||||
/>
|
||||
<div className="w-full truncate text-[13px] font-medium leading-[19.5px] text-white">
|
||||
{c.name}
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{categoryPages.length > 1 ? (
|
||||
<div
|
||||
className="flex h-[30px] items-center justify-center gap-1.5"
|
||||
aria-label="Category pagination"
|
||||
>
|
||||
{categoryPages.map((_, index) => (
|
||||
<button
|
||||
key={`category-dot-${index}`}
|
||||
type="button"
|
||||
aria-label={`Go to category page ${index + 1}`}
|
||||
aria-current={activeCategoryPage === index}
|
||||
onClick={() => {
|
||||
const row = categoryRowRef.current;
|
||||
if (!row) return;
|
||||
row.scrollTo({
|
||||
left: row.clientWidth * index,
|
||||
behavior: "smooth",
|
||||
});
|
||||
setActiveCategoryPage(index);
|
||||
}}
|
||||
className={`h-1.5 rounded-full transition-all ${
|
||||
activeCategoryPage === index
|
||||
? "w-6 bg-ark-gold"
|
||||
: "w-1.5 bg-[#7C7C7C]"
|
||||
}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="mt-7 hidden grid-cols-3 gap-3 min-[440px]:gap-3.5 md:grid md:grid-cols-5 md:gap-3 lg:grid-cols-6 xl:grid-cols-7 xl:gap-4">
|
||||
{cats.map((c) => {
|
||||
const { line1, line2 } = categoryCardLines(c.name);
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user