Search code examples
javascriptastrojsdynamic-routing

AstroJs: Is it possible to have multiple returns inside getStaticPaths()?


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.


Solution

  • 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:

    Create a collection

    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,
    };
    

    Generate the pages using getStaticPaths

    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/