feat(ui): add /dash route, shared nav, project dashboard with /v1/projects API

Restructure routes: / and /dash show a project overview dashboard,
/activity hosts the existing timeline, /cv remains. Shared Layout
component provides consistent nav header and footer across all routes.

New /v1/projects endpoint aggregates per-repo activity stats (commits,
issues, PRs, date range) from existing event data via SQL. Dashboard
ranks projects by weighted recency + volume score and renders a card
grid.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 15:19:49 +03:00
parent a71b4e6b84
commit a70fab4feb
11 changed files with 305 additions and 63 deletions

View File

@@ -0,0 +1,42 @@
import { NavLink, Outlet } from 'react-router-dom';
import Container from 'react-bootstrap/Container';
const externalLinks = [
{ url: 'https://linkedin.com/in/thijssen/', label: 'linkedin' },
{ url: 'https://stackoverflow.com/users/68115/grenade', label: 'stackoverflow' },
{ url: 'https://github.com/grenade', label: 'github' },
{ url: 'https://git.lair.cafe/grenade', label: 'gitea' },
];
export function Layout() {
return (
<>
<Container className="py-4">
<header className="site-header d-flex flex-wrap justify-content-between align-items-center mb-4">
<h1 className="mb-0">hi, i'm rob</h1>
<nav className="d-flex flex-wrap gap-3 align-items-center">
<NavLink to="/" end>dash</NavLink>
<NavLink to="/activity">activity</NavLink>
<NavLink to="/cv">cv</NavLink>
<span className="nav-divider">|</span>
{externalLinks.map((el) => (
<a
key={el.url}
href={el.url}
target="_blank"
rel="noopener noreferrer"
>
{el.label}
</a>
))}
</nav>
</header>
<Outlet />
</Container>
<footer className="site-footer">
no cookies are set or read by this site, which is why no consent banner
is shown.
</footer>
</>
);
}