Skip to content

Commit

Permalink
feat: cross-frames
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed Feb 9, 2024
1 parent b5f2a94 commit 802326c
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 12 deletions.
29 changes: 29 additions & 0 deletions example/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ app.frame('/', (context) => {
const { buttonValue, inputText, status } = context
const fruit = inputText || buttonValue
return {
action: '/action',
image: (
<div
style={{
Expand Down Expand Up @@ -56,6 +57,34 @@ app.frame('/', (context) => {
}
})

app.frame('/action', ({ buttonValue, inputText }) => {
const fruit = inputText || buttonValue || ''
return {
action: '/',
image: (
<div
style={{
backgroundColor: 'red',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 60,
width: '100%',
height: '100%',
}}
>
Yuck! {fruit}! Enter another one.
</div>
),
intents: [
<Button value="watermelon">Watermelon</Button>,
<Button value="mango">Mango</Button>,
<Button value="pear">Pear</Button>,
<Button.Reset>Reset</Button.Reset>,
],
}
})

app.frame('/buttons', ({ buttonValue }) => {
return {
image: (
Expand Down
17 changes: 11 additions & 6 deletions src/farc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ import {
import { deserializeJson } from './utils/deserializeJson.js'
import { getFrameContext } from './utils/getFrameContext.js'
import { parseIntents } from './utils/parseIntents.js'
import { parsePath } from './utils/parsePath.js'
import { serializeJson } from './utils/serializeJson.js'
import { toBaseUrl } from './utils/toBaseUrl.js'

export type FrameHandlerReturnType = {
action?: string
image: JSX.Element
imageAspectRatio?: FrameImageAspectRatio | undefined
intents?: FrameIntents | undefined
Expand All @@ -51,7 +53,7 @@ export class Farc<
: undefined
const context = await getFrameContext(c, previousContext)

const { imageAspectRatio, intents } = await handler(
const { action, imageAspectRatio, intents } = await handler(
context,
previousContext,
)
Expand All @@ -72,25 +74,28 @@ export class Farc<
if (serializedPreviousContext)
postSearch.set('previousContext', serializedPreviousContext)

if (context.url !== parsePath(c.req.url)) return c.redirect(context.url)
return c.render(
<html lang="en">
<head>
<meta property="fc:frame" content="vNext" />
<meta
property="fc:frame:image"
content={`${toBaseUrl(context.url)}/image?${ogSearch.toString()}`}
content={`${parsePath(context.url)}/image?${ogSearch.toString()}`}
/>
<meta
property="fc:frame:image:aspect_ratio"
content={imageAspectRatio ?? '1.91:1'}
/>
<meta
property="og:image"
content={`${toBaseUrl(context.url)}/image?${ogSearch.toString()}`}
content={`${parsePath(context.url)}/image?${ogSearch.toString()}`}
/>
<meta
property="fc:frame:post_url"
content={`${toBaseUrl(context.url)}?${postSearch}`}
content={`${
action ? toBaseUrl(c.req.url) + (action || '') : context.url
}?${postSearch}`}
/>
{parsedIntents}

Expand All @@ -107,7 +112,7 @@ export class Farc<
})

// OG Image Route
this.get(`${toBaseUrl(path)}/image`, async (c) => {
this.get(`${parsePath(path)}/image`, async (c) => {
const query = c.req.query()
const parsedContext = deserializeJson<FrameContext>(query.context)
const parsedPreviousContext = query.previousContext
Expand All @@ -122,7 +127,7 @@ export class Farc<

// Frame Preview Routes
this.use(
`${toBaseUrl(path)}/preview`,
`${parsePath(path)}/preview`,
jsxRenderer(
(props) => {
const { children } = props
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { type JSXNode } from 'hono/jsx'
export type FrameContext<P extends string = string> = {
buttonIndex?: number
buttonValue?: string
initialUrl: string
inputText?: string
request: Context<Env, P>['req']
/**
Expand Down
14 changes: 12 additions & 2 deletions src/utils/getFrameContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { type Context } from 'hono'

import { type FrameContext, type PreviousFrameContext } from '../types.js'
import { getIntentState } from './getIntentState.js'
import { toBaseUrl } from './toBaseUrl.js'
import { parsePath } from './parsePath.js'

export async function getFrameContext(
ctx: Context,
Expand All @@ -24,14 +24,24 @@ export async function getFrameContext(
return 'initial'
})()

// If there are no previous contexts, the initial URL is the current URL.
const initialUrl = !previousFrameContext
? parsePath(req.url)
: previousFrameContext.initialUrl

// If the user has clicked a reset button, we want to set the URL back to the
// initial URL.
const url = reset ? initialUrl : parsePath(req.url)

return {
buttonIndex,
buttonValue,
initialUrl,
inputText,
request: req,
status,
trustedData,
untrustedData,
url: toBaseUrl(req.url),
url,
}
}
5 changes: 5 additions & 0 deletions src/utils/parsePath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function parsePath(path_: string) {
let path = path_.split('?')[0]
if (path.endsWith('/')) path = path.slice(0, -1)
return path
}
6 changes: 2 additions & 4 deletions src/utils/toBaseUrl.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export function toBaseUrl(path_: string) {
let path = path_.split('?')[0]
if (path.endsWith('/')) path = path.slice(0, -1)
return path
export function toBaseUrl(url: string) {
return new URL(url).origin
}

0 comments on commit 802326c

Please sign in to comment.