diff --git a/docs/pages/guides/create-frame.mdx b/docs/pages/guides/create-frame.mdx index f6e9fbae4..3e29ef334 100644 --- a/docs/pages/guides/create-frame.mdx +++ b/docs/pages/guides/create-frame.mdx @@ -8,7 +8,9 @@ description: "Frames.js is the react based framework for making frames. Debugger This guide shows you how to add frames rendering to your next.js + tailwind app using frames.js. ## Steps + ::::steps + ### Create a new repo Create a new Next.js app @@ -24,7 +26,6 @@ Add `frames.js` to your project yarn add frames.js ``` - ### Create your Frames app ```tsx [./app/frames/frames.ts] @@ -34,6 +35,7 @@ export const frames = createFrames(); ``` ### Create a route + ```tsx [./app/frames/route.tsx] /* eslint-disable react/jsx-key */ import { Button } from "frames.js/next"; @@ -49,10 +51,10 @@ const handleRequest = frames(async (ctx) => { ), buttons: [ - , - , ], @@ -73,7 +75,12 @@ export async function generateMetadata() { title: "My Page", // provide a full URL to your /frames endpoint other: await fetchMetadata( - new URL("/frames", process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : "http://localhost:3000") + new URL( + "/frames", + process.env.VERCEL_URL + ? `https://${process.env.VERCEL_URL}` + : "http://localhost:3000" + ) ), }; } @@ -88,3 +95,7 @@ export default function Page() { ### Done! 🎉 :::: + +## Next Steps + +- Read the [`createFrames`](/reference/core/createFrames) and [`Button`](/reference/core/Button) documentation diff --git a/docs/pages/guides/multiple-frames.mdx b/docs/pages/guides/multiple-frames.mdx index 2cff40e25..37e30b68f 100644 --- a/docs/pages/guides/multiple-frames.mdx +++ b/docs/pages/guides/multiple-frames.mdx @@ -5,67 +5,168 @@ description: "" # Multi-Page Frames -You will want to connect multiple frames together. -There's two different ways of navigating between frames. +Frames.js can be used to create multi-page applications by defining multiple Frames that are linked together. -The first way is by defining the `state` prop of a `Button`, and using that state to return a different Frame in the handler. See below +## Creating a Multi-Page Application -```tsx -/* eslint-disable react/jsx-key */ -import { createFrames, Button } from "frames.js/next"; +Frames are connected by [`Button`](/reference/core/Button) targets, similar to how Next.js `Link` components work. + +:::steps + +### Create your frames app + +We create a new directory `./frames` with a `frames.ts` file to export our frames application from because it needs to be used from multiple routes. -const totalPages = 5; +```tsx [frames.ts] +import { createFrames } from "frames.js/next"; -const frames = createFrames({ - basePath: "/examples/new-api/frames", - initialState: { - pageIndex: 0, - }, +export const frames = createFrames({ + basePath: "/frames", }); +``` + +### Define your initial route -const handleRequest = frames(async (ctx) => { - const pageIndex = Number(ctx.searchParams.pageIndex || 0); +The first frame is always fetched via a GET request and is typically included alongside existing OpenGraph data via the [`generateMetadata`](https://nextjs.org/docs/app/api-reference/functions/generate-metadata) function in Next.js if you have an existing site. - const imageUrl = `https://picsum.photos/seed/frames.js-${pageIndex}/300/200`; +#### Define the initial frame +Create a `./frames/route.tsx` file that contains your initial frame. This frame will include buttons to navigate to other frames. + +```tsx [route.tsx] +/* eslint-disable react/jsx-key */ +import { frames } from "./frames"; +import { Button } from "frames.js/next"; + +export const GET = frames(async () => { return { - image: ( -
- Image -
- This is slide {pageIndex + 1} / {totalPages} -
-
- ), + image:
Welcome
, buttons: [ + // With query params , - , ], - textInput: "Type something!", }; }); +``` + +#### Export the initial frame metadata + +In your `page.tsx` file, fetch the initial frame's metadata and include it alongside your existing page's metadata. -export const GET = handleRequest; -export const POST = handleRequest; +`fetchMetadata` is a helper function that fetches the metadata for a frame from the frames.js handler and formats it for use in the `generateMetadata` function. + +```tsx [page.tsx] +import { fetchMetadata } from "frames.js/next"; + +export async function generateMetadata() { + return { + title: "My Page", + // provide a full URL to your /frames endpoint + other: await fetchMetadata( + new URL( + "/frames", + process.env.VERCEL_URL + ? `https://${process.env.VERCEL_URL}` + : "http://localhost:3000" + ) + ), + }; +} + +export default function Page() { + return My existing page; +} ``` -The second way to navigate between frames is by defining a `Button` with `type`, `post`, with a `target` that points at another Frame. -This can be a Frame on the same domain, or a Frame on another website entirely. In order to link between Frames in the same project, you need to set up a frames.js handler on the `POST` route of the path defined in the target. +### Create the other routes + +Create additional frames in the `./frames` directory. + +#### Route 1 + +Create a directory `./frames/route1/route.tsx` with a `POST` handler that returns the frame content. + +```tsx [route1.tsx] +/* eslint-disable react/jsx-key */ +import { frames } from "../frames"; +import { Button } from "frames.js/next"; + +export const POST = frames(async (ctx) => { + const foo = ctx.searchParams.foo; + + return { + image:
Route 1 foo: {foo}
, // foo: bar + buttons: [ + , + ], + }; +}); +``` + +#### Route 2 + +Create a directory `./frames/route2/route.tsx` with a `POST` handler that returns the frame content. + +```tsx [route2.tsx] +/* eslint-disable react/jsx-key */ +import { frames } from "../frames"; +import { Button } from "frames.js/next"; + +export const POST = frames(async () => { + return { + image:
Route 2
, + buttons: [ + , + ], + }; +}); +``` + +### (Optional) Navigate back to the initial frame -{/* -TODO: Link to examples - */} \ No newline at end of file +If you want to navigate back to the initial frame you need to export a `POST` handler for the initial route. You may want to refactor the initial frame handler into a `frameHandler` variable that is exported as both `GET` and `POST` + +```tsx [route.tsx] +import { frames } from "./frames"; + +const frameHandler = frames(async () => { + return { + image:
Welcome
+ buttons: [ + , + , + ], + }; +}); + +export const GET = frameHandler; +export const POST = frameHandler; +``` + +You can then navigate back to the initial frame by linking to the initial route. + +```tsx + +``` + +::: + +## Notes + +The second way to navigate between frames is by defining a [`Button`](/reference/core/Button) with `type`, `post`, with a `target` that points at another Frame. +This can be a Frame on the same domain, or a Frame on another website entirely. In order to link between Frames in the same project, you need to set up a frames.js handler on the `POST` route of the path defined in the target. diff --git a/docs/pages/reference/core/Button.mdx b/docs/pages/reference/core/Button.mdx index 919aefccf..e95a4d30b 100644 --- a/docs/pages/reference/core/Button.mdx +++ b/docs/pages/reference/core/Button.mdx @@ -20,15 +20,22 @@ This button sends a request to a URL on which it was rendered. If you want to na The `target` path will be resolved relatively to current URL. -### Passing state when button is clicked using query parameters +### Passing state between frames ```tsx - ``` -The state will be available in handler `ctx.pressedButton.state`. +The state will be available in the frame handler via `ctx.searchParams` e.g. + +```ts +ctx.searchParams.foo; // bar +``` ## Post Redirect Button @@ -39,7 +46,10 @@ It accepts same props as `post` button. ```tsx import { Button } from "frames.js/core"; -; ```