#I need to replace a component in Content Collection renderer How do I do ?

25 messages · Page 1 of 1 (latest)

sage roost
rough gorge
sage roost
#

Yeah I am importing correctly the Content element but adding my custom compontent like this <Content components={{img: Picture }}/> does nothing 😦

#

and typing is not helping me to find is the component is named differently

rough gorge
#

What does your code look like?

sage roost
#

the page looks like this

---
import { getCollection } from 'astro:content';
import Picture from 'components/Picture.astro'
import Article from 'layouts/Article.astro'

export const prerender = true
// 1. Generate a new path for every collection entry
export async function getStaticPaths() {
    const blogEntries = await getCollection('projects');
    return blogEntries.map((entry) => ({
        params: { project: entry.slug }, props: { entry },
    }))
}
// 2. For your template, you can get the entry directly from the prop
const { entry } = Astro.props as Awaited<ReturnType<typeof getStaticPaths>>[0]['props'];
const { Content } = await entry.render();
---
<Article title={entry.data.title} image={[entry.data.image]} description={entry.data.description} link={entry.data.link} breadcrumb={[{text: 'Accueil', href: '/'}, {text: 'Projets', href: '/projets'}, {text: entry.data.title}]}>
    <h1>{entry.data.title}</h1>
    <p class="flex justify-end font-lights my-0">
        {entry.data.created && (
            <span>Sortie initial le {entry.data.created.toLocaleDateString('fr')}</span>
        )}
        <!-- <p>Software updated: {entry.data.updated.toLocaleDateString()}</p> -->
    </p>

    <Content components={{img: Picture }}/>

</Article>

#

and the Picture Component Wrap around both the HTMLImageElement and the Image element of Astro

#

but add features like AVIF and WebP support in a picture element

rough gorge
#

Ahh I see, what does the <Picture> component looks like?

sage roost
#
---
import { getImage } from 'astro:assets'
import AstroUtils from '../libs/AstroUtils'
import { objectOmit } from '@dzeio/object-util'

const formats = [
    'avif',
    'webp'
]

export interface Props extends Omit<astroHTML.JSX.ImgHTMLAttributes, 'src'> {
    src: ImageMetadata | string
    srcDark?: ImageMetadata | string
    width?: number
    height?: number
}

type PictureResult = {
    format: 'new'
    formats: Array<{format: string, img: Awaited<ReturnType<typeof getImage>>}>
    src: Awaited<ReturnType<typeof getImage>>
} | {
    format: 'raw'
    src: string
}

interface Result {
    light: PictureResult
    dark?: PictureResult | undefined
}

async function resolvePicture(image: ImageMetadata | string): Promise<PictureResult> {
    const ext = typeof image === 'string' ? image.substring(image.lastIndexOf('.')) : image.format
    if (ext === 'svg') {
        return {
            format: 'raw',
            src: typeof image === 'string' ? image : image.src
        }
    }

    const imageFormats: Array<{format: string, img: Awaited<ReturnType<typeof getImage>>}> = await Promise.all(
        formats.map(async (it) => ({
            img: await getImage({src: Astro.props.src, format: it, width: Astro.props.width, height: Astro.props.height}),
            format: it
        }))
    )

    const orig = await getImage({src: Astro.props.src, format: ext, width: Astro.props.width, height: Astro.props.height})

    return {
        format: 'new',
        formats: imageFormats,
        src: orig
    }
}

const res = await AstroUtils.wrap<Result>(async () => {
    return {
        light: await resolvePicture(Astro.props.src),
        dark: Astro.props.srcDark ? await resolvePicture(Astro.props.srcDark) : undefined
    }
})

const props = objectOmit(Astro.props, 'src', 'srcDark', 'class')

---

{res.light.format === 'new' && (
    <picture {...props} {...res.light.src.attributes} class:list={[res.light.src.attributes.class, Astro.props.class, {'dark:hidden': res.dark}]}>
        {res.light.formats.map((it) => (
            <source srcset={it.img.src} type={`image/${it.format}`} />
        ))}
        <img src={res.light.src.src} />
    </picture>
) || (
    <img {...props} class:list={[Astro.props.class, {'dark:hidden': res.dark}]} src={res.light.src as string} />
)}

{res.dark && res.dark.format === 'new' && (
    <picture {...props} {...res.dark.src.attributes} class:list={[res.dark.src.attributes.class, Astro.props.class, 'hidden', 'dark:block']}>
        {res.dark.formats.map((it) => (
            <source srcset={it.img.src} type={`image/${it.format}`} />
        ))}
        <img src={res.dark.src.src} />
    </picture>
) || (res.dark && (
    <img {...props} class:list={[Astro.props.class, 'hidden', 'dark:block']} src={res.dark.src as string} />
))}

it's a big boy

#

but it works perfectly in my other places

rough gorge
#

That is weird 🤔, are you able to override other tags like <h1>?

sage roost
#

it doesn't seems to work

#

Changed h2 to the astro file below but it is still an H2 in the rendered HTML

<p class="POKEMON"><slot /></p>
#

the Content Collection rendering is done here src/pages/projets/[project].astro the collection is here src/content/projects

#

also the Picture component is here src\components\Picture.astro

rough gorge
#

Ahh I see the problem, the content collection is using .md files but this is only compatible with .mdx files

sage roost
#

ok, I will try to convert my files to MDX

#

it is working, will it also work for .md files in the future ?

rough gorge
sage roost
#

ok Thanks you very much for your help !

#

I'll check if I go the route of full MDX or try to use remark to update content

#

Just something else, How does the Content Collection works under the hood ? is it using remark to process the files ?
if so is it possible to add some pre processing to change components ?

#

by an integration or something else ?