I am working on a project using AstroJS. The goal is to have a few images, a title, and a description appear on a single page following the dynamic routes method using the getStaticPaths function.
Start with Image library
src
images
apple
apple-01.jpg
apple-02.jpg
apple-03.jpg
apple-03.jpg
banana
banana-01.jpg
banana-02.jpg
banana-03.jpg
banana-03.jpg
And page outcome as expected
/page/{path}
------------
{Title}
{Description}
{Image}
{Image}
{Image}
------------
Fortunately, I've succeeded in getting multiple images onto a single page following Bryce Russell's coding example. However, I am struggling to find a way to include the title and description, despite trying some form of Data Passing Props in combination with Bryce Russell's coding example.
This code below is my 8th attempt, and...
// [page].astro
---
import fg from "fast-glob";
export async function getStaticPaths() {
//Data array for titles and description based on image folder name
const labels = [
{page: 'image folder name', title: "Title goes here", desc: "description goes here"},
{page: 'image folder name', title: "Title goes here", desc: "description goes here"}
];
//Create labels (Title and Description) based on [page].astro
return labels.map((label) => {
return {
params: { id: label.page },
props: { title: label.title, desc: label.desc }
};
});
// Get all collection folder paths: 'src/images/[collection]'
const collections: string[] = fg.sync("src/images/*", {
onlyDirectories: true,
});
// Create a new route for every collection
return collections.map((collection) => {
return {
params: { collection: collection.split("/").pop() },
props: {
images: fg.sync(`${collection}/**/*.{png,jpg}`).map((img) => img.replace("", "/")),
},
};
});
}
export interface Props {
images: string[];
}
const { collection } = Astro.params;
const { label } = Astro.params
const { images, title, desc } = Astro.props;
---
<div>
<section>
{title}
{desc}
</section>
<section>
{
images.map((img) => (
<img src={img} loading="lazy" />
))
}
</section>
</div>
Obviously, I've made it so sloppy, and I knew this is not the correct way to do this. Clearly, getStaticPaths() will not allow two returns of .map() in the same function. Unless I am missing something?
As much as I've tried to find solutions, I have looked into Astro docs, attempted to find some tips, examples, or tricks. I am not having any luck.
So I was hoping I could get some help finding solutions and getting a better understanding of how to use getStaticPaths() to collect multiple images and data (title and description) into a single page following a routing path. Unless there is another way to do this? What would you recommend?
Thanks in advance.
As you've discovered, Astro.glob
and import.meta.glob()
don't work if the path contains dynamic parts like the name of something in a collection. But the following works:
Start the fruit
content collection by placing the following in src/content/fruit/apple.yaml
title: 'Apple'
description: 'Appples are awesome.'
images:
- src: './apple-1.jpg'
alt: 'image one desc'
- src: './apple-2.jpg'
alt: 'image two desc'
Don't forget to add the image files, e.g. src/content/fruit/apple-1.jpg
Describe your collection for schema validation and image handling by placing the following in src/content/config.ts
:
import { defineCollection, z } from "astro:content";
// from https://docs.astro.build/en/guides/images/#images-in-content-collections
const fruitCollection = defineCollection({
schema: ({ image }) => z.object({
title: z.string(),
description: z.string(),
images: z.array( z.object({
src: image(),
alt: z.string(),
})),
}),
});
export const collections = {
fruit: fruitCollection,
};
Have Astro generate the pages by placing the following in src/pages/[...slug].astro
:
---
import { Image } from "astro:assets";
import { getCollection } from 'astro:content';
// from https://docs.astro.build/en/tutorials/add-content-collections/#generate-pages-from-a-collection
export async function getStaticPaths() {
const entries = await getCollection('fruit');
return entries.map(entry => ({
params: { slug: entry.id }, props: { entry },
}));
}
const { entry } = Astro.props;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Astro</title>
</head>
<body>
<h1>{entry.data.title}</h1>
<p>{entry.data.description}</p>
{entry.data.images.map(image =>
<Image src={image.src} alt={image.alt} />)}
</body>
</html>
Visit http://localhost:4321/apple/