Skip to content

Commit

Permalink
Merge pull request #6 from goldsky-io/static-default-frame
Browse files Browse the repository at this point in the history
Static default frame
  • Loading branch information
patsissons authored Feb 24, 2024
2 parents 28e4e68 + 1ce7a3d commit 86ed661
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 62 deletions.
50 changes: 36 additions & 14 deletions src/lib/components/Seo/seo.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,35 @@
$: ({ ids, ogImage, seoTitle, seoDescription } = hydrate(metadata))
function frameHtml(frame: Partial<Frame>) {
function frameHtml(frame: Partial<Frame>, ogImage: string, route: string) {
const action = routeAction()
const buttons: Frame['buttons'] = frame.buttons || [
{ label: '🔄 Refresh latest', action: 'post' },
{ label: `🔄 Refresh ${action}`, action: 'post' },
]
// we don't include tokenId in the frame context because we don't want to
// refresh the same token over and over
const { tokenId, ...state } = context
// token pages are mostly static, so we can use the dynamic image
// everything else uses our placeholder static image and will rely on the refresh button
const image = imageUrl(true)
return getFrameHtmlHead({
version: 'vNext',
postUrl: `${baseUrl}/frame?${new URLSearchParams({ context: JSON.stringify(state) }).toString()}`,
image: ogImage,
postUrl: `${baseUrl}/frame?${new URLSearchParams({ action, context: JSON.stringify(state) }).toString()}`,
image,
ogImage,
buttons,
...frame,
})
function routeAction() {
if (route === '/') return 'latest POAP'
if (route === '/token') return 'POAP'
if (route === '/account') return 'account POAPs'
if (route === '/event') return 'event POAPs'
return 'latest'
}
}
function hydrate(metadata?: POAPEventMetadata | POAPEventMetadata[]) {
Expand All @@ -52,15 +66,6 @@
seoDescription: truncateText(composeDescription(metdataArray), 155),
}
function imageUrl() {
const at = new Date().getTime()
if (context.tokenId) return `${baseUrl}/og/token/${context.tokenId}?at=${at}`
if (context.eventIds) return `${baseUrl}/og/event/${context.eventIds.join(',')}?at=${at}`
if (context.account) return `${baseUrl}/og/account/${context.account}?at=${at}`
return `${baseUrl}/images/twitter-card.png`
}
function composeTitle(metadata: POAPEventMetadata[] | undefined) {
if (!metadata || metadata.length === 0) return title
if (metadata.length === 1) {
Expand All @@ -83,6 +88,23 @@
return text.length > length ? `${text.slice(0, length - 1)}…` : text
}
}
function imageUrl(_static = false) {
const at = new Date().getTime()
const params = new URLSearchParams({
at: at.toString(),
})
if (_static) {
params.set('static', 'true')
}
const search = params.toString()
if (context.tokenId) return `${baseUrl}/og/token/${context.tokenId}?${search}`
if (context.eventIds) return `${baseUrl}/og/event/${context.eventIds.join(',')}?${search}`
if (context.account) return `${baseUrl}/og/account/${context.account}?${search}`
return `${baseUrl}/images/twitter-card.png`
}
</script>

<svelte:head>
Expand All @@ -95,5 +117,5 @@
<meta name="twitter:description" content={seoDescription} />
<meta name="twitter:image" content={ogImage} />
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
{@html frameHtml(frame)}
{@html frameHtml(frame, ogImage, route)}
</svelte:head>
3 changes: 2 additions & 1 deletion src/routes/frame/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { RequestHandler } from './$types'
export const POST: RequestHandler = async ({ request, url, fetch }) => {
const baseUrl = import.meta.env.DEV ? 'http://localhost:5173' : 'https://vpoap.vercel.app'
const context = JSON.parse(url.searchParams.get('context') || '{}') as SeoContext
const action = url.searchParams.get('action') || 'latest'
const body = (await request.json()) as FrameActionPayload

const { isValid, message } = await validateFrameMessage(body)
Expand All @@ -19,7 +20,7 @@ export const POST: RequestHandler = async ({ request, url, fetch }) => {
version: 'vNext',
buttons: [
{
label: '🔄 Refresh latest',
label: `🔄 Refresh ${action}`,
action: 'post',
},
],
Expand Down
5 changes: 3 additions & 2 deletions src/routes/og/account/[address]/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { fetchLatestAccountPOAPToken } from '$lib/server/poap'
import { tokenResponse } from '../../token/[id]/tokenResponse'
import type { RequestHandler } from './$types'

export const GET: RequestHandler = async ({ params, fetch }) => {
export const GET: RequestHandler = async ({ params, url, fetch }) => {
const address = await fetchReverseENS(params.address)
if (!address) throw error(422, `Invalid address: ${params.address}`)

Expand All @@ -28,5 +28,6 @@ export const GET: RequestHandler = async ({ params, fetch }) => {
const tokenId = data.account.tokens[0]?.id
if (!tokenId) throw error(404, 'POAP token not found for account')

return tokenResponse(tokenId, fetch)
const _static = url.searchParams.get('static') === 'true'
return tokenResponse(tokenId, fetch, _static)
}
5 changes: 3 additions & 2 deletions src/routes/og/event/[id]/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { fetchLatestEventPOAPTokens } from '$lib/server/poap'
import { tokenResponse } from '../../token/[id]/tokenResponse'
import type { RequestHandler } from './$types'

export const GET: RequestHandler = async ({ params, fetch }) => {
export const GET: RequestHandler = async ({ params, url, fetch }) => {
const ids = params.id
.split(',')
.map((id) => Number(id.trim()))
Expand All @@ -19,5 +19,6 @@ export const GET: RequestHandler = async ({ params, fetch }) => {
.sort((a, b) => Number(b.created) - Number(a.created))[0]?.id
if (!tokenId) throw error(404, 'POAP token not found for events')

return tokenResponse(tokenId, fetch)
const _static = url.searchParams.get('static') === 'true'
return tokenResponse(tokenId, fetch, _static)
}
5 changes: 3 additions & 2 deletions src/routes/og/token/[id]/+server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { tokenResponse } from './tokenResponse'
import type { RequestHandler } from './$types'

export const GET: RequestHandler = ({ params: { id }, fetch }) => {
return tokenResponse(id, fetch, true)
export const GET: RequestHandler = ({ params: { id }, url, fetch }) => {
const _static = url.searchParams.get('static') === 'true'
return tokenResponse(id, fetch, _static)
}
10 changes: 8 additions & 2 deletions src/routes/og/token/[id]/debug/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@ import { loadTokenData } from '../../../../token/[id]/data'
import backgroundImage from '../og-background.png?arraybuffer'
import type { PageServerLoad } from './$types'

export const load: PageServerLoad = async ({ fetch, params }) => {
export const load: PageServerLoad = async ({ fetch, url, params }) => {
const data = await loadTokenData(params.id, fetch)

if (!data.token) {
throw error(404, 'Token not found')
}

const _static = url.searchParams.has('static')
const { token, metadata, ens } = data

if (_static) {
ens.avatar = undefined
token.owner.id = '0x0000000000000000000000000000000000000000'
}

const avatar =
ens.avatar ||
renderIcon(
Expand All @@ -33,5 +38,6 @@ export const load: PageServerLoad = async ({ fetch, params }) => {
ens,
avatar,
background,
isStatic: _static,
}
}
93 changes: 57 additions & 36 deletions src/routes/og/token/[id]/og-token.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
* @type {string}
*/
export let background
/**
* @type {boolean}
*/
export let isStatic = false
</script>

<div
Expand Down Expand Up @@ -90,40 +94,50 @@
style:text-overflow="ellipsis"
style:white-space="nowrap"
>
{metadata.name}
{#if isStatic}
Visual POAP Feed
{:else}
{metadata.name}
{/if}
</h2>
</div>
<div style:flex="1 1 0%" style:display="flex" style:overflow="hidden">
<p style:margin="0" style:overflow="hidden" style:white-space="pre-wrap">
{metadata.description.replace(/\r?\n/g, ' ')}
</p>
</div>
<div
style:display="flex"
style:align-items="center"
style:justify-content="space-between"
style:color="rgb(67, 56, 202)"
style:font-family="monospace"
>
<p style:margin="4px 0">
Token
<span style:margin-left="4px" style:font-family="monospace">
#{token.id}
</span>
</p>
<p style:margin="0">
Mint
<span style:margin-left="4px" style:font-family="monospace">
#{token.mintOrder}
</span>
</p>
<p style:margin="0">
Event
<span style:margin-left="4px" style:font-family="monospace">
#{token.event.id}
</span>
{#if isStatic}
Hit the refresh button to watch live POAPS!
{:else}
{metadata.description.replace(/\r?\n/g, ' ')}
{/if}
</p>
</div>
{#if !isStatic}
<div
style:display="flex"
style:align-items="center"
style:justify-content="space-between"
style:color="rgb(67, 56, 202)"
style:font-family="monospace"
>
<p style:margin="4px 0">
Token
<span style:margin-left="4px" style:font-family="monospace">
#{token.id}
</span>
</p>
<p style:margin="0">
Mint
<span style:margin-left="4px" style:font-family="monospace">
#{token.mintOrder}
</span>
</p>
<p style:margin="0">
Event
<span style:margin-left="4px" style:font-family="monospace">
#{token.event.id}
</span>
</p>
</div>
{/if}
<div style:display="flex" style:align-items="center" style:justify-content="space-between">
<div
style:display="flex"
Expand All @@ -135,6 +149,7 @@
<p style:margin="0" style:color="rgb(67, 56, 202)" style:font-size="14px">
{token.owner.id}
</p>

<span
style:margin="0"
style:background-color="rgb(64, 64, 64)"
Expand All @@ -146,15 +161,21 @@
style:font-size="12px"
style:line-height="16px"
>
{token.owner.tokensOwned}
{#if isStatic}
{:else}
{token.owner.tokensOwned}
{/if}
</span>
</div>
<p style:margin="0" style:text-align="right" style:font-size="14px">
{formatDistanceToNow(Number(token.created) * 1000, {
includeSeconds: true,
addSuffix: true,
})}
</p>
{#if !isStatic}
<p style:margin="0" style:text-align="right" style:font-size="14px">
{formatDistanceToNow(Number(token.created) * 1000, {
includeSeconds: true,
addSuffix: true,
})}
</p>
{/if}
</div>
</div>
<div
Expand All @@ -174,7 +195,7 @@
style:height="214px"
style:border-radius="9999px"
style:object-fit="scale-down"
src={metadata.image_url}
src={isStatic ? 'https://poap.xyz/apple-touch-icon.png' : metadata.image_url}
alt="{metadata.name} POAP image"
/>
</div>
Expand Down
11 changes: 8 additions & 3 deletions src/routes/og/token/[id]/tokenResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ import backgroundImage from './og-background.png?arraybuffer'
import OgToken from './og-token.svelte'
import { svelteToPngResponse } from './svelte-to-png'

export async function tokenResponse(id: string, fetch: Fetch, disableDefaultAvatarUrl = false) {
export async function tokenResponse(id: string, fetch: Fetch, _static = false) {
try {
const props = await loadTokenData(id, fetch, disableDefaultAvatarUrl)
const props = await loadTokenData(id, fetch, true)
if (!props.token) throw error(404, 'Token not found')

if (_static) {
props.ens.avatar = undefined
props.token.owner.id = '0x0000000000000000000000000000000000000000'
}

const avatar =
props.ens.avatar ||
renderIcon(
Expand All @@ -30,7 +35,7 @@ export async function tokenResponse(id: string, fetch: Fetch, disableDefaultAvat

return await svelteToPngResponse(
OgToken,
{ ...props, avatar, background },
{ ...props, avatar, background, isStatic: _static },
{
width: 1200,
height: 630,
Expand Down

0 comments on commit 86ed661

Please sign in to comment.