Repository navigation
Portfolio fixes: deep links, mobile nav, OG image, card links, code-splitting, page titles - #9
Conversation
|
Review of PR 9 Well-scoped PR with clear commits. Notes below, none blocking. Potential issues
Good
Tests Nit: the CLAUDE.md line references in Project Data Management (153-242) may be stale. 🤖 Generated with Claude Code |
…on GitHub Pages BrowserRouter routes like /assets/projects and /concepts returned GitHub's "Page not found" when requested directly. A postbuild step now copies dist/index.html to dist/404.html, and the sitemap lists the project routes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
Nine inline links overflowed phone widths. Below 1024px a menu button (aria-expanded, Escape to close) reveals a stacked link list that closes on navigation. Nav items are defined once and shared by both layouts; desktop links no longer wrap between lg and xl. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
…tags index.html pointed og:image and twitter:image at /og-image.jpg, which 404ed, so shared links rendered without a preview. Adds a 1200x630 card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
Cards with a detailUrl were wrapped in a <Link> that also contained Deep Dive, Live Demo and Repository links (invalid <a> in <a>). The title is now the only card-level link, stretched over the card with an ::after overlay; secondary links sit above it, and the stopPropagation workaround is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
All routes shipped in one 2.1 MB bundle (678 KB gzipped), so the homepage downloaded ECharts, Cytoscape and Leaflet even though only the visualization pages use them. Projects, Concepts and the six project routes now load with React.lazy inside one Suspense boundary whose fallback keeps the Layout. Homepage script: 275.8 KB (86 KB gzipped). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
All routes showed the same tab title, so bookmarks and history entries for a
case study were indistinguishable from the homepage. Each page now renders a
<title> ("Page Name | Don Branson") that React 19 hoists into <head>; the
static title in index.html remains the no-JS fallback.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
efe0ae3 to
05e30f6
Compare
ReviewOverall this is a clean, well-scoped PR. The commits are separated sensibly and CLAUDE.md is updated to match. I read the diff only and did not run the build. Notes, roughly by importance: Worth considering
Minor
Good
TestsThere is no test framework (noted in CLAUDE.md), so the Playwright manual checks are the only coverage. A smoke test that visits each route and checks the title would guard the lazy-route and 404 changes. No security concerns. External links use 🤖 Generated with Claude Code |
With lazy routes, a tab opened before a deploy requests chunk filenames the deploy deleted (gh-pages replaces dist). The rejected import was uncaught, so React unmounted the root and the visitor saw a white page. RouteErrorBoundary wraps the routes, keeps the nav and footer, and offers a reload; it resets on pathname change so nav links still work. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
ProjectsPage has no heavy dependencies; splitting its ~11 KB out only added a network round trip on the most-visited secondary route. Lazy loading now covers just the six project routes that carry ECharts, Cytoscape and Leaflet. Main bundle: 290.4 KB (90.0 KB gzipped). CLAUDE.md updated, including the new RouteErrorBoundary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
…atus /assets/projects and the five project routes only resolve through the 404.html SPA fallback, so crawlers fetch them with HTTP 404 and Search Console would report 'Submitted URL not found'. Reverts the sitemap to main's entries; per-route pages that return 200 are tracked as a separate change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
HomePage keeps the full 'Don Branson | Generative AI Architect & Systems Engineer' title (matching index.html), which reverses the documented 'Page Name | Don Branson' order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
The menu was rendered only while open, so the toggle's aria-controls pointed at a missing ID whenever it was closed. #mobile-menu is now always rendered and toggled with the hidden attribute (display: none, so its links stay out of the tab order when closed). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
|
Review Overall this is a clean, well-scoped PR. The commits are separated sensibly and the CLAUDE.md updates match the code. I reviewed the diff only and didn't build or run it. Worth considering
Minor
Tests and security
Positives
Nothing here blocks merging. |
…o load RouteErrorBoundary told every visitor the site had probably been updated, even for ordinary render bugs that a reload can't fix. Chunk-load failures (matched on the Chrome, Firefox and Safari messages) keep that message; any other error gets a generic one plus a Go to homepage link. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
React.lazy caches a rejected import, so after a deploy the stale route kept failing until a manual reload. A vite:preloadError listener now reloads once to pick up the new build; a 10-second sessionStorage guard prevents reload loops (e.g. offline), letting RouteErrorBoundary show its message instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
ReviewSolid, well-scoped PR. The commit-per-change structure, the comments explaining why, and the accessibility work (aria-expanded/aria-controls, Escape to close, stretched-link instead of nested anchors) are all good. No blocking issues found. I read the diff only and did not build or run it. Suggestions / things to double-check
Nice bundle win (2.1 MB to 278 KB). LGTM modulo the small points above. |
…links - Layout takes an optional title and renders '<title> | Don Branson' once, so the suffix convention lives in one place instead of nine hand-written <title>s. The homepage omits it and keeps index.html's full site title (no special case). - renderNavLink takes a 'desktop' | 'mobile' variant backed by one style table instead of four positional class strings; isActive (whose '/' branch was dead) folds into isItemActive. - ProjectCard returns its wrapper directly (the cardContent alias was left over from the removed Link/no-Link branches), and the action row lifts every link above the stretched-link overlay with [&>a]:relative [&>a]:z-10 instead of repeating 'relative z-10' on each link. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
… boundary Both rendered near-identical centered heading/message/button markup. StatusPage takes a title, heading, message and a list of link/button actions; the 404 page gains the focus ring the boundary already had. The boundary also drops its componentDidCatch console.error, which duplicated React 19's own logging of caught errors, and inlines its one-use chunk-error helper. CLAUDE.md documents the title prop and StatusPage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
Same behavior (Number(null) is already 0), half the lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
ReviewWell-structured PR: one commit per concern, clear rationale, and the bundle reduction (2.1 MB → 278 KB) is a real win. No blocking issues found. What looks good
Suggestions / minor issues
TestsThere's still no test framework (as documented in CLAUDE.md). Manual Playwright verification is described in the PR, which is good. The new logic (error boundary reset, reload guard, mobile menu) would be good first candidates if you add Vitest + Testing Library later. SecurityNothing concerning: external links keep Overall: LGTM, with the above as optional polish. |
- Offline, the automatic reload swapped the working site for the browser's offline page. It now skips the reload when navigator.onLine is false, leaving RouteErrorBoundary's message and Reload button. - event.preventDefault() made Vite's import wrapper resolve to undefined, so React threw an unrelated error and the boundary briefly showed 'Something went wrong' before the reload landed. The event is no longer cancelled; the original chunk error reaches the boundary, which shows 'This page didn't load' until the reload completes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
RouteErrorBoundary reset only when the pathname changed, so 'Go to homepage' from an error on '/' (or a hash link) left the error screen up. It now resets on location.key, which is new for every navigation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
A route whose CSS chunk was removed by a deploy would otherwise get the generic 'Something went wrong' message instead of the reload prompt. Latent today (no lazy route imports CSS). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
ReviewSolid PR: the commits are well-scoped, comments explain the why, and it follows the CLAUDE.md conventions ( What looks good
Suggestions / minor points
Overall: LGTM, with the description update being the main ask. |
Offline, a failed chunk showed 'The site was probably updated… Reloading fetches the latest version' with a Reload button, which would swap the site for the browser's offline page (the outcome main.tsx already avoids). Offline chunk failures now say 'You appear to be offline' and offer only Go to homepage, which works offline. The three cases render one StatusPage with computed heading, message and actions instead of duplicated branches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
A native fragment navigation (e.g. /#about from an error page on the initial load) can leave location.key at 'default', so the error screen didn't clear. The key is now pathname + hash + location.key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN
Review of PR #9Well-scoped and well-documented PR. I reviewed the diff for CLAUDE.md, package.json, App.tsx and Layout.tsx and found no blocking concerns. What looks good
Suggestions (non-blocking)
TestsThere is no test framework (per CLAUDE.md), so the Playwright run in the test plan is the only coverage. If you add Vitest later, a smoke test for the menu toggle, Escape and the error boundary would be worthwhile. Security / performanceNo security concerns: external links keep |
Builds on #10 (Concepts page removal, merged). Supersedes #7 and #8. One commit per change:
Broken or blocking (design review P0)
33af66dDeep links and refreshes 404 on GitHub Pages. Apostbuildscript copiesdist/index.htmltodist/404.html. (This commit also added the routes topublic/sitemap.xml;78003f7below reverts that.)d7fd5d0Navigation overflowed at phone width. Belowlg(1024px) a menu button (aria-expanded,aria-controls, closes on Escape and on link tap) reveals a stacked list. Nav items are defined once and shared by both layouts; desktop links no longer wrap at 1024px.9e9112aMissing social preview image. Adds the 1200×630public/og-image.jpgthatog:image/twitter:imagealready referenced.415d41eNested links in project cards. The title is the only card-level link, stretched over the card with an::afteroverlay; Demo / Repository / Hugging Face links sit above it. Removes thestopPropagationworkaround.Performance and meta
44f2214Code-split routes. Home and 404 stay eager; Projects and the six project routes useReact.lazyinside oneSuspenseboundary whose fallback keeps the Layout. Homepage script: 2,128.6 KB → 278.2 KB (678.4 → 87.0 KB gzipped).e9c133fPer-route titles. Each page renders<title>Page Name | Don Branson</title>, hoisted by React 19;index.html's title stays as the no-JS fallback.05e30f6Docs.CLAUDE.mdupdated for lazy routes and the title convention.Test plan
Production build served by
vite preview, driven with Playwright (earlier rounds also used a server mimicking GitHub Pages'404.htmlfallback):npm run buildpasses;dist/404.htmlanddist/og-image.jpgpresentnpm run lint0 errors (same 3 pre-existing warnings)npm run deploy: open a deep link on donbr.github.io and re-scrape in LinkedIn Post InspectorKnown limitations
404.htmlwith HTTP status 404; browsers render normally but crawlers may skip deep routes. Prerendering would fix it; out of scope./assets/projects/situational-awarenessstill loads ~1 MB of ECharts on demand.postbuildscript) are in the next PR in the stack.Deployment
No deploy workflow; merging doesn't publish. Run
npm run deployfrommainafter merge.🤖 Generated with Claude Code
https://claude.ai/code/session_01Ppa5DyJCZ1CowKtz58QARN