feat: add support for back button and haptics

This commit is contained in:
veganbeef 2025-06-23 12:05:13 -07:00
parent f97a697f88
commit e349724267
No known key found for this signature in database
5 changed files with 51 additions and 12 deletions

View File

@ -347,7 +347,7 @@ export async function init() {
"@farcaster/frame-sdk": ">=0.0.31 <1.0.0",
"@farcaster/frame-wagmi-connector": ">=0.0.19 <1.0.0",
"@farcaster/mini-app-solana": ">=0.0.17 <1.0.0",
"@neynar/react": "^1.2.2",
"@neynar/react": "^1.2.5",
"@radix-ui/react-label": "^2.1.1",
"@solana/wallet-adapter-react": "^0.15.38",
"@tanstack/react-query": "^5.61.0",

View File

@ -1,6 +1,6 @@
{
"name": "@neynar/create-farcaster-mini-app",
"version": "1.4.0",
"version": "1.4.1",
"type": "module",
"private": false,
"access": "public",

View File

@ -18,7 +18,7 @@ export function Providers({ session, children }: { session: Session | null, chil
return (
<SessionProvider session={session}>
<WagmiProvider>
<MiniAppProvider analyticsEnabled={true}>
<MiniAppProvider analyticsEnabled={true} backButtonEnabled={true}>
<SafeFarcasterSolanaProvider endpoint={solanaEndpoint}>
{children}
</SafeFarcasterSolanaProvider>

View File

@ -5,6 +5,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
import { signIn, signOut, getCsrfToken } from "next-auth/react";
import sdk, {
SignIn as SignInCore,
type Haptics,
} from "@farcaster/frame-sdk";
import {
useAccount,
@ -52,13 +53,17 @@ export default function Demo(
added,
notificationDetails,
actions,
setInitialTab,
setActiveTab,
currentTab,
haptics,
} = useMiniApp();
const [isContextOpen, setIsContextOpen] = useState(false);
const [activeTab, setActiveTab] = useState<Tab>('home');
const [txHash, setTxHash] = useState<string | null>(null);
const [sendNotificationResult, setSendNotificationResult] = useState("");
const [copied, setCopied] = useState(false);
const [neynarUser, setNeynarUser] = useState<NeynarUser | null>(null);
const [hapticIntensity, setHapticIntensity] = useState<Haptics.ImpactOccurredType>('medium');
const { address, isConnected } = useAccount();
const chainId = useChainId();
@ -66,6 +71,13 @@ export default function Demo(
const solanaWallet = useSolanaWallet();
const { publicKey: solanaPublicKey } = solanaWallet;
// Set initial tab to home on page load
useEffect(() => {
if (isSDKLoaded) {
setInitialTab('home');
}
}, [isSDKLoaded, setInitialTab]);
useEffect(() => {
console.log("isSDKLoaded", isSDKLoaded);
console.log("context", context);
@ -226,7 +238,7 @@ export default function Demo(
<h1 className="text-2xl font-bold text-center mb-4">{title}</h1>
{activeTab === 'home' && (
{currentTab === 'home' && (
<div className="flex items-center justify-center h-[calc(100vh-200px)] px-6">
<div className="text-center w-full max-w-md mx-auto">
<p className="text-lg mb-2">Put your content here!</p>
@ -235,7 +247,7 @@ export default function Demo(
</div>
)}
{activeTab === 'actions' && (
{currentTab === 'actions' && (
<div className="space-y-3 px-6 w-full max-w-md mx-auto">
<ShareButton
buttonText="Share Mini App"
@ -251,8 +263,6 @@ export default function Demo(
<Button onClick={() => actions.openUrl("https://www.youtube.com/watch?v=dQw4w9WgXcQ")} className="w-full">Open Link</Button>
<Button onClick={actions.close} className="w-full">Close Mini App</Button>
<Button onClick={actions.addMiniApp} disabled={added} className="w-full">
Add Mini App to Client
</Button>
@ -280,10 +290,39 @@ export default function Demo(
>
{copied ? "Copied!" : "Copy share URL"}
</Button>
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
Haptic Intensity
</label>
<select
value={hapticIntensity}
onChange={(e) => setHapticIntensity(e.target.value as typeof hapticIntensity)}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-purple-500"
>
<option value="light">Light</option>
<option value="medium">Medium</option>
<option value="heavy">Heavy</option>
<option value="soft">Soft</option>
<option value="rigid">Rigid</option>
</select>
<Button
onClick={async () => {
try {
await haptics.impactOccurred(hapticIntensity);
} catch (error) {
console.error('Haptic feedback failed:', error);
}
}}
className="w-full"
>
Trigger Haptic Feedback
</Button>
</div>
</div>
)}
{activeTab === 'context' && (
{currentTab === 'context' && (
<div className="mx-6">
<h2 className="text-lg font-semibold mb-2">Context</h2>
<div className="p-4 bg-gray-100 dark:bg-gray-800 rounded-lg">
@ -294,7 +333,7 @@ export default function Demo(
</div>
)}
{activeTab === 'wallet' && USE_WALLET && (
{currentTab === 'wallet' && USE_WALLET && (
<div className="space-y-3 px-6 w-full max-w-md mx-auto">
{address && (
<div className="text-xs w-full">
@ -389,7 +428,7 @@ export default function Demo(
</div>
)}
<Footer activeTab={activeTab} setActiveTab={setActiveTab} showWallet={USE_WALLET} />
<Footer activeTab={currentTab as Tab} setActiveTab={setActiveTab} showWallet={USE_WALLET} />
</div>
</div>
);

View File

@ -97,7 +97,7 @@ export function ShareButton({ buttonText, cast, className = '', isLoading = fals
parent: cast.parent,
channelKey: cast.channelKey,
close: cast.close,
}, 'share-button');
});
} catch (error) {
console.error('Failed to share:', error);
} finally {