Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
25f310d
style: bring marketing/SEO pages in line with Peanut design system
Hugo0 Feb 16, 2026
3fbc449
feat: programmatic SEO pages, i18n, DS showcase, LP refactor
Hugo0 Feb 16, 2026
5c147f9
Add image support and draft/published filtering to content loaders
Hugo0 Feb 16, 2026
e488e6a
fix: prettier formatting, dynamicParams, content caching
Hugo0 Feb 16, 2026
931a050
✨ V3 transitivity UI + binary cashback + points animations
Hugo0 Feb 18, 2026
2e79309
fix: useCountUp render loop causing flickering animation
Hugo0 Feb 18, 2026
e821397
style: fix prettier formatting
Hugo0 Feb 18, 2026
c4869b2
fix: kernel client stuck loading screen + retry logic
jjramirezn Feb 19, 2026
bb3d194
Merge pull request #1685 from peanutprotocol/hotfix/loading-screen
Hugo0 Feb 19, 2026
e6b966f
zerodev package update
Hugo0 Feb 19, 2026
2dbe78f
feat: MDX content rendering pipeline with interactive components
Hugo0 Feb 21, 2026
ac8534e
fix: CI auth for private content submodule, publish argentina
Hugo0 Feb 22, 2026
bd0e575
feat: MDX-first rendering for all marketing pages + cleanup
Hugo0 Feb 22, 2026
8e2694f
feat: SEO improvements — breadcrumbs, FAQ schema, sitemap dates, ping…
Hugo0 Feb 22, 2026
46053e2
Merge branch 'feat/seo' into release/prod-2025-02-25
Hugo0 Feb 24, 2026
9dd6178
merge prod hotfixes into release (hotfix/loading-screen #1685)
Hugo0 Feb 25, 2026
533d245
merge V3 transitivity UI + points animations into release
Hugo0 Feb 25, 2026
3f305a0
chore: gitignore .claude directory
Hugo0 Feb 25, 2026
05a104d
fix: use hasCashbackLeft (boolean) in CashCard, matching BE response
Hugo0 Feb 25, 2026
25f385f
chore: point content submodule to main (new content pages)
Hugo0 Feb 25, 2026
8b70a98
fix: publish all SEO content + guard corridor loader against undefine…
Hugo0 Feb 25, 2026
d28d85a
fix: SEO page polish — breadcrumbs, flags, hero, exchange widget, con…
Hugo0 Feb 25, 2026
9e07236
fix: ExchangeWidget overflow + bulk migrate content to inline widget
Hugo0 Feb 25, 2026
580887b
fix: SEO audit — OG URL, robots.txt locales, deduplicate extractors, …
Hugo0 Feb 25, 2026
848151c
chore: remove thin programmatic pages, unpublish blog/team from produ…
Hugo0 Feb 25, 2026
3b47bdd
fix: scroll freeze on mobile, modal bug, null guards, small fixes
Hugo0 Feb 25, 2026
1a0c833
fix: update content submodule — escape <20 in MDX tables
Hugo0 Feb 25, 2026
c9561fa
ci: retrigger after pushing content submodule
Hugo0 Feb 25, 2026
f314e48
fix: show loading spinner on sign test tx button while user data loads
Hugo0 Feb 26, 2026
2c054ff
style: run prettier on all files
Hugo0 Feb 26, 2026
c536f83
docs: add CI and tech stack badges to README
Hugo0 Feb 26, 2026
d509eb7
fix: prevent withdraw success screen from redirecting away from /home
Hugo0 Feb 26, 2026
0421615
fix: prevent infinite loading from stale SW-cached auth responses
Hugo0 Feb 26, 2026
4e48a4c
fix: refresh JWT cookie maxAge only on successful auth
Hugo0 Feb 26, 2026
33a6fe0
fix: typo "friends your friends" and document blog dynamicParams gotcha
Hugo0 Feb 26, 2026
3da3330
ci: add SUBMODULE_TOKEN to preview workflow for private content submo…
Hugo0 Feb 26, 2026
5f2745b
test: add unit tests for get-user-from-cookie auth cookie lifecycle
Hugo0 Feb 26, 2026
ce45dd0
chore: remove one-shot migration script, stale TODO doc, deprecated a…
Hugo0 Feb 26, 2026
9f29a47
ci: add --archive=tgz to vercel deploy to handle >15k files
Hugo0 Feb 26, 2026
3d25321
fix: sanitize blog slug to prevent stored XSS (CodeQL high)
Hugo0 Feb 26, 2026
5a251a7
fix: restore lockfile to zerodev 5.5.7, revert CashCard threshold (BE…
Hugo0 Feb 26, 2026
f9e26b0
Merge pull request #1691 from peanutprotocol/release/prod-2025-02-25
Hugo0 Feb 26, 2026
50e71ca
fix: lazy-load bundle analyzer to avoid prod build failure
Hugo0 Feb 26, 2026
154c3cc
fix: remove hardcoded 20% from cashback CTA, cap invite graph at 200 …
Hugo0 Feb 26, 2026
f5425c1
fix: improve QR scanner detection reliability
Hugo0 Feb 26, 2026
8333000
fix: currency picker z-index on SEO pages, accurate cashback percentage
Hugo0 Feb 26, 2026
53f81ed
style: run prettier
Hugo0 Feb 26, 2026
9549863
Expand help center: i18n, Crisp chat, new articles
Hugo0 Feb 26, 2026
9632b9d
Deprecate peanut.to, fix CI workflows and README badges
Hugo0 Feb 26, 2026
9c3e981
Redirect /support to /en/help and remove dead support page
Hugo0 Feb 26, 2026
d360045
Merge pull request #1698 from peanutprotocol/fix/support-redirect
Hugo0 Feb 26, 2026
e6bc884
Fix broken internal links, add validation script, fix RelatedPages ca…
Hugo0 Feb 26, 2026
e05ff76
Add internal link validation to CI pipeline
Hugo0 Feb 26, 2026
28f676e
Add valid-links generator script for content LLM context
Hugo0 Feb 26, 2026
a1ff12a
Fix validate-links: match single-quoted href, strip trailing slashes
Hugo0 Feb 26, 2026
99ea9fc
Format generate-valid-links.ts with prettier
Hugo0 Feb 26, 2026
7a31491
Update content submodule to main (PR #4 merged)
Hugo0 Feb 26, 2026
a512647
Auto-update content submodule on peanut-content changes
Hugo0 Feb 26, 2026
4a561d6
Address CodeRabbit review feedback
Hugo0 Feb 26, 2026
16d5740
Merge pull request #1700 from peanutprotocol/fix/broken-internal-links
Hugo0 Feb 26, 2026
73eaa42
Fix auto-update workflow: use GITHUB_TOKEN for push
Hugo0 Feb 26, 2026
8896da6
Fix auto-update: clear persisted credentials before push
Hugo0 Feb 26, 2026
d7379b0
Auto-update content: create PR instead of direct push
Hugo0 Feb 26, 2026
92e0cf8
Fix auto-update: override credentials for branch push
Hugo0 Feb 26, 2026
d97c43c
Fix auto-update: separate checkout from submodule auth
Hugo0 Feb 26, 2026
fab5971
Fix auto-update: use GitHub API for signed commits
Hugo0 Feb 26, 2026
0c1ef20
Fix auto-update: remove non-existent label
Hugo0 Feb 26, 2026
3b5f3e8
Update content submodule to latest main
github-actions[bot] Feb 26, 2026
78d93fa
Merge pull request #1701 from peanutprotocol/auto/update-content-2026…
Hugo0 Feb 26, 2026
907c878
Merge branch 'main' into chore/sync-131
kushagrasarathe Feb 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .cursorrules
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
- **Never run jq command** - it crashes you.
- **Never run sleep** from command line - it hibernates pc.
- **Do not generate .md files** unless explicity told to do so.
- **Comments** should always be made in all lowercase and simple english
- **Error messages**, any error being shown in the ui should be user friendly and easy to understand, and any error being logged in consoles and sentry should be descriptive for developers to help with debugging
- **Never add AI co-author to commits** - do not add "Co-Authored-By" lines for AI assistants in git commits

Expand Down
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export NEXT_PUBLIC_PEANUT_WS_URL="wss://api.staging.peanut.me"
# export PEANUT_API_URL="http://127.0.0.1:5000/" # If running api locally
# export NEXT_PUBLIC_PEANUT_API_URL="http://127.0.0.1:5000/" # If running api locally

export PEANUT_API_KEY="" # See in docs.peanut.to
export PEANUT_API_KEY="" # See in docs.peanut.me

export NODE_ENV="development"

Expand Down Expand Up @@ -53,7 +53,7 @@ export PROMO_LIST={}
#generate these with scripts/generate.mjs
export NEXT_PUBLIC_VAPID_PUBLIC_KEY=
export VAPID_PRIVATE_KEY=
export NEXT_PUBLIC_VAPID_SUBJECT="mailto:hello@peanut.to"
export NEXT_PUBLIC_VAPID_SUBJECT="mailto:hello@peanut.me"
export NEXT_PUBLIC_FETCH_TIMEOUT_MS=10000

# one signal
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/preview.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: Preview deploy
on:
pull_request:
branches:
- peanut-wallet
- peanut-wallet-dev
- main
- dev

jobs:
Deploy-Preview:
Expand All @@ -12,6 +12,7 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.SUBMODULE_TOKEN }}
- uses: pnpm/action-setup@v4
with:
version: 9
Expand All @@ -24,4 +25,4 @@ jobs:
- name: Build Project Artifacts
run: vercel build --target=preview --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy Project Artifacts to Vercel
run: vercel deploy --prebuilt --target=preview --token=${{ secrets.VERCEL_TOKEN }}
run: vercel deploy --prebuilt --archive=tgz --target=preview --token=${{ secrets.VERCEL_TOKEN }}
4 changes: 4 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.SUBMODULE_TOKEN }}

