From 06f31cc20255110c18abf23c5ffdaca18b942a61 Mon Sep 17 00:00:00 2001 From: Madeleine Charity Date: Mon, 23 Feb 2026 12:10:21 -0500 Subject: [PATCH] Update x402 agent demo to use Privy design language Migrate the x402 agent demo from ad-hoc violet/offblack color scheme to the canonical Privy design system extracted from privy-next-starter. - Replace violet (#8B5CF6) with Privy primary (#5B4FFF) - Replace offblack (#0f0f10) buttons with #5B4FFF/#4A3EE6 - Standardize borders to #E2E3F0, highlight bgs to #E0E7FF - Add .button-primary, .button-outline, .button classes to globals.css - Load Inter font via next/font/google - Update CLAUDE.md styling conventions Co-Authored-By: Claude Opus 4.6 Committed-By-Agent: claude --- examples/privy-next-x402-agent-demo/CLAUDE.md | 9 +- .../app/agent/[id]/fund/page.tsx | 78 ++++---- .../app/agent/[id]/page.tsx | 26 +-- .../app/agent/[id]/policy/page.tsx | 36 ++-- .../app/globals.css | 175 +++++++----------- .../privy-next-x402-agent-demo/app/layout.tsx | 9 +- .../privy-next-x402-agent-demo/app/page.tsx | 69 ++++--- .../components/ActionCard.tsx | 8 +- .../components/AgentCard.tsx | 12 +- .../components/StepIndicator.tsx | 10 +- 10 files changed, 198 insertions(+), 234 deletions(-) diff --git a/examples/privy-next-x402-agent-demo/CLAUDE.md b/examples/privy-next-x402-agent-demo/CLAUDE.md index 81b7401..99f7a19 100644 --- a/examples/privy-next-x402-agent-demo/CLAUDE.md +++ b/examples/privy-next-x402-agent-demo/CLAUDE.md @@ -163,9 +163,12 @@ NEXT_PUBLIC_BASE_URL=http://localhost:3000 ## Styling Conventions -- Uses Privy brand colors: violet (`#8B5CF6`), offblack (`#0f0f10`) -- Tailwind for layout and spacing -- Card-based UI with subtle shadows and hover effects +- Uses Privy brand colors: primary (`#5B4FFF`), hover (`#4A3EE6`), active (`#3F35D9`) +- Borders: `#E2E3F0`, highlight backgrounds: `#E0E7FF`, code/info backgrounds: `#F1F2F9` +- Three button classes defined in globals.css: `.button-primary`, `.button-outline`, `.button` +- Font: Inter via `next/font/google` +- Tailwind CSS v4 for layout and spacing +- Card-based UI with rounded-2xl corners and subtle hover effects ## API Route Patterns diff --git a/examples/privy-next-x402-agent-demo/app/agent/[id]/fund/page.tsx b/examples/privy-next-x402-agent-demo/app/agent/[id]/fund/page.tsx index cf197d1..dda66d5 100644 --- a/examples/privy-next-x402-agent-demo/app/agent/[id]/fund/page.tsx +++ b/examples/privy-next-x402-agent-demo/app/agent/[id]/fund/page.tsx @@ -1,9 +1,9 @@ -'use client'; +"use client"; -import { useEffect, useState } from 'react'; -import { useRouter, useParams } from 'next/navigation'; -import { Logo } from '@/components/Logo'; -import { StepIndicator, WIZARD_STEPS } from '@/components/StepIndicator'; +import { useEffect, useState } from "react"; +import { useRouter, useParams } from "next/navigation"; +import { Logo } from "@/components/Logo"; +import { StepIndicator, WIZARD_STEPS } from "@/components/StepIndicator"; interface Agent { id: string; @@ -20,9 +20,9 @@ interface Agent { } const FUNDING_OPTIONS = [ - { amount: 0.10, label: '$0.10', description: 'Light usage' }, - { amount: 0.50, label: '$0.50', description: 'Recommended' }, - { amount: 1, label: '$1', description: 'Heavy usage' }, + { amount: 0.1, label: "$0.10", description: "Light usage" }, + { amount: 0.5, label: "$0.50", description: "Recommended" }, + { amount: 1, label: "$1", description: "Heavy usage" }, ]; export default function FundStep() { @@ -34,14 +34,14 @@ export default function FundStep() { const [error, setError] = useState(null); useEffect(() => { - const storedAgent = sessionStorage.getItem('agent'); + const storedAgent = sessionStorage.getItem("agent"); if (!storedAgent) { - router.push('/'); + router.push("/"); return; } const parsedAgent = JSON.parse(storedAgent); if (parsedAgent.id !== params.id) { - router.push('/'); + router.push("/"); return; } setAgent(parsedAgent); @@ -54,9 +54,9 @@ export default function FundStep() { setError(null); try { - const response = await fetch('/api/agent/fund', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, + const response = await fetch("/api/agent/fund", { + method: "POST", + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ walletAddress: agent.wallet.address, amount: selectedAmount, @@ -66,7 +66,7 @@ export default function FundStep() { const data = await response.json(); if (!data.success) { - throw new Error(data.error || 'Failed to fund wallet'); + throw new Error(data.error || "Failed to fund wallet"); } // Update agent balance (convert USD to cents) @@ -74,12 +74,12 @@ export default function FundStep() { ...agent, balance: agent.balance + selectedAmount * 100, }; - sessionStorage.setItem('agent', JSON.stringify(updatedAgent)); + sessionStorage.setItem("agent", JSON.stringify(updatedAgent)); // Navigate to policy step router.push(`/agent/${agent.id}/policy`); } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to fund wallet'); + setError(err instanceof Error ? err.message : "Failed to fund wallet"); setIsLoading(false); } }; @@ -87,7 +87,7 @@ export default function FundStep() { if (!agent) { return (
-
+
); } @@ -95,7 +95,7 @@ export default function FundStep() { return (
{/* Header */} -
+
@@ -103,7 +103,7 @@ export default function FundStep() { href="https://docs.privy.io" target="_blank" rel="noopener noreferrer" - className="text-sm text-slate-600 hover:text-slate-900" + className="text-sm text-[#5B4FFF]" > Docs @@ -111,7 +111,7 @@ export default function FundStep() { href="https://docs.privy.io/recipes/x402" target="_blank" rel="noopener noreferrer" - className="text-sm text-slate-600 hover:text-slate-900" + className="text-sm text-[#5B4FFF]" > x402 → @@ -124,7 +124,7 @@ export default function FundStep() {
-
+
{/* Wallet info */} -
+
-
+
Agent Wallet
- {agent.wallet.address.slice(0, 6)}...{agent.wallet.address.slice(-4)} + {agent.wallet.address.slice(0, 6)}... + {agent.wallet.address.slice(-4)}
@@ -185,18 +186,22 @@ export default function FundStep() { onClick={() => setSelectedAmount(option.amount)} className={`relative rounded-2xl border-2 p-6 text-center transition-all ${ selectedAmount === option.amount - ? 'border-violet-500 bg-violet-50 shadow-lg' - : 'border-slate-200 bg-white hover:border-slate-300 hover:shadow-md' + ? "border-[#5B4FFF] bg-[#E0E7FF] shadow-lg" + : "border-[#E2E3F0] bg-white hover:border-gray-300 hover:shadow-md" }`} > - {option.description === 'Recommended' && ( -
+ {option.description === "Recommended" && ( +
Popular
)} -
{option.label}
+
+ {option.label} +
USDC
-
{option.description}
+
+ {option.description} +
))}
@@ -211,15 +216,15 @@ export default function FundStep() { {/* Actions */}
- - {/* Info note */} -

- Funds are transferred from a demo treasury. No real USDC is involved. -

); diff --git a/examples/privy-next-x402-agent-demo/app/agent/[id]/page.tsx b/examples/privy-next-x402-agent-demo/app/agent/[id]/page.tsx index 87c2c5c..a9b09d7 100644 --- a/examples/privy-next-x402-agent-demo/app/agent/[id]/page.tsx +++ b/examples/privy-next-x402-agent-demo/app/agent/[id]/page.tsx @@ -113,7 +113,7 @@ export default function ActionsStep() { if (!agent) { return (
-
+
); } @@ -121,7 +121,7 @@ export default function ActionsStep() { return (
{/* Header */} -
+
{useCustom && ( -
+
@@ -274,7 +274,7 @@ export default function PolicyStep() { placeholder="0.00" min="0.01" step="0.01" - className="w-full rounded-xl border border-slate-200 py-3 pl-8 pr-4 text-lg focus:border-violet-500 focus:outline-none focus:ring-2 focus:ring-violet-500/20" + className="w-full rounded-xl border border-[#E2E3F0] py-3 pl-8 pr-4 text-lg focus:border-[#5B4FFF] focus:outline-none focus:ring-2 focus:ring-[#5B4FFF]/20" />
@@ -283,7 +283,7 @@ export default function PolicyStep() {
{/* Policy preview */} -
+

Policy summary

@@ -360,14 +360,14 @@ export default function PolicyStep() { - {error && ( -

{error}

- )} + {error &&

{error}

}
- - {/* Demo note */} -

- This is a demo using testnet USDC. No real funds are involved. -

{/* Footer */} -