Skip to content
This repository has been archived by the owner on Sep 16, 2024. It is now read-only.

Commit

Permalink
finish edge function
Browse files Browse the repository at this point in the history
  • Loading branch information
LekoArts committed Nov 5, 2023
1 parent 992c064 commit bd1c13b
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 48 deletions.
Binary file added netlify/edge-functions/inter-500.ttf
Binary file not shown.
Binary file added netlify/edge-functions/inter-700.ttf
Binary file not shown.
147 changes: 138 additions & 9 deletions netlify/edge-functions/og.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,156 @@ import React from "https://esm.sh/react@18.2.0"
import type { Config } from "@netlify/edge-functions"
import { ImageResponse } from "https://deno.land/x/og_edge/mod.ts"

const WIDTH = 1600
const HEIGHT = 836

type Weight = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
type Style = "normal" | "italic"

const customFonts: Array<{ name: string; weight: Weight; style: Style; fileName: string }> = [
{
name: `Inter`,
weight: 500,
style: `normal`,
fileName: `inter-500.ttf`,
},
{
name: `Inter`,
weight: 700,
style: `normal`,
fileName: `inter-700.ttf`,
},
]

const fonts = Promise.all(customFonts.map((font) => fetch(new URL(`./${font.fileName}`, import.meta.url))))

export default async function handler(req: Request) {
const { searchParams } = new URL(req.url)

const fontsDatas = await fonts

const fontsOptions = fontsDatas.map((fontData, i) => ({
name: customFonts[i].name,
data: fontData,
style: customFonts[i].style,
weight: customFonts[i].weight,
}))

const hasTitle = searchParams.has(`title`)
const title = hasTitle ? (searchParams.get(`title`) as string) : `Digital Garden`
const subTitle = hasTitle ? `Digital Garden` : `Lennart Jörgens`
const lastUpdated = searchParams.get(`lastUpdated`) ?? null
const tags = searchParams.get(`tags`) ?? null

return new ImageResponse(
(
<div
className="parent"
style={{
width: `100%`,
height: `100%`,
display: `flex`,
alignItems: `center`,
fontFamily: `"Inter", sans-serif`,
width: `${WIDTH}px`,
height: `${HEIGHT}px`,
flexDirection: `column`,
justifyContent: `center`,
fontSize: 128,
background: `lavender`,
alignItems: `center`,
position: `relative`,
background: `url(https://www.lekoarts.de/social/digital-garden-template.png?v1)`,
}}
>
Hello World 123!
<div
className="text"
style={{
display: `flex`,
flexDirection: `column`,
textAlign: `center`,
alignItems: `center`,
maxWidth: `1400px`,
}}
>
<h2
className="subtitle"
style={{
display: `flex`,
backgroundImage: `linear-gradient(to bottom, #FFFFFF 0%, #B8C6E9 100%)`,
backgroundClip: `text`,
WebkitBackgroundClip: `text`,
WebkitTextFillColor: `transparent`,
color: `transparent`,
fontSize: `57.33px`,
fontWeight: 500,
marginTop: `0`,
marginBottom: `16px`,
letterSpacing: `0.025em`,
}}
>
{subTitle}
</h2>
<h1
className="title"
style={{
display: `flex`,
wordBreak: `break-word`,
background: `linear-gradient(to bottom, #7AD28D 0%, #1B9C68 100%)`,
backgroundClip: `text`,
WebkitBackgroundClip: `text`,
WebkitTextFillColor: `transparent`,
color: `transparent`,
fontSize: `68.80px`,
fontWeight: 700,
margin: `0`,
lineHeight: 1.15,
}}
>
{title}
</h1>
</div>
{lastUpdated ? (
<div
className="date"
style={{
display: `flex`,
position: `absolute`,
left: `80px`,
bottom: `80px`,
background: `linear-gradient(to bottom, #FFFFFF 0%, #C3F1C3 100%)`,
backgroundClip: `text`,
WebkitBackgroundClip: `text`,
WebkitTextFillColor: `transparent`,
fontSize: `27.65px`,
color: `transparent`,
textAlign: `left`,
}}
>
Last updated: {lastUpdated}
</div>
) : null}
{tags ? (
<div
className="tags"
style={{
display: `flex`,
position: `absolute`,
right: `80px`,
bottom: `80px`,
background: `linear-gradient(to bottom, #FFFFFF 0%, #C3F1C3 100%)`,
backgroundClip: `text`,
WebkitBackgroundClip: `text`,
WebkitTextFillColor: `transparent`,
fontSize: `27.65px`,
color: `transparent`,
textAlign: `left`,
}}
>
Tags: {tags.split(`,`).join(`, `)}
</div>
) : null}
</div>
),
{
width: 1600,
height: 836,
debug: true,
width: WIDTH,
height: HEIGHT,
fonts: fontsOptions,
}
)
}
Expand Down
1 change: 1 addition & 0 deletions src/constants/meta.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export const site = {
defaultOgImage: `/social/default-og-image.png?v=1`,
twitter: `@lekoarts_de`,
defaultGardenOgImage: `/social/digital-garden.png`,
gardenOgEdge: `/og/garden`,
}
92 changes: 53 additions & 39 deletions src/templates/garden.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type DataProps = {
}
}

