Skip to content
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

feat: Dynamic og image #1344 #1616

Open
wants to merge 100 commits into
base: v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
c044e22
kickstart dynamic og
vasfvitor Oct 11, 2023
93dc3a3
Update [...path].png.ts
vasfvitor Oct 11, 2023
9d3bef0
abstract breakText()
vasfvitor Oct 11, 2023
2c4b469
og templates (short, long, blog)
vasfvitor Oct 11, 2023
2bc0766
add TODO
vasfvitor Oct 12, 2023
2cc6d5c
set /blog og image png
vasfvitor Oct 12, 2023
4c0cfd2
move ts files to /assets
vasfvitor Oct 12, 2023
e18fe47
Update templates.ts
vasfvitor Oct 12, 2023
7935d48
refactor - remove long/short templates
vasfvitor Oct 12, 2023
5a018ed
feat: blog excerpt optional param
vasfvitor Oct 12, 2023
34e68dc
set font (SF PRO 500)
vasfvitor Oct 13, 2023
6c17be9
kickstart dynamic og
vasfvitor Oct 11, 2023
4022623
Update [...path].png.ts
vasfvitor Oct 11, 2023
fccf10e
abstract breakText()
vasfvitor Oct 11, 2023
60e923d
og templates (short, long, blog)
vasfvitor Oct 11, 2023
8b14324
add TODO
vasfvitor Oct 12, 2023
73f4ee7
set /blog og image png
vasfvitor Oct 12, 2023
833d5a1
move ts files to /assets
vasfvitor Oct 12, 2023
c372881
Update templates.ts
vasfvitor Oct 12, 2023
dc769c3
refactor - remove long/short templates
vasfvitor Oct 12, 2023
a756f1d
feat: blog excerpt optional param
vasfvitor Oct 12, 2023
8832790
set font (SF PRO 500)
vasfvitor Oct 13, 2023
df5e31e
Merge branch 'dynamic-og-images' of https://github.com/vasfvitor/taur…
vasfvitor Oct 13, 2023
1210ddb
sanitize frontmatter
vasfvitor Oct 13, 2023
05af38e
override head
vasfvitor Oct 14, 2023
53fca0f
remove comment (fixed issue)
vasfvitor Oct 14, 2023
204d853
fix: png output size to match svg's
vasfvitor Oct 14, 2023
a45dd74
font config
vasfvitor Oct 17, 2023
f8c9e93
fix: font config path
vasfvitor Oct 17, 2023
a4dc0ff
add reference
vasfvitor Oct 24, 2023
f5f60e3
add todo
vasfvitor Oct 24, 2023
569ee21
refactor: OG head logic
vasfvitor Oct 24, 2023
f65de16
fix: trailing slash :+1: and edge cases
vasfvitor Oct 25, 2023
edffcbe
move const to utils
vasfvitor Oct 25, 2023
a153089
revert: move const to utils
vasfvitor Oct 25, 2023
b993510
basic setup astro-og-canvas
vasfvitor Nov 12, 2023
ec974ed
temp
vasfvitor Nov 28, 2023
95b4894
Update [...docs].ts
vasfvitor Nov 30, 2023
afd3d05
Update Head.astro
vasfvitor Nov 30, 2023
2f0dcc5
move files around
vasfvitor Nov 30, 2023
068d977
00 hack
vasfvitor Nov 30, 2023
7285217
Merge branch 'next' into dynamic-og-images
vasfvitor Dec 15, 2023
e57a436
Merge branch 'og-canvas-modified' into dynamic-og-images
vasfvitor Dec 15, 2023
7d671ac
undo first draft changes
vasfvitor Dec 15, 2023
f7fbecf
resolve conflicts
vasfvitor Dec 15, 2023
3f0d50b
done background
vasfvitor Dec 15, 2023
d03c769
patch extra field (for blog post date)
vasfvitor Dec 15, 2023
f574e70
patch force logo to bottom right on ltr
vasfvitor Dec 15, 2023
1066e6d
removed head prop on config
vasfvitor Dec 15, 2023
32c6b33
Update pnpm-lock.yaml
vasfvitor Dec 15, 2023
e57b2a6
bit cleanup
vasfvitor Dec 15, 2023
247986d
add comments on 00 hack
vasfvitor Dec 15, 2023
a2a2ad8
change to use unchached image
vasfvitor Dec 15, 2023
01d1009
Revert "change to use unchached image"
vasfvitor Dec 15, 2023
f18295c
add fonts and change sizes
vasfvitor Dec 16, 2023
3e1bbf2
add preview page at `/preview`
vasfvitor Dec 20, 2023
ebfd535
Delete NotoSans_Condensed-Bold.ttf
vasfvitor Dec 20, 2023
5f518df
improve font size strategy and add comments
vasfvitor Dec 20, 2023
13ac3aa
use env var
vasfvitor Dec 20, 2023
2d3dfb4
Update [...docs].ts
vasfvitor Dec 20, 2023
d9f14a6
undo patch-1
vasfvitor Dec 21, 2023
2c623fa
undo patch-2
vasfvitor Dec 21, 2023
ee3fe94
update config without patch
vasfvitor Dec 21, 2023
e4f9df7
Update [...docs].ts
vasfvitor Dec 21, 2023
8786bf8
logo size
vasfvitor Dec 23, 2023
cd7fbf0
font Inter, 2 lines, trim
vasfvitor Dec 23, 2023
ffa021b
remove unused date function
vasfvitor Dec 23, 2023
8f205fc
update comments
vasfvitor Dec 23, 2023
72b37d4
Merge branch 'next' into dynamic-og-images
vasfvitor Dec 23, 2023
747f882
Noto Sans SC
vasfvitor Dec 23, 2023
de25f46
use Noto Sans non variable
vasfvitor Dec 24, 2023
e478bda
remove font files
vasfvitor Dec 24, 2023
210c8c4
Create _open-graph-files.md
vasfvitor Dec 24, 2023
49d3d73
reduce length to fix one image
vasfvitor Jan 2, 2024
a48dc91
format
vasfvitor Jan 2, 2024
b25db9b
remove preview page
vasfvitor Jan 2, 2024
24830b4
skip og on non production builds
vasfvitor Jan 2, 2024
bed1eae
Merge branch 'next' into dynamic-og-images
vasfvitor Jan 2, 2024
bebeb96
build og on local dev
vasfvitor Jan 2, 2024
d6a787d
Merge branch 'dynamic-og-images' of https://github.com/vasfvitor/taur…
vasfvitor Jan 2, 2024
60c97dd
Merge branch 'next' into dynamic-og-images
vasfvitor Feb 24, 2024
a1a614f
Update pnpm-lock.yaml
vasfvitor Feb 24, 2024
684abe1
Merge branch 'next' into dynamic-og-images
vasfvitor Feb 24, 2024
239495b
Update pnpm-lock.yaml
vasfvitor Feb 24, 2024
bacb77e
Update astro.config.mjs
vasfvitor Jul 12, 2024
3edc067
Update package.json
vasfvitor Jul 12, 2024
c0419a7
Update pnpm-lock.yaml
vasfvitor Jul 12, 2024
5f2f8dc
Update astro.config.mjs
vasfvitor Jul 12, 2024
c595656
Merge branch 'dynamic-og-images' of https://github.com/vasfvitor/taur…
vasfvitor Jul 12, 2024
4f05919
Revert "Update astro.config.mjs"
vasfvitor Jul 12, 2024
3b5e846
Revert "Update package.json"
vasfvitor Jul 12, 2024
051b5a3
Revert "Update pnpm-lock.yaml"
vasfvitor Jul 12, 2024
ca398cd
Merge branch 'v2' into dynamic-og-images
vasfvitor Jul 12, 2024
404908a
Update pnpm-lock.yaml
vasfvitor Jul 12, 2024
41a2151
format
vasfvitor Jul 13, 2024
3954ad7
Update astro.config.mjs
vasfvitor Jul 13, 2024
1b2b8e0
better text fitting and ...
vasfvitor Jul 13, 2024
452d553
override head
vasfvitor Jul 13, 2024
49669c1
Create preview.astro
vasfvitor Jul 13, 2024
050fa32
add is:inline
vasfvitor Jul 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 2 additions & 27 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -92,38 +92,13 @@ export default defineConfig({
rss: `${site}/rss`,
},
components: {
Head: 'src/components/overrides/Head.astro',
Header: './src/components/overrides/Header.astro',
Footer: 'src/components/overrides/Footer.astro',
ThemeSelect: 'src/components/overrides/ThemeSelect.astro',
PageFrame: 'src/components/overrides/PageFrame.astro',
},
head: [
{
tag: 'meta',
attrs: { property: 'og:image', content: site + '/og.png?v=1' },
},
{
tag: 'meta',
attrs: { property: 'twitter:image', content: site + '/og.png?v=1' },
},
{
tag: 'script',
attrs: {
src: '/navigate.js',
},
},
{
tag: 'link',
attrs: {
rel: 'manifest',
href: '/manifest.json',
},
},
{
tag: 'meta',
attrs: { name: 'theme-color', content: '#181818' },
},
],
// head: moved to Head.astro override
editLink: {
baseUrl:
process.env.NODE_ENV === 'development'
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
"preview": "astro preview"
},
"dependencies": {
"@fontsource-variable/inter": "^5.0.16",
"@fontsource/noto-sans-sc": "^5.0.17",
"@astrojs/markdown-remark": "^5.0.0",
"@astrojs/rss": "^4.0.5",
"@astrojs/starlight": "^0.24.0",
Expand All @@ -29,6 +31,8 @@
"astro": "^4.4.4",
"astro-d2": "^0.3.0",
"astro-feelback": "^0.3.4",
"astro-og-canvas": "^0.4.2",
"canvaskit-wasm": "^0.39.1",
"astrojs-service-worker": "^2.0.0",
"jsdom": "^24.0.0",
"prettier": "^3.2.5",
Expand Down
52 changes: 52 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added src/assets/og-bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/og-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions src/components/overrides/Head.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
/** TODO: Check how to override the current metatag 'content' instead
* so that the settings on @file astro.config can be utilized along
* without conflicts.
*
* Tested with these (from Starlight source @file head.astro) but couldn't get around getting the
* default head into a format to pass into the @function createHead
* (virtual needs /// <reference path="../node_modules/@astrojs/starlight/virtual.d.ts"/> on @file env.ts)
*
* ---
* import { createHead } from 'node_modules/@astrojs/starlight/utils/head';
* import config from 'virtual:starlight/user-config';
* const head = createHead(headDefaults, config.head, data.head);
* ---
* {head.map(({ tag: Tag, attrs, content }) => <Tag {...attrs} set:html={content} />)}
*
*/

import type { Props } from '@astrojs/starlight/props';
import Default from '@astrojs/starlight/components/Head.astro';

import { getOgImageUrl } from 'src/utils/getOgImageUrl';

const { isFallback } = Astro.props;
const ogImageUrl = getOgImageUrl(Astro.url.pathname, !!isFallback);
const imageSrc = ogImageUrl ?? 'og.png';

let canonicalImageSrc = new URL(imageSrc, Astro.site);

// Override URL for development environment
const isDev = import.meta.env.DEV;
if (isDev) {
canonicalImageSrc = new URL(imageSrc, Astro.url);
}
---

<Default {...Astro.props}><slot /></Default>

<!-- og-images -->
<meta property="og:image" content={canonicalImageSrc} />
<meta name="twitter:image" content={canonicalImageSrc} />

<!-- other -->
<script is:inline src="/navigate.js"></script>
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#181818" />
9 changes: 9 additions & 0 deletions src/pages/0/0.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { allPages } from '../../utils/content';

// https://github.com/withastro/docs/blob/main/src/pages/0/0.ts
// https://www.github.com/withastro/docs/pull/4266/commits/030073f32d6dfe586c6e1da8d48d6b5485541ba2

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't find an issue, can we open one to point to so we know when this hack may be replaced by an improved implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

export function GET() {
allPages[0];
return new Response('');
}
110 changes: 110 additions & 0 deletions src/pages/open-graph/[...docs].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import type { CollectionEntry } from 'astro:content';
import { OGImageRoute } from 'astro-og-canvas';
import { allPages } from 'src/utils/content';

// setup rtlLanguages here
const rtlLanguages = new Set(['']);
const getLangFromSlug = (slug: CollectionEntry<'docs'>['slug']) => slug.split('/')[0];

/** Paths for all of our Markdown content we want to generate OG images for. */
const paths = process.env.CONTEXT == 'production' || import.meta.env.DEV ? allPages : [];
// const paths = allPages // use this to build locally

/** An object mapping file paths to file metadata. */
const pages = Object.fromEntries(paths.map(({ id, slug, data }) => [id, { data, slug }]));

/**
* TODO: This can be improved
* Helper function to clamp a string
* @returns A string that fits in two lines with "..." at the end if text is longer than MAX_LEN
*/
function clampTwoLines(txt: string, fontSize: number): string {
// those numbers are what more or less fit to description and title size, not precisely
// it can vary based on font, as of now it matches Inter.
// Maybe this can help? https://github.com/adambisek/string-pixel-width/blob/master/src/pixelWidthCalculator.html
// or this https://github.com/Evgenus/js-server-text-width
let MAX_LEN = 73;
// title:
if (fontSize > 60) {
MAX_LEN = 48;
}
if (txt.length > MAX_LEN) {
txt = txt.trim().substring(0, MAX_LEN).trim();
txt[txt.length - 1] === '.' ? (txt += '..') : (txt += '...');
}
const arTxt = breakText(txt, 2, 80 / 2);
return arTxt.join('');
}

function breakText(str: string, maxLines: number, maxLineLen: number) {
const segmenterTitle = new Intl.Segmenter('en-US', { granularity: 'word' });
const segments = segmenterTitle.segment(str);

let linesOut = [''];
let lineNo = 0;
let offsetInLine = 0;
for (const word of Array.from(segments)) {
if (offsetInLine + word.segment.length >= maxLineLen) {
lineNo++;
offsetInLine = 0;
linesOut.push('');
}

if (lineNo >= maxLines) {
return linesOut.slice(0, maxLines);
}

linesOut[lineNo] += word.segment;
offsetInLine += word.segment.length;
}

return linesOut;
}

// REFERENCE:
// https://github.com/delucis/astro-og-canvas/tree/latest/packages/astro-og-canvas
export const { getStaticPaths, GET } = OGImageRoute({
param: 'docs',
pages,
getImageOptions: async (_, { data, slug }: (typeof pages)[string]) => {
/** titleSize and descSize are coupled with @function clampTwoLines() */
let [titleSize, descSize] = [72, 48];
let description = '';
let title = clampTwoLines(data.title, titleSize);
if (data.description) {
description = clampTwoLines(data.description, descSize);
}
if (slug.startsWith('blog/') && data.date && data.excerpt) {
description = clampTwoLines(data.excerpt, descSize);
}
return {
title,
description,
dir: rtlLanguages.has(getLangFromSlug(slug)) ? 'rtl' : 'ltr',
padding: 66,
bgImage: { path: './src/assets/og-bg.png' },
logo: { path: './src/assets/og-logo.png' },
font: {
title: {
/** Size is coupled with @function clampTwoLines() */
size: titleSize,
lineHeight: 1.25,
weight: 'Normal',
families: ['Inter', 'Noto Sans SC Thin'],
},
description: {
/** Size is coupled with @function clampTwoLines() */
size: descSize,
lineHeight: 1.25,
weight: 'Normal',
families: ['Inter', 'Noto Sans SC Thin'],
},
},
fonts: [
'./node_modules/@fontsource-variable/inter/files/inter-latin-standard-normal.woff2',
// simplified chinese
'./node_modules/@fontsource/noto-sans-sc/files/noto-sans-sc-chinese-simplified-400-normal.woff2',
],
};
},
});
11 changes: 11 additions & 0 deletions src/pages/open-graph/_open-graph-files.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Open Graph files:

```sh
src/assets/og-bg.png - Background image
src/assets/og-logo.png - Logo image
src/components/overrides/Head.astro - Head override to inject social metatags
src/pages/0/0.ts - Chris\'s "00 hack" to make it work in Starlight in this specific setup
src/utils/content.ts - Export docs collection
src/utils/getOgImageUrl.ts - Used in the head override to get the url for current page
src/pages/open-graph/[...docs].ts - Customize and generate each image and rtlLanguages
```
Loading
Loading