From 1b5c5c229496ef75ec72d5c5a3ba9050aeac8a81 Mon Sep 17 00:00:00 2001 From: Leonardo Zizzamia Date: Thu, 8 Feb 2024 17:49:02 -0800 Subject: [PATCH 1/4] lol --- .changeset/curly-bottles-knock.md | 5 +++++ src/components/FrameMetadata.tsx | 3 ++- src/core/getFrameHtmlResponse.test.ts | 6 ++++++ src/core/getFrameHtmlResponse.ts | 6 +++--- src/version.ts | 2 +- 5 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 .changeset/curly-bottles-knock.md diff --git a/.changeset/curly-bottles-knock.md b/.changeset/curly-bottles-knock.md new file mode 100644 index 0000000000..d5baa4d320 --- /dev/null +++ b/.changeset/curly-bottles-knock.md @@ -0,0 +1,5 @@ +--- +'@coinbase/onchainkit': patch +--- + +- **feat**: ~~~~ diff --git a/src/components/FrameMetadata.tsx b/src/components/FrameMetadata.tsx index 23d300a68a..4ee712db08 100644 --- a/src/components/FrameMetadata.tsx +++ b/src/components/FrameMetadata.tsx @@ -67,7 +67,8 @@ export function FrameMetadata({ return ( - {!!image && } + + {!!input && } {!!button1 && } diff --git a/src/core/getFrameHtmlResponse.test.ts b/src/core/getFrameHtmlResponse.test.ts index fbf0ba4381..21ce3912ae 100644 --- a/src/core/getFrameHtmlResponse.test.ts +++ b/src/core/getFrameHtmlResponse.test.ts @@ -30,6 +30,7 @@ describe('getFrameHtmlResponse', () => { + @@ -52,6 +53,7 @@ describe('getFrameHtmlResponse', () => { + `); @@ -71,6 +73,7 @@ describe('getFrameHtmlResponse', () => { + `); @@ -88,6 +91,7 @@ describe('getFrameHtmlResponse', () => { expect(html).toContain( '', ); + expect(html).toContain(''); expect(html).toContain( '', ); @@ -104,6 +108,7 @@ describe('getFrameHtmlResponse', () => { expect(html).toContain( '', ); + expect(html).toContain(''); expect(html).toContain( '', ); @@ -120,6 +125,7 @@ describe('getFrameHtmlResponse', () => { expect(html).toContain( '', ); + expect(html).toContain(''); expect(html).toContain(''); expect(html).not.toContain('fc:frame:post_url'); }); diff --git a/src/core/getFrameHtmlResponse.ts b/src/core/getFrameHtmlResponse.ts index ecf4b07e46..c0bc7d31f8 100644 --- a/src/core/getFrameHtmlResponse.ts +++ b/src/core/getFrameHtmlResponse.ts @@ -19,8 +19,8 @@ function getFrameHtmlResponse({ refreshPeriod, refresh_period, }: FrameMetadataType): string { - // Set the image metadata if it exists. - const imageHtml = image ? ` \n` : ''; + const imageHtml = ` \n`; + const ogImageHtml = ` \n`; // Set the input metadata if it exists. const inputHtml = input @@ -61,7 +61,7 @@ function getFrameHtmlResponse({ -${buttonsHtml}${imageHtml}${inputHtml}${postUrlHtml}${refreshPeriodHtml} +${buttonsHtml}${imageHtml}${ogImageHtml}${inputHtml}${postUrlHtml}${refreshPeriodHtml} `; diff --git a/src/version.ts b/src/version.ts index ed0f9da241..46d7dc0dd5 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const version = '0.5.3'; +export const version = '0.5.4'; From 993431a67b11d9102b2b6b99095784cde3ad3faa Mon Sep 17 00:00:00 2001 From: Leonardo Zizzamia Date: Thu, 8 Feb 2024 22:29:42 -0800 Subject: [PATCH 2/4] feat: dope --- .changeset/curly-bottles-knock.md | 2 +- src/components/FrameMetadata.test.tsx | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.changeset/curly-bottles-knock.md b/.changeset/curly-bottles-knock.md index d5baa4d320..e53484d6fe 100644 --- a/.changeset/curly-bottles-knock.md +++ b/.changeset/curly-bottles-knock.md @@ -2,4 +2,4 @@ '@coinbase/onchainkit': patch --- -- **feat**: ~~~~ +- **feat**: automated the `og:image` property for `getFrameHtmlResponse` and `FrameMetadata`. By @zizzamia #109 diff --git a/src/components/FrameMetadata.test.tsx b/src/components/FrameMetadata.test.tsx index bfaeb197e0..15fd8d7d4d 100644 --- a/src/components/FrameMetadata.test.tsx +++ b/src/components/FrameMetadata.test.tsx @@ -15,7 +15,7 @@ describe('FrameMetadata', () => { expect( meta.container.querySelector('meta[property="fc:frame:image"]')?.getAttribute('content'), ).toBe('https://example.com/image.png'); - expect(meta.container.querySelectorAll('meta').length).toBe(2); + expect(meta.container.querySelectorAll('meta').length).toBe(3); }); it('renders with input', () => { @@ -26,7 +26,7 @@ describe('FrameMetadata', () => { expect( meta.container.querySelector('meta[property="fc:frame:input:text"]')?.getAttribute('content'), ).toBe('test'); - expect(meta.container.querySelectorAll('meta').length).toBe(3); + expect(meta.container.querySelectorAll('meta').length).toBe(4); }); it('renders with two basic buttons', () => { @@ -56,7 +56,7 @@ describe('FrameMetadata', () => { ?.getAttribute('content'), ).toBe('post_redirect'); // Length - expect(meta.container.querySelectorAll('meta').length).toBe(5); + expect(meta.container.querySelectorAll('meta').length).toBe(6); }); it('renders with all buttons', () => { @@ -133,7 +133,7 @@ describe('FrameMetadata', () => { ?.getAttribute('content'), ).toBe('https://zizzamia.xyz/api/frame/link'); // Length - expect(meta.container.querySelectorAll('meta').length).toBe(11); + expect(meta.container.querySelectorAll('meta').length).toBe(12); }); it('renders with post_url', () => { @@ -144,7 +144,7 @@ describe('FrameMetadata', () => { expect( meta.container.querySelector('meta[property="fc:frame:post_url"]')?.getAttribute('content'), ).toBe('https://example.com'); - expect(meta.container.querySelectorAll('meta').length).toBe(3); + expect(meta.container.querySelectorAll('meta').length).toBe(4); }); it('renders with refresh_period', () => { @@ -155,7 +155,7 @@ describe('FrameMetadata', () => { .querySelector('meta[property="fc:frame:refresh_period"]') ?.getAttribute('content'), ).toBe('10'); - expect(meta.container.querySelectorAll('meta').length).toBe(3); + expect(meta.container.querySelectorAll('meta').length).toBe(4); }); it('renders with wrapper', () => { @@ -168,7 +168,7 @@ describe('FrameMetadata', () => { expect(meta.container.querySelector('#wrapper')).not.toBeNull(); expect(meta.container.querySelector('meta[property="fc:frame:image"]')).not.toBeNull(); - expect(meta.container.querySelectorAll('meta').length).toBe(2); + expect(meta.container.querySelectorAll('meta').length).toBe(3); }); it('renders with action mint', () => { @@ -200,7 +200,7 @@ describe('FrameMetadata', () => { .querySelector('meta[property="fc:frame:button:1:target"]') ?.getAttribute('content'), ).toBe('https://zizzamia.xyz/api/frame/mint'); - expect(meta.container.querySelectorAll('meta').length).toBe(5); + expect(meta.container.querySelectorAll('meta').length).toBe(6); }); it('renders with action link', () => { @@ -232,7 +232,7 @@ describe('FrameMetadata', () => { .querySelector('meta[property="fc:frame:button:1:target"]') ?.getAttribute('content'), ).toBe('https://zizzamia.xyz/api/frame/link'); - expect(meta.container.querySelectorAll('meta').length).toBe(5); + expect(meta.container.querySelectorAll('meta').length).toBe(6); }); it('should not render action target if action is not link or mint', () => { @@ -244,6 +244,6 @@ describe('FrameMetadata', () => { />, ); expect(meta.container.querySelector('meta[property="fc:frame:button:1:target"')).toBeNull(); - expect(meta.container.querySelectorAll('meta').length).toBe(5); + expect(meta.container.querySelectorAll('meta').length).toBe(6); }); }); From d0edd01927f94e7155ed81bbbf114959c21214fe Mon Sep 17 00:00:00 2001 From: Leonardo Zizzamia Date: Thu, 8 Feb 2024 23:36:56 -0800 Subject: [PATCH 3/4] ok --- src/components/FrameMetadata.test.tsx | 4 ++-- src/core/getFrameHtmlResponse.test.ts | 8 +++++--- src/core/getFrameHtmlResponse.ts | 18 ++++++------------ 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/components/FrameMetadata.test.tsx b/src/components/FrameMetadata.test.tsx index 0274091640..48c3480ed9 100644 --- a/src/components/FrameMetadata.test.tsx +++ b/src/components/FrameMetadata.test.tsx @@ -23,7 +23,7 @@ describe('FrameMetadata', () => { expect( meta.container.querySelector('meta[property="fc:frame:image"]')?.getAttribute('content'), ).toBe('https://example.com/image.png'); - expect(meta.container.querySelectorAll('meta').length).toBe(2); + expect(meta.container.querySelectorAll('meta').length).toBe(3); }); it('renders with image aspect ratio', () => { @@ -38,7 +38,7 @@ describe('FrameMetadata', () => { .querySelector('meta[property="fc:frame:image:aspect_ratio"]') ?.getAttribute('content'), ).toBe('1:1'); - expect(meta.container.querySelectorAll('meta').length).toBe(3); + expect(meta.container.querySelectorAll('meta').length).toBe(4); }); it('renders with input', () => { diff --git a/src/core/getFrameHtmlResponse.test.ts b/src/core/getFrameHtmlResponse.test.ts index 62f675afde..195a1c8170 100644 --- a/src/core/getFrameHtmlResponse.test.ts +++ b/src/core/getFrameHtmlResponse.test.ts @@ -32,8 +32,8 @@ describe('getFrameHtmlResponse', () => { - + @@ -58,6 +58,7 @@ describe('getFrameHtmlResponse', () => { + @@ -80,6 +81,7 @@ describe('getFrameHtmlResponse', () => { + @@ -100,8 +102,8 @@ describe('getFrameHtmlResponse', () => { - + `); @@ -120,8 +122,8 @@ describe('getFrameHtmlResponse', () => { - + `); diff --git a/src/core/getFrameHtmlResponse.ts b/src/core/getFrameHtmlResponse.ts index dce90d3734..9dbd4c6f26 100644 --- a/src/core/getFrameHtmlResponse.ts +++ b/src/core/getFrameHtmlResponse.ts @@ -19,17 +19,11 @@ function getFrameHtmlResponse({ refreshPeriod, refresh_period, }: FrameMetadataType): string { - const ogImageHtml = ` \n`; - - // Set the image metadata if it exists. - let imageHtml = ''; - if (typeof image === 'string') { - imageHtml = ` \n`; - } else { - imageHtml = ` \n`; - if (image.aspectRatio) { - imageHtml += ` \n`; - } + const imgSrc = typeof image === 'string' ? image : image.src; + const ogImageHtml = ` \n`; + let imageHtml = ` \n`; + if (typeof image !== 'string' && image.aspectRatio) { + imageHtml += ` \n`; } // Set the input metadata if it exists. @@ -71,7 +65,7 @@ function getFrameHtmlResponse({ -${buttonsHtml}${imageHtml}${ogImageHtml}${inputHtml}${postUrlHtml}${refreshPeriodHtml} +${buttonsHtml}${ogImageHtml}${imageHtml}${inputHtml}${postUrlHtml}${refreshPeriodHtml} `; From a676a5eaadc2ec1a6e2c5209158bbf59c014f65c Mon Sep 17 00:00:00 2001 From: Leonardo Zizzamia Date: Fri, 9 Feb 2024 23:04:55 -0800 Subject: [PATCH 4/4] done --- .changeset/curly-bottles-knock.md | 2 +- src/components/FrameMetadata.test.tsx | 30 +++++++++++++++++++++++ src/components/FrameMetadata.tsx | 8 +++++++ src/core/getFrameHtmlResponse.test.ts | 34 +++++++++++++++++++++++++++ src/core/getFrameHtmlResponse.ts | 13 +++++++++- 5 files changed, 85 insertions(+), 2 deletions(-) diff --git a/.changeset/curly-bottles-knock.md b/.changeset/curly-bottles-knock.md index e53484d6fe..880746f8f9 100644 --- a/.changeset/curly-bottles-knock.md +++ b/.changeset/curly-bottles-knock.md @@ -2,4 +2,4 @@ '@coinbase/onchainkit': patch --- -- **feat**: automated the `og:image` property for `getFrameHtmlResponse` and `FrameMetadata`. By @zizzamia #109 +- **feat**: automated the `og:image` and `og:title` properties for `getFrameHtmlResponse` and `FrameMetadata`. By @zizzamia #109 diff --git a/src/components/FrameMetadata.test.tsx b/src/components/FrameMetadata.test.tsx index 48c3480ed9..b408e9a2b7 100644 --- a/src/components/FrameMetadata.test.tsx +++ b/src/components/FrameMetadata.test.tsx @@ -269,4 +269,34 @@ describe('FrameMetadata', () => { expect(meta.container.querySelector('meta[property="fc:frame:button:1:target"')).toBeNull(); expect(meta.container.querySelectorAll('meta').length).toBe(6); }); + + it('should set og:description', () => { + const meta = render( + , + ); + expect( + meta.container.querySelector('meta[property="og:description"]')?.getAttribute('content'), + ).toBe('This is the description'); + expect(meta.container.querySelectorAll('meta').length).toBe(4); + }); + + it('should set og:title', () => { + const meta = render( + , + ); + expect(meta.container.querySelector('meta[property="og:title"]')?.getAttribute('content')).toBe( + 'This is the title', + ); + expect(meta.container.querySelectorAll('meta').length).toBe(4); + }); + + it('should not render og:description and og:title if not provided', () => { + const meta = render(); + expect(meta.container.querySelector('meta[property="og:description"]')).toBeNull(); + expect(meta.container.querySelector('meta[property="og:title"]')).toBeNull(); + expect(meta.container.querySelectorAll('meta').length).toBe(3); + }); }); diff --git a/src/components/FrameMetadata.tsx b/src/components/FrameMetadata.tsx index 9008e7f9b1..0579540392 100644 --- a/src/components/FrameMetadata.tsx +++ b/src/components/FrameMetadata.tsx @@ -2,6 +2,8 @@ import { Fragment } from 'react'; import type { FrameMetadataType, FrameImageMetadata } from '../core/types'; type FrameMetadataReact = FrameMetadataType & { + ogDescription?: string; + ogTitle?: string; wrapper?: React.ComponentType; }; @@ -40,6 +42,8 @@ type FrameMetadataReact = FrameMetadataType & { * @param {Array<{ label: string, action?: string }>} props.buttons - The buttons. * @param {string | { src: string, aspectRatio?: string }} props.image - The image URL. * @param {string} props.input - The input text. + * @param {string} props.ogDescription - The Open Graph description. + * @param {string} props.ogTitle - The Open Graph title. * @param {string} props.postUrl - The post URL. * @param {number} props.refreshPeriod - The refresh period. * @param {React.ComponentType | undefined} props.wrapper - The wrapper component meta tags are rendered in. @@ -49,6 +53,8 @@ export function FrameMetadata({ buttons, image, input, + ogDescription, + ogTitle, postUrl, post_url, refreshPeriod, @@ -68,6 +74,8 @@ export function FrameMetadata({ // with Helmet as a wrapper component, it is crucial to flatten the Buttons loop. return ( + {!!ogDescription && } + {!!ogTitle && } {!!imageSrc && } diff --git a/src/core/getFrameHtmlResponse.test.ts b/src/core/getFrameHtmlResponse.test.ts index 195a1c8170..edc77fdbf4 100644 --- a/src/core/getFrameHtmlResponse.test.ts +++ b/src/core/getFrameHtmlResponse.test.ts @@ -23,6 +23,8 @@ describe('getFrameHtmlResponse', () => { expect(html).toBe(` + + @@ -54,6 +56,8 @@ describe('getFrameHtmlResponse', () => { expect(html).toBe(` + + @@ -77,6 +81,8 @@ describe('getFrameHtmlResponse', () => { expect(html).toBe(` + + @@ -98,6 +104,8 @@ describe('getFrameHtmlResponse', () => { expect(html).toBe(` + + @@ -118,6 +126,8 @@ describe('getFrameHtmlResponse', () => { expect(html).toBe(` + + @@ -212,6 +222,30 @@ describe('getFrameHtmlResponse', () => { expect(html).toContain(''); expect(html).not.toContain('fc:frame:button:1:target'); }); + + it('should set og:description and og:title to default values if not provided', () => { + const html = getFrameHtmlResponse({ + buttons: [{ label: 'button1' }], + image: 'image', + postUrl: 'post_url', + }); + + expect(html).toContain(''); + expect(html).toContain(''); + }); + + it('should set og:description and og:title to provided values', () => { + const html = getFrameHtmlResponse({ + buttons: [{ label: 'button1' }], + image: 'image', + postUrl: 'post_url', + ogDescription: 'description', + ogTitle: 'title', + }); + + expect(html).toContain(''); + expect(html).toContain(''); + }); }); export { getFrameHtmlResponse }; diff --git a/src/core/getFrameHtmlResponse.ts b/src/core/getFrameHtmlResponse.ts index 9dbd4c6f26..603bc797b6 100644 --- a/src/core/getFrameHtmlResponse.ts +++ b/src/core/getFrameHtmlResponse.ts @@ -1,11 +1,18 @@ import { FrameMetadataType, FrameImageMetadata } from './types'; +type FrameMetadataHTMLResponse = FrameMetadataType & { + ogDescription?: string; + ogTitle?: string; +}; + /** * Returns an HTML string containing metadata for a new valid frame. * * @param buttons: The buttons to use for the frame. * @param image: The image to use for the frame. * @param input: The text input to use for the frame. + * @param ogDescription: The Open Graph description for the frame. + * @param ogTitle: The Open Graph title for the frame. * @param postUrl: The URL to post the frame to. * @param refreshPeriod: The refresh period for the image used. * @returns An HTML string containing metadata for the frame. @@ -14,11 +21,13 @@ function getFrameHtmlResponse({ buttons, image, input, + ogDescription, + ogTitle, postUrl, post_url, refreshPeriod, refresh_period, -}: FrameMetadataType): string { +}: FrameMetadataHTMLResponse): string { const imgSrc = typeof image === 'string' ? image : image.src; const ogImageHtml = ` \n`; let imageHtml = ` \n`; @@ -64,6 +73,8 @@ function getFrameHtmlResponse({ let html = ` + + ${buttonsHtml}${ogImageHtml}${imageHtml}${inputHtml}${postUrlHtml}${refreshPeriodHtml}