const GardenTemplate: React.FC<PageProps<DataProps>> = ({ data: { garden }, location: { pathname }, children }) => {
const GardenTemplate: React.FC<PageProps<DataProps>> = ({ data: { garden }, children }) => {
const [hasShareApi, setHasShareApi] = React.useState(false)

React.useEffect(() => {
Expand Down Expand Up @@ -116,44 +116,58 @@ const GardenTemplate: React.FC<PageProps<DataProps>> = ({ data: { garden }, loca

export default GardenTemplate

export const Head: HeadFC<DataProps> = ({ data: { garden } }) => (
<SEO
title={garden.title}
pathname={garden.slug}
description={garden.description ? garden.description : garden.excerpt}
image={garden.image}
>
<meta name="twitter:label1" value="Time To Read" />
<meta name="twitter:data1" value={`${garden.timeToRead} Minutes`} />
<meta name="twitter:label2" value="Tags" />
<meta name="twitter:data2" value={garden.tags.join(`, `)} />
<meta name="article:published_time" content={garden.seoDate} />
<meta name="article:modified_time" content={garden.seoLastUpdated} />
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
article({
isGarden: true,
post: {
title: garden.title,
description: garden.description ? garden.description : garden.excerpt,
slug: garden.slug,
image: garden.image,
date: garden.seoDate,
lastUpdated: garden.seoLastUpdated,
year: garden.yearDate,
},
category: {
name: `Digital Garden`,
slug: `/garden`,
},
})
),
}}
/>
</SEO>
)
export const Head: HeadFC<DataProps> = ({ data: { garden } }) => {
// You can set image in frontmatter to overwrite the default image
// The OG Edge image should not be used in those cases
const hasDefaultOgImage = garden.image === site.defaultGardenOgImage

const ogURL = new URL(site.gardenOgEdge, site.url)
ogURL.searchParams.set(`title`, garden.title)
ogURL.searchParams.set(`lastUpdated`, garden.lastUpdated)
ogURL.searchParams.set(`tags`, garden.tags.join(`,`))

// The image link passed to <SEO /> has to be a relative path as it will prepend the site URL
const ogImage = hasDefaultOgImage ? `${ogURL.pathname}${ogURL.search}` : garden.image

return (
<SEO
title={garden.title}
pathname={garden.slug}
description={garden.description ? garden.description : garden.excerpt}
image={ogImage}
>
<meta name="twitter:label1" value="Time To Read" />
<meta name="twitter:data1" value={`${garden.timeToRead} Minutes`} />
<meta name="twitter:label2" value="Tags" />
<meta name="twitter:data2" value={garden.tags.join(`, `)} />
<meta name="article:published_time" content={garden.seoDate} />
<meta name="article:modified_time" content={garden.seoLastUpdated} />
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(
article({
isGarden: true,
post: {
title: garden.title,
description: garden.description ? garden.description : garden.excerpt,
slug: garden.slug,
image: ogImage,
date: garden.seoDate,
lastUpdated: garden.seoLastUpdated,
year: garden.yearDate,
},
category: {
name: `Digital Garden`,
slug: `/garden`,
},
})
),
}}
/>
</SEO>
)
}

export const query = graphql`
query ($id: String!) {
Expand Down

0 comments on commit bd1c13b

Please sign in to comment.