feat: use the first image of an article as og:image
This commit is contained in:
		
							parent
							
								
									5ef4dda34e
								
							
						
					
					
						commit
						db09d3bf88
					
				
					 3 changed files with 46 additions and 6 deletions
				
			
		| 
						 | 
					@ -3,7 +3,7 @@ title: 'My Terminal Setup'
 | 
				
			||||||
description: 'A walkthrough of my current terminal configuration'
 | 
					description: 'A walkthrough of my current terminal configuration'
 | 
				
			||||||
pubDate: '2025-06-08'
 | 
					pubDate: '2025-06-08'
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Here's my current terminal setup:
 | 
					Here's my current terminal setup:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Shell: ZSH with Oh My Zsh
 | 
					- Shell: ZSH with Oh My Zsh
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,12 +3,9 @@ import Layout from '../../layouts/Layout.astro';
 | 
				
			||||||
import { getCollection, getEntry } from 'astro:content';
 | 
					import { getCollection, getEntry } from 'astro:content';
 | 
				
			||||||
import Comments from "../../components/Comments.astro";
 | 
					import Comments from "../../components/Comments.astro";
 | 
				
			||||||
import {getImage} from "astro:assets";
 | 
					import {getImage} from "astro:assets";
 | 
				
			||||||
import { unified } from "unified";
 | 
					 | 
				
			||||||
import { select } from "unist-util-select";
 | 
					 | 
				
			||||||
import remarkMdx from "remark-mdx";
 | 
					 | 
				
			||||||
import remarkParse from "remark-parse";
 | 
					 | 
				
			||||||
import {siteConfig} from "../../config";
 | 
					import {siteConfig} from "../../config";
 | 
				
			||||||
import ReplyViaEmail from "../../components/ReplyViaEmail.astro";
 | 
					import ReplyViaEmail from "../../components/ReplyViaEmail.astro";
 | 
				
			||||||
 | 
					import { ExtractFirstImage } from '../../plugins/extract-images';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function getStaticPaths() {
 | 
					export async function getStaticPaths() {
 | 
				
			||||||
  const blogEntries = await getCollection('posts');
 | 
					  const blogEntries = await getCollection('posts');
 | 
				
			||||||
| 
						 | 
					@ -36,8 +33,9 @@ let matchedImage_src;
 | 
				
			||||||
if (matchedImage && !customFeaturedImage) {
 | 
					if (matchedImage && !customFeaturedImage) {
 | 
				
			||||||
    matchedImage_src = await getImage({src: featuredImages[matchedImage], format: 'webp'}) || null;
 | 
					    matchedImage_src = await getImage({src: featuredImages[matchedImage], format: 'webp'}) || null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					const firstImageURL = await ExtractFirstImage(Content,Astro.url.origin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const cover = customFeaturedImage || matchedImage_src?.src || `/post/${slug}/featured.png` || '';
 | 
					const cover = customFeaturedImage || matchedImage_src?.src || firstImageURL || `/post/${slug}/featured.png` || '';
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<Layout
 | 
					<Layout
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/plugins/extract-images.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/plugins/extract-images.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					import {loadRenderers} from "astro:container";
 | 
				
			||||||
 | 
					import {getContainerRenderer as getMDXRenderer} from "@astrojs/mdx";
 | 
				
			||||||
 | 
					import {experimental_AstroContainer as AstroContainer} from "astro/container";
 | 
				
			||||||
 | 
					import {transform, walk} from "ultrahtml";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function ExtractFirstImage(Content, baseUrl = '') {
 | 
				
			||||||
 | 
					    // Load MDX renderer. Other renderers for UI frameworks (e.g. React, Vue, etc.) would need adding here if you were using those.
 | 
				
			||||||
 | 
					    const renderers = await loadRenderers([getMDXRenderer()]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Create a new Astro container that we can render components with.
 | 
				
			||||||
 | 
					    // See https://docs.astro.build/en/reference/container-reference/
 | 
				
			||||||
 | 
					    const container = await AstroContainer.create({renderers});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Use the Astro container to render the content to a string.
 | 
				
			||||||
 | 
					    const rawContent = await container.renderToString(Content);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let firstImageUrl = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The transform function returns a promise, so we need to await it
 | 
				
			||||||
 | 
					    await transform(rawContent.replace(/^<!DOCTYPE html>/, ''), [
 | 
				
			||||||
 | 
					        async (node) => {
 | 
				
			||||||
 | 
					            await walk(node, (node) => {
 | 
				
			||||||
 | 
					                if (node.name === "img" && node.attributes.src) {
 | 
				
			||||||
 | 
					                    // Store the first image URL we find
 | 
				
			||||||
 | 
					                    if (!firstImageUrl) {
 | 
				
			||||||
 | 
					                        firstImageUrl = node.attributes.src.startsWith("/")
 | 
				
			||||||
 | 
					                            ? baseUrl + node.attributes.src
 | 
				
			||||||
 | 
					                            : node.attributes.src;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    // Still update the src attribute if needed
 | 
				
			||||||
 | 
					                    if (node.attributes.src.startsWith("/")) {
 | 
				
			||||||
 | 
					                        node.attributes.src = baseUrl + node.attributes.src;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return node;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Return the URL value, not a Promise
 | 
				
			||||||
 | 
					    return firstImageUrl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue