Add opengraph image generation for projects & blog
This commit is contained in:
		
							parent
							
								
									f98b23e29a
								
							
						
					
					
						commit
						718b3eccae
					
				| 
						 | 
					@ -22,6 +22,8 @@
 | 
				
			||||||
        "@astrojs/tailwind": "^5.1.0",
 | 
					        "@astrojs/tailwind": "^5.1.0",
 | 
				
			||||||
        "@tailwindcss/typography": "^0.5.12",
 | 
					        "@tailwindcss/typography": "^0.5.12",
 | 
				
			||||||
        "astro": "^4.5.16",
 | 
					        "astro": "^4.5.16",
 | 
				
			||||||
 | 
					        "astro-og-canvas": "^0.4.2",
 | 
				
			||||||
 | 
					        "canvaskit-wasm": "^0.39.1",
 | 
				
			||||||
        "clsx": "^2.1.0",
 | 
					        "clsx": "^2.1.0",
 | 
				
			||||||
        "fuse.js": "^7.0.0",
 | 
					        "fuse.js": "^7.0.0",
 | 
				
			||||||
        "sharp": "^0.33.3",
 | 
					        "sharp": "^0.33.3",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,12 @@ dependencies:
 | 
				
			||||||
  astro:
 | 
					  astro:
 | 
				
			||||||
    specifier: ^4.5.16
 | 
					    specifier: ^4.5.16
 | 
				
			||||||
    version: 4.5.16(typescript@5.4.4)
 | 
					    version: 4.5.16(typescript@5.4.4)
 | 
				
			||||||
 | 
					  astro-og-canvas:
 | 
				
			||||||
 | 
					    specifier: ^0.4.2
 | 
				
			||||||
 | 
					    version: 0.4.2(astro@4.5.16)
 | 
				
			||||||
 | 
					  canvaskit-wasm:
 | 
				
			||||||
 | 
					    specifier: ^0.39.1
 | 
				
			||||||
 | 
					    version: 0.39.1
 | 
				
			||||||
  clsx:
 | 
					  clsx:
 | 
				
			||||||
    specifier: ^2.1.0
 | 
					    specifier: ^2.1.0
 | 
				
			||||||
    version: 2.1.0
 | 
					    version: 2.1.0
 | 
				
			||||||
| 
						 | 
					@ -1524,6 +1530,10 @@ packages:
 | 
				
			||||||
    resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==}
 | 
					    resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==}
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /@webgpu/types@0.1.21:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-pUrWq3V5PiSGFLeLxoGqReTZmiiXwY3jRkIG5sLLKjyqNxrwm/04b4nw7LSmGWJcKk59XOM/YRTUwOzo4MMlow==}
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /acorn-jsx@5.3.2(acorn@8.11.3):
 | 
					  /acorn-jsx@5.3.2(acorn@8.11.3):
 | 
				
			||||||
    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
 | 
					    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
 | 
				
			||||||
    peerDependencies:
 | 
					    peerDependencies:
 | 
				
			||||||
| 
						 | 
					@ -1614,6 +1624,18 @@ packages:
 | 
				
			||||||
    hasBin: true
 | 
					    hasBin: true
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /astro-og-canvas@0.4.2(astro@4.5.16):
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-OQsH6Gr2HX9ZRHdVy2OcXVBIPI65WvEtLG/60krnphh8d3ldhuAFunymYaNGcrdSZcYgXkHWejbPt//3qaRidA==}
 | 
				
			||||||
 | 
					    engines: {node: '>=18.14.1'}
 | 
				
			||||||
 | 
					    peerDependencies:
 | 
				
			||||||
 | 
					      astro: ^3.0.0 || ^4.0.0
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      astro: 4.5.16(typescript@5.4.4)
 | 
				
			||||||
 | 
					      canvaskit-wasm: 0.37.2
 | 
				
			||||||
 | 
					      deterministic-object-hash: 2.0.2
 | 
				
			||||||
 | 
					      entities: 4.5.0
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /astro@4.5.16(typescript@5.4.4):
 | 
					  /astro@4.5.16(typescript@5.4.4):
 | 
				
			||||||
    resolution: {integrity: sha512-1nOVsMq2OJiXnG6gO0Y77vTAboGN9nLQSy/8SGazq4h6x+alzbsMbQbArBgvaLzOSUXD0m91XLs3D8bOSuavrQ==}
 | 
					    resolution: {integrity: sha512-1nOVsMq2OJiXnG6gO0Y77vTAboGN9nLQSy/8SGazq4h6x+alzbsMbQbArBgvaLzOSUXD0m91XLs3D8bOSuavrQ==}
 | 
				
			||||||
    engines: {node: '>=18.14.1', npm: '>=6.14.0'}
 | 
					    engines: {node: '>=18.14.1', npm: '>=6.14.0'}
 | 
				
			||||||
