Skip to content

feat(ui): align onboarding uploads with hi-fi designs - #227

Merged
markboenigk merged 15 commits into
benevolentbandwidth:mainfrom
Gill87:cursor/bc09b719
Jul 30, 2026
Merged

feat(ui): align onboarding uploads with hi-fi designs#227
markboenigk merged 15 commits into
benevolentbandwidth:mainfrom
Gill87:cursor/bc09b719

Conversation

@Gill87

@Gill87 Gill87 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR aligns onboarding and upload screens with the hi-fi design system, consolidates duplicated upload UI, applies consistent Manrope branding across Manage and Results headers, adds vehicle-specific Results icons, and prevents cancelled uploads from completing after Cancel or unmount.

Motivation

Upload and onboarding screens had inconsistent styling and duplicated presentation code. Cancelled uploads could still write storage and navigate after a delayed file read. Header brand treatment also drifted from the hi-fi Manrope styling, and Results vehicle icons needed type-specific artwork without enlarging or over-contrasting the meta row.

Changes

Frontend

  • Consolidated saved-session and route upload presentation into shared HiFiUploadPage, preserving accepted file types, size limits, parsing paths, storage keys, and destinations.
  • Updated saved-session copy for CSV or JSON imports; kept route upload JSON-only.
  • Added upload operation guards so cancelled or unmounted uploads cannot write storage, update state, or navigate after a delayed file read or reject.
  • Added Vitest coverage for cancelled uploads that resolve or reject after invalidation.
  • Restored Manrope via next/font, set body and brand header tokens to use it, and kept the brand name as non-clickable text in onboarding, Manage, and Results headers.
  • Added title-cased Truck, Car, and Bicycle labels with matching inline vehicle icons sized for the Results meta row.
  • Restored native select option contrast and truncate behavior in the edit-page CSV mapping overlay.
  • Reordered welcome cards and adjusted welcome layout for short viewports.

Backend and infrastructure

  • Backend, deployment, and documentation behavior are unchanged.

Validation

  • npm test -- src/tests/uploadOperation.test.ts — 3 tests passed.
  • npx tsc --noEmit --pretty false — passed.
  • npx eslint --max-warnings=0 src/app/results/components/VehicleTypeIcon.tsx src/app/upload-route/page.tsx src/app/upload-save-point/page.tsx src/tests/uploadOperation.test.ts src/app/components/navbar/Navbar.tsx src/app/components/navbar/MobileNavbar.tsx src/app/results/components/MobileResultsNavbar.tsx src/app/edit/formStyles.v2.ts — passed.
  • Manual check of non-clickable brand headers, Manrope brand text, and Results vehicle icon size/color at desktop and mobile widths — passed.

Intentionally skipped

  • npm --prefix app/ui run test — full suite was not run locally.
  • npm --prefix app/ui run build — production build was not run locally.

Risk

Main risks are visual regression in header typography, Results icon sizing, and upload control states during processing. Upload parsing and storage keys stay on the existing paths; cancellation only blocks stale async completion after Cancel or leave.

Rollout and Recovery

No migration, feature flag, or deployment sequencing is required. Revert the UI commits if a visual regression appears. To undo cancellation safety alone, remove the operation guard and restore prior upload completion behavior without changing persisted data formats.

Gill87 and others added 14 commits July 3, 2026 10:12
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Invalidate in-flight upload work when cancellation or unmounting occurs so stale file reads cannot overwrite the user's navigation intent.

Co-authored-by: Cursor <cursoragent@cursor.com>
Run the pull request workflow against the corrected description and current branch head.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Gill87

Gill87 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Hey Mark, I saw that Vincent also sent in some PRs that overlap with this PR and address some of the same issues. I had my agent create a quick summary comparing the PRs so we can decide the best merge order and reduce any confusion.

PR 227 vs 230 / 231

Overlap: Onboarding upload UI, welcome card order, and CSV mapping select styling.

Scored on:

  • Code cleanliness
  • Code quality
  • UX/UI
  • Net product improvement

Preferred Merge: PR 227

PR 227 is the strongest primary merge.

It:

  • Removes duplicated upload UI
  • Aligns screens with the hi-fi design system
  • Fixes a real cancelled-upload race condition
  • Includes tests

Merge PR 230 and PR 231 only as selective follow-ups—not as replacements.

PR Summary
227 ✅ Best overall primary merge
230 ⭐ Best CSV mapper UX alone
231 📱 Best as a ported responsive slice

Scorecard

Criterion PR 227 (yours) PR 230 PR 231
Code cleanliness Shared HiFiUploadPage; design tokens; thin page wrappers Keeps duplicate upload CSS; ~175-line custom listbox overlay Small, focused CSS/markup edits
Code quality Cancellation guard + Vitest; locks controls while processing Viewport-aware listbox is solid; no unit tests; mapping cannot clear Low risk; addresses deferred review comments
UX / UI Cohesive hi-fi upload, branding, Results icons; native select contrast fix Polished CSV dropdown + taller modal; upload restyle is partial Card wrap, CTA hover target, short-viewport Back button, LCP priority
App improvement Broad: UX consistency + correctness bugfix Narrow but deep: CSV workflow polish; conflicts with 227 uploads Narrow: responsive/a11y polish on landing/welcome
Validation CI green; focused tests; full suite not run locally CI green; format/test/build/browser QA skipped CI green; lint, format, typecheck, test, and build all run

Why PR 227 Wins

Both 227 and 230:

  • Restyle upload-route
  • Restyle upload-save-point
  • Swap the welcome card order

