A Astro blog hosted on Vercel

create image gallery collection and layout

authored by Clayton Cook and committed by Clay 367bea8a a349e42e

Changed files
+148 -1
src
+15 -1
src/content.config.ts
··· 1 1 import { glob } from 'astro/loaders'; 2 2 import { defineCollection, z } from 'astro:content'; 3 + import { image } from './utils'; 3 4 4 5 const blog = defineCollection({ 5 6 // Load Markdown and MDX files in the `src/content/blog/` directory. ··· 19 20 }), 20 21 }); 21 22 22 - export const collections = { blog }; 23 + const gallery = defineCollection({ 24 + loader: image('./src/content/gallery'), 25 + schema: ({ image }) => z.object({ 26 + title: z.string(), 27 + artist: z.string(), 28 + alt: z.string(), 29 + path: z.string(), 30 + image: image(), 31 + width: z.number(), 32 + height: z.number() 33 + }), 34 + }); 35 + 36 + export const collections = { blog, gallery };
src/content/gallery/Michigan_in_the_Summer.png

This is a binary file and will not be displayed.

+56
src/layouts/GalleryPost.astro
··· 1 + --- 2 + import type { CollectionEntry } from "astro:content"; 3 + import { Head, Footer, Navigation } from "@/components/organisms"; 4 + import { Image } from "astro:assets"; 5 + import SpeedInsights from "@vercel/speed-insights/astro"; 6 + import Analytics from "@vercel/analytics/astro"; 7 + 8 + type Props = CollectionEntry<"gallery">["data"]; 9 + 10 + const { title, alt, image, width, height } = Astro.props; 11 + --- 12 + 13 + <html lang="en"> 14 + <head> 15 + <Head title={title} description={alt} /> 16 + <style> 17 + article { 18 + display: flex; 19 + flex-direction: column; 20 + width: 100%; 21 + gap: 1rem; 22 + } 23 + 24 + h1 { 25 + margin-bottom: 0; 26 + } 27 + 28 + img { 29 + height: 100%; 30 + width: 100%; 31 + object-fit: contain; 32 + } 33 + </style> 34 + </head> 35 + 36 + <body data-theme="dark"> 37 + <Navigation /> 38 + <main> 39 + <article> 40 + <h1>{title}</h1> 41 + <a href={image.src}> 42 + <Image 43 + src={image} 44 + alt={alt} 45 + width={width} 46 + height={height} 47 + /> 48 + </a> 49 + <p>{alt}</p> 50 + </article> 51 + <Footer /> 52 + <SpeedInsights /> 53 + <Analytics /> 54 + </main> 55 + </body> 56 + </html>
+22
src/pages/gallery/[...slug].astro
··· 1 + --- 2 + import { type CollectionEntry, getCollection } from "astro:content"; 3 + import BlogPost from "@/layouts/BlogPost.astro"; 4 + import { render } from "astro:content"; 5 + import GalleryPost from "@/layouts/GalleryPost.astro"; 6 + 7 + export async function getStaticPaths() { 8 + const gallery = await getCollection("gallery"); 9 + return gallery.map((image) => ({ 10 + params: { 11 + slug: image.data.title.toLowerCase().replaceAll(" ", "-"), 12 + }, 13 + props: image, 14 + })); 15 + } 16 + type Props = CollectionEntry<"gallery">; 17 + 18 + const post = Astro.props; 19 + const { Content } = await render(post); 20 + --- 21 + 22 + <GalleryPost {...post.data} />
+55
src/pages/gallery/index.astro
··· 1 + --- 2 + import { 3 + Head, 4 + Footer, 5 + Navigation, 6 + BlogPreviewCard, 7 + } from "@/components/organisms"; 8 + import { SITE_TITLE, SITE_DESCRIPTION } from "@/consts"; 9 + import { getCollection } from "astro:content"; 10 + import SpeedInsights from "@vercel/speed-insights/astro"; 11 + import Analytics from "@vercel/analytics/astro"; 12 + 13 + const gallery = await getCollection("gallery"); 14 + --- 15 + 16 + <!doctype html> 17 + <html lang="en"> 18 + <head> 19 + <Head title={SITE_TITLE} description={SITE_DESCRIPTION} /> 20 + <style> 21 + main > section { 22 + width: 100%; 23 + } 24 + 25 + main > section > ul { 26 + display: flex; 27 + flex-direction: column; 28 + gap: 2rem; 29 + list-style: none; 30 + padding: 0; 31 + } 32 + </style> 33 + </head> 34 + <body data-theme="dark"> 35 + <Navigation /> 36 + <main> 37 + <h1>Gallery</h1> 38 + <section> 39 + { 40 + gallery.length !== 0 && ( 41 + <ul> 42 + {gallery.map((image) => ( 43 + <li>{image}</li> 44 + ))} 45 + </ul> 46 + ) 47 + } 48 + {gallery.length === 0 && <h2>There are no images yet! 😢</h2>} 49 + </section> 50 + </main> 51 + <Footer /> 52 + <SpeedInsights /> 53 + <Analytics /> 54 + </body> 55 + </html>