keystatic icon indicating copy to clipboard operation
keystatic copied to clipboard

Astro images relative paths with nested content

Open Matthijz98 opened this issue 1 year ago • 2 comments

I am trying to add Keystatic to a few Astro sites I manage. But there is one problem I just can not seem to fix asked in the Discord but tought this is a beter place because it is not a config error as far as i know.

I really like and depend on the Astro image component. But in order for the Astro image component to work the imports of the images need to be relative. And after doing some research that can work in Keystatic as well

With a config something like this:

images: {
  directory: 'src/content/kvb1/images',
  publicPath: '../../content/kvb1/images/',
},

I have content collections data like this: image When adding a image to the intro.mdoc the mdoc file in the root of the content collections it work fine without any problem.

image Also Keystatic work fine.

But when trying to add a image to a mdoc file inside a nested folder the uploading works fine image The mdoc file show the images added as:

![](../../content/kvb1/images/techniek/motor-en-aandrijving/binnenboordmotor/thumb.jpg)

but for it to work i should be:

![](../../../../content/kvb1/images/techniek/motor-en-aandrijving/binnenboordmotor/thumb.jpg)

But now Keystatic does not work anymore

Also:

  • when deleting a image that is in a nested folder the image get deleted but the folder structure is not

Matthijz98 avatar Jan 31 '24 10:01 Matthijz98

I hacked my way around it after watching this stream. Still has some problems but seams to work for now:

My key static config:

content: fields.document({
    images: {
        directory: 'src/assets/kvb1/images/',
        publicPath: '/assets/kvb1/images/',
    },
}),

When saving a image with key static it is stored in the assets folder. The markdoc image is added like this:

![](/assets/kvb1/images/intro/KWM11521.jpg)

Then to get the astro image component working i made a custom markdoc image component:

---
import type {ImageMetadata} from 'astro';
const {src, alt, title, __optimizedSrc} = Astro.props
import {Image} from 'astro:assets';

const fixedSrc = '/src' + src // append /src/ because the glob import works from project root

const images = import.meta.glob<{ default: ImageMetadata }>('/src/assets/**/*.{jpeg,jpg,png,gif}')  // use /**/* so it finds nested images

if (!images[fixedSrc]) throw new Error(`"${fixedSrc}" does not exist in glob: "src/assets/**.{jpeg,jpg,png,gif}"`);
---
<figure class="w-fit">
    <Image src={images[fixedSrc]()} alt={alt} class="rounded"
           widths={[800, 1600]}
           sizes={`(max-width: 720px) 800px, (max-width: 1600px) 1600px, ${images[fixedSrc]().width}px`}/>
    <figcaption class="text-center">{title}</figcaption>
</figure>

And then this custom image component is added to the mdoc config

nodes: {
        image:{
            ...nodes.image,
            render: component('./src/components/mdoc/Image.astro'),
            attributes: {
                src: { type: String },
                alt: { type: String },
                title: { type: String },
            },
        },

Some problems this solution still has:

  • The glob import imports all images and does at 10-20% to the build time
  • VScode and Webstorm do not like the image paths that keystatic use so editing outside key static is a bit broken

Matthijz98 avatar Feb 10 '24 10:02 Matthijz98

Hey friends!

After asking the question about nested collections and assets in the Astro Discord, I was pointed to this solution:

Define a path alias in your tsconfig.json like so:

{
  "extends": "astro/tsconfigs/strict",
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "react",
+    "baseUrl": ".",
+    "paths": {
+      "@assets/*": ["src/assets/*"]
+    }
  }
}

...and then, you can set the publicPath to @assets/... for images, and... it will work!

image: fields.object({
  file: fields.image({
    label: 'Image',
    directory: 'src/assets/images',
    publicPath: '@assets/images',
  }),
}),

This will bypass the problem of having to work out how to construct ../../../ segments based on the slug nesting 🔥

simonswiss avatar Feb 15 '24 03:02 simonswiss