Trying to preview a componentBlock image in the editor
Hey, Im having a hard time figuring this one out!
I'm using Astro. I've created two component blocks that I want to use in blog posts: Youtube Videos, and images. I've been able to preview the youtube videos in my editor without issue, with the help of this video.
But for the life of me, I don't know how to render a preview of the image as well. I've changed my config file from TS to TSX, imported React, etc... and I just can't get a dang image to preview.
Digging through the KeyStatic Docs, I think this organization principle might be relevant...
Regardless of where the posts entries are created, the coverImage image will be generated in public/images/posts/{post-slug}.
My best guess is that, since images must be generated within the same folder as a post (I hope I'm wrong here -- am i?), then there's no way to preview the images since there's no way to dynamically generate the path to the image.
Please tell me I'm wrong. There simply must be a way to preview images within the document editor!
Here's the relevant code (keystatic.config.tsx)
// keystatic.config.tsx
import { config, fields, collection, component } from '@keystatic/core'
import React from 'react'
export default config({
storage: {
kind: 'local',
},
collections: {
posts: collection({
label: 'Posts',
slugField: 'title',
path: 'src/content/posts/*/',
format: { contentField: 'content' },
schema: {
title: fields.slug({ name: { label: 'Title' } }),
content: fields.document({
label: 'Content',
formatting: true,
links: true,
componentBlocks: {
youtubeVideo: component({
label: 'YouTube Video',
preview: ({ fields }) => (
<div style={{ padding: '1rem', backgroundColor: '#f9f9f9' }}>
{fields.youtubeVideoId.value ? (
<iframe
width='100%'
height='315'
src={`https://www.youtube.com/embed/${fields.youtubeVideoId.value}`}
frameBorder='0'
allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'
allowFullScreen
></iframe>
) : (
<p>Please enter a YouTube video ID</p>
)}
<h3>{fields.videoTitle.value}</h3>
<p>{fields.videoDescription.value}</p>
</div>
),
schema: {
youtubeVideoId: fields.text({ label: 'YouTube Video ID' }),
videoTitle: fields.text({ label: 'Video Title' }),
videoDescription: fields.text({ label: 'Video Description' }),
},
}),
astroImage: component({
label: 'Astro Image',
preview: ({ fields }) => {
const image = fields.imageSrc.value
const imageUrl = image
? `content/posts/{post.name}/content/${image.filename}`
: ''
return imageUrl ? (
<img
src={imageUrl}
alt={fields.imageAlt.value || 'Astro Image'}
title={fields.imageTitle.value}
style={{ maxWidth: '100%', height: 'auto' }}
/>
) : (
<p>Please select an image</p>
)
},
schema: {
imageSrc: fields.image({
label: 'Image Source',
directory: 'src/content/posts/*/content',
}),
imageTitle: fields.text({ label: 'Image Title' }),
imageAlt: fields.text({ label: 'Alt Text' }),
},
}),
},
}),
},
}),
},
})
I would appreciate any help very much, I simply must be wrong that this is not possible!
Thank you very much.
I have to admit that the docs are not that clear on it, but at the end of the first paragraph of the "Content components" article ContentView is mentioned. It is a property on almost all content components.
The greater problem is that you are using the deprecated document-field, which is superseeded by the markdoc-/mdx-field; those use the new content components.
Just as a suggestion, I would consider extracting the individual content component definition and placing it in a source file near the astro render component for clarity.