- uses: actions/setup-node@v4
with:
Expand All @@ -26,6 +27,9 @@ jobs:
- name: Check formatting
run: pnpm prettier --check .

- name: Validate internal links
run: pnpm validate-links

- name: Run Unit Tests
run: pnpm test

Expand Down
60 changes: 60 additions & 0 deletions .github/workflows/update-content.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Update content submodule

on:
repository_dispatch:
types: [content-updated]
workflow_dispatch:

permissions:
contents: write
pull-requests: write

jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Init and update submodule
env:
SUBMODULE_TOKEN: ${{ secrets.SUBMODULE_TOKEN }}
run: |
git config submodule.src/content.url "https://x-access-token:${SUBMODULE_TOKEN}@github.com/peanutprotocol/peanut-content.git"
git submodule update --init src/content
cd src/content
git fetch origin main
git checkout origin/main

- name: Check for changes
id: check
run: |
if git diff --quiet src/content; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
fi

- name: Create PR
if: steps.check.outputs.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH="auto/update-content-$(date -u +%Y%m%d-%H%M%S)"
TREE=$(git write-tree)
PARENT=$(git rev-parse HEAD)
Comment on lines +42 to +44
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE=".github/workflows/update-content.yml"

# Check if file exists
if [[ ! -f "$FILE" ]]; then
  echo "ERROR: File $FILE not found"
  exit 1