However:

  • 227 extracts a shared upload component and uses design tokens.
  • 230 duplicates the same upload styling in multiple places and retains the old structure.

Additionally, 227 fixes a correctness bug:

  • Cancelled uploads no longer continue writing to storage or navigating after cancellation.

Neither 230 nor 231 addresses this issue.

Tradeoff

PR 227 is a larger, multi-concern PR (branding, Results icons, upload cancellation).

That additional scope is justified because it removes duplicate implementations instead of maintaining them indefinitely.


What to Take from PR 230

After merging 227:

  • Port MappingFieldSelect
  • Port the taller CSV mapping panel
  • Reintroduce an explicit empty/clear option so users can undo an incorrect mapping

Do not port:

  • The duplicated upload page restyle

What to Take from PR 231

After merging 227:

  • Port the ≤520px landing/welcome card stacking
  • Port the CTA-only hover behavior

Skip:

  • Replacing 227's normal-flow Back button with 231's absolute-position + max-height breakpoint implementation

PR 227 already handles this area more cleanly.


Suggested Merge Order

  1. Merge PR 227
  2. Cherry-pick PR 231's landing card wrap onto main
  3. Reapply PR 230's CSV listbox on top of 227's native select contrast fix:
    • Add a clearable empty option
    • Perform a quick accessibility pass

Source: GitHub diffs and CI for PRs 227, 230, and 231 (July 19, 2026).

@markboenigk

Copy link
Copy Markdown
Collaborator

Review

Reviewed via 3 parallel agents split across the upload-cancellation logic, header/branding changes, and Results icons/CSV overlay. No blocking correctness bugs, but a few gaps between the PR description and actual behavior worth addressing before merge.

High

  • Manrope isn't actually applied outside ShellNavbar. globals.css still hardcodes body { font-family: Arial, Helvetica, sans-serif; }, and Navbar.tsx / MobileNavbar.tsx / MobileResultsNavbar.tsx / the desktop header in results/page.tsx never reference var(--font-manrope) — only ShellNavbar sets it inline via style. The PR description says Manage and Results header branding is aligned with Manrope, but those will still render in Arial.

Medium

  • Vehicle icon sizing/color regression in RouteCard.tsx. Old inline SVG was h-4 w-4 with an explicit muted text-[var(--edit-text-secondary)]. The new VehicleTypeIcon call has no className override, so it defaults to h-6 w-6 (50% larger) inside a text-[12px] meta row and inherits full-contrast currentColor instead of the muted tone. Worth a visual check against the hi-fi design.
  • No exhaustiveness check in VehicleTypeIcon.tsx. vehicleType is typed as plain string (matches Route.vehicleType, not the actual z.enum(["truck","car","bicycle"])), and the switch silently falls back to the Car icon for any unrecognized value with no build-time signal.
  • Four independent copies of the "brand links home" pattern. ShellNavbar, Navbar, MobileNavbar, and MobileResultsNavbar each hand-roll the same <Link href="/" aria-label="..."> markup with different className sources. Worth extracting to a shared BrandLink/Logo component to avoid future drift.
  • Guard test coverage is shallow. uploadOperation.test.ts only exercises the standalone utility, not its usage in upload-route/page.tsx / upload-save-point/page.tsx — nothing would fail if a future edit dropped one of the scattered isCurrentOperation() checks before a router.push/sessionStorage.setItem. Also untested: a rejected (not resolved) file read after cancellation, and rapid cancel-then-restart / mid-processing unmount.

Low / nits

  • upload-save-point/page.tsx: the CSV quota-exceeded catch writing setContinueError isn't gated by isCurrentOperation() — harmless today (no await in between) but fragile against future refactors.
  • useRef(createUploadOperation()) re-invokes the factory every render (result discarded past the first) — not idiomatic lazy-init, though harmless.
  • CSVUploadOverlay.tsx: the new <select> lost the old <span>'s truncate class, so long field labels may now hard-clip instead of ellipsis.
  • Inline style={{textDecoration:"none"}} mixed with Tailwind classes in Navbar/MobileNavbar/MobileResultsNavbar — a no-underline class would be more consistent.
  • formStyles.mobile.ts's RESULTS_MOBILE_NAV_TITLE export looks dead after MobileResultsNavbar switched to the shared style — worth confirming nothing else imports it.

What's done well

  • The upload-guard design itself (monotonic counter, invalidate() on both cancel and unmount, per-side-effect isCurrentOperation() checks placed immediately before every state write/storage write/navigation) is correct — no race condition found in upload-route or upload-save-point.
  • Accepted file types, size limits, and storage keys are unchanged from main — the consolidation didn't regress upload behavior.
  • All brand links correctly use Next.js <Link> (client-side nav) with a descriptive aria-label.
  • layout.tsx font wiring (Geist/Geist Mono/Manrope via next/font/google) is correct, no duplication or FOUC risk.
  • The CSV overlay contrast fix is a genuine, browser-respected fix replacing a broken opacity-hack overlay.
  • Vehicle icons are hand-rolled inline SVG rather than pulled from an icon library — no bundle bloat.

Apply Manrope to brand headers, restore vehicle icon size/color, make the brand name non-clickable, and harden upload cancellation guards.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Gill87

Gill87 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

Hey @markboenigk,

Thanks for your feedback. I went ahead and addressed the high, medium, and nitpicks. This UI PR should be good to merge.

@markboenigk
markboenigk merged commit 27b4800 into benevolentbandwidth:main Jul 30, 2026
4 checks passed
@markboenigk markboenigk mentioned this pull request Jul 30, 2026
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants