UNPKG

portfolio-xs

Version:

This is a tool to generate portfolio based with your markdown file

112 lines (102 loc) 3.7 kB
import React, { useEffect, useState, useMemo, Suspense } from "react"; import { Routes, Route, HashRouter as Router } from "react-router-dom"; import Layout from "./layout.jsx"; import { Flipper, Flipped } from "react-flip-toolkit"; import ProjectCard from "./projectCard.jsx"; import pageMap from "./pageMap.js"; export default function App() { const [rawList, setRawList] = useState([]); const [filterCategory, setFilterCategory] = useState("All"); const [sortOrder, setSortOrder] = useState("Created"); const [columns, setColumns] = useState(1); useEffect(() => { fetch("./rawList.json") .then((res) => res.json()) .then(setRawList) .catch((err) => console.error("Failed to load project list", err)); }, []); // 1) filter + sort first const visibleList = useMemo(() => { const filtered = filterCategory === "All" ? rawList : rawList.filter((p) => p.category === filterCategory); const sorted = [...filtered].sort((a, b) => { const da = sortOrder === "Created" ? a.created : a.updated; const db = sortOrder === "Created" ? b.created : b.updated; return new Date(db) - new Date(da); }); return sorted; }, [rawList, filterCategory, sortOrder]); // 2) chunk AFTER filter/sort const chunkProjects = (projects, cols) => { const rows = []; for (let i = 0; i < projects.length; i += cols) { rows.push(projects.slice(i, i + cols)); } return rows; }; const chunked = useMemo(() => chunkProjects(visibleList, columns), [visibleList, columns]); // 3) layout logic should not depend on chunked (which depends on columns) useEffect(() => { const updateLayout = () => { const width = window.innerWidth; const count = visibleList.length; if (width >= 1360) { // e.g., only go 3 columns if there are enough items to make it worthwhile setColumns(count >= 9 ? 3 : 2); } else if (width >= 680) { setColumns(2); } else { setColumns(1); } }; updateLayout(); window.addEventListener("resize", updateLayout); return () => window.removeEventListener("resize", updateLayout); }, [visibleList.length]); return ( <Router> <Suspense fallback={<div>Loading...</div>}> <Routes> <Route path="/" element={ <Layout rawList={rawList} filterCategory={filterCategory} sortOrder={sortOrder} setFilterCategory={setFilterCategory} setSortOrder={setSortOrder} /> } > <Route index element={ <Flipper flipKey={`${columns}-${filterCategory}-${sortOrder}-${visibleList.length}`}> <div className="project-list"> {chunked.map((row, rowIndex) => ( <div className="project-row" key={`row-${columns}-${rowIndex}`}> {row.map((project) => ( <Flipped key={project.path} flipId={project.path}> <div className="card-wrap"> <ProjectCard project={project} /> </div> </Flipped> ))} </div> ))} </div> </Flipper> } /> {Object.entries(pageMap).map(([path, Comp]) => ( <Route key={path} path={path} element={<Comp />} /> ))} </Route> </Routes> </Suspense> </Router> ); }