Skip to content

feat: branded error routes, project skeleton, footer contact, creator tab URL (#117 #120 #122 #125)#186

Merged
sshdopey merged 5 commits into
Heliobond:mainfrom
gregemax:feat/issues-117-120-122-125
Jul 4, 2026
Merged

feat: branded error routes, project skeleton, footer contact, creator tab URL (#117 #120 #122 #125)#186
sshdopey merged 5 commits into
Heliobond:mainfrom
gregemax:feat/issues-117-120-122-125

Conversation

@gregemax

Copy link
Copy Markdown
Contributor

Summary

This PR resolves four issues in a single batch. Every change is a self-contained commit; no existing behaviour is altered beyond what each issue describes.


Changes

#125 — Add branded not-found and error routes

Files: src/app/not-found.tsx (new), src/app/error.tsx (new)

Unknown routes and runtime errors previously fell through to the bare Next.js framework defaults. Two branded App Router special files now replace them:

  • not-found.tsx — pure Server Component. Renders the Helio orb (160 px, static), a solar-accent 404 eyebrow, a display-type heading, a one-sentence explanation, and a primary pill CTA back to /. Uses design-system tokens throughout (--font-display, --solar, --radius-pill, etc.).
  • error.tsx — Client Component ('use client' — required by Next.js for error boundaries). Logs error to the console (ready to wire to Sentry). Surfaces error.digest as a reference string when present. Offers two recovery actions: Try again (reset()) and Go home (href="/"). Same token set and Helio orb as the 404 page.

Both pages sit inside the root layout so the TopBar and Footer shell are always visible.


#117 — Pixel-perfect loading skeleton for the projects grid

File: src/screens/Explore.tsx

The grid's loading state and ProjectCardSkeleton component already existed but the skeleton's structure did not match the real ProjectCard, meaning the layout shifted visibly when live data landed. Rewritten to mirror the real card exactly:

Area Before After
Hero height 160 px 168 px (matches ProjectCard)
Location badge missing pill ghost absolute-positioned bottom-left
Title thin 18 px bar 22 px block at 68% width (h3 equivalent)
Scores two small inline bars two 84 × 84 px circles with gap: 18 (exact ScoreGauge size)
Footer missing funded label+value stack left, verified chip right, above var(--ink-12) top border

Animation delays stagger 50–300 ms top-to-bottom via the existing hb-pulse keyframe in app.css. CSSProperties helper keeps inline styles DRY. prefers-reduced-motion is handled globally by the base reset.

Also fixed a pre-existing variable shadow: TABS.map((t) => ...) where the iterator t shadowed the useTranslations result — renamed to tb.


#120 — Wire the footer "Talk to a human" action

File: src/shell/Footer.tsx

The button was a no-op <button> with no handler, directly undermining the trust message it was meant to carry. Replaced with an anchor tag pointing to mailto:hello@heliobond.io. Clicking it now opens the user's mail client with the contact address pre-filled. Visual styling is unchanged (ink colour, weight 600, hb-textlink hover class, textDecoration: none).


#122 — Persist selected creator tab in the URL

File: src/app/creator/page.tsx

The active tab was useState local state, so a page refresh or a shared link always landed on Apply regardless of where the user was. Replaced with useSearchParams + router.replace:

  • /creator → defaults to Apply
  • /creator?tab=build → opens Build project directly
  • /creator?tab=dashboard → opens Dashboard directly
  • Refreshing the page restores the same tab
  • router.replace(..., { scroll: false }) keeps the history stack clean — back/forward navigates between pages, not between tabs
  • A VALID_TABS set guards against invalid ?tab= values (falls back to apply)
  • useSearchParams is isolated in CreatorPageInner; the default export wraps it in <Suspense> to satisfy Next.js's static prerender requirement and prevent a full CSR bailout

Commits

7023658 feat: add branded not-found and error routes (#125)
f281a80 feat: pixel-perfect ProjectCardSkeleton for project grid loading (#117)
c1b38f5 fix: wire footer Talk to a human to mailto contact link (#120)
0f6e1ed feat: persist creator tab selection in URL query param (#122)

Closes

Closes #125
Closes #117
Closes #120
Closes #122

gregemax added 4 commits June 30, 2026 14:00
- src/app/not-found.tsx — Server Component; Helio orb + solar 404 label +
  display heading + back-to-home pill link. Replaces the Next.js default
  for all unknown routes.
- src/app/error.tsx — Client Component (required by Next.js); logs the
  error, surfaces error.digest as a ref, offers Try again (reset()) and
  Go home actions. Replaces the framework default crash screen.

Both pages use design-system tokens (--font-display, --font-body,
--font-data, --solar, --ink, --radius-pill, --dur-press, --ease-out)
and honour the TopBar/Footer shell via the root layout.
…iobond#117)

The skeleton now mirrors the real ProjectCard structure exactly so there
is zero layout shift when live data lands:

  • Hero: 168 px (matches card image area) + location-badge pill ghost
    positioned at bottom-left (absolute, same as the real badge)
  • Title: 22 px high block at 68% width (font-display h3 equivalent)
  • Scores: two 84 × 84 px circles (exact ScoreGauge size) with gap: 18
  • Footer: funded label+value stack on the left, verified chip on the
    right, above a 1 px var(--ink-12) top border — identical to real card

Animation delays cascade 50–300 ms top-to-bottom (hb-pulse keyframe,
already in app.css). CSSProperties helper keeps the inline styles DRY.
prefers-reduced-motion is handled globally by the base reset.
The button was a dead no-op. Replaced with an <a href="mailto:hello@heliobond.io">
so the action has a real destination — opens the user's mail client with
the contact address pre-filled.

Styling is unchanged (ink, 600 weight, hb-textlink hover class);
textDecoration: none keeps it consistent with the other footer links.
Active tab is now stored in ?tab= (apply | build | dashboard) so:
  • /creator?tab=build deep-links directly to the builder
  • refreshing the page restores the same tab
  • browser back/forward moves between pages, not tabs (router.replace)

Implementation:
  • useSearchParams reads ?tab= and falls back to 'apply' for unknown
    or missing values (VALID_TABS guard prevents junk params from
    breaking the page)
  • router.replace({ scroll: false }) writes the new value without
    adding a history entry and without scrolling to top
  • CreatorPageInner holds useSearchParams; the default export wraps it
    in <Suspense> to satisfy Next.js's static prerender requirement and
    prevent a full CSR bailout
  • Fixed a pre-existing variable shadow: TABS.map((t) => ...) where t
    clashed with the useTranslations result — renamed iterator to tb
@gregemax gregemax requested a review from dadadave80 as a code owner June 30, 2026 13:16
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

@gregemax is attempting to deploy a commit to the David Dada's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Jun 30, 2026

Copy link
Copy Markdown

@gregemax Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@sshdopey sshdopey merged commit 2438dae into Heliobond:main Jul 4, 2026
0 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants