Files
jmartgraphix.com/client/src/pages/HomePage.tsx
T
jmartin d950092772 Add jmartgraphix logo, favicons, and social share image
Place brand mark in header, footer, and hero; ship PNG favicons,
apple-touch icon, PWA manifest, and 1200×630 Open Graph card.
2026-07-24 10:23:51 -04:00

114 lines
3.6 KiB
TypeScript

import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { api, type Project, type SiteSettings, type Category } from "../lib/api";
import { ProjectCard } from "../components/ProjectCard";
import "./HomePage.scss";
export function HomePage() {
const [site, setSite] = useState<SiteSettings | null>(null);
const [featured, setFeatured] = useState<Project[]>([]);
const [recent, setRecent] = useState<Project[]>([]);
const [categories, setCategories] = useState<Category[]>([]);
useEffect(() => {
Promise.all([
api.site(),
api.featured().catch(() => [] as Project[]),
api.projects({ sort: "date", perPage: 6 }),
api.categories(),
]).then(([s, f, r, c]) => {
setSite(s);
setFeatured(f);
setRecent(r.data);
setCategories(c);
});
}, []);
const heroTitle = site?.heroTitle || site?.name || "jmartgraphix";
const heroSub = site?.heroSubtitle || "3D · Design · Motion · Craft";
return (
<div className="home page-enter">
<section className="home-hero">
<div className="container">
<img
src="/logo.png"
alt="jmartgraphix"
className="home-hero__logo"
width={96}
height={96}
decoding="async"
/>
<p className="home-hero__eyebrow">Portfolio</p>
<h1>
<span className="home-hero__serif">{heroTitle}</span>
</h1>
<p className="home-hero__sub">{heroSub}</p>
<p className="home-hero__about">
{site?.about ||
"A curated collection of 3D modeling, CAD, animation, and visual design."}
</p>
<div className="home-hero__actions">
<Link to="/portfolio" className="btn btn--primary">
View portfolio
</Link>
<Link to="/resume" className="btn btn--ghost">
Resume
</Link>
</div>
</div>
</section>
<section className="home-cats container">
<div className="home-cats__list">
{categories.map((c) => (
<Link key={c.id} to={`/portfolio/${c.slug}`} className="home-cats__chip">
{c.name}
{typeof c.projectCount === "number" && (
<span>{c.projectCount}</span>
)}
</Link>
))}
<Link to="/portfolio/game-dev" className="home-cats__chip home-cats__chip--view">
Game Dev view
</Link>
<Link to="/portfolio/engineering" className="home-cats__chip home-cats__chip--view">
Engineering view
</Link>
</div>
</section>
{featured.length > 0 && (
<section className="container home-section">
<div className="home-section__head">
<h2>Featured</h2>
<Link to="/portfolio">All work </Link>
</div>
<div className="project-grid">
{featured.map((p, i) => (
<ProjectCard key={p.id} project={p} index={i} />
))}
</div>
</section>
)}
<section className="container home-section">
<div className="home-section__head">
<h2>Recent</h2>
</div>
{recent.length === 0 ? (
<p className="home-empty">
Projects will appear here once published.
</p>
) : (
<div className="project-grid">
{recent.map((p, i) => (
<ProjectCard key={p.id} project={p} index={i} />
))}
</div>
)}
</section>
</div>
);
}