add safe area

This commit is contained in:
Tony D'Addeo 2024-12-23 12:18:38 -06:00 committed by lucas-neynar
parent 11faa1a25d
commit 7cde86a049
No known key found for this signature in database
3 changed files with 227 additions and 196 deletions

View File

@ -12,7 +12,7 @@
"@farcaster/auth-kit": "^0.6.0", "@farcaster/auth-kit": "^0.6.0",
"@farcaster/frame-core": "^0.0.19", "@farcaster/frame-core": "^0.0.19",
"@farcaster/frame-node": "^0.0.7", "@farcaster/frame-node": "^0.0.7",
"@farcaster/frame-sdk": "^0.0.20", "@farcaster/frame-sdk": "^0.0.21",
"@farcaster/frame-wagmi-connector": "^0.0.6", "@farcaster/frame-wagmi-connector": "^0.0.6",
"@tanstack/react-query": "^5.61.0", "@tanstack/react-query": "^5.61.0",
"@upstash/redis": "^1.34.3", "@upstash/redis": "^1.34.3",

View File

@ -243,204 +243,211 @@ export default function Demo(
} }
return ( return (
<div className="w-[300px] mx-auto py-4 px-2"> <div style={{
<h1 className="text-2xl font-bold text-center mb-4">{title}</h1> paddingTop: context?.client.safeAreaInsets?.top ?? 0,
paddingBottom: context?.client.safeAreaInsets?.bottom ?? 0,
paddingLeft: context?.client.safeAreaInsets?.left ?? 0,
paddingRight: context?.client.safeAreaInsets?.right ?? 0 ,
}}>
<div className="w-[300px] mx-auto py-2 px-2">
<h1 className="text-2xl font-bold text-center mb-4">{title}</h1>
<div className="mb-4"> <div className="mb-4">
<h2 className="font-2xl font-bold">Context</h2> <h2 className="font-2xl font-bold">Context</h2>
<button <button
onClick={toggleContext} onClick={toggleContext}
className="flex items-center gap-2 transition-colors" className="flex items-center gap-2 transition-colors"
>
<span
className={`transform transition-transform ${
isContextOpen ? "rotate-90" : ""
}`}
> >
<span
</span> className={`transform transition-transform ${
Tap to expand isContextOpen ? "rotate-90" : ""
</button> }`}
>
</span>
Tap to expand
</button>
{isContextOpen && ( {isContextOpen && (
<div className="p-4 mt-2 bg-gray-100 dark:bg-gray-800 rounded-lg"> <div className="p-4 mt-2 bg-gray-100 dark:bg-gray-800 rounded-lg">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-"> <pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
{JSON.stringify(context, null, 2)} {JSON.stringify(context, null, 2)}
</pre> </pre>
</div>
)}
</div>
<div>
<h2 className="font-2xl font-bold">Actions</h2>
<div className="mb-4">
<div className="p-2 bg-gray-100 dark:bg-gray-800 rounded-lg my-2">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
sdk.actions.signIn
</pre>
</div>
<SignIn />
</div>
<div className="mb-4">
<div className="p-2 bg-gray-100 dark:bg-gray-800 rounded-lg my-2">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
sdk.actions.openUrl
</pre>
</div>
<Button onClick={openUrl}>Open Link</Button>
</div>
<div className="mb-4">
<div className="p-2 bg-gray-100 dark:bg-gray-800 rounded-lg my-2">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
sdk.actions.openUrl
</pre>
</div>
<Button onClick={openWarpcastUrl}>Open Warpcast Link</Button>
</div>
<div className="mb-4">
<div className="p-2 bg-gray-100 dark:bg-gray-800 rounded-lg my-2">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
sdk.actions.close
</pre>
</div>
<Button onClick={close}>Close Frame</Button>
</div>
</div>
<div className="mb-4">
<h2 className="font-2xl font-bold">Last event</h2>
<div className="p-4 mt-2 bg-gray-100 dark:bg-gray-800 rounded-lg">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
{lastEvent || "none"}
</pre>
</div>
</div>
<div>
<h2 className="font-2xl font-bold">Add to client & notifications</h2>
<div className="mt-2 mb-4 text-sm">
Client fid {context?.client.clientFid},
{added ? " frame added to client," : " frame not added to client,"}
{notificationDetails
? " notifications enabled"
: " notifications disabled"}
</div>
<div className="mb-4">
<div className="p-2 bg-gray-100 dark:bg-gray-800 rounded-lg my-2">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
sdk.actions.addFrame
</pre>
</div>
{addFrameResult && (
<div className="mb-2 text-sm">
Add frame result: {addFrameResult}
</div> </div>
)} )}
<Button onClick={addFrame} disabled={added}>
Add frame to client
</Button>
</div> </div>
{sendNotificationResult && ( <div>
<div className="mb-2 text-sm"> <h2 className="font-2xl font-bold">Actions</h2>
Send notification result: {sendNotificationResult}
</div>
)}
<div className="mb-4">
<Button onClick={sendNotification} disabled={!notificationDetails}>
Send notification
</Button>
</div>
</div>
<div> <div className="mb-4">
<h2 className="font-2xl font-bold">Wallet</h2> <div className="p-2 bg-gray-100 dark:bg-gray-800 rounded-lg my-2">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
{address && ( sdk.actions.signIn
<div className="my-2 text-xs"> </pre>
Address: <pre className="inline">{truncateAddress(address)}</pre>
</div>
)}
{chainId && (
<div className="my-2 text-xs">
Chain ID: <pre className="inline">{chainId}</pre>
</div>
)}
<div className="mb-4">
<Button
onClick={() =>
isConnected
? disconnect()
: connect({ connector: config.connectors[0] })
}
>
{isConnected ? "Disconnect" : "Connect"}
</Button>
</div>
<div className="mb-4">
<SignMessage />
</div>
{isConnected && (
<>
<div className="mb-4">
<SendEth />
</div> </div>
<div className="mb-4"> <SignIn />
<Button </div>
onClick={sendTx}
disabled={!isConnected || isSendTxPending} <div className="mb-4">
isLoading={isSendTxPending} <div className="p-2 bg-gray-100 dark:bg-gray-800 rounded-lg my-2">
> <pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
Send Transaction (contract) sdk.actions.openUrl
</Button> </pre>
{isSendTxError && renderError(sendTxError)} </div>
{txHash && ( <Button onClick={openUrl}>Open Link</Button>
<div className="mt-2 text-xs"> </div>
<div>Hash: {truncateAddress(txHash)}</div>
<div> <div className="mb-4">
Status:{" "} <div className="p-2 bg-gray-100 dark:bg-gray-800 rounded-lg my-2">
{isConfirming <pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
? "Confirming..." sdk.actions.openUrl
: isConfirmed </pre>
? "Confirmed!" </div>
: "Pending"} <Button onClick={openWarpcastUrl}>Open Warpcast Link</Button>
</div>
<div className="mb-4">
<div className="p-2 bg-gray-100 dark:bg-gray-800 rounded-lg my-2">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
sdk.actions.close
</pre>
</div>
<Button onClick={close}>Close Frame</Button>
</div>
</div>
<div className="mb-4">
<h2 className="font-2xl font-bold">Last event</h2>
<div className="p-4 mt-2 bg-gray-100 dark:bg-gray-800 rounded-lg">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
{lastEvent || "none"}
</pre>
</div>
</div>
<div>
<h2 className="font-2xl font-bold">Add to client & notifications</h2>
<div className="mt-2 mb-4 text-sm">
Client fid {context?.client.clientFid},
{added ? " frame added to client," : " frame not added to client,"}
{notificationDetails
? " notifications enabled"
: " notifications disabled"}
</div>
<div className="mb-4">
<div className="p-2 bg-gray-100 dark:bg-gray-800 rounded-lg my-2">
<pre className="font-mono text-xs whitespace-pre-wrap break-words max-w-[260px] overflow-x-">
sdk.actions.addFrame
</pre>
</div>
{addFrameResult && (
<div className="mb-2 text-sm">
Add frame result: {addFrameResult}
</div>
)}
<Button onClick={addFrame} disabled={added}>
Add frame to client
</Button>
</div>
{sendNotificationResult && (
<div className="mb-2 text-sm">
Send notification result: {sendNotificationResult}
</div>
)}
<div className="mb-4">
<Button onClick={sendNotification} disabled={!notificationDetails}>
Send notification
</Button>
</div>
</div>
<div>
<h2 className="font-2xl font-bold">Wallet</h2>
{address && (
<div className="my-2 text-xs">
Address: <pre className="inline">{truncateAddress(address)}</pre>
</div>
)}
{chainId && (
<div className="my-2 text-xs">
Chain ID: <pre className="inline">{chainId}</pre>
</div>
)}
<div className="mb-4">
<Button
onClick={() =>
isConnected
? disconnect()
: connect({ connector: config.connectors[0] })
}
>
{isConnected ? "Disconnect" : "Connect"}
</Button>
</div>
<div className="mb-4">
<SignMessage />
</div>
{isConnected && (
<>
<div className="mb-4">
<SendEth />
</div>
<div className="mb-4">
<Button
onClick={sendTx}
disabled={!isConnected || isSendTxPending}
isLoading={isSendTxPending}
>
Send Transaction (contract)
</Button>
{isSendTxError && renderError(sendTxError)}
{txHash && (
<div className="mt-2 text-xs">
<div>Hash: {truncateAddress(txHash)}</div>
<div>
Status:{" "}
{isConfirming
? "Confirming..."
: isConfirmed
? "Confirmed!"
: "Pending"}
</div>
</div> </div>
</div> )}
)} </div>
</div> <div className="mb-4">
<div className="mb-4"> <Button
<Button onClick={signTyped}
onClick={signTyped} disabled={!isConnected || isSignTypedPending}
disabled={!isConnected || isSignTypedPending} isLoading={isSignTypedPending}
isLoading={isSignTypedPending} >
> Sign Typed Data
Sign Typed Data </Button>
</Button> {isSignTypedError && renderError(signTypedError)}
{isSignTypedError && renderError(signTypedError)} </div>
</div> <div className="mb-4">
<div className="mb-4"> <Button
<Button onClick={handleSwitchChain}
onClick={handleSwitchChain} disabled={isSwitchChainPending}
disabled={isSwitchChainPending} isLoading={isSwitchChainPending}
isLoading={isSwitchChainPending} >
> Switch to {chainId === base.id ? "Optimism" : "Base"}
Switch to {chainId === base.id ? "Optimism" : "Base"} </Button>
</Button> {isSwitchChainError && renderError(switchChainError)}
{isSwitchChainError && renderError(switchChainError)} </div>
</div> </>
</> )}
)} </div>
</div> </div>
</div> </div>
); );

