-
Notifications
You must be signed in to change notification settings - Fork 4
feat(seo): dynamic OG images #101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+481
−11
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
6f4a200
Initial prototype
WarningImHack3r c1be525
Fix stuff, more HTML
WarningImHack3r f0b9059
Merge branch 'main' into dynamic-og-images
WarningImHack3r 0f0929d
Upgrade satori
WarningImHack3r c3a7f04
Merge branch 'main' into dynamic-og-images
WarningImHack3r 9dab72f
Merge branch 'main' into dynamic-og-images
WarningImHack3r dc70a6c
Merge branch 'main' into dynamic-og-images
WarningImHack3r 9df5abb
fix lockfile
WarningImHack3r 5571591
update satori
WarningImHack3r 2135546
feat(server): use GH app instead of a raw token
WarningImHack3r 94550a4
Merge branch 'main' into dynamic-og-images
WarningImHack3r 7d6ba4d
Update README.md
WarningImHack3r c2b60f9
Merge branch 'main' into dynamic-og-images
WarningImHack3r 9aa0dde
Merge branch 'main' into dynamic-og-images
WarningImHack3r 428f6c1
Merge branch 'main' into dynamic-og-images
WarningImHack3r 5c1e2a4
finalize design, fix CSS issues
WarningImHack3r afa84b8
Merge branch 'main' into dynamic-og-images
WarningImHack3r df219cb
add another Svelte logo in the background
WarningImHack3r 7f05142
implement og for all pages
WarningImHack3r effcb7c
fix hf link
WarningImHack3r 6693382
remove unused url param
WarningImHack3r 9d0ce3f
add cache control header
WarningImHack3r 0246597
fix case
WarningImHack3r 90a3f41
fix lint
WarningImHack3r File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,25 @@ | ||
import type { MetaTagsProps } from "svelte-meta-tags"; | ||
|
||
export function load({ data }) { | ||
export function load({ data, url }) { | ||
return { | ||
...data, | ||
pageMetaTags: Object.freeze({ | ||
title: `Detail of ${data.itemMetadata.org}/${data.itemMetadata.repo}#${data.itemMetadata.id}` | ||
title: `Detail of ${data.itemMetadata.org}/${data.itemMetadata.repo}#${data.itemMetadata.id}`, | ||
openGraph: { | ||
images: [ | ||
{ | ||
get url() { | ||
const ogUrl = new URL("og", url.origin); | ||
ogUrl.searchParams.set("title", data.item.info.title); | ||
ogUrl.searchParams.set( | ||
"description", | ||
`${data.itemMetadata.org}/${data.itemMetadata.repo}#${data.itemMetadata.id}` | ||
); | ||
return ogUrl.href; | ||
} | ||
} | ||
] | ||
} | ||
}) satisfies MetaTagsProps | ||
}; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { render } from "svelte/server"; | ||
import { read } from "$app/server"; | ||
import DMSerifDisplay from "@fontsource/dm-serif-display/files/dm-serif-display-latin-400-normal.woff"; | ||
import Pretendard from "@fontsource/pretendard/files/pretendard-latin-400-normal.woff"; | ||
import PretendardSemibold from "@fontsource/pretendard/files/pretendard-latin-600-normal.woff"; | ||
import { Resvg } from "@resvg/resvg-js"; | ||
import satori from "satori"; | ||
import { html } from "satori-html"; | ||
import type { RequestHandler } from "./$types"; | ||
import Thumbnail from "./Thumbnail.svelte"; | ||
import { OG_HEIGHT, OG_WIDTH } from "./constants"; | ||
|
||
const sansFont = read(Pretendard).arrayBuffer(); | ||
const sansFontSemibold = read(PretendardSemibold).arrayBuffer(); | ||
const displayFont = read(DMSerifDisplay).arrayBuffer(); | ||
|
||
// Sources: https://github.com/huggingface/chat-ui/blob/ebeff50ac0ac4367a8e1a32b46dcc5ac2e8fc43f/src/routes/assistant/%5BassistantId%5D/thumbnail.png/%2Bserver.ts#L44-L82 | ||
// https://geoffrich.net/posts/svelte-social-image/ | ||
export const GET: RequestHandler = async ({ url }) => { | ||
const renderedComponent = render(Thumbnail, { | ||
props: { | ||
title: url.searchParams.get("title") ?? "", | ||
description: url.searchParams.get("description") ?? undefined | ||
} | ||
}); | ||
|
||
const reactLike = html(`<style>${renderedComponent.head}</style>${renderedComponent.body}`); | ||
|
||
const svg = await satori(reactLike, { | ||
width: OG_WIDTH, | ||
height: OG_HEIGHT, | ||
fonts: [ | ||
{ | ||
name: "SansFont", | ||
data: await sansFont, | ||
weight: 400, | ||
style: "normal" | ||
}, | ||
{ | ||
name: "SansFontSemibold", | ||
data: await sansFontSemibold, | ||
weight: 600, | ||
style: "normal" | ||
}, | ||
{ | ||
name: "DisplayFont", | ||
data: await displayFont, | ||
weight: 400, | ||
style: "normal" | ||
} | ||
] | ||
}); | ||
|
||
const png = new Resvg(svg, { | ||
fitTo: { | ||
mode: "original" | ||
} | ||
}) | ||
.render() | ||
.asPng(); | ||
|
||
// `png` is not usable directly inside `new Response()` for some reason, TS says | ||
let bodyData; | ||
if (png instanceof ArrayBuffer) { | ||
bodyData = png; | ||
} else if (png.buffer instanceof ArrayBuffer) { | ||
bodyData = png.buffer; | ||
} else { | ||
bodyData = new Uint8Array(png); | ||
} | ||
|
||
return new Response(bodyData, { | ||
headers: { | ||
"Content-Type": "image/png", | ||
"Cache-Control": "public, max-age=31536000, immutable" | ||
} | ||
}); | ||
}; | ||
WarningImHack3r marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<script lang="ts"> | ||
type Props = { | ||
title: string; | ||
description?: string; | ||
}; | ||
|
||
let { title, description }: Props = $props(); | ||
</script> | ||
|
||
<div class="flex h-full w-full border-b border-orange-600" style:border-bottom-width="32px"> | ||
<img | ||
src="https://raw.githubusercontent.com/sveltejs/branding/master/svelte-logo.svg" | ||
alt="Svelte" | ||
class="absolute -top-40 -right-40 opacity-20" | ||
style:height="150%" | ||
/> | ||
<div class="flex flex-col p-8"> | ||
<div class="flex items-center" style:gap="8"> | ||
<img | ||
src="https://raw.githubusercontent.com/sveltejs/branding/master/svelte-logo.svg" | ||
alt="Svelte" | ||
class="w-16" | ||
/> | ||
<span class="flex text-4xl" style:gap="6"> | ||
<span style:font-family="DisplayFont">Svelte</span> | ||
<span class="text-orange-600" style:font-family="SansFontSemibold">Changelog</span> | ||
</span> | ||
</div> | ||
<div class="my-auto flex flex-col justify-center"> | ||
<p class="text-7xl" style:font-family="DisplayFont">{title}</p> | ||
{#if description} | ||
<p class="text-4xl text-gray-600" style:font-family="SansFont">{description}</p> | ||
{/if} | ||
</div> | ||
</div> | ||
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// Source: https://vercel.com/docs/og-image-generation#technical-details | ||
|
||
export const OG_WIDTH = 1_200; | ||
export const OG_HEIGHT = 630; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,25 @@ | ||
import type { MetaTagsProps } from "svelte-meta-tags"; | ||
|
||
export function load({ data }) { | ||
export function load({ data, url }) { | ||
return { | ||
...data, | ||
pageMetaTags: Object.freeze({ | ||
title: data.currentPackage.pkg.name | ||
title: data.currentPackage.pkg.name, | ||
openGraph: { | ||
images: [ | ||
{ | ||
get url() { | ||
const ogUrl = new URL("og", url.origin); | ||
ogUrl.searchParams.set("title", data.currentPackage.pkg.name); | ||
ogUrl.searchParams.set( | ||
"description", | ||
`${data.currentPackage.repoOwner}/${data.currentPackage.repoName}` | ||
); | ||
return ogUrl.href; | ||
} | ||
} | ||
] | ||
} | ||
}) satisfies MetaTagsProps | ||
}; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,21 @@ | ||
import type { MetaTagsProps } from "svelte-meta-tags"; | ||
|
||
export function load({ data }) { | ||
export function load({ data, url }) { | ||
return { | ||
...data, | ||
pageMetaTags: Object.freeze({ | ||
title: "All Packages" | ||
title: "All Packages", | ||
openGraph: { | ||
images: [ | ||
{ | ||
get url() { | ||
const ogUrl = new URL("og", url.origin); | ||
ogUrl.searchParams.set("title", "All Packages"); | ||
return ogUrl.href; | ||
} | ||
} | ||
] | ||
} | ||
}) satisfies MetaTagsProps | ||
}; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,21 @@ | ||
import type { MetaTagsProps } from "svelte-meta-tags"; | ||
|
||
export function load({ data, params }) { | ||
export function load({ data, params, url }) { | ||
return { | ||
...data, | ||
pageMetaTags: Object.freeze({ | ||
title: `Tracker for ${params.org}/${params.repo}` | ||
title: `Tracker for ${params.org}/${params.repo}`, | ||
openGraph: { | ||
images: [ | ||
{ | ||
get url() { | ||
const ogUrl = new URL("og", url.origin); | ||
ogUrl.searchParams.set("title", `Tracker • ${params.org}/${params.repo}`); | ||
return ogUrl.href; | ||
} | ||
} | ||
] | ||
} | ||
}) satisfies MetaTagsProps | ||
}; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.