feat(landing): homepage rebuild — persona manifesto, card beat high, /lp/card retired - #2686
feat(landing): homepage rebuild — persona manifesto, card beat high, /lp/card retired#26860xkkonrad wants to merge 12 commits into
Conversation
…, 11 sections diet to 5 beats Locked plan (mono projects/lp-refresh): card beat imports /shhhhh straight after the hero, manifesto + problem prose follow, works-today grid carries the surviving proof (live FX widget, compare links), exclusion ending closes. /lp/card retired via permanent redirect to /shhhhh; sitemap and robots entries removed. Sticky bar splits by audience (SIGN UP NOW + TRY THE DOOR). Weekly admission copy moves 20 -> 50 per product/card.md ruling 2026-08-12. New landing copy ships EN-first in all catalogs; localization follows before prod merge.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR replaces the legacy card landing page with new localized landing sections, updates CTA and balance-aware routing, removes the old ChangesLanding page update
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant LandingPageClient
participant CardBeat
participant WorksToday
participant AuthAndWallet
participant Router
LandingPageClient->>CardBeat: render localized card beta section
CardBeat->>Router: track door CTA and navigate to /shhhhh
LandingPageClient->>WorksToday: render product capability section
WorksToday->>AuthAndWallet: read authentication and balance
AuthAndWallet-->>WorksToday: return account state
WorksToday->>Router: navigate exchange CTA by account state
``
</details>
<!-- walkthrough_end -->
<!-- pre_merge_checks_walkthrough_start -->
<details>
<summary>🚥 Pre-merge checks | ✅ 4 | ❌ 1</summary>
### ❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |
| Docstring Coverage | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
<details>
<summary>✅ Passed checks (4 passed)</summary>
| Check name | Status | Explanation |
| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------ |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title clearly summarizes the homepage rebuild, new persona and card sections, and retirement of /lp/card. |
</details>
</details>
<!-- pre_merge_checks_walkthrough_end -->
<!-- finishing_touch_checkbox_start -->
<details>
<summary>✨ Finishing Touches 💡 1</summary>
<!-- finishing_touch_suggestion:docstrings -->
<details>
<summary>📝 Generate docstrings 💡</summary>
- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> Create stacked PR
- [ ] <!-- {"checkboxId": "3e1879ae-f29b-4d0d-8e06-d12b7ba33d98"} --> Commit on current branch
</details>
<details>
<summary>🧪 Generate unit tests (beta)</summary>
- [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-5268456290"} --> Create PR with unit tests
- [ ] <!-- {"checkboxId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "radioGroupId": "utg-output-choice-group-5268456290"} --> Commit unit tests in branch `feat/lp-refresh`
</details>
</details>
<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->
---
Thanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=peanutprotocol/peanut-ui&utm_content=2686)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
<details>
<summary>❤️ Share</summary>
- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)
</details>
<sub>Comment `@coderabbitai help` to get the list of available commands.</sub>
<!-- tips_end -->
|
Code-analysis diffPainscore total: 7148.37 → 7152.85 (+4.48) 🆕 New findings (62)
…and 42 more. ✅ Resolved (63)
…and 43 more. 📈 Painscore deltas (top movers)
|
🧪 UI test report — ✅ all greenSuites
📊 Coverage (unit)
⏱ 10 slowest test cases
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/LandingPage/NotForYou.tsx`:
- Around line 36-43: Replace all four nested Link/Button CTA pairs in
src/components/LandingPage/NotForYou.tsx (lines 36-43) and
src/components/LandingPage/StickyMobileCTA.tsx (lines 80-93) with styled Link
elements, preserving each CTA’s href, text, styling, and behavior while ensuring
each uses a single semantic navigation control.
In `@src/i18n/es-ar.json`:
- Around line 120-159: Translate all newly added landing-page entries in
src/i18n/es-ar.json lines 120-159 into natural Argentine Spanish, preserving
placeholders, punctuation, and key names. Apply the same localization to
src/i18n/pt-br.json lines 120-159 in Brazilian Portuguese, including CTA,
eligibility, card, fee, security, and waitlist text; do not leave English copy
in either catalog.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 5cea8541-5975-430f-ba42-c8be181e735c
📒 Files selected for processing (29)
redirects.jsonsrc/app/lp/card/CardLandingPage.tsxsrc/app/lp/card/page.tsxsrc/app/robots.tssrc/app/shhhhh/ShhhhhLandingPage.tsxsrc/app/shhhhh/page.tsxsrc/app/sitemap.tssrc/components/LandingPage/CardBeat.tsxsrc/components/LandingPage/CardPioneers.tsxsrc/components/LandingPage/LandingPageClient.tsxsrc/components/LandingPage/LandingPageContent.tsxsrc/components/LandingPage/Manifesto.tsxsrc/components/LandingPage/NotForYou.tsxsrc/components/LandingPage/PioneerCard3D.tsxsrc/components/LandingPage/ProblemProse.tsxsrc/components/LandingPage/StickyMobileCTA.tsxsrc/components/LandingPage/WorksToday.tsxsrc/components/LandingPage/index.tssrc/components/LandingPage/landing.types.tssrc/components/LandingPage/landingStrings.tssrc/i18n/app/messages/en.jsonsrc/i18n/app/messages/es-419.jsonsrc/i18n/app/messages/es-AR.jsonsrc/i18n/app/messages/pt-BR.jsonsrc/i18n/en.jsonsrc/i18n/es-419.jsonsrc/i18n/es-ar.jsonsrc/i18n/pt-br.jsonsrc/i18n/types.ts
💤 Files with no reviewable changes (8)
- src/components/LandingPage/PioneerCard3D.tsx
- src/components/LandingPage/CardPioneers.tsx
- src/app/lp/card/page.tsx
- src/components/LandingPage/LandingPageContent.tsx
- src/app/robots.ts
- src/app/lp/card/CardLandingPage.tsx
- src/components/LandingPage/index.ts
- src/app/sitemap.ts
… FX widget landing mode, sticky-bar migration branch + robust suppression, card kill switch, shared ScarcityCounter, dead code out 17-item consolidated fix from 7 review angles + visual/copy QA: zero-fee claim now appears exactly once; ExchangeRateWidget gains hideCta/hideFees/default corridor props (USD->BRL — widget enforces a USD leg); StickyMobileCTA regains the pwa-sunset store branch and suppresses via data-own-cta + MutationObserver instead of one-shot id lookup; disableCardBeat kill switch; DOOR_TRY gains surface on /shhhhh; /lp/card purged from build scripts, /shhhhh added to the sitemap; ScarcityCounter shared by homepage + /shhhhh with ADMISSIONS_PER_WEEK=50 in doorTally.utils; TweetCarousel + 10 orphaned i18n keys deleted; static beats back to server slots; card face ssr:false behind a reserved box; content submodule bumped to the Sumsub FAQ fix.
# Conflicts: # src/app/lp/card/page.tsx
The manifesto rebuild rewrote sections that already earn their keep. Most of the approved v3 page is the live folds in a new order, so restore them and re-sequence instead of writing new ones. Two folds are new. A black door fold distils the /shhhhh hero — same catalog, same scarcity counter — and every click in it goes to /shhhhh, so the fold makes the offer and the page does the work. A cream problem fold names the three people we built peanut for, right before the product folds answer them. Restored from dev: the tweet wall, the hero, NoFees, the sticky mobile bar, the exchange-rate widget, the landing string bag, and the marquee words from the content system. Dropped with the rebuild: CardBeat, Manifesto, ProblemProse, WorksToday, NotForYou. The DropLink fold leaves the homepage because v3 has no slot for it; the component stays for /exchange. Manteca turns blue: it now follows RegulatedRails, which is cream. On the black fold the button and the card carry pink drop shadows, because a black shadow is invisible there. disableCardBeat becomes disableLandingCardFold and hides the door fold together with the closed-beta strip under it.
A transform is ignored on a non-replaced inline element, and next/link renders an inline anchor, so the card sat straight instead of at -12deg.
Visual QA — v3.1 rebuild (commit 26fb7dd)Two independent verification passes against the Vercel preview, both green: 1. vs mockup v3.1 — PASS, no blockers. All 12 folds in the approved order with exact background colours (computed styles): pink → black door → cream problem → blue → yellow → pink → cream → blue → pink → yellow → cream FAQ → black. Scarcity counter pops 2. vs live peanut.me — zero genuine divergences. Every reused fold is innerText-identical to live with matching section backgrounds and widget inventories (exchange widget, 9 partner logos, tweet carousel, FAQ question-for-question, footer links). Only deliberate deltas: fold order, Manteca cream→blue, DropLink removed, two new folds. Zero React hydration warnings; console set identical to live. Notes on record (non-blockers):
Merge gates unchanged: Rain 14-day marketing review · es-419/es-AR/pt-BR for the new ProblemFold keys · human review. Stays draft until then. 🤖 Generated with Claude Code |
The three placeholder line icons were generic stock shapes that belonged to no other Peanut surface. Each card now carries art the site already uses, so the fold reads as ours. "Living across borders" takes the marquee's thumbs-up turned over — the verdict every neobank hands these people. "Sending money home" is a Knerd percent, outline rather than filled: at this size the filled cut closes its counters and reads as a blob. "Paid from abroad" is the pinch hand cut out of the no-hidden-fees art into its own asset, so the card pulls 11KB of paths instead of the whole 34KB banner. One 44px-tall slot holds all three, because the glyph and the drawings need different type sizes to carry the same optical weight.
The landing page names cities and repeats product claims that all have a real
article behind them, and none of it was reachable. This links the ones with a
genuine destination and leaves the rest alone — "Instant" has no article, so
it stays plain text.
MarqueeComp now takes {label, href} items alongside plain strings, so a strip
can link some words and not others. Every existing caller passes strings and
is untouched. The strip under the door fold links all five words to /shhhhh,
since the whole strip is the door. Marquee thumbs lose their "Marquee Image"
alt: now that the strips carry links, a screen reader would read that filler
between every one.
The city line stays one translated string per locale. A helper splits it on
the city names — aliases cover "New York", "Nueva York" and "Nova York" — and
wraps the matches. A locale whose wording drops a city loses that link and
keeps its sentence, which is why the helper matches rather than interpolates.
Round 2 QA — brand icons + article links (54c1c97, 9e1d308)Verified on the redeployed preview:
Known trade-off on record: react-fast-marquee's autoFill clones linked words, so each is multiple tab stops (library gives no clone hook). Accepted for now; alternative is aria-hidden strip + visually-hidden link list. 🤖 Generated with Claude Code |
Konrad drew a peace hand and a coin stack for the problem cards, so the placeholder marks go: the turned-over thumbs-up and the pinch hand cropped out of the no-hidden-fees banner last round. That crop had exactly one consumer, so the asset goes with it. Card 2 keeps the Knerd percent, and all three still share one 44px slot so the card tops line up. The door fold loses its body paragraph. It was the /shhhhh pitch repeated a click early, scarcity count and all — the fold only has to make the offer. Wordmark, tagline, door, card. The shared ScarcityCounter stays; /shhhhh is still its caller.
The works-with strip named nine partners and answered nothing about any of them. Each logo now opens the page that honestly explains what it does with Peanut: Wise and Revolut their compare pages, Mercado Pago the QR explainer, PIX the Brazil page, and the SEPA/ACH banks the bank-deposit article. Brubank and Stripe stay unlinked — no article covers their rail, and a logo that lands somewhere vague is worse than one that does nothing. Mercado Pago and PIX are the only two marks in the set that aren't a heavy wordmark, and both were disappearing into the pink tile, so those two get a white card behind them. Round-2 links also stop underlining at rest. Eight underlined words in a scrolling strip read as clutter; the underline now waits for the cursor.
…more Six of the seven landing FAQs have a help article that answers the question properly, and none of them said so. The FAQ panel takes an optional learnMoreHref per question and the landing page supplies it from a map keyed on the content system's question ids — the content file stays free of code concerns, and a question with no honest article simply has no entry. "Why Peanut?" has none; "My question is not here" already links the help centre. Both other FAQsPanel callers pass nothing and are unchanged. Konrad asked for the learn-more links right-aligned, remembering they used to be. Git says otherwise: neither has ever carried an alignment class. The securityBuiltIn one only looks centred on a phone because it inherits text-center from the feature card while the paragraph beside it opts out with text-left. Right-aligning all three is the change he actually wants; there was nothing to revert. The 24/7 card also drops "real humans" — we shouldn't promise a person picks up. Spanish and Portuguese first sentences follow; second sentences untouched.
Round 3 QA (2f60cbf, c73c6d4, 3b2ae4e)Verified on the redeployed preview, CI fully green:
🤖 Generated with Claude Code |
Both cards were carrying raster art at 44px. The peace hand already existed as a vector — the same hand-peace.svg the footer and the security fold use, so the homepage now draws from the same file instead of a near-duplicate PNG. Konrad supplied the coin stack as an SVG too. Ratios differ from the PNGs (37x57 and 197x173), but the shared 44px slot sizes on height, so the row still lines up.
react-fast-marquee sets overflow-x:hidden on its container. A visible Y axis against a hidden X axis computes to auto, so the strip clips vertically too — and the tiles carried mb-2 with no top margin, sitting flush against that edge. Hovering lifted a tile 2px into it and sheared off its top border. my-2 gives the tile 8px above to move into. Measured under a real hover: the tile top sat 2px past the clip edge before, and 6px clear of it after.
Round 4 QA (ad7a9e4, e7a97d5)Verified on the redeployed preview, CI green:
🤖 Generated with Claude Code |
Summary
Rebuild of the peanut.me homepage per mockup v3.1 (mono
projects/lp-refresh/mockups/mockup.html, Konrad-approved 2026-08-13). Doctrine: reuse the live page heavily — the homepage is the live sections reordered, plus two new folds. The earlier v1 implementation on this branch was rejected as too busy and is fully unwound (additive commits, no force-push).New fold order (bg): live hero (pink) → ShhhhhFold (black, NEW) → ProblemFold (cream, NEW) → NoFees (blue) → yourMoney (yellow) → TweetCarousel (pink) → RegulatedRails (cream) → Manteca (blue ← was cream) → securityBuiltIn (pink) → sendInSeconds (yellow) → FAQs → footer. Yellow marquee strips between every fold as on live; the strip after ShhhhhFold carries the /shhhhh words (IYKYK · WORD TRAVELS · …).
ScarcityCounter(51→50), TRY THE DOOR + waitlist link, blurredPixelatedCardFaceat −12°. Every click routes to/shhhhh— no inline join logic. Copy comes from the existingshhhhh.*next-intl catalog (already localized, 4 locales). Pink drop shadows on this fold only (black shadows vanish on black).src/i18ncatalogs. sendInSeconds keeps the full scroll-freeze grow-button machinery./lp/cardretired (redirect →/shhhhhin redirects.json, route deleted, sitemap + robots cleaned), sharedScarcityCounter, 20→50/week admission copy across /shhhhh + metadata perproduct/card.mdruling 2026-08-12.disableLandingCardFold(default off) hides ShhhhhFold + its marquee strip in one flip, mirroring the olddisableCardPioneersgating./questsunchanged.Design source: mockup v3.1 + decisions in mono
projects/lp-refresh/README.md.Task
TASK-21424 — https://app.notion.com/p/3ba83811757981dd8b7cd252044265e5
Risks / notes for review
/compare/wise|paypal|western-union, which 404 (onlypeanut-vs-*slugs are generated). Worth a separate one-line PR.npm run buildcould not run locally (sandbox OOM, environmental); typecheck + 231 suites / 2939 tests green locally — CI + Vercel preview are the build verification.QA
🤖 Generated with Claude Code