View File

@ -134,6 +134,14 @@
qrcode "^1.5.3" qrcode "^1.5.3"
react-remove-scroll "^2.5.7" react-remove-scroll "^2.5.7"
"@farcaster/frame-core@0.0.20":
version "0.0.20"
resolved "https://registry.yarnpkg.com/@farcaster/frame-core/-/frame-core-0.0.20.tgz#2e872db2d17b20d12d602510b5dc6dfb39e942b6"
integrity sha512-MMHMy/wSFpCThJKaX+MKGZTZeAPDEMD2uXMsfRlQ/DrLtfWR7R8NuOjoPLGaipmPVNTzIBJm4BJ0+71zitdSGQ==
dependencies:
ox "^0.4.0"
zod "^3.23.8"
"@farcaster/frame-core@^0.0.19": "@farcaster/frame-core@^0.0.19":
version "0.0.19" version "0.0.19"
resolved "https://registry.yarnpkg.com/@farcaster/frame-core/-/frame-core-0.0.19.tgz#76621fe6e207c3a5c78a22aa679bbbd7beafdd11" resolved "https://registry.yarnpkg.com/@farcaster/frame-core/-/frame-core-0.0.19.tgz#76621fe6e207c3a5c78a22aa679bbbd7beafdd11"
@ -150,12 +158,12 @@
"@farcaster/frame-core" "^0.0.19" "@farcaster/frame-core" "^0.0.19"
ox "^0.4.0" ox "^0.4.0"
"@farcaster/frame-sdk@^0.0.20": "@farcaster/frame-sdk@^0.0.21":
version "0.0.20" version "0.0.21"
resolved "https://registry.yarnpkg.com/@farcaster/frame-sdk/-/frame-sdk-0.0.20.tgz#253dba9a1aba23c63e01617720835fe6b2b0880b" resolved "https://registry.yarnpkg.com/@farcaster/frame-sdk/-/frame-sdk-0.0.21.tgz#f5d595003c5e88233cdf63e3793a35c4d6617413"
integrity sha512-9EbB3A9V1ZSH4NvhHVbylcDVNevJqpuGkwz4I+0bKF2936qxvMlcWclDZVEmfO/woYH0ZQgy47YYRIiS3YpIQw== integrity sha512-FaeHdaIRQP6VqBtnwcrgggWcE+a/0hWzuIpp5NcnfYvo8a1JMpkOXspWFAa3fYfCyl9Dm9QF6jXt+T5tiALsPQ==
dependencies: dependencies:
"@farcaster/frame-core" "^0.0.19" "@farcaster/frame-core" "0.0.20"
comlink "^4.4.2" comlink "^4.4.2"
eventemitter3 "^5.0.1" eventemitter3 "^5.0.1"
ox "^0.4.0" ox "^0.4.0"
@ -4838,7 +4846,16 @@ strict-uri-encode@^2.0.0:
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0: "string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^4.1.0, string-width@^4.2.0:
version "4.2.3" version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -4933,7 +4950,14 @@ string_decoder@~1.1.1:
dependencies: dependencies:
safe-buffer "~5.1.0" safe-buffer "~5.1.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: "strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==