feat: branded error routes, project skeleton, footer contact, creator tab URL (#117 #120 #122 #125)#186
Merged
Conversation
- 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 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. |
|
@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! 🚀 |
This was referenced Jul 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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-accent404eyebrow, 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). Logserrorto the console (ready to wire to Sentry). Surfaceserror.digestas 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.tsxThe grid's
loadingstate andProjectCardSkeletoncomponent already existed but the skeleton's structure did not match the realProjectCard, meaning the layout shifted visibly when live data landed. Rewritten to mirror the real card exactly:ProjectCard)gap: 18(exactScoreGaugesize)var(--ink-12)top borderAnimation delays stagger 50–300 ms top-to-bottom via the existing
hb-pulsekeyframe inapp.css.CSSPropertieshelper keeps inline styles DRY.prefers-reduced-motionis handled globally by the base reset.Also fixed a pre-existing variable shadow:
TABS.map((t) => ...)where the iteratortshadowed theuseTranslationsresult — renamed totb.#120 — Wire the footer "Talk to a human" action
File:
src/shell/Footer.tsxThe 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 tomailto: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-textlinkhover class,textDecoration: none).#122 — Persist selected creator tab in the URL
File:
src/app/creator/page.tsxThe active tab was
useStatelocal state, so a page refresh or a shared link always landed on Apply regardless of where the user was. Replaced withuseSearchParams+router.replace:/creator→ defaults to Apply/creator?tab=build→ opens Build project directly/creator?tab=dashboard→ opens Dashboard directlyrouter.replace(..., { scroll: false })keeps the history stack clean — back/forward navigates between pages, not between tabsVALID_TABSset guards against invalid?tab=values (falls back toapply)useSearchParamsis isolated inCreatorPageInner; the default export wraps it in<Suspense>to satisfy Next.js's static prerender requirement and prevent a full CSR bailoutCommits
Closes
Closes #125
Closes #117
Closes #120
Closes #122