import { ChevronRight } from "lucide-react"; import { Link } from "react-router-dom"; import { useEffect, useRef, useState } from "react"; import { getJSON, itemsOrEmpty, type Category } from "../api"; import { CategoryIcon } from "../components/CategoryIcon"; import { FigmaBanner } from "../components/FigmaBanner"; import { ComingSoonLatestUpdateRow, LatestUpdateRow, } from "../components/LatestUpdateRow"; import { RecommendedCard } from "../components/RecommendedCard"; import { SectionHeader } from "../components/SectionHeader"; import { langQuery, useI18n } from "../i18n"; import { categoryCardLines } from "../utils/categoryDisplay"; import { postToResource, type PostBackedResource, } from "../utils/postResourceAdapter"; import type { Post } from "../types/post"; export function Home() { const { t, lang } = useI18n(); const [cats, setCats] = useState([]); const [rec, setRec] = useState([]); const [latest, setLatest] = useState([]); const [err, setErr] = useState(null); const recRowRef = useRef(null); const [canScrollRec, setCanScrollRec] = useState(false); useEffect(() => { const q = `?lang=${encodeURIComponent(langQuery(lang))}`; Promise.all([ getJSON(`/api/categories${q}`), getJSON<{ items: Post[] }>(`/api/posts/recommended${q}&limit=12`), getJSON<{ items: Post[] }>(`/api/posts/latest${q}&limit=8`), ]) .then(([c, r, l]) => { setCats(itemsOrEmpty(c)); setRec( itemsOrEmpty(r.items).map((post) => postToResource(post, lang, itemsOrEmpty(c)), ), ); setLatest( itemsOrEmpty(l.items).map((post) => postToResource(post, lang, itemsOrEmpty(c)), ), ); }) .catch((e) => setErr(String(e))); }, [lang]); const iconKeyForResource = (r: PostBackedResource) => cats.find((c) => c.id === r.categoryId)?.iconKey ?? "folder"; useEffect(() => { const row = recRowRef.current; if (!row) { setCanScrollRec(false); return; } const updateCanScroll = () => { setCanScrollRec(row.scrollWidth > row.clientWidth + 1); }; updateCanScroll(); const resizeObserver = new ResizeObserver(updateCanScroll); resizeObserver.observe(row); return () => resizeObserver.disconnect(); }, [rec.length]); const scrollRec = (dir: 1 | -1) => { recRowRef.current?.scrollBy({ left: dir * 280, behavior: "smooth" }); }; const latestPlaceholderCount = Math.max(0, 5 - latest.length); if (err) { return (
{err}
); } return (
{cats.map((c) => { const { line1, line2 } = categoryCardLines(c.name); return (
{line1}
{line2 ? (
{line2}
) : null}
); })}
{rec.map((r, index) => (
))}
{canScrollRec ? ( ) : null}
{latest.map((r) => ( ))} {Array.from({ length: latestPlaceholderCount }).map((_, index) => ( ))}
); }