--- import { Image } from "astro:assets"; import { getCollection, getEntries, type CollectionEntry } from "astro:content"; import GalleryLayout from "@layouts/GalleryLayout.astro"; import { t } from "@i18n"; import UserComponent from "@components/UserComponent.astro"; import { IconNoOneUnder18, IconSquareRSS } from "@components/icons"; type GameWithPubDate = CollectionEntry<"games"> & { data: { pubDate: Date } }; const games = await Promise.all( ((await getCollection("games", (game) => !game.data.isDraft && game.data.pubDate)) as GameWithPubDate[]) .sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime()) .map(async (game) => ({ ...game, authors: await getEntries(game.data.authors), })), ); --- <GalleryLayout pageTitle="Games" class="h-feed"> <Fragment slot="head"> <meta property="og:description" content="Bad Manners || A game that I've gone and done." /> <meta name="description" content="A safe vore videogame created by Bad Manners." /> </Fragment> <h1 class="p-name m-2 text-3xl font-semibold text-stone-800 dark:text-stone-100">Games</h1> <hr class="mb-3 ml-[2px] mt-2 h-[4px] max-w-xs rounded-sm bg-stone-800 dark:bg-stone-100" aria-hidden /> <div class="my-4 flex w-full"> <p class="p-summary grow">A game that I've gone and done.</p> <a class="u-url text-link ml-2 p-1 md:mr-5" href="/games/feed.xml" rel="alternate" title="RSS feed" data-tooltip> <IconSquareRSS width="2rem" height="2rem" /> <span class="sr-only">RSS feed</span> </a> </div> <ul class="my-6 flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal"> { games.map((game, i) => ( <li class="h-entry"> <a class="u-url text-link hover:underline focus:underline" href={`/games/${game.slug}`} title={t(game.data.lang, "game/warnings", game.data.platforms, game.data.contentWarning)} data-tooltip > {game.data.thumbnail ? ( <div class="flex aspect-square max-w-[192px] justify-center"> <Image loading={i < 10 ? "eager" : "lazy"} class="u-photo m-auto" src={game.data.thumbnail} alt={`Thumbnail for ${game.data.title}`} width={192} /> </div> ) : null} <div class="max-w-[192px] text-sm"> <span class="p-name" aria-label="Title"> {game.data.title} </span> <br /> {game.data.isAgeRestricted ? ( <span class="inline-block align-middle" aria-label="Age restricted"> <IconNoOneUnder18 width="1.25rem" height="1.25rem" /> </span> ) : null} <time class="dt-published italic" datetime={game.data.pubDate.toISOString().slice(0, 10)} aria-label="Publish date" > {game.data.pubDate.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })} </time> </div> </a> <div class="sr-only select-none"> <p class="p-category" aria-label="Category"> Game </p> <p class="p-summary" aria-label="Summary"> {t(game.data.lang, "game/warnings", game.data.platforms, game.data.contentWarning)} </p> <p class="p-language" aria-label="Language"> {t(game.data.lang, "language/language")} </p> <div aria-label="Authors"> <span>{game.authors.length == 1 ? "Author:" : "Authors:"}</span> {game.authors.map((author) => ( <UserComponent rel="author" class="p-author" user={author} lang={game.data.lang} /> ))} </div> </div> </li> )) } </ul> </GalleryLayout>