- Make constants in schema explicit - Enumerate tag-categories - More i18n utilities - Better anonymous user support without special field - Remove most tuples and unchecked type-casting
130 lines
4.4 KiB
Text
130 lines
4.4 KiB
Text
---
|
||
import type { GetStaticPaths, Page } from "astro";
|
||
import { Image } from "astro:assets";
|
||
import { getCollection } from "astro:content";
|
||
import GalleryLayout from "../../layouts/GalleryLayout.astro";
|
||
import type { CollectionEntry } from "astro:content";
|
||
import { t } from "../../i18n";
|
||
|
||
type Props = {
|
||
page: Page<CollectionEntry<"stories">>;
|
||
};
|
||
|
||
export const getStaticPaths: GetStaticPaths = async ({ paginate }) => {
|
||
const stories = (await getCollection("stories", (story) => !story.data.isDraft && story.data.pubDate)).sort(
|
||
(a, b) => b.data.pubDate!.getTime() - a.data.pubDate!.getTime(),
|
||
);
|
||
return paginate(stories, { pageSize: 30 }) satisfies { props: Props }[];
|
||
};
|
||
|
||
const { page } = Astro.props;
|
||
const totalPages = Math.ceil(page.total / page.size);
|
||
---
|
||
|
||
<GalleryLayout pageTitle="Stories">
|
||
<meta slot="head-description" property="og:description" content={`Bad Manners || ${page.total} stories.`} />
|
||
<h1 class="m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">Stories</h1>
|
||
<p class="my-4">The bulk of my content!</p>
|
||
<p class="text-center font-light text-stone-950 dark:text-white">
|
||
{
|
||
page.start == page.end
|
||
? `Displaying story #${page.start + 1}`
|
||
: `Displaying stories #${page.start + 1}–${page.end + 1}`
|
||
} / {page.total}
|
||
</p>
|
||
<div class="mx-auto mb-6 mt-2 flex w-fit rounded-lg border border-stone-400 dark:border-stone-500">
|
||
{
|
||
page.url.prev && (
|
||
<a class="text-link border-r border-stone-400 px-2 py-1 underline dark:border-stone-500" href={page.url.prev}>
|
||
Previous page
|
||
</a>
|
||
)
|
||
}
|
||
{
|
||
[...Array(totalPages).keys()].map((p) =>
|
||
p + 1 == page.currentPage ? (
|
||
<span class="border-r border-stone-400 px-4 py-1 font-semibold text-stone-900 dark:border-stone-500 dark:text-stone-50">
|
||
{p + 1}
|
||
</span>
|
||
) : (
|
||
<a
|
||
class="text-link border-r border-stone-400 px-2 py-1 underline dark:border-stone-500"
|
||
href={page.url.current.replace(`/${page.currentPage}`, `/${p + 1}`)}
|
||
>
|
||
{p + 1}
|
||
</a>
|
||
),
|
||
)
|
||
}
|
||
{
|
||
page.url.next && (
|
||
<a class="text-link px-2 py-1 underline" href={page.url.next}>
|
||
Next page
|
||
</a>
|
||
)
|
||
}
|
||
</div>
|
||
<ul class="flex flex-wrap items-start justify-center gap-4 text-center md:justify-normal">
|
||
{
|
||
page.data.map((story) => (
|
||
<li class="break-inside-avoid">
|
||
<a
|
||
class="text-link hover:underline focus:underline"
|
||
href={`/stories/${story.slug}`}
|
||
title={t(story.data.lang, "story/warnings", story.data.wordCount, story.data.contentWarning.trim())}
|
||
>
|
||
{story.data.thumbnail ? (
|
||
<div class="flex aspect-square max-w-[192px] justify-center">
|
||
<Image
|
||
class="m-auto"
|
||
src={story.data.thumbnail}
|
||
alt={`Thumbnail for ${story.data.title}`}
|
||
width={192}
|
||
/>
|
||
</div>
|
||
) : null}
|
||
<div class="max-w-[192px] text-sm">
|
||
<span>{story.data.title}</span>
|
||
<br />
|
||
<span class="italic">
|
||
{story.data.pubDate!.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}
|
||
</span>
|
||
</div>
|
||
</a>
|
||
</li>
|
||
))
|
||
}
|
||
</ul>
|
||
<div class="mx-auto my-6 flex w-fit rounded-lg border border-stone-400 dark:border-stone-500">
|
||
{
|
||
page.url.prev && (
|
||
<a class="text-link border-r border-stone-400 px-2 py-1 underline dark:border-stone-500" href={page.url.prev}>
|
||
Previous page
|
||
</a>
|
||
)
|
||
}
|
||
{
|
||
[...Array(totalPages).keys()].map((p) =>
|
||
p + 1 == page.currentPage ? (
|
||
<span class="border-r border-stone-400 px-4 py-1 font-semibold text-stone-900 dark:border-stone-500 dark:text-stone-50">
|
||
{p + 1}
|
||
</span>
|
||
) : (
|
||
<a
|
||
class="text-link border-r border-stone-400 px-2 py-1 underline dark:border-stone-500"
|
||
href={page.url.current.replace(`/${page.currentPage}`, `/${p + 1}`)}
|
||
>
|
||
{p + 1}
|
||
</a>
|
||
),
|
||
)
|
||
}
|
||
{
|
||
page.url.next && (
|
||
<a class="text-link px-2 py-1 underline" href={page.url.next}>
|
||
Next page
|
||
</a>
|
||
)
|
||
}
|
||
</div>
|
||
</GalleryLayout>
|