feat: ask for splash image url

This commit is contained in:
lucas-neynar 2025-03-13 14:07:55 -07:00
parent 853c63e024
commit 3186cb7fc8
No known key found for this signature in database
9 changed files with 29 additions and 226 deletions

View File

@ -38,6 +38,24 @@ async function init() {
return true;
}
},
{
type: 'input',
name: 'buttonText',
message: 'Enter the button text for your frame:',
default: 'Launch Frame',
validate: (input) => {
if (input.trim() === '') {
return 'Button text cannot be empty';
}
return true;
}
},
{
type: 'input',
name: 'splashImageUrl',
message: 'Enter the URL for your splash image\n(optional -- leave blank to use the default public/splash.png image or replace public/splash.png with your own)\n\nExternal splash image URL:',
default: null
},
{
type: 'password',
name: 'seedPhrase',
@ -92,9 +110,11 @@ async function init() {
const envExampleContent = fs.readFileSync(envExamplePath, 'utf8');
// Write it to .env
fs.writeFileSync(envPath, envExampleContent);
// Append project name and description to .env
// Append project name, description, and button text to .env
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_NAME="${answers.projectName}"`);
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_DESCRIPTION="${answers.description}"`);
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_BUTTON_TEXT="${answers.buttonText}"`);
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_SPLASH_IMAGE_URL="${answers.splashImageUrl}"`);
fs.unlinkSync(envExamplePath);
console.log('\nCreated .env file from .env.example');
} else {
@ -138,7 +158,7 @@ async function init() {
execSync('git add .', { cwd: projectPath });
execSync('git commit -m "initial commit from frames-v2-quickstart"', { cwd: projectPath });
console.log(`\n🪐 ✨ Successfully created frame ${projectName} with git and dependencies installed! ✨🪐`);
console.log(`\n🪐✨ Successfully created frame ${projectName} with git and dependencies installed! ✨🪐`);
console.log('\nTo run the app:');
console.log(` cd ${projectName}`);
console.log(' npm run dev\n');

View File

@ -3,6 +3,7 @@ import { join } from 'path';
export async function GET() {
const appUrl = process.env.NEXT_PUBLIC_URL;
const splashImageUrl = process.env.NEXT_PUBLIC_FRAME_SPLASH_IMAGE_URL || `${appUrl}/splash.png`;
let accountAssociation; // TODO: add type
try {
@ -22,8 +23,8 @@ export async function GET() {
iconUrl: `${appUrl}/icon.png`,
homeUrl: appUrl,
imageUrl: `${appUrl}/frames/hello/opengraph-image`,
buttonTitle: "Launch Frame",
splashImageUrl: `${appUrl}/splash.png`,
buttonTitle: process.env.NEXT_PUBLIC_FRAME_BUTTON_TEXT || "Launch Frame",
splashImageUrl,
splashBackgroundColor: "#f7f7f7",
webhookUrl: `${appUrl}/api/webhook`,
},

View File

@ -1,32 +0,0 @@
import { ImageResponse } from "next/og";
export const runtime = "edge";
export const alt = "Hello Frame";
export const size = {
width: 600,
height: 400,
};
export const contentType = "image/png";
interface Props {
params: Promise<{
name: string;
}>;
}
export default async function Image({ params }: Props) {
const { name } = await params;
return new ImageResponse(
(
<div tw="h-full w-full flex flex-col justify-center items-center relative bg-white">
<h1 tw="text-6xl">Hello, {name}</h1>
</div>
),
{
...size,
}
);
}

View File

@ -1,47 +0,0 @@
import { Metadata } from "next";
import App from "~/app/app";
const appUrl = process.env.NEXT_PUBLIC_URL;
interface Props {
params: Promise<{
name: string;
}>;
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { name } = await params;
const frame = {
version: "next",
imageUrl: `${appUrl}/frames/hello/${name}/opengraph-image`,
button: {
title: "Launch Frame",
action: {
type: "launch_frame",
name: process.env.NEXT_PUBLIC_FRAME_NAME || "Frames v2 Demo",
url: `${appUrl}/frames/hello/${name}/`,
splashImageUrl: `${appUrl}/splash.png`,
splashBackgroundColor: "#f7f7f7",
},
},
};
return {
title: `Hello, ${name}`,
description: `A personalized hello frame for ${name}`,
openGraph: {
title: `Hello, ${name}`,
description: `A personalized hello frame for ${name}`,
},
other: {
"fc:frame": JSON.stringify(frame),
},
};
}
export default async function HelloNameFrame({ params }: Props) {
const { name } = await params;
return <App title={`Hello, ${name}`} />;
}

View File

@ -1,24 +0,0 @@
import { ImageResponse } from "next/og";
export const runtime = "edge";
export const alt = "Hello Frame";
export const size = {
width: 600,
height: 400,
};
export const contentType = "image/png";
export default async function Image() {
return new ImageResponse(
(
<div tw="h-full w-full flex flex-col justify-center items-center relative bg-white">
<h1 tw="text-6xl">Hello, world!</h1>
</div>
),
{
...size,
}
);
}

View File

@ -1,35 +0,0 @@
import { Metadata } from "next";
import App from "~/app/app";
const appUrl = process.env.NEXT_PUBLIC_URL;
const frame = {
version: "next",
imageUrl: `${appUrl}/frames/hello/opengraph-image`,
button: {
title: "Launch Frame",
action: {
type: "launch_frame",
name: process.env.NEXT_PUBLIC_FRAME_NAME || "Frames v2 Demo",
url: `${appUrl}/frames/hello/`,
splashImageUrl: `${appUrl}/splash.png`,
splashBackgroundColor: "#f7f7f7",
},
},
};
export const metadata: Metadata = {
title: "Hello, world!",
description: "A simple hello world frame",
openGraph: {
title: "Hello, world!",
description: "A simple hello world frame",
},
other: {
"fc:frame": JSON.stringify(frame),
},
};
export default function HelloFrame() {
return <App title={"Hello, world!"} />;
}

View File

@ -1,35 +0,0 @@
import { ImageResponse } from "next/og";
export const runtime = "edge";
export const alt = "Hello Frame";
export const size = {
width: 600,
height: 600,
};
export const contentType = "image/png";
interface Props {
params: Promise<{
chainId: string;
address: string;
}>;
}
export default async function Image({ params }: Props) {
const { chainId, address } = await params;
const token = `eip155:${chainId}/erc20:${address}`;
return new ImageResponse(
(
<div tw="h-full w-full flex flex-col justify-center items-center relative bg-white">
<h1 tw="text-6xl">View Token</h1>
<p>{token}</p>
</div>
),
{
...size,
}
);
}

View File

@ -1,47 +0,0 @@
import { Metadata } from "next";
const appUrl = process.env.NEXT_PUBLIC_URL;
interface Props {
params: Promise<{
chainId: string;
address: string;
}>;
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { chainId, address } = await params;
const token = `eip155:${chainId}/erc20:${address}`;
const frame = {
version: "next",
imageUrl: `${appUrl}/frames/token/${chainId}/${address}/opengraph-image`,
aspectRatio: "1:1",
button: {
title: "View Token",
action: {
type: "view_token",
token,
},
},
};
return {
title: "View Token",
description: token,
openGraph: {
title: "View Token",
description: token,
},
other: {
"fc:frame": JSON.stringify(frame),
},
};
}
export default async function HelloNameFrame({ params }: Props) {
const { chainId, address } = await params;
const token = `eip155:${chainId}/erc20:${address}`;
return <h1>View token: {token}</h1>;
}

View File

@ -4,18 +4,20 @@ import App from "./app";
const appUrl = process.env.NEXT_PUBLIC_URL;
// frame preview metadata
// question: do we need metadata both in this file and in the .well-known/farcaster.json file?
const appName = process.env.NEXT_PUBLIC_FRAME_NAME || "Frames v2 Demo";
const splashImageUrl = process.env.NEXT_PUBLIC_FRAME_SPLASH_IMAGE_URL || `${appUrl}/splash.png`;
const frame = {
version: "next",
imageUrl: `${appUrl}/opengraph-image`,
button: {
title: "Launch Frame",
title: process.env.NEXT_PUBLIC_FRAME_BUTTON_TEXT || "Launch Frame",
action: {
type: "launch_frame",
name: appName,
url: appUrl,
splashImageUrl: `${appUrl}/splash.png`,
splashImageUrl,
splashBackgroundColor: "#f7f7f7",
},
},