fi

# Find relevant lines
echo "=== Checking git commands order ==="
rg -n "(git add|git write-tree|git rev-parse)" "$FILE" -A 1 -B 1 || echo "No matches found"

echo ""
echo "=== Full context around lines 40-50 ==="
sed -n '40,50p' "$FILE"

Repository: peanutprotocol/peanut-ui

Length of output: 986


🏁 Script executed:

#!/bin/bash
FILE=".github/workflows/update-content.yml"

echo "=== Checking for git add commands in entire file ==="
rg -n "git add" "$FILE" || echo "No 'git add' found"

echo ""
echo "=== Checking for submodule-related commands ==="
rg -n "submodule|git fetch" "$FILE" || echo "No submodule commands found"

echo ""
echo "=== Full run block context (lines 38-60) ==="
sed -n '38,60p' "$FILE"

Repository: peanutprotocol/peanut-ui

Length of output: 1995


🏁 Script executed:

#!/bin/bash
FILE=".github/workflows/update-content.yml"

echo "=== Full workflow structure (all step names) ==="
rg -n "name:" "$FILE" | head -20

echo ""
echo "=== Check for any index-resetting commands between lines 18-60 ==="
sed -n '18,60p' "$FILE" | rg -n "reset|checkout|clean|rm -rf"  || echo "No index-resetting commands found"

