From c044e22ee81bf45fe5d054226e7a4530246e4d9f Mon Sep 17 00:00:00 2001 From: vasfvitor Date: Wed, 11 Oct 2023 12:51:25 -0300 Subject: [PATCH] kickstart dynamic og --- astro.config.mjs | 11 +- src/components/overrides/Head.astro | 18 +++ src/pages/social-images/[...path].png.ts | 134 +++++++++++++++++++++++ 3 files changed, 153 insertions(+), 10 deletions(-) create mode 100644 src/components/overrides/Head.astro create mode 100644 src/pages/social-images/[...path].png.ts diff --git a/astro.config.mjs b/astro.config.mjs index ed31adda2c..a62e28dd91 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -78,17 +78,8 @@ export default defineConfig({ MarkdownContent: 'starlight-blog/overrides/MarkdownContent.astro', Sidebar: 'starlight-blog/overrides/Sidebar.astro', ThemeSelect: 'starlight-blog/overrides/ThemeSelect.astro', + Head: '@components/overrides/Head.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' }, - }, - ], // TODO: Be sure this is updated when the branch is switched editLink: { baseUrl: 'https://github.com/tauri-apps/tauri-docs/edit/next', diff --git a/src/components/overrides/Head.astro b/src/components/overrides/Head.astro new file mode 100644 index 0000000000..756ab4c9c1 --- /dev/null +++ b/src/components/overrides/Head.astro @@ -0,0 +1,18 @@ +--- +import type { Props } from '@astrojs/starlight/props'; +import Default from '@astrojs/starlight/components/Head.astro'; + +const socialImage = new URL( + `/social-images/content/docs${ + Astro.url.pathname == '/' ? '/index' : Astro.url.pathname.replace(/\/$/, '') + }.png`, + Astro.url +); +--- + + + + + diff --git a/src/pages/social-images/[...path].png.ts b/src/pages/social-images/[...path].png.ts new file mode 100644 index 0000000000..380b626995 --- /dev/null +++ b/src/pages/social-images/[...path].png.ts @@ -0,0 +1,134 @@ +// ISSUE: Some pages don't have description field in the frontmatter, but have title. In those cases it is returning undefined written on the OG image. Example: /features/commands/ + +// TODO: Define default or import from somewhere else +const SITE_TITLE = 'Tauri'; +const SITE_DESCRIPTION = 'Tauri is awesome'; + +import { createRequire } from 'module'; + +// We can't import sharp normally because it's a CJS thing and those don't seems to work well with Astro, Vite, everyone +const cjs = createRequire(import.meta.url); +const sharp = cjs('sharp'); + +const blogPosts = Object.fromEntries( + Object.entries(import.meta.glob('../../content/docs/**/*.{md,mdx}')).map(([path, getInfo]) => { + path = path.replaceAll('../', ''); + path = path.replace('.mdx', ''); + path = path.replace('.md', ''); + + return [path, getInfo]; + }) +); + +export async function getStaticPaths() { + const paths = ['index']; + + for (const [path, getInfo] of Object.entries(blogPosts)) { + const info = (await getInfo()) as Record; + + if (!info.frontmatter.draft) { + paths.push(path); + } + } + + return paths.map((path) => ({ params: { path } })); +} + +export async function GET({ params, request }) { + const getInfo = blogPosts[params.path]; + + let template; + if (getInfo) { + const info = (await getInfo()) as Record; + template = createTemplate(info.frontmatter.title, info.frontmatter.description); + } else { + template = createTemplate(SITE_TITLE, SITE_DESCRIPTION); + } + + // Generate our image + const svgBuffer = Buffer.from(template); + const body = await sharp(svgBuffer).resize(1200, 675).png().toBuffer(); + + return new Response(body); +} + +// breaks a string into a set of strings with a maximum length. +// This is used to prevent horizontal text overflow +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; +} + +function createTemplate(title: string, description: string): string { + const [titleFirstLine, titleSecondLine] = breakText(title, 2, 30); + + const [descriptionFirstLine, descriptionSecondLine, descriptionThirdLine] = breakText( + description, + 3, + 40 + ); + // TODO: Make a proper design and revise text layout. + return ` + + + ${titleFirstLine || ''} + ${titleSecondLine || ''} + + ${descriptionFirstLine || ''} + ${descriptionSecondLine || ''} + ${descriptionThirdLine || ''} + TAURI IS AWESOME + + + + + + + + `; +}