Skip to content

Commit f16e742

Browse files
committed
fix: make button docs more visible, multi-page docs
1 parent f54db19 commit f16e742

File tree

3 files changed

+162
-52
lines changed

3 files changed

+162
-52
lines changed

docs/pages/guides/create-frame.mdx

+15-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ description: "Frames.js is the react based framework for making frames. Debugger
88
This guide shows you how to add frames rendering to your next.js + tailwind app using frames.js.
99

1010
## Steps
11+
1112
::::steps
13+
1214
### Create a new repo
1315

1416
Create a new Next.js app
@@ -24,7 +26,6 @@ Add `frames.js` to your project
2426
yarn add frames.js
2527
```
2628

27-
2829
### Create your Frames app
2930

3031
```tsx [./app/frames/frames.ts]
@@ -34,6 +35,7 @@ export const frames = createFrames();
3435
```
3536

3637
### Create a route
38+
3739
```tsx [./app/frames/route.tsx]
3840
/* eslint-disable react/jsx-key */
3941
import { Button } from "frames.js/next";
@@ -49,10 +51,10 @@ const handleRequest = frames(async (ctx) => {
4951
</span>
5052
),
5153
buttons: [
52-
<Button action="post" target={{ query: { value: "Yes" }}}>
54+
<Button action="post" target={{ query: { value: "Yes" } }}>
5355
Say Yes
5456
</Button>,
55-
<Button action="post" target={{ query: { value: "No" }}}>
57+
<Button action="post" target={{ query: { value: "No" } }}>
5658
Say No
5759
</Button>,
5860
],
@@ -73,7 +75,12 @@ export async function generateMetadata() {
7375
title: "My Page",
7476
// provide a full URL to your /frames endpoint
7577
other: await fetchMetadata(
76-
new URL("/frames", process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : "http://localhost:3000")
78+
new URL(
79+
"/frames",
80+
process.env.VERCEL_URL
81+
? `https://${process.env.VERCEL_URL}`
82+
: "http://localhost:3000"
83+
)
7784
),
7885
};
7986
}
@@ -88,3 +95,7 @@ export default function Page() {
8895
### Done! 🎉
8996

9097
::::
98+
99+
## Next Steps
100+
101+
- Read the [`createFrames`](/reference/core/createFrames) and [`Button`](/reference/core/Button) documentation

docs/pages/guides/multiple-frames.mdx

+133-44
Original file line numberDiff line numberDiff line change
@@ -5,67 +5,156 @@ description: ""
55

66
# Multi-Page Frames
77

8-
You will want to connect multiple frames together.
9-
There's two different ways of navigating between frames.
8+
Frames.js can be used to create multi-page applications by defining multiple Frames that are linked together.
109

11-
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
10+
## Creating a Multi-Page Application
1211

13-
```tsx
14-
/* eslint-disable react/jsx-key */
15-
import { createFrames, Button } from "frames.js/next";
12+
Frames are connected by [`Button`](/reference/core/Button) targets, similar to how Next.js `Link` components work.
13+
14+
:::steps
15+
16+
### Create your frames app
1617

17-
const totalPages = 5;
18+
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.
19+
20+
```tsx [frames.ts]
21+
import { createFrames } from "frames.js/next";
22+
23+
export const frames = createFrames({
24+
basePath: "/frames",
25+
});
26+
```
1827

19-
const frames = createFrames({
20-
basePath: "/examples/new-api/frames",
21-
initialState: {
22-
pageIndex: 0,
23-
},
28+
### Define your initial route
29+
30+
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.
31+
32+
#### Define the initial frame
33+
34+
Create a `./frames/route.tsx` file that contains your initial frame. This frame will include buttons to navigate to other frames.
35+
36+
```tsx [route.tsx]
37+
/* eslint-disable react/jsx-key */
38+
import { frames } from "./frames";
39+
40+
export const GET = frames(async () => {
41+
return {
42+
image: <div tw="flex">Welcome</div>
43+
buttons: [
44+
// With query params
45+
<Button action="post" target={{pathname: "/frames/route1", query: {foo: "bar"}}}>Go to route 1</Button>,
46+
// Without query params
47+
<Button action="post" target="/frames/route2">Go to route 2</Button>,
48+
],
49+
};
2450
});
51+
```
2552

26-
const handleRequest = frames(async (ctx) => {
27-
const pageIndex = Number(ctx.searchParams.pageIndex || 0);
53+
#### Export the initial frame metadata
2854

29-
const imageUrl = `https://picsum.photos/seed/frames.js-${pageIndex}/300/200`;
55+
In your `page.tsx` file, fetch the initial frame's metadata and include it alongside your existing page's metadata.
3056

57+
`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.
58+
59+
```tsx [page.tsx]
60+
import { fetchMetadata } from "frames.js/next";
61+
62+
export async function generateMetadata() {
3163
return {
32-
image: (
33-
<div tw="flex flex-col">
34-
<img width={300} height={200} src={imageUrl} alt="Image" />
35-
<div tw="flex">
36-
This is slide {pageIndex + 1} / {totalPages}
37-
</div>
38-
</div>
64+
title: "My Page",
65+
// provide a full URL to your /frames endpoint
66+
other: await fetchMetadata(
67+
new URL(
68+
"/frames",
69+
process.env.VERCEL_URL
70+
? `https://${process.env.VERCEL_URL}`
71+
: "http://localhost:3000"
72+
)
3973
),
74+
};
75+
}
76+
77+
export default function Page() {
78+
return <span>My existing page</span>;
79+
}
80+
```
81+
82+
### Create the other routes
83+
84+
Create additional frames in the `./frames` directory.
85+
86+
#### Route 1
87+
88+
Create a directory `./frames/route1/route.tsx` with a `POST` handler that returns the frame content.
89+
90+
```tsx [route1.tsx]
91+
import { frames } from "./frames";
92+
93+
export const POST = frames(async (ctx) => {
94+
const foo = ctx.searchParams.foo;
95+
96+
return {
97+
image: <div tw="flex">Route 1 foo: {foo}</div>, // foo: bar
4098
buttons: [
41-
<Button
42-
action="post"
43-
target={{
44-
query: { pageIndex: (pageIndex - 1) % totalPages },
45-
}}
46-
>
47-
99+
<Button action="post" target="/frames/route2">
100+
Go to route 2
48101
</Button>,
49-
<Button
50-
action="post"
51-
target={{
52-
query: { pageIndex: (pageIndex + 1) % totalPages },
53-
}}
54-
>
55-
102+
],
103+
};
104+
});
105+
```
106+
107+
#### Route 2
108+
109+
Create a directory `./frames/route2/route.tsx` with a `POST` handler that returns the frame content.
110+
111+
```tsx [route2.tsx]
112+
import { frames } from "./frames";
113+
114+
export const POST = frames(async () => {
115+
return {
116+
image: <div tw="flex">Route 2</div>,
117+
buttons: [
118+
<Button action="post" target="/frames/route1">
119+
Go to route 1
56120
</Button>,
57121
],
58-
textInput: "Type something!",
59122
};
60123
});
124+
```
125+
126+
### (Optional) Navigate back to the initial frame
127+
128+
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`
61129

62-
export const GET = handleRequest;
63-
export const POST = handleRequest;
130+
```tsx [route.tsx]
131+
import { frames } from "./frames";
132+
133+
const frameHandler = frames(async () => {
134+
return {
135+
image: <div tw="flex">Welcome</div>
136+
buttons: [
137+
<Button action="post" target="/frames/route1">Go to route 1</Button>,
138+
<Button action="post" target="/frames/route2">Go to route 2</Button>,
139+
],
140+
};
141+
});
142+
143+
export const GET = frameHandler;
144+
export const POST = frameHandler;
64145
```
65146

66-
The second way to navigate between frames is by defining a `Button` with `type`, `post`, with a `target` that points at another Frame.
67-
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.
147+
You can then navigate back to the initial frame by linking to the initial route.
148+
149+
```tsx
150+
<Button action="post" target="/frames">
151+
Go back
152+
</Button>
153+
```
68154

69-
{/*
70-
TODO: Link to examples
71-
*/}
155+
:::
156+
157+
## Notes
158+
159+
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.
160+
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.

docs/pages/reference/core/Button.mdx

+14-4
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,22 @@ This button sends a request to a URL on which it was rendered. If you want to na
2020

2121
The `target` path will be resolved relatively to current URL.
2222

23-
### Passing state when button is clicked using query parameters
23+
### Passing state between frames
2424

2525
```tsx
26-
<Button action="post" target={{ query: { foo: "bar" }, pathname: "/next-route"}}>
26+
<Button
27+
action="post"
28+
target={{ query: { foo: "bar" }, pathname: "/next-route" }}
29+
>
2730
Click me
2831
</Button>
2932
```
3033

31-
The state will be available in handler `ctx.pressedButton.state`.
34+
The state will be available in the frame handler via `ctx.searchParams` e.g.
35+
36+
```ts
37+
ctx.searchParams.foo; // bar
38+
```
3239

3340
## Post Redirect Button
3441

@@ -39,7 +46,10 @@ It accepts same props as `post` button.
3946
```tsx
4047
import { Button } from "frames.js/core";
4148

42-
<Button action="post_redirect" target={{ query: { foo: "bar" }, pathname: "/next-route"}}>
49+
<Button
50+
action="post_redirect"
51+
target={{ query: { foo: "bar" }, pathname: "/next-route" }}
52+
>
4353
Click me
4454
</Button>;
4555
```

0 commit comments

Comments
 (0)