echo ""
echo "=== Complete 'Init and update submodule' step (lines 18-36) ==="
sed -n '18,36p' "$FILE"

Repository: peanutprotocol/peanut-ui

Length of output: 1226


🏁 Script executed:

#!/bin/bash

# Let's check the full picture and understand git submodule behavior
echo "=== Key question: Does 'git checkout' inside a submodule stage the change in parent? ==="
echo "Testing git submodule staging behavior..."

python3 << 'PYTHON_EOF'
# Simulate and document the git submodule behavior
behavior_summary = """
When you run in parent repo:
  1. git submodule update --init src/content
     -> Stages the submodule pointer in parent's index to match .gitmodules

When you then cd INTO the submodule and run:
  2. git fetch origin main
  3. git checkout origin/main
     -> Changes the submodule's working tree and index
     -> DOES NOT update the parent repo's index

The parent repo's working tree SHOWS the new submodule SHA
(because you checked out a new commit in the working tree)
But the parent repo's INDEX still has the OLD SHA from step 1.

When git write-tree reads the parent repo's index, it captures the OLD SHA.

RESULT: The commit created has the old submodule SHA, not the new one.
"""

print(behavior_summary)
PYTHON_EOF

echo ""
echo "=== Verification: Check workflow again for explicit staging ==="
grep -n "git add\|git stage" ".github/workflows/update-content.yml" || echo "No explicit staging found"

Repository: peanutprotocol/peanut-ui

Length of output: 978


Stage src/content before git write-tree to capture the updated submodule SHA.

The step "Init and update submodule" runs git checkout origin/main inside src/content, but this updates only the submodule's working tree—not the parent repo's index. The parent index still holds the old submodule SHA from git submodule update --init. When git write-tree reads the index, it snapshots the old SHA, producing a commit that doesn't reflect the actual submodule update.

Proposed fix
               run: |
                   BRANCH="auto/update-content-$(date -u +%Y%m%d-%H%M%S)"
+                  git add src/content
                   TREE=$(git write-tree)
                   PARENT=$(git rev-parse HEAD)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/update-content.yml around lines 42 - 44, The commit
currently snapshots the parent index with the old submodule SHA because the
updated submodule working tree in src/content isn't staged before calling git
write-tree; after the "Init and update submodule" step and before the lines that
set BRANCH, TREE, and PARENT, stage the submodule update by running a git add of
src/content (i.e., update the parent index to the new submodule SHA), then
proceed to run git write-tree so TREE reflects the updated submodule SHA.

# create signed commit via GitHub API (verified signature)
COMMIT_SHA=$(gh api repos/${{ github.repository }}/git/commits \
--method POST \
-f message="Update content submodule to latest main" \
-f "tree=$TREE" \
-f "parents[]=$PARENT" \
--jq '.sha')
# create branch pointing to signed commit
gh api repos/${{ github.repository }}/git/refs \
--method POST \
-f "ref=refs/heads/$BRANCH" \
-f "sha=$COMMIT_SHA"
gh pr create \
--head "$BRANCH" \
--title "Update content submodule" \
--body "Auto-generated: updates content submodule to latest peanut-content main."
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,4 @@ public/swe-worker*

# mobile POC
android/
.claude/
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[submodule "src/assets/animations"]
path = src/assets/animations
url = https://github.com/peanutprotocol/peanut-animations.git
[submodule "src/content"]
path = src/content
url = https://github.com/peanutprotocol/peanut-content.git
branch = main
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# Peanut UI

