onwidget / astrowind

⭕️ AstroWind: A free template using Astro 4.0 and Tailwind CSS. Astro starter theme.
https://astrowind.vercel.app
MIT License
3.17k stars 941 forks source link

Using local image as hero image in blog post #516

Open EdwardDeaver opened 1 day ago

EdwardDeaver commented 1 day ago

Hello,

How do you use a local image in the Image front matter field of a blog post?

Astro is telling me import errors.

'Image's and getImage's src parameter must be an imported image or an URL, it cannot be a string filepath.'

adamthewilliam commented 23 hours ago

Hey @EdwardDeaver,

Here is an example of how I have implemented local images with blog posts. My example includes an image which is passed in as a prop to the SinglePost component and an openGraph image which is used in the metadata object.

Example blog post content:

---
publishDate: 2023-08-06T00:00:00Z
author: 
title: 
excerpt: 
image: ~/assets/images/image.png
ogImage: ~/assets/images/open-graph/image.png
tags:
metadata:
  canonical: 
---

Example [...blog].index.astro page:

import type { InferGetStaticPropsType, GetStaticPaths } from 'astro';

import merge from 'lodash.merge';
import type { ImageMetadata } from 'astro';
import Layout from '~/layouts/PageLayout.astro';
import SinglePost from '~/components/blog/SinglePost.astro';
import ToBlogLink from '~/components/blog/ToBlogLink.astro';

import { getCanonical, getPermalink } from '~/utils/permalinks';
import { getStaticPathsBlogPost, blogPostRobots } from '~/utils/blog';
import { findImage } from '~/utils/images';
import type { MetaData } from '~/types';
import RelatedPosts from '~/components/blog/RelatedPosts.astro';

export const prerender = true;

export const getStaticPaths = (async () => {
  return await getStaticPathsBlogPost();
}) satisfies GetStaticPaths;

type Props = InferGetStaticPropsType<typeof getStaticPaths>;

const { post } = Astro.props as Props;

const url = getCanonical(getPermalink(post.permalink, 'post'));
const image = (await findImage(post.image)) as ImageMetadata | string | undefined;
const ogImage = (await findImage(post.ogImage)) as ImageMetadata | string | undefined;

const metadata = merge(
  {
    title: post.title,
    description: post.excerpt,
    robots: {
      index: blogPostRobots?.index,
      follow: blogPostRobots?.follow,
    },
    openGraph: {
      type: 'article',
      ...(ogImage
        ? { images: [{ url: ogImage, width: (image as ImageMetadata)?.width, height: (ogImage as ImageMetadata)?.height }] }
        : {}),
    },
  },
  { ...(post?.metadata ? { ...post.metadata, canonical: post.metadata?.canonical || url } : {}) }
) as MetaData;
---

<Layout metadata={metadata}>
  <SinglePost post={{ ...post, image: image }} url={url}>
    {post.Content ? <post.Content /> : <Fragment set:html={post.content || ''} />}
  </SinglePost>
  <ToBlogLink />
  <RelatedPosts post={post} />
</Layout>