Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion go/http/evm_paywall_template.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion go/http/svm_paywall_template.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion python/x402/http/paywall/evm_paywall_template.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion python/x402/http/paywall/svm_paywall_template.py

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions typescript/packages/http/paywall/src/IntroAnimation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function IntroAnimation({ children }: { children: React.ReactNode }) {
return <>{children}</>;
}
43 changes: 32 additions & 11 deletions typescript/packages/http/paywall/src/PaywallApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,22 @@ export function PaywallApp() {

if (!paymentRequired || !paymentRequired.accepts || paymentRequired.accepts.length === 0) {
return (
<div className="container">
<div className="header">
<h1 className="title">Payment Required</h1>
<p className="subtitle">Loading payment details...</p>
<div className="paywall-page">
<div className="card">
<div className="card-body">
<div className="amount-section">
<div className="amount-value">...</div>
<div className="amount-asset">Loading payment details</div>
</div>
</div>
<div className="card-footer">
<span className="powered-by">
Powered by{" "}
<a href="https://x402.org" target="_blank" rel="noopener noreferrer">
x402
</a>
</span>
</div>
</div>
</div>
);
Expand Down Expand Up @@ -59,13 +71,22 @@ export function PaywallApp() {
}

return (
<div className="container">
<div className="header">
<h1 className="title">Payment Required</h1>
<p className="subtitle">
Unsupported network configuration for this paywall. Please contact the application
developer.
</p>
<div className="paywall-page">
<div className="card">
<div className="card-body">
<div className="amount-section">
<div className="amount-value">Unsupported network</div>
<div className="amount-asset">Please contact the application developer.</div>
</div>
</div>
<div className="card-footer">
<span className="powered-by">
Powered by{" "}
<a href="https://x402.org" target="_blank" rel="noopener noreferrer">
x402
</a>
</span>
</div>
</div>
</div>
);
Expand Down
75 changes: 75 additions & 0 deletions typescript/packages/http/paywall/src/WalletSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useEffect, useMemo, useRef, useState } from "react";

type WalletSelectOption = {
value: string;
label: string;
};

type WalletSelectProps = {
value: string;
onChange: (value: string) => void;
options: WalletSelectOption[];
placeholder?: string;
};

export function WalletSelect({
value,
onChange,
options,
placeholder = "Select a wallet",
}: WalletSelectProps) {
const [isOpen, setIsOpen] = useState(false);
const containerRef = useRef<HTMLDivElement | null>(null);

const selectedOption = useMemo(
() => options.find(option => option.value === value),
[options, value],
);

useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (!containerRef.current) {
return;
}
if (!containerRef.current.contains(event.target as Node)) {
setIsOpen(false);
}
}

document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);

return (
<div className="wallet-select" ref={containerRef}>
<button
type="button"
className="input wallet-select-trigger"
aria-haspopup="listbox"
aria-expanded={isOpen}
onClick={() => setIsOpen(prev => !prev)}
>
<span>{selectedOption?.label || placeholder}</span>
</button>
{isOpen && (
<div className="wallet-select-menu" role="listbox">
{options.map(option => (
<button
key={option.value}
type="button"
role="option"
aria-selected={option.value === value}
className={`wallet-select-option ${option.value === value ? "selected" : ""}`}
onClick={() => {
onChange(option.value);
setIsOpen(false);
}}
>
{option.label}
</button>
))}
</div>
)}
</div>
);
}
4 changes: 4 additions & 0 deletions typescript/packages/http/paywall/src/baseTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export function getBaseTemplate(): string {
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<title>Payment Required</title>
</head>
<body>
<div id="root"></div>
Expand Down
Loading
Loading