[![Tests](https://github.com/peanutprotocol/peanut-ui/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/peanutprotocol/peanut-ui/actions/workflows/tests.yml)
[![CodeQL](https://github.com/peanutprotocol/peanut-ui/actions/workflows/github-code-scanning/codeql/badge.svg?branch=main)](https://github.com/peanutprotocol/peanut-ui/security/code-scanning)
[![Next.js](https://img.shields.io/badge/Next.js-16-black?logo=next.js)](https://nextjs.org/)
[![React](https://img.shields.io/badge/React-19-61DAFB?logo=react)](https://react.dev/)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.6-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
[![Tailwind CSS](https://img.shields.io/badge/Tailwind-4-06B6D4?logo=tailwindcss&logoColor=white)](https://tailwindcss.com/)
[![i18n](https://img.shields.io/badge/i18n-5_locales-blue)](https://peanut.me)
[![PWA Ready](https://img.shields.io/badge/PWA-ready-5A0FC8?logo=pwa)](https://peanut.me)

Live at: [peanut.me](https://peanut.me) | [staging.peanut.me](https://staging.peanut.me)

## Getting Started
Expand Down Expand Up @@ -68,3 +79,14 @@ describe('Bank Account Formatting', () => {
```

The CI pipeline runs tests on all PRs. Failed tests will block merging.

## Archived Branches

This repo previously hosted two other apps under the `peanut.to` domain. Both are now deprecated in favor of `peanut.me` (this branch). Their final states are preserved as tags:

| Tag | Was | Last commit | Notes |
|-----|-----|-------------|-------|
| `archive/peanut-to` | `main` → `peanut.to` | Nov 2025 | Link-based send/claim app, cashout, SDK pages |
| `archive/legacy-peanut-to` | `legacy` → `legacy.peanut.to` | Mar 2025 | Batch send, raffles, leaderboard |

To browse the old code: `git checkout archive/peanut-to`
6 changes: 2 additions & 4 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
const os = require('os')
const { execSync } = require('child_process')
const withBundleAnalyzer = require('@next/bundle-analyzer')({
// Only enable in production builds when explicitly requested
enabled: process.env.ANALYZE === 'true' && process.env.NODE_ENV !== 'development',
})
const withBundleAnalyzer =
process.env.ANALYZE === 'true' ? require('@next/bundle-analyzer')({ enabled: true }) : (config) => config

const redirectsConfig = require('./redirects.json')

Expand Down
11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
"test:e2e:headed": "playwright test --headed",
"script": "NODE_OPTIONS=\"--experimental-json-modules\" tsx"
"script": "NODE_OPTIONS=\"--experimental-json-modules\" tsx",
"validate-content": "tsx scripts/validate-content.ts",
"validate-links": "tsx scripts/validate-links.ts"
},
"dependencies": {
"@dicebear/collection": "^9.2.2",
Expand Down Expand Up @@ -52,19 +54,22 @@
"@vercel/analytics": "^1.4.1",
"@wagmi/core": "2.19.0",
"@zerodev/passkey-validator": "^5.6.0",
"@zerodev/sdk": "5.5.0",
"@zerodev/sdk": "5.5.7",
"autoprefixer": "^10.4.20",
"canvas-confetti": "^1.9.3",
"classnames": "^2.5.1",
"d3-force": "^3.0.0",
"embla-carousel-react": "^8.6.0",
"ethers": "5.7.2",
"framer-motion": "^11.11.17",
"gray-matter": "^4.0.3",
"i18n-iso-countries": "^7.13.0",
"iban-to-bic": "^1.4.0",
"js-cookie": "^3.0.5",
"jsqr": "^1.4.0",
"marked": "^17.0.2",
"next": "16.0.10",
"next-mdx-remote": "^6.0.0",
"nuqs": "^2.8.6",
"pix-utils": "^2.8.2",
"pulltorefreshjs": "^0.1.22",
Expand All @@ -79,6 +84,8 @@
"react-redux": "^9.2.0",
"react-tooltip": "^5.28.0",
"redux": "^5.0.1",
"remark-gfm": "^4.0.1",
"shiki": "^3.22.0",
"siwe": "^2.3.2",
"tailwind-merge": "^1.14.0",
"tailwind-scrollbar": "^3.1.0",
Expand Down
Loading
Loading