| 
						 | 
					@ -1882,6 +1904,16 @@ packages:
 | 
				
			||||||
    resolution: {integrity: sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==}
 | 
					    resolution: {integrity: sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==}
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /canvaskit-wasm@0.37.2:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-212imazRF98gLOTiU4JAXM7xDvaknI7jaPtAg4ETXGW5rLQs6pomgIvVPUSfoKnQVTdGgzj+B4e+/u0Da20aGg==}
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /canvaskit-wasm@0.39.1:
 | 
				
			||||||
 | 
					    resolution: {integrity: sha512-Gy3lCmhUdKq+8bvDrs9t8+qf7RvcjuQn+we7vTVVyqgOVO1UVfHpsnBxkTZw+R4ApEJ3D5fKySl9TU11hmjl/A==}
 | 
				
			||||||
 | 
					    dependencies:
 | 
				
			||||||
 | 
					      '@webgpu/types': 0.1.21
 | 
				
			||||||
 | 
					    dev: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /ccount@2.0.1:
 | 
					  /ccount@2.0.1:
 | 
				
			||||||
    resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
 | 
					    resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
 | 
				
			||||||
    dev: false
 | 
					    dev: false
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
import { ViewTransitions } from "astro:transitions";
 | 
					import { ViewTransitions } from "astro:transitions";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Props {
 | 
					export interface Props {
 | 
				
			||||||
    title: string;
 | 
					    title: string;
 | 
				
			||||||
    description: string;
 | 
					    description: string;
 | 
				
			||||||
    image?: string;
 | 
					    image?: string;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 194 KiB  | 
| 
						 | 
					@ -4,8 +4,15 @@ import BaseHead from "@components/BaseHead.astro";
 | 
				
			||||||
import Header from "@components/Header.astro";
 | 
					import Header from "@components/Header.astro";
 | 
				
			||||||
import Footer from "@components/Footer.astro";
 | 
					import Footer from "@components/Footer.astro";
 | 
				
			||||||
import Drawer from "@components/Drawer.astro";
 | 
					import Drawer from "@components/Drawer.astro";
 | 
				
			||||||
const { title, description } = Astro.props;
 | 
					 | 
				
			||||||
import { SITE } from "@consts";
 | 
					import { SITE } from "@consts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface Props {
 | 
				
			||||||
 | 
					    title: string;
 | 
				
			||||||
 | 
					    description: string;
 | 
				
			||||||
 | 
					    image?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { title, description, image } = Astro.props;
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!doctype html>
 | 
					<!doctype html>
 | 
				
			||||||
| 
						 | 
					@ -14,6 +21,7 @@ import { SITE } from "@consts";
 | 
				
			||||||
        <BaseHead
 | 
					        <BaseHead
 | 
				
			||||||
            title={`${title} | ${SITE.TITLE}`}
 | 
					            title={`${title} | ${SITE.TITLE}`}
 | 
				
			||||||
            description={description}
 | 
					            description={description}
 | 
				
			||||||
 | 
					            {image}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
    </head>
 | 
					    </head>
 | 
				
			||||||
    <body>
 | 
					    <body>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,11 @@ const post = Astro.props;
 | 
				
			||||||
const { title, summary } = post.data;
 | 
					const { title, summary } = post.data;
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<PageLayout title={title} description={summary}>
 | 
					<PageLayout
 | 
				
			||||||
 | 
					    title={title}
 | 
				
			||||||
 | 
					    description={summary}
 | 
				
			||||||
 | 
					    image={"/open-graph/blog/" + post.slug + ".png"}
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
    <TopLayout>
 | 
					    <TopLayout>
 | 
				
			||||||
        <div class="animate">
 | 
					        <div class="animate">
 | 
				
			||||||
            <ArticleTopLayout entry={post} />
 | 
					            <ArticleTopLayout entry={post} />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					import { OGImageRoute } from "astro-og-canvas";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { getCollection } from "astro:content";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const projects = Object.fromEntries(
 | 
				
			||||||
 | 
					    (await getCollection("projects"))
 | 
				
			||||||
 | 
					        .filter((project) => !project.data.draft)
 | 
				
			||||||
 | 
					        .map((project) => [
 | 
				
			||||||
 | 
					            "projects/" + project.slug,
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                title: project.data.title,
 | 
				
			||||||
 | 
					                description: project.data.summary,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ])
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					const blogs = Object.fromEntries(
 | 
				
			||||||
 | 
					    (await getCollection("blog"))
 | 
				
			||||||
 | 
					        .filter((blog) => !blog.data.draft)
 | 
				
			||||||
 | 
					        .map((blog) => [
 | 
				
			||||||
 | 
					            "blog/" + blog.slug,
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                title: blog.data.title,
 | 
				
			||||||
 | 
					                description: blog.data.summary,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ])
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const { getStaticPaths, GET } = OGImageRoute({
 | 
				
			||||||
 | 
					    param: "route",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // A collection of pages to generate images for.
 | 
				
			||||||
 | 
					    // The keys of this object are used to generate the path for that image.
 | 
				
			||||||
 | 
					    pages: {
 | 
				
			||||||
 | 
					        ...projects,
 | 
				
			||||||
 | 
					        ...blogs,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // For each page, this callback will be used to customize the OpenGraph image.
 | 
				
			||||||
 | 
					    getImageOptions: (_, page) => ({
 | 
				
			||||||
 | 
					        title: page.title,
 | 
				
			||||||
 | 
					        description: page.description,
 | 
				
			||||||
 | 
					        bgImage: {
 | 
				
			||||||
 | 
					            path: "./src/images/open-graph-background.png",
 | 
				
			||||||
 | 
					            fit: "cover",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        logo: {
 | 
				
			||||||
 | 
					            path: "./src/images/me.jpg",
 | 
				
			||||||
 | 
					            size: [300],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        // There are a bunch more options you can use here!
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,11 @@ const project = Astro.props;
 | 
				
			||||||
const { title, summary } = project.data;
 | 
					const { title, summary } = project.data;
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<PageLayout title={title} description={summary}>
 | 
					<PageLayout
 | 
				
			||||||
 | 
					    title={title}
 | 
				
			||||||
 | 
					    description={summary}
 | 
				
			||||||
 | 
					    image={"/open-graph/projects/" + project.slug + ".png"}
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
    <TopLayout>
 | 
					    <TopLayout>
 | 
				
			||||||
        <div class="animate">
 | 
					        <div class="animate">
 | 
				
			||||||
            <ArticleTopLayout entry={project} />
 | 
					            <ArticleTopLayout entry={project} />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue