I am working with Astro. The project uses quite a few images, and I want to simplify the way I currently add new images. My routes are like:
example/pictures/[collection]
( "[" and "]" stands for a dynamic route )
Allowing for example:
example/pictures/mixed-tecnique
example/pictures/graphite
example/pictures/acrylic
In the file pages/pictures/[collection].astro
I want to do the following (or something similar):
---
import * as collections from "public/img/collections"
const { collection } = Astro.props
---
{collections[collection].map(imgSrc => <img src={imgSrc} />)}
So now, to have a new Collection route, I just have to create a new folder and drop the images there.
Is there any way to do something to reach the same result? Thanks in advance!!
I am working with Astro. The project uses quite a few images, and I want to simplify the way I currently add new images. My routes are like:
example./pictures/[collection]
( "[" and "]" stands for a dynamic route )
Allowing for example:
example./pictures/mixed-tecnique
example./pictures/graphite
example./pictures/acrylic
In the file pages/pictures/[collection].astro
I want to do the following (or something similar):
---
import * as collections from "public/img/collections"
const { collection } = Astro.props
---
{collections[collection].map(imgSrc => <img src={imgSrc} />)}
So now, to have a new Collection route, I just have to create a new folder and drop the images there.
Is there any way to do something to reach the same result? Thanks in advance!!
Share Improve this question edited Feb 28, 2024 at 5:56 VLAZ 29.1k9 gold badges62 silver badges84 bronze badges asked Jan 15, 2023 at 15:24 Genaro BonavitaGenaro Bonavita 711 silver badge3 bronze badges3 Answers
Reset to default 12This is how I achieve:
---
const images = await Astro.glob("/src/assets/img/salon/*").then(files => {
return files.map(file => file.default);
});
---
<div class="swiper">
<!-- Additional required wrapper -->
<div class="swiper-wrapper">
<!-- Slides -->
{
images.map(image => (
<div class="flex items-center justify-center swiper-slide">
<img
class="object-contain h-full rounded-lg"
src={image}
alt=""
loading="lazy"
/>
</div>
))
}
</div>
...
</div>
If you are using experimental assets feature:
{
images.map(({ src /* width and height is also available */ }) => (
<div class="flex items-center justify-center swiper-slide">
<img
class="object-contain h-full rounded-lg"
src={src}
alt=""
loading="lazy"
/>
</div>
))
}
There are a bunch of different ways to implement a feature like this but here is a simple example making use of the fast-glob
library
public
pictures
mixed-technique
example.png
example.png
example.png
graphite
example.png
example.png
example.png
arcylic
example.png
example.png
example.png
// src/pages/pictures/[collection].astro
---
import fg from 'fast-glob';
export async function getStaticPaths() {
// get all collection folder paths: 'public/pictures/[collection]'
const collections: string[] = fg.sync('public/pictures/*', { onlyDirectories: true })
// Create a new route for every collection
return collections.map(collection => {
// Create Route
return {
params: {
// Return folder name of collection as dynamic parameter [collection]
collection: collection.split('/').pop()
},
props: {
// Return array of all image srcs in collection as prop 'images'
images: fg.sync(`${collection}/**/*.{png,jpg}`).map(img => img.replace('public/', '/'))
}
}
})
}
export interface Props {
images: string[];
}
const { collection } = Astro.params
const { images } = Astro.props
---
<html lang="en">
<head>
<!-- ... -->
</head>
<body>
{ images.map(img => <img src={img}/>) }
</body>
</html>
Note: I used
fast-glob
instead ofAstro.glob
orimport.meta.glob()
because it can take a variable as an argument (makes this logic easier/more dynamic) and because it only returns an array of file/folder paths instead of also attempting to return file content
---
import { Image } from 'astro:assets';
const imageFiles = await Astro.glob('./images/*');
---
<div class="columns-1 sm:columns-2 md:columns-3 lg:columns-4 gap-3 mb-5 mx-auto w-full px-4">
{
imageFiles.map((img) => (
<Image
src={img.default}
width="600"
alt="Photo of a pizza"
class="mb-3 w-full rounded"
/>
))
}
</div>