A playground where I can test different styles and functionality.
Log inAuthentication, design systems, live data, full-stack API integration, and real-user performance monitoring — all in one project.
Auth0 integration with CSP headers, proxy middleware, and protected routes.
Real-user Core Web Vitals collected via sendBeacon, aggregated as P75 in Postgres, and displayed on a protected dashboard.
Token-driven palette, theme toggling, and reusable components.
Live player stats via API proxy with batch loading and error handling.
Card browser with infinite scroll, URL-synced filters, and per-set grids built on the TCGdex SDK.
Four-view calendar with multi-day events, time-grid overlap layout, and Pokémon card attachments.
Pokémon browser using the PokeAPI Hasura endpoint — typed queries, field selection, plain fetch over Apollo.
// middleware.ts
export async function middleware(req) {
const session = await auth0.getSession();
if (!session && isProtected(req)) {
return redirect("/auth/login");
}
// attach CSP + nonce headers
return addSecurityHeaders(req);
}A token-driven palette with semantic color aliases, consistent spacing, and theme toggling.
Live player statistics proxied through the API layer with batch loading and error recovery.
| Player | Team | PTS | REB | AST |
|---|---|---|---|---|
| Luka Doncic | LAL | 28.4 | 8.3 | 8.1 |
| Jayson Tatum | BOS | 27.0 | 8.5 | 4.6 |
| Shai Gilgeous | OKC | 31.2 | 5.5 | 6.0 |
| Nikola Jokic | DEN | 26.3 | 12.4 | 9.0 |
Server-side proxy hides API keys from the client.
Multiple players fetched in parallel with loading states.
Granular error recovery per player, not per page.
Full card browser with infinite scroll, URL-synced filters, per-set grids, and deep card detail — built on the TCGdex SDK.
IntersectionObserver sentinel loads next pages as you scroll — reconnects after each fetch so wide viewports never stall.
Search, type filter, and page number live in the URL. Shareable, bookmarkable, and back/forward navigable.
Set metadata fetched server-side via TCGdex SDK. Paginated card grids are client components with Suspense boundaries.
Day, week, month, and year views with multi-day events, an overlapping-event layout engine, and Pokémon card attachments — built to track what we pull playing Pokémon Pocket together.
Day and week views use an absolute-positioned time grid — events span their real duration and sit side by side when they overlap.
Attach cards pulled from Pocket to any event. Search the full TCGdex catalog and log what you got, when you got it.
Events spanning multiple days show on every day they cover, with continuation bars in month view and all-day row promotion in week/day view.
Browse 1,000+ Pokémon via a Hasura GraphQL endpoint — typed queries, field selection, and a live query inspector. Plain fetch, no Apollo.
Field selection means the card only fetches id, name, types, and two stats — not the full 40-field REST response.
Plain fetch with a 10-line wrapper. Apollo earns its cost for normalized caches and subscriptions; for a browser it's just weight.
A collapsible panel shows the actual GraphQL query and variables as you search and filter — updates in real time.
Real-user Core Web Vitals collected from every page load. P75 scores aggregated in Postgres and displayed on a protected dashboard — field data, not lab simulations.
| Page | LCP | P75 |
|---|---|---|
| /protected/vitals | 1.8s | 75th |
| /calendar | 2.1s | 75th |
| /tcg/browse | 2.9s | 75th |
The web-vitals package fires each metric from real browsers over real connections. sendBeacon guarantees delivery even when the user navigates away before the metric fires.
PERCENTILE_CONT(0.75) aggregates the 75th percentile natively in SQL — no extra tooling. P75 is the same threshold Google uses for search ranking.
BFF proxy keeps auth tokens server-side. Data lives in our own DB so the dashboard can be embedded anywhere, not just